Browse Source

Added transform by matrix functions to Plane. Added camera clipping plane support. Added basic reflective+refractive water shader + material.

Lasse Öörni 12 years ago
parent
commit
cadb503976

+ 6 - 1
Bin/CoreData/Shaders/GLSL/Transform.vert

@@ -46,7 +46,12 @@ vec2 GetTexCoord(vec2 texCoord)
 
 
 vec4 GetClipPos(vec3 worldPos)
 vec4 GetClipPos(vec3 worldPos)
 {
 {
-    return cViewProj * vec4(worldPos, 1.0);
+    vec4 ret = cViewProj * vec4(worldPos, 1.0);
+    // While getting the clip coordinate, also automatically set gl_ClipVertex for user clip planes
+    #ifndef GL_ES
+    gl_ClipVertex = ret;
+    #endif
+    return ret;
 }
 }
 
 
 float GetZonePos(vec3 worldPos)
 float GetZonePos(vec3 worldPos)

+ 30 - 0
Bin/CoreData/Shaders/GLSL/Water.frag

@@ -0,0 +1,30 @@
+#include "Uniforms.frag"
+#include "Samplers.frag"
+#include "Fog.frag"
+
+varying vec4 vScreenPos;
+varying vec4 vRefractUV;
+varying vec2 vReflectUV;
+
+uniform float cDistortStrength;
+uniform float cDistortSpeed;
+uniform float cReflectionMix;
+uniform float cRefractionMix;
+uniform vec3 cWaterTint;
+
+void main()
+{
+    vec2 refractUV = vScreenPos.xy / vScreenPos.w;
+    vec2 reflectUV = vReflectUV.xy / vScreenPos.w;
+    float t = vRefractUV.x + vRefractUV.z + cElapsedTimePS * cDistortSpeed;
+    vec2 distort = vec2(-sin(t), cos(t)) * cDistortStrength;
+    refractUV += distort;
+    reflectUV += distort;
+
+    vec3 refract = texture2D(sEnvMap, refractUV).rgb;
+    vec3 reflect = texture2D(sDiffMap, reflectUV).rgb;
+
+    vec3 final = (cRefractionMix * refract + cReflectionMix * reflect) * cWaterTint;
+
+    gl_FragColor = float4(GetFog(final, vRefractUV.w), 1.0);
+}

+ 24 - 0
Bin/CoreData/Shaders/GLSL/Water.vert

@@ -0,0 +1,24 @@
+#include "Uniforms.vert"
+#include "Transform.vert"
+#include "ScreenPos.vert"
+
+varying vec4 vScreenPos;
+varying vec4 vRefractUV;
+varying vec2 vReflectUV;
+
+void main()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    gl_Position = GetClipPos(worldPos);
+    vScreenPos = GetScreenPos(gl_Position);
+    vRefractUV = vec4(worldPos, GetDepth(gl_Position));
+    // GetQuadTexCoord() returns a float2 that is OK for quad rendering; multiply it with output W
+    // coordinate to make it work with arbitrary meshes such as the water plane (perform divide in pixel shader)
+    // Also because the quadTexCoord is based on the clip position, and Y is flipped when rendering to a texture
+    // on OpenGL, must flip again to cancel it out
+    vReflectUV = GetQuadTexCoord(gl_Position);
+    vReflectUV.y = 1.0 - vReflectUV.y;
+    vReflectUV *= gl_Position.w;
+
+}

+ 4 - 0
Bin/CoreData/Shaders/GLSL/Water.xml

@@ -0,0 +1,4 @@
+<shaders>
+    <shader type="vs" />
+    <shader type="ps" />
+</shaders>

+ 48 - 0
Bin/CoreData/Shaders/HLSL/Water.hlsl

@@ -0,0 +1,48 @@
+#include "Uniforms.hlsl"
+#include "Samplers.hlsl"
+#include "Transform.hlsl"
+#include "ScreenPos.hlsl"
+#include "Fog.hlsl"
+
+uniform float cDistortStrength;
+uniform float cDistortSpeed;
+uniform float cReflectionMix;
+uniform float cRefractionMix;
+uniform float3 cWaterTint;
+
+void VS(float4 iPos : POSITION,
+    out float4 oScreenPos : TEXCOORD0,
+    out float4 oRefractUV : TEXCOORD1,
+    out float2 oReflectUV : TEXCOORD2,
+    out float4 oPos : POSITION)
+{
+    float4x3 modelMatrix = iModelMatrix;
+    float3 worldPos = GetWorldPos(modelMatrix);
+    oPos = GetClipPos(worldPos);
+    oScreenPos = GetScreenPos(oPos);
+    oRefractUV = float4(worldPos, GetDepth(oPos));
+    // GetQuadTexCoord() returns a float2 that is OK for quad rendering; multiply it with output W
+    // coordinate to make it work with arbitrary meshes such as the water plane (perform divide in pixel shader)
+    oReflectUV = GetQuadTexCoord(oPos) * oPos.w;
+}
+
+void PS(
+    float4 iScreenPos : TEXCOORD0,
+    float4 iRefractUV : TEXCOORD1,
+    float2 iReflectUV : TEXCOORD2,
+    out float4 oColor : COLOR0)
+{
+    float2 refractUV = iScreenPos.xy / iScreenPos.w;
+    float2 reflectUV = iReflectUV.xy / iScreenPos.w;
+    float t = iRefractUV.x + iRefractUV.z + cElapsedTimePS * cDistortSpeed;
+    float2 distort = float2(-sin(t), cos(t)) * cDistortStrength;
+    refractUV += distort;
+    reflectUV += distort;
+
+    float3 refract = tex2D(sEnvMap, refractUV).rgb;
+    float3 reflect = tex2D(sDiffMap, reflectUV).rgb;
+
+    float3 final = (cRefractionMix * refract + cReflectionMix * reflect) * cWaterTint;
+
+    oColor = float4(GetFog(final, iRefractUV.w), 1.0);
+}

+ 4 - 0
Bin/CoreData/Shaders/HLSL/Water.xml

@@ -0,0 +1,4 @@
+<shaders>
+    <shader type="vs" />
+    <shader type="ps" />
+</shaders>

+ 3 - 0
Bin/CoreData/Techniques/Water.xml

@@ -0,0 +1,3 @@
+<technique>
+    <pass name="refract" vs="Water" ps="Water" />
+</technique>

+ 8 - 0
Bin/Data/Materials/Water.xml

@@ -0,0 +1,8 @@
+<material>
+    <technique name="Techniques/Water.xml" />
+    <parameter name="DistortSpeed" value="5.0" />
+    <parameter name="DistortStrength" value="0.001" />
+    <parameter name="ReflectionMix" value="0.33" />
+    <parameter name="RefractionMix" value="0.66" />
+    <parameter name="WaterTint" value="0.7 0.7 0.9" />
+</material>

+ 40 - 15
Source/Engine/Graphics/Camera.cpp

@@ -73,7 +73,8 @@ Camera::Camera(Context* context) :
     reflectionPlane_(Plane::UP),
     reflectionPlane_(Plane::UP),
     autoAspectRatio_(true),
     autoAspectRatio_(true),
     flipVertical_(false),
     flipVertical_(false),
-    useReflection_(false)
+    useReflection_(false),
+    useClipping_(false)
 {
 {
     reflectionMatrix_ = reflectionPlane_.ReflectionMatrix();
     reflectionMatrix_ = reflectionPlane_.ReflectionMatrix();
 }
 }
@@ -101,7 +102,9 @@ void Camera::RegisterObject(Context* context)
     ATTRIBUTE(Camera, VAR_INT, "View Override Flags", viewOverrideFlags_, VO_NONE, AM_DEFAULT);
     ATTRIBUTE(Camera, VAR_INT, "View Override Flags", viewOverrideFlags_, VO_NONE, AM_DEFAULT);
     REF_ACCESSOR_ATTRIBUTE(Camera, VAR_VECTOR2, "Projection Offset", GetProjectionOffset, SetProjectionOffset, Vector2, Vector2::ZERO, AM_DEFAULT);
     REF_ACCESSOR_ATTRIBUTE(Camera, VAR_VECTOR2, "Projection Offset", GetProjectionOffset, SetProjectionOffset, Vector2, Vector2::ZERO, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Camera, VAR_VECTOR4, "Reflection Plane", GetReflectionPlaneAttr, SetReflectionPlaneAttr, Vector4, Vector4(0.0f, 1.0f, 0.0f, 0.0f), AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Camera, VAR_VECTOR4, "Reflection Plane", GetReflectionPlaneAttr, SetReflectionPlaneAttr, Vector4, Vector4(0.0f, 1.0f, 0.0f, 0.0f), AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(Camera, VAR_VECTOR4, "Clip Plane", GetClipPlaneAttr, SetClipPlaneAttr, Vector4, Vector4(0.0f, 1.0f, 0.0f, 0.0f), AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Camera, VAR_BOOL, "Use Reflection", GetUseReflection, SetUseReflection, bool, false, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Camera, VAR_BOOL, "Use Reflection", GetUseReflection, SetUseReflection, bool, false, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(Camera, VAR_BOOL, "Use Clipping", GetUseClipping, SetUseClipping, bool, false, AM_DEFAULT);
 }
 }
 
 
 void Camera::SetNearClip(float nearClip)
 void Camera::SetNearClip(float nearClip)
@@ -215,15 +218,30 @@ void Camera::SetUseReflection(bool enable)
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 
-void Camera::SetReflectionPlane(const Plane& reflectionPlane)
+void Camera::SetReflectionPlane(const Plane& plane)
 {
 {
-    reflectionPlane_ = reflectionPlane;
+    reflectionPlane_ = plane;
     reflectionMatrix_ = reflectionPlane_.ReflectionMatrix();
     reflectionMatrix_ = reflectionPlane_.ReflectionMatrix();
     viewDirty_ = true;
     viewDirty_ = true;
     frustumDirty_ = true;
     frustumDirty_ = true;
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 
+void Camera::SetUseClipping(bool enable)
+{
+    useClipping_ = enable;
+    projectionDirty_ = true;
+    MarkNetworkUpdate();
+}
+
+void Camera::SetClipPlane(const Plane& plane)
+{
+    clipPlane_ = plane;
+    projectionDirty_ = true;
+    MarkNetworkUpdate();
+}
+
+
 void Camera::SetFlipVertical(bool enable)
 void Camera::SetFlipVertical(bool enable)
 {
 {
     flipVertical_ = enable;
     flipVertical_ = enable;
@@ -373,6 +391,13 @@ Matrix4 Camera::GetProjection(bool apiSpecific) const
 {
 {
     Matrix4 ret(Matrix4::ZERO);
     Matrix4 ret(Matrix4::ZERO);
 
 
+    // Whether to construct matrix using OpenGL or Direct3D clip space convention
+    #ifdef USE_OPENGL
+    bool openGLFormat = apiSpecific;
+    #else
+    bool openGLFormat = false;
+    #endif
+
     if (!orthographic_)
     if (!orthographic_)
     {
     {
         float nearClip = GetNearClip();
         float nearClip = GetNearClip();
@@ -380,15 +405,10 @@ Matrix4 Camera::GetProjection(bool apiSpecific) const
         float w = h / aspectRatio_;
         float w = h / aspectRatio_;
         float q, r;
         float q, r;
 
 
-        if (apiSpecific)
+        if (openGLFormat)
         {
         {
-            #ifdef USE_OPENGL
             q = (farClip_ + nearClip) / (farClip_ - nearClip);
             q = (farClip_ + nearClip) / (farClip_ - nearClip);
             r = -2.0f * farClip_ * nearClip / (farClip_ - nearClip);
             r = -2.0f * farClip_ * nearClip / (farClip_ - nearClip);
-            #else
-            q = farClip_ / (farClip_ - nearClip);
-            r = -q * nearClip;
-            #endif
         }
         }
         else
         else
         {
         {
@@ -411,15 +431,10 @@ Matrix4 Camera::GetProjection(bool apiSpecific) const
         float w = h / aspectRatio_;
         float w = h / aspectRatio_;
         float q, r;
         float q, r;
 
 
-        if (apiSpecific)
+        if (openGLFormat)
         {
         {
-            #ifdef USE_OPENGL
             q = 2.0f / farClip_;
             q = 2.0f / farClip_;
             r = -1.0f;
             r = -1.0f;
-            #else
-            q = 1.0f / farClip_;
-            r = 0.0f;
-            #endif
         }
         }
         else
         else
         {
         {
@@ -554,11 +569,21 @@ void Camera::SetReflectionPlaneAttr(Vector4 value)
     SetReflectionPlane(Plane(value));
     SetReflectionPlane(Plane(value));
 }
 }
 
 
+void Camera::SetClipPlaneAttr(Vector4 value)
+{
+    SetClipPlane(Plane(value));
+}
+
 Vector4 Camera::GetReflectionPlaneAttr() const
 Vector4 Camera::GetReflectionPlaneAttr() const
 {
 {
     return reflectionPlane_.ToVector4();
     return reflectionPlane_.ToVector4();
 }
 }
 
 
+Vector4 Camera::GetClipPlaneAttr() const
+{
+    return clipPlane_.ToVector4();
+}
+
 void Camera::OnNodeSet(Node* node)
 void Camera::OnNodeSet(Node* node)
 {
 {
     if (node)
     if (node)

+ 19 - 4
Source/Engine/Graphics/Camera.h

@@ -76,10 +76,14 @@ public:
     void SetAutoAspectRatio(bool enable);
     void SetAutoAspectRatio(bool enable);
     /// Set projection offset. It needs to be calculated as (offset in pixels) / (viewport dimensions.)
     /// Set projection offset. It needs to be calculated as (offset in pixels) / (viewport dimensions.)
     void SetProjectionOffset(const Vector2& offset);
     void SetProjectionOffset(const Vector2& offset);
-    /// Set reflection mode. The reflection plane is specified in world space.
+    /// Set reflection mode.
     void SetUseReflection(bool enable);
     void SetUseReflection(bool enable);
     /// Set reflection plane in world space for reflection mode.
     /// Set reflection plane in world space for reflection mode.
-    void SetReflectionPlane(const Plane& reflectionPlane);
+    void SetReflectionPlane(const Plane& plane);
+    /// Set whether to use a custom clip plane.
+    void SetUseClipping(bool enable);
+    /// Set custom clipping plane in world space.
+    void SetClipPlane(const Plane& plane);
     /// Set vertical flipping mode. Called internally by View to resolve OpenGL / Direct3D9 rendertarget sampling differences.
     /// Set vertical flipping mode. Called internally by View to resolve OpenGL / Direct3D9 rendertarget sampling differences.
     void SetFlipVertical(bool enable);
     void SetFlipVertical(bool enable);
     
     
@@ -143,6 +147,10 @@ public:
     bool GetUseReflection() const { return useReflection_; }
     bool GetUseReflection() const { return useReflection_; }
     /// Return the reflection plane.
     /// Return the reflection plane.
     const Plane& GetReflectionPlane() const { return reflectionPlane_; }
     const Plane& GetReflectionPlane() const { return reflectionPlane_; }
+    /// Return whether is using a custom clipping plane.
+    bool GetUseClipping() const { return useClipping_; }
+    /// Return the custom clipping plane.
+    const Plane& GetClipPlane() const { return clipPlane_; }
     /// Return vertical flipping mode.
     /// Return vertical flipping mode.
     bool GetFlipVertical() const { return flipVertical_; }
     bool GetFlipVertical() const { return flipVertical_; }
     /// Return whether to reverse culling; affected by vertical flipping and reflection.
     /// Return whether to reverse culling; affected by vertical flipping and reflection.
@@ -162,7 +170,11 @@ public:
     void SetReflectionPlaneAttr(Vector4 value);
     void SetReflectionPlaneAttr(Vector4 value);
     /// Return reflection plane attribute.
     /// Return reflection plane attribute.
     Vector4 GetReflectionPlaneAttr() const;
     Vector4 GetReflectionPlaneAttr() const;
-
+    /// Set clipping plane attribute.
+    void SetClipPlaneAttr(Vector4 value);
+    /// Return clipping plane attribute.
+    Vector4 GetClipPlaneAttr() const;
+    
 protected:
 protected:
     /// Handle node being assigned.
     /// Handle node being assigned.
     virtual void OnNodeSet(Node* node);
     virtual void OnNodeSet(Node* node);
@@ -170,7 +182,6 @@ protected:
     virtual void OnMarkedDirty(Node* node);
     virtual void OnMarkedDirty(Node* node);
     
     
 private:
 private:
-
     /// Cached view matrix.
     /// Cached view matrix.
     mutable Matrix3x4 view_;
     mutable Matrix3x4 view_;
     /// Cached projection matrix.
     /// Cached projection matrix.
@@ -209,6 +220,8 @@ private:
     Vector2 projectionOffset_;
     Vector2 projectionOffset_;
     /// Reflection plane.
     /// Reflection plane.
     Plane reflectionPlane_;
     Plane reflectionPlane_;
+    /// Clipping plane.
+    Plane clipPlane_;
     /// Reflection matrix calculated from the plane.
     /// Reflection matrix calculated from the plane.
     Matrix3x4 reflectionMatrix_;
     Matrix3x4 reflectionMatrix_;
     /// Auto aspect ratio flag.
     /// Auto aspect ratio flag.
@@ -217,6 +230,8 @@ private:
     bool flipVertical_;
     bool flipVertical_;
     /// Reflection mode enabled flag.
     /// Reflection mode enabled flag.
     bool useReflection_;
     bool useReflection_;
+    /// Use custom clip plane flag.
+    bool useClipping_;
 };
 };
 
 
 }
 }

+ 19 - 0
Source/Engine/Graphics/Direct3D9/D3D9Graphics.cpp

@@ -1812,6 +1812,24 @@ void Graphics::SetStencilTest(bool enable, CompareMode mode, StencilOp pass, Ste
     }
     }
 }
 }
 
 
+void Graphics::SetClipPlane(bool enable, const Plane& clipPlane, const Matrix3x4& view, const Matrix4& projection)
+{
+    if (enable != useClipPlane_)
+    {
+        impl_->device_->SetRenderState(D3DRS_CLIPPLANEENABLE, enable ? 1 : 0);
+        useClipPlane_ = enable;
+    }
+    
+    if (enable)
+    {
+        Matrix4 viewProj = projection * view;
+        // Intercept convention needs to be reversed
+        Plane plane = clipPlane;
+        plane.intercept_ *= -1.0f;
+        impl_->device_->SetClipPlane(0, plane.Transformed(viewProj).ToVector4().Data());
+    }
+}
+
 void Graphics::SetStreamFrequency(unsigned index, unsigned frequency)
 void Graphics::SetStreamFrequency(unsigned index, unsigned frequency)
 {
 {
     if (index < MAX_VERTEX_STREAMS && streamFrequencies_[index] != frequency)
     if (index < MAX_VERTEX_STREAMS && streamFrequencies_[index] != frequency)
@@ -2556,6 +2574,7 @@ void Graphics::ResetCachedState()
     stencilRef_ = 0;
     stencilRef_ = 0;
     stencilCompareMask_ = M_MAX_UNSIGNED;
     stencilCompareMask_ = M_MAX_UNSIGNED;
     stencilWriteMask_ = M_MAX_UNSIGNED;
     stencilWriteMask_ = M_MAX_UNSIGNED;
+    useClipPlane_ = false;
     impl_->blendEnable_ = FALSE;
     impl_->blendEnable_ = FALSE;
     impl_->srcBlend_ = D3DBLEND_ONE;
     impl_->srcBlend_ = D3DBLEND_ONE;
     impl_->destBlend_ = D3DBLEND_ZERO;
     impl_->destBlend_ = D3DBLEND_ZERO;

+ 7 - 3
Source/Engine/Graphics/Direct3D9/D3D9Graphics.h

@@ -26,6 +26,7 @@
 #include "Color.h"
 #include "Color.h"
 #include "Image.h"
 #include "Image.h"
 #include "Object.h"
 #include "Object.h"
+#include "Plane.h"
 #include "Rect.h"
 #include "Rect.h"
 #include "GraphicsDefs.h"
 #include "GraphicsDefs.h"
 
 
@@ -34,9 +35,6 @@ namespace Urho3D
 
 
 class Image;
 class Image;
 class IndexBuffer;
 class IndexBuffer;
-class Matrix3;
-class Matrix4;
-class Matrix3x4;
 class GPUObject;
 class GPUObject;
 class GraphicsImpl;
 class GraphicsImpl;
 class RenderSurface;
 class RenderSurface;
@@ -207,6 +205,8 @@ public:
     void SetScissorTest(bool enable, const IntRect& rect);
     void SetScissorTest(bool enable, const IntRect& rect);
     /// Set stencil test.
     /// Set stencil test.
     void SetStencilTest(bool enable, CompareMode mode = CMP_ALWAYS, StencilOp pass = OP_KEEP, StencilOp fail = OP_KEEP, StencilOp zFail = OP_KEEP, unsigned stencilRef = 0, unsigned compareMask = M_MAX_UNSIGNED, unsigned writeMask = M_MAX_UNSIGNED);
     void SetStencilTest(bool enable, CompareMode mode = CMP_ALWAYS, StencilOp pass = OP_KEEP, StencilOp fail = OP_KEEP, StencilOp zFail = OP_KEEP, unsigned stencilRef = 0, unsigned compareMask = M_MAX_UNSIGNED, unsigned writeMask = M_MAX_UNSIGNED);
+    /// Set a custom clipping plane. The plane is specified in world space, but is dependent on the view and projection matrices.
+    void SetClipPlane(bool enable, const Plane& clipPlane = Plane::UP, const Matrix3x4& view = Matrix3x4::IDENTITY, const Matrix4& projection = Matrix4::IDENTITY);
     /// Set vertex buffer stream frequency.
     /// Set vertex buffer stream frequency.
     void SetStreamFrequency(unsigned index, unsigned frequency);
     void SetStreamFrequency(unsigned index, unsigned frequency);
     /// Reset stream frequencies.
     /// Reset stream frequencies.
@@ -340,6 +340,8 @@ public:
     unsigned GetStencilCompareMask() const { return stencilCompareMask_; }
     unsigned GetStencilCompareMask() const { return stencilCompareMask_; }
     /// Return stencil write bitmask.
     /// Return stencil write bitmask.
     unsigned GetStencilWriteMask() const { return stencilWriteMask_; }
     unsigned GetStencilWriteMask() const { return stencilWriteMask_; }
+    /// Return whether a custom clipping plane is in use.
+    bool GetUseClipPlane() const { return useClipPlane_; }
     /// Return stream frequency by vertex buffer index.
     /// Return stream frequency by vertex buffer index.
     unsigned GetStreamFrequency(unsigned index) const;
     unsigned GetStreamFrequency(unsigned index) const;
     /// Return rendertarget width and height.
     /// Return rendertarget width and height.
@@ -553,6 +555,8 @@ private:
     unsigned stencilCompareMask_;
     unsigned stencilCompareMask_;
     /// Stencil write bitmask.
     /// Stencil write bitmask.
     unsigned stencilWriteMask_;
     unsigned stencilWriteMask_;
+    /// Custom clip plane enable flag.
+    bool useClipPlane_;
     /// Default texture filtering mode.
     /// Default texture filtering mode.
     TextureFilterMode defaultTextureFilterMode_;
     TextureFilterMode defaultTextureFilterMode_;
     /// Remembered shader parameter sources.
     /// Remembered shader parameter sources.

+ 32 - 0
Source/Engine/Graphics/OpenGL/OGLGraphics.cpp

@@ -1792,6 +1792,37 @@ void Graphics::SetScissorTest(bool enable, const IntRect& rect)
     }
     }
 }
 }
 
 
+void Graphics::SetClipPlane(bool enable, const Plane& clipPlane, const Matrix3x4& view, const Matrix4& projection)
+{
+    #ifndef GL_ES_VERSION_2_0
+    if (enable != useClipPlane_)
+    {
+        if (enable)
+            glEnable(GL_CLIP_PLANE0);
+        else
+            glDisable(GL_CLIP_PLANE0);
+        useClipPlane_ = enable;
+    }
+    
+    if (enable)
+    {
+        Matrix4 viewProj = projection * view;
+        // Intercept convention needs to be reversed
+        Plane plane = clipPlane;
+        plane.intercept_ *= -1.0f;
+        Vector4 planeVec =  plane.Transformed(viewProj).ToVector4();
+        
+        GLdouble planeData[4];
+        planeData[0] = planeVec.x_;
+        planeData[1] = planeVec.y_;
+        planeData[2] = planeVec.z_;
+        planeData[3] = planeVec.w_;
+        
+        glClipPlane(GL_CLIP_PLANE0, &planeData[0]);
+    }
+    #endif
+}
+
 void Graphics::SetStreamFrequency(unsigned index, unsigned frequency)
 void Graphics::SetStreamFrequency(unsigned index, unsigned frequency)
 {
 {
 }
 }
@@ -2766,6 +2797,7 @@ void Graphics::ResetCachedState()
     stencilCompareMask_ = M_MAX_UNSIGNED;
     stencilCompareMask_ = M_MAX_UNSIGNED;
     stencilWriteMask_ = M_MAX_UNSIGNED;
     stencilWriteMask_ = M_MAX_UNSIGNED;
     lastInstanceOffset_ = 0;
     lastInstanceOffset_ = 0;
+    useClipPlane_ = false;
     impl_->activeTexture_ = 0;
     impl_->activeTexture_ = 0;
     impl_->enabledAttributes_ = 0;
     impl_->enabledAttributes_ = 0;
     impl_->boundFbo_ = impl_->systemFbo_;
     impl_->boundFbo_ = impl_->systemFbo_;

+ 7 - 4
Source/Engine/Graphics/OpenGL/OGLGraphics.h

@@ -27,8 +27,8 @@
 #include "GraphicsDefs.h"
 #include "GraphicsDefs.h"
 #include "HashMap.h"
 #include "HashMap.h"
 #include "Image.h"
 #include "Image.h"
-#include "Matrix3x4.h"
 #include "Object.h"
 #include "Object.h"
+#include "Plane.h"
 #include "Rect.h"
 #include "Rect.h"
 
 
 namespace Urho3D
 namespace Urho3D
@@ -36,9 +36,6 @@ namespace Urho3D
 
 
 class Image;
 class Image;
 class IndexBuffer;
 class IndexBuffer;
-class Matrix3;
-class Matrix4;
-class Matrix3x4;
 class GPUObject;
 class GPUObject;
 class GraphicsImpl;
 class GraphicsImpl;
 class RenderSurface;
 class RenderSurface;
@@ -214,6 +211,8 @@ public:
     void SetScissorTest(bool enable, const IntRect& rect);
     void SetScissorTest(bool enable, const IntRect& rect);
     /// Set stencil test.
     /// Set stencil test.
     void SetStencilTest(bool enable, CompareMode mode = CMP_ALWAYS, StencilOp pass = OP_KEEP, StencilOp fail = OP_KEEP, StencilOp zFail = OP_KEEP, unsigned stencilRef = 0, unsigned compareMask = M_MAX_UNSIGNED, unsigned writeMask = M_MAX_UNSIGNED);
     void SetStencilTest(bool enable, CompareMode mode = CMP_ALWAYS, StencilOp pass = OP_KEEP, StencilOp fail = OP_KEEP, StencilOp zFail = OP_KEEP, unsigned stencilRef = 0, unsigned compareMask = M_MAX_UNSIGNED, unsigned writeMask = M_MAX_UNSIGNED);
+    /// Set a custom clipping plane. The plane is specified in world space, but is dependent on the view and projection matrices.
+    void SetClipPlane(bool enable, const Plane& clipPlane = Plane::UP, const Matrix3x4& view = Matrix3x4::IDENTITY, const Matrix4& projection = Matrix4::IDENTITY);
     /// Set vertex buffer stream frequency. No-op on OpenGL.
     /// Set vertex buffer stream frequency. No-op on OpenGL.
     void SetStreamFrequency(unsigned index, unsigned frequency);
     void SetStreamFrequency(unsigned index, unsigned frequency);
     /// Reset stream frequencies. No-op on OpenGL.
     /// Reset stream frequencies. No-op on OpenGL.
@@ -353,6 +352,8 @@ public:
     unsigned GetStencilCompareMask() const { return stencilCompareMask_; }
     unsigned GetStencilCompareMask() const { return stencilCompareMask_; }
     /// Return stencil write bitmask.
     /// Return stencil write bitmask.
     unsigned GetStencilWriteMask() const { return stencilWriteMask_; }
     unsigned GetStencilWriteMask() const { return stencilWriteMask_; }
+    /// Return whether a custom clipping plane is in use.
+    bool GetUseClipPlane() const { return useClipPlane_; }
     /// Return stream frequency by vertex buffer index. Always returns 0 on OpenGL.
     /// Return stream frequency by vertex buffer index. Always returns 0 on OpenGL.
     unsigned GetStreamFrequency(unsigned index) const { return 0; }
     unsigned GetStreamFrequency(unsigned index) const { return 0; }
     /// Return rendertarget width and height.
     /// Return rendertarget width and height.
@@ -570,6 +571,8 @@ private:
     Matrix3 tempMatrices3_[NUM_TEMP_MATRICES];
     Matrix3 tempMatrices3_[NUM_TEMP_MATRICES];
     /// Temp matrices for transposing shader parameters.
     /// Temp matrices for transposing shader parameters.
     Matrix4 tempMatrices4_[NUM_TEMP_MATRICES];
     Matrix4 tempMatrices4_[NUM_TEMP_MATRICES];
+    /// Custom clip plane enable flag.
+    bool useClipPlane_;
     /// Releasing GPU objects flag.
     /// Releasing GPU objects flag.
     bool releasingGPUObjects_;
     bool releasingGPUObjects_;
 };
 };

+ 7 - 1
Source/Engine/Graphics/View.cpp

@@ -1320,6 +1320,7 @@ void View::ExecuteRenderPathCommands()
                     SetRenderTargets(command);
                     SetRenderTargets(command);
                     SetTextures(command);
                     SetTextures(command);
                     graphics_->SetFillMode(camera_->GetFillMode());
                     graphics_->SetFillMode(camera_->GetFillMode());
+                    graphics_->SetClipPlane(camera_->GetUseClipping(), camera_->GetClipPlane(), camera_->GetView(), camera_->GetProjection());
                     batchQueues_[command.pass_].Draw(this, command.useScissor_, command.markToStencil_);
                     batchQueues_[command.pass_].Draw(this, command.useScissor_, command.markToStencil_);
                 }
                 }
                 break;
                 break;
@@ -1353,6 +1354,7 @@ void View::ExecuteRenderPathCommands()
                         
                         
                         SetTextures(command);
                         SetTextures(command);
                         graphics_->SetFillMode(camera_->GetFillMode());
                         graphics_->SetFillMode(camera_->GetFillMode());
+                        graphics_->SetClipPlane(camera_->GetUseClipping(), camera_->GetClipPlane(), camera_->GetView(), camera_->GetProjection());
                         i->litBatches_.Draw(i->light_, this);
                         i->litBatches_.Draw(i->light_, this);
                     }
                     }
                     
                     
@@ -1368,7 +1370,6 @@ void View::ExecuteRenderPathCommands()
                     PROFILE(RenderLightVolumes);
                     PROFILE(RenderLightVolumes);
                     
                     
                     SetRenderTargets(command);
                     SetRenderTargets(command);
-                    
                     for (Vector<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
                     for (Vector<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
                     {
                     {
                         // If reusing shadowmaps, render each of them before the lit batches
                         // If reusing shadowmaps, render each of them before the lit batches
@@ -1405,6 +1406,7 @@ void View::ExecuteRenderPathCommands()
     graphics_->SetDepthStencil(GetDepthStencil(renderTarget_));
     graphics_->SetDepthStencil(GetDepthStencil(renderTarget_));
     graphics_->SetViewport(viewRect_);
     graphics_->SetViewport(viewRect_);
     graphics_->SetFillMode(FILL_SOLID);
     graphics_->SetFillMode(FILL_SOLID);
+    graphics_->SetClipPlane(false);
 }
 }
 
 
 void View::SetRenderTargets(RenderPathCommand& command)
 void View::SetRenderTargets(RenderPathCommand& command)
@@ -1569,6 +1571,7 @@ void View::RenderQuad(RenderPathCommand& command)
     graphics_->SetDepthTest(CMP_ALWAYS);
     graphics_->SetDepthTest(CMP_ALWAYS);
     graphics_->SetDepthWrite(false);
     graphics_->SetDepthWrite(false);
     graphics_->SetFillMode(FILL_SOLID);
     graphics_->SetFillMode(FILL_SOLID);
+    graphics_->SetClipPlane(false);
     graphics_->SetScissorTest(false);
     graphics_->SetScissorTest(false);
     graphics_->SetStencilTest(false);
     graphics_->SetStencilTest(false);
     
     
@@ -1674,6 +1677,7 @@ void View::BlitFramebuffer(Texture2D* source, RenderSurface* destination, bool d
     graphics_->SetDepthTest(CMP_ALWAYS);
     graphics_->SetDepthTest(CMP_ALWAYS);
     graphics_->SetDepthWrite(depthWrite);
     graphics_->SetDepthWrite(depthWrite);
     graphics_->SetFillMode(FILL_SOLID);
     graphics_->SetFillMode(FILL_SOLID);
+    graphics_->SetClipPlane(false);
     graphics_->SetScissorTest(false);
     graphics_->SetScissorTest(false);
     graphics_->SetStencilTest(false);
     graphics_->SetStencilTest(false);
     graphics_->SetRenderTarget(0, destination);
     graphics_->SetRenderTarget(0, destination);
@@ -2503,6 +2507,7 @@ void View::SetupLightVolumeBatch(Batch& batch)
     graphics_->SetDepthBias(0.0f, 0.0f);
     graphics_->SetDepthBias(0.0f, 0.0f);
     graphics_->SetDepthWrite(false);
     graphics_->SetDepthWrite(false);
     graphics_->SetFillMode(FILL_SOLID);
     graphics_->SetFillMode(FILL_SOLID);
+    graphics_->SetClipPlane(false);
     
     
     if (type != LIGHT_DIRECTIONAL)
     if (type != LIGHT_DIRECTIONAL)
     {
     {
@@ -2545,6 +2550,7 @@ void View::RenderShadowMap(const LightBatchQueue& queue)
     
     
     graphics_->SetColorWrite(false);
     graphics_->SetColorWrite(false);
     graphics_->SetFillMode(FILL_SOLID);
     graphics_->SetFillMode(FILL_SOLID);
+    graphics_->SetClipPlane(false);
     graphics_->SetStencilTest(false);
     graphics_->SetStencilTest(false);
     graphics_->SetRenderTarget(0, shadowMap->GetRenderSurface()->GetLinkedRenderTarget());
     graphics_->SetRenderTarget(0, shadowMap->GetRenderSurface()->GetLinkedRenderTarget());
     graphics_->SetDepthStencil(shadowMap);
     graphics_->SetDepthStencil(shadowMap);

+ 6 - 0
Source/Engine/LuaScript/pkgs/Graphics/Camera.pkg

@@ -25,6 +25,8 @@ class Camera : public Component
     void SetProjectionOffset(const Vector2& offset);
     void SetProjectionOffset(const Vector2& offset);
     void SetUseReflection(bool enable);
     void SetUseReflection(bool enable);
     void SetReflectionPlane(const Plane& reflectionPlane);
     void SetReflectionPlane(const Plane& reflectionPlane);
+    void SetUseClipping(bool enable);
+    void SetClipPlane(const Plane& clipPlane);
 
 
     float GetFarClip() const;
     float GetFarClip() const;
     float GetNearClip() const;
     float GetNearClip() const;
@@ -55,6 +57,8 @@ class Camera : public Component
     const Vector2& GetProjectionOffset() const;
     const Vector2& GetProjectionOffset() const;
     bool GetUseReflection() const;
     bool GetUseReflection() const;
     const Plane& GetReflectionPlane() const;
     const Plane& GetReflectionPlane() const;
+    bool GetUseClipping() const;
+    const Plane& GetClipPlane() const;
 
 
     float GetDistance(const Vector3& worldPos) const;
     float GetDistance(const Vector3& worldPos) const;
     float GetDistanceSquared(const Vector3& worldPos) const;
     float GetDistanceSquared(const Vector3& worldPos) const;
@@ -85,6 +89,8 @@ class Camera : public Component
     tolua_property__get_set Vector2& projectionOffset;
     tolua_property__get_set Vector2& projectionOffset;
     tolua_property__get_set bool useReflection;
     tolua_property__get_set bool useReflection;
     tolua_property__get_set Plane& reflectionPlane;
     tolua_property__get_set Plane& reflectionPlane;
+    tolua_property__get_set bool useClipping;
+    tolua_property__get_set Plane& clipPlane;
     tolua_readonly tolua_property__is_set bool projectionValid;
     tolua_readonly tolua_property__is_set bool projectionValid;
     tolua_readonly tolua_property__get_set Matrix3x4 effectiveWorldTransform;
     tolua_readonly tolua_property__get_set Matrix3x4 effectiveWorldTransform;
 };
 };

+ 1 - 0
Source/Engine/LuaScript/pkgs/Math/MathDefs.pkg

@@ -26,6 +26,7 @@ float Lerp(float lhs, float rhs, float t);
 float Min(float lhs, float rhs);
 float Min(float lhs, float rhs);
 float Max(float lhs, float rhs);
 float Max(float lhs, float rhs);
 float Abs(float value);
 float Abs(float value);
+float Sign(float value);
 float Clamp(float value, float min, float max);
 float Clamp(float value, float min, float max);
 bool Equals(float lhs, float rhs);
 bool Equals(float lhs, float rhs);
 
 

+ 1 - 0
Source/Engine/LuaScript/pkgs/Math/Matrix3x4.pkg

@@ -30,6 +30,7 @@ class Matrix3x4
     void SetScale(float scale);
     void SetScale(float scale);
     
     
     Matrix3 ToMatrix3() const;
     Matrix3 ToMatrix3() const;
+    Matrix4 ToMatrix4() const;
     Matrix3 RotationMatrix() const;
     Matrix3 RotationMatrix() const;
     Vector3 Translation() const;
     Vector3 Translation() const;
     Quaternion Rotation() const;
     Quaternion Rotation() const;

+ 6 - 0
Source/Engine/LuaScript/pkgs/Math/Plane.pkg

@@ -13,10 +13,16 @@ class Plane
     void Define(const Vector3& v0, const Vector3& v1, const Vector3& v2);
     void Define(const Vector3& v0, const Vector3& v1, const Vector3& v2);
     void Define(const Vector3& normal, const Vector3& point);
     void Define(const Vector3& normal, const Vector3& point);
     void Define(const Vector4& plane);
     void Define(const Vector4& plane);
+    void Transform(const Matrix3& transform);
+    void Transform(const Matrix3x4& transform);
+    void Transform(const Matrix4& transform);
 
 
     float Distance(const Vector3& point) const;
     float Distance(const Vector3& point) const;
     Vector3 Reflect(const Vector3& direction) const;
     Vector3 Reflect(const Vector3& direction) const;
     Matrix3x4 ReflectionMatrix() const;
     Matrix3x4 ReflectionMatrix() const;
+    Plane Transformed(const Matrix3& transform) const;
+    Plane Transformed(const Matrix3x4& transform) const;
+    Plane Transformed(const Matrix4& transform) const;
     Vector4 ToVector4() const;
     Vector4 ToVector4() const;
 
 
     Vector3 normal_ @ normal;
     Vector3 normal_ @ normal;

+ 2 - 0
Source/Engine/Math/MathDefs.h

@@ -66,6 +66,8 @@ inline float Min(float lhs, float rhs) { return lhs < rhs ? lhs : rhs; }
 inline float Max(float lhs, float rhs) { return lhs > rhs ? lhs : rhs; }
 inline float Max(float lhs, float rhs) { return lhs > rhs ? lhs : rhs; }
 /// Return absolute value of a float.
 /// Return absolute value of a float.
 inline float Abs(float value) { return value >= 0.0f ? value : -value; }
 inline float Abs(float value) { return value >= 0.0f ? value : -value; }
+/// Return the sign of a float (-1, 0 or 1.)
+inline float Sign(float value) { return value > 0.0f ? 1.0f : (value < 0.0f ? -1.0f : 0.0f); }
 
 
 /// Clamp a float to a range.
 /// Clamp a float to a range.
 inline float Clamp(float value, float min, float max)
 inline float Clamp(float value, float min, float max)

+ 23 - 0
Source/Engine/Math/Matrix3x4.h

@@ -373,6 +373,29 @@ public:
         );
         );
     }
     }
     
     
+    /// Convert to a 4x4 matrix by filling in an identity last row.
+    Matrix4 ToMatrix4() const
+    {
+        return Matrix4(
+            m00_,
+            m01_,
+            m02_,
+            m03_,
+            m10_,
+            m11_,
+            m12_,
+            m13_,
+            m20_,
+            m21_,
+            m22_,
+            m23_,
+            0.0f,
+            0.0f,
+            0.0f,
+            1.0f
+        );
+    }
+    
     /// Return the rotation matrix with scaling removed.
     /// Return the rotation matrix with scaling removed.
     Matrix3 RotationMatrix() const
     Matrix3 RotationMatrix() const
     {
     {

+ 34 - 0
Source/Engine/Math/Plane.cpp

@@ -29,6 +29,21 @@ namespace Urho3D
 // Static initialization order can not be relied on, so do not use Vector3 constants
 // Static initialization order can not be relied on, so do not use Vector3 constants
 const Plane Plane::UP(Vector3(0.0f, 1.0f, 0.0f), Vector3(0.0f, 0.0f, 0.0f));
 const Plane Plane::UP(Vector3(0.0f, 1.0f, 0.0f), Vector3(0.0f, 0.0f, 0.0f));
 
 
+void Plane::Transform(const Matrix3& transform)
+{
+    *this = Transformed(transform);
+}
+
+void Plane::Transform(const Matrix3x4& transform)
+{
+    *this = Transformed(transform);
+}
+
+void Plane::Transform(const Matrix4& transform)
+{
+    *this = Transformed(transform);
+}
+
 Matrix3x4 Plane::ReflectionMatrix() const
 Matrix3x4 Plane::ReflectionMatrix() const
 {
 {
     float negIntercept = -intercept_;
     float negIntercept = -intercept_;
@@ -49,4 +64,23 @@ Matrix3x4 Plane::ReflectionMatrix() const
     );
     );
 }
 }
 
 
+Plane Plane::Transformed(const Matrix3& transform) const
+{
+    Vector3 newNormal = (transform * normal_).Normalized();
+    Vector3 newPoint = newNormal * intercept_;
+    return Plane(newNormal, newPoint);
+}
+
+Plane Plane::Transformed(const Matrix3x4& transform) const
+{
+    Vector3 newNormal = (transform * normal_).Normalized();
+    Vector3 newPoint = transform * (normal_ * intercept_);
+    return Plane(newNormal, newPoint);
+}
+
+Plane Plane::Transformed(const Matrix4& transform) const
+{
+    return Plane(transform.Inverse().Transpose() * ToVector4());
+}
+
 }
 }

+ 13 - 0
Source/Engine/Math/Plane.h

@@ -87,12 +87,25 @@ public:
         intercept_ = plane.w_;
         intercept_ = plane.w_;
     }
     }
     
     
+    /// Transform with a 3x3 matrix.
+    void Transform(const Matrix3& transform);
+    /// Transform with a 3x4 matrix.
+    void Transform(const Matrix3x4& transform);
+    /// Transform with a 4x4 matrix.
+    void Transform(const Matrix4& transform);
+    
     /// Return signed distance to a point.
     /// Return signed distance to a point.
     float Distance(const Vector3& point) const { return normal_.DotProduct(point) - intercept_; }
     float Distance(const Vector3& point) const { return normal_.DotProduct(point) - intercept_; }
     /// Reflect a normalized direction vector.
     /// Reflect a normalized direction vector.
     Vector3 Reflect(const Vector3& direction) const { return direction - (2.0f * normal_.DotProduct(direction) * normal_); }
     Vector3 Reflect(const Vector3& direction) const { return direction - (2.0f * normal_.DotProduct(direction) * normal_); }
     /// Return a reflection matrix.
     /// Return a reflection matrix.
     Matrix3x4 ReflectionMatrix() const;
     Matrix3x4 ReflectionMatrix() const;
+    /// Return transformed by a 3x3 matrix.
+    Plane Transformed(const Matrix3& transform) const;
+    /// Return transformed by a 3x4 matrix.
+    Plane Transformed(const Matrix3x4& transform) const;
+    /// Return transformed by a 4x4 matrix.
+    Plane Transformed(const Matrix4& transform) const;
     /// Return as a vector.
     /// Return as a vector.
     Vector4 ToVector4() const { return Vector4(normal_, intercept_); }
     Vector4 ToVector4() const { return Vector4(normal_, intercept_); }
 
 

+ 4 - 0
Source/Engine/Script/GraphicsAPI.cpp

@@ -101,6 +101,10 @@ static void RegisterCamera(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Camera", "bool get_useReflection() const", asMETHOD(Camera, GetUseReflection), asCALL_THISCALL);
     engine->RegisterObjectMethod("Camera", "bool get_useReflection() const", asMETHOD(Camera, GetUseReflection), asCALL_THISCALL);
     engine->RegisterObjectMethod("Camera", "void set_reflectionPlane(const Plane&in) const", asMETHOD(Camera, SetReflectionPlane), asCALL_THISCALL);
     engine->RegisterObjectMethod("Camera", "void set_reflectionPlane(const Plane&in) const", asMETHOD(Camera, SetReflectionPlane), asCALL_THISCALL);
     engine->RegisterObjectMethod("Camera", "const Plane& get_reflectionPlane() const", asMETHOD(Camera, GetReflectionPlane), asCALL_THISCALL);
     engine->RegisterObjectMethod("Camera", "const Plane& get_reflectionPlane() const", asMETHOD(Camera, GetReflectionPlane), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Camera", "void set_useClipping(bool)", asMETHOD(Camera, SetUseClipping), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Camera", "bool get_useClipping() const", asMETHOD(Camera, GetUseClipping), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Camera", "void set_clipPlane(const Plane&in) const", asMETHOD(Camera, SetClipPlane), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Camera", "const Plane& get_clipPlane() const", asMETHOD(Camera, GetClipPlane), asCALL_THISCALL);
     engine->RegisterObjectMethod("Camera", "void set_viewMask(uint)", asMETHOD(Camera, SetViewMask), asCALL_THISCALL);
     engine->RegisterObjectMethod("Camera", "void set_viewMask(uint)", asMETHOD(Camera, SetViewMask), asCALL_THISCALL);
     engine->RegisterObjectMethod("Camera", "uint get_viewMask() const", asMETHOD(Camera, GetViewMask), asCALL_THISCALL);
     engine->RegisterObjectMethod("Camera", "uint get_viewMask() const", asMETHOD(Camera, GetViewMask), asCALL_THISCALL);
     engine->RegisterObjectMethod("Camera", "void set_viewOverrideFlags(uint)", asMETHOD(Camera, SetViewOverrideFlags), asCALL_THISCALL);
     engine->RegisterObjectMethod("Camera", "void set_viewOverrideFlags(uint)", asMETHOD(Camera, SetViewOverrideFlags), asCALL_THISCALL);

+ 8 - 0
Source/Engine/Script/MathAPI.cpp

@@ -61,6 +61,7 @@ static void RegisterMathFunctions(asIScriptEngine* engine)
     engine->RegisterGlobalFunction("float Atan(float)", asFUNCTION(Atan), asCALL_CDECL);
     engine->RegisterGlobalFunction("float Atan(float)", asFUNCTION(Atan), asCALL_CDECL);
     engine->RegisterGlobalFunction("float Atan2(float, float)", asFUNCTION(Atan2), asCALL_CDECL);
     engine->RegisterGlobalFunction("float Atan2(float, float)", asFUNCTION(Atan2), asCALL_CDECL);
     engine->RegisterGlobalFunction("float Abs(float)", asFUNCTIONPR(Abs, (float), float), asCALL_CDECL);
     engine->RegisterGlobalFunction("float Abs(float)", asFUNCTIONPR(Abs, (float), float), asCALL_CDECL);
+    engine->RegisterGlobalFunction("float Sign(float)", asFUNCTION(Sign), asCALL_CDECL);
     engine->RegisterGlobalFunction("float Sqrt(float)", asFUNCTION(sqrtf), asCALL_CDECL);
     engine->RegisterGlobalFunction("float Sqrt(float)", asFUNCTION(sqrtf), asCALL_CDECL);
     engine->RegisterGlobalFunction("float Pow(float, float)", asFUNCTION(powf), asCALL_CDECL);
     engine->RegisterGlobalFunction("float Pow(float, float)", asFUNCTION(powf), asCALL_CDECL);
     engine->RegisterGlobalFunction("float Min(float, float)", asFUNCTIONPR(Min, (float, float), float), asCALL_CDECL);
     engine->RegisterGlobalFunction("float Min(float, float)", asFUNCTIONPR(Min, (float, float), float), asCALL_CDECL);
@@ -629,6 +630,7 @@ static void RegisterMatrix3x4(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Matrix3x4", "void SetScale(float)", asMETHODPR(Matrix3x4, SetScale, (float), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Matrix3x4", "void SetScale(float)", asMETHODPR(Matrix3x4, SetScale, (float), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Matrix3x4", "void SetTranslation(const Vector3&in)", asMETHODPR(Matrix3x4, SetTranslation, (const Vector3&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Matrix3x4", "void SetTranslation(const Vector3&in)", asMETHODPR(Matrix3x4, SetTranslation, (const Vector3&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Matrix3x4", "Matrix3 ToMatrix3() const", asMETHODPR(Matrix3x4, ToMatrix3, () const, Matrix3), asCALL_THISCALL);
     engine->RegisterObjectMethod("Matrix3x4", "Matrix3 ToMatrix3() const", asMETHODPR(Matrix3x4, ToMatrix3, () const, Matrix3), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Matrix3x4", "Matrix4 ToMatrix4() const", asMETHODPR(Matrix3x4, ToMatrix4, () const, Matrix4), asCALL_THISCALL);
     engine->RegisterObjectMethod("Matrix3x4", "Vector3 Translation() const", asMETHODPR(Matrix3x4, Translation, () const, Vector3), asCALL_THISCALL);
     engine->RegisterObjectMethod("Matrix3x4", "Vector3 Translation() const", asMETHODPR(Matrix3x4, Translation, () const, Vector3), asCALL_THISCALL);
     engine->RegisterObjectMethod("Matrix3x4", "void Decompose(Vector3&, Quaternion&, Vector3&) const", asMETHODPR(Matrix3x4, Decompose, (Vector3&, Quaternion&, Vector3&) const, void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Matrix3x4", "void Decompose(Vector3&, Quaternion&, Vector3&) const", asMETHODPR(Matrix3x4, Decompose, (Vector3&, Quaternion&, Vector3&) const, void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Matrix3x4", "Matrix3x4 Inverse() const", asMETHODPR(Matrix3x4, Inverse, () const, Matrix3x4), asCALL_THISCALL);
     engine->RegisterObjectMethod("Matrix3x4", "Matrix3x4 Inverse() const", asMETHODPR(Matrix3x4, Inverse, () const, Matrix3x4), asCALL_THISCALL);
@@ -683,8 +685,14 @@ static void RegisterPlane(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Plane", "void Define(const Vector3&in, const Vector3&in, const Vector3&in)", asMETHODPR(Plane, Define, (const Vector3&, const Vector3&, const Vector3&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Plane", "void Define(const Vector3&in, const Vector3&in, const Vector3&in)", asMETHODPR(Plane, Define, (const Vector3&, const Vector3&, const Vector3&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Plane", "void Define(const Vector3&in, const Vector3&in)", asMETHODPR(Plane, Define, (const Vector3&, const Vector3&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Plane", "void Define(const Vector3&in, const Vector3&in)", asMETHODPR(Plane, Define, (const Vector3&, const Vector3&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Plane", "void Define(const Vector4&in)", asMETHODPR(Plane, Define, (const Vector4&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Plane", "void Define(const Vector4&in)", asMETHODPR(Plane, Define, (const Vector4&), void), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Plane", "void Transform(const Matrix3&in)", asMETHODPR(Plane, Transform, (const Matrix3&), void), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Plane", "void Transform(const Matrix3x4&in)", asMETHODPR(Plane, Transform, (const Matrix3x4&), void), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Plane", "void Transform(const Matrix4&in)", asMETHODPR(Plane, Transform, (const Matrix4&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Plane", "float Distance(const Vector3&in) const", asMETHOD(Plane, Distance), asCALL_THISCALL);
     engine->RegisterObjectMethod("Plane", "float Distance(const Vector3&in) const", asMETHOD(Plane, Distance), asCALL_THISCALL);
     engine->RegisterObjectMethod("Plane", "Vector3 Reflect(const Vector3&in) const", asMETHOD(Plane, Reflect), asCALL_THISCALL);
     engine->RegisterObjectMethod("Plane", "Vector3 Reflect(const Vector3&in) const", asMETHOD(Plane, Reflect), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Plane", "Plane Transformed(const Matrix3&in) const", asMETHODPR(Plane, Transformed, (const Matrix3&) const, Plane), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Plane", "Plane Transformed(const Matrix3x4&in) const", asMETHODPR(Plane, Transformed, (const Matrix3x4&) const, Plane), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Plane", "Plane Transformed(const Matrix4&in) const", asMETHODPR(Plane, Transformed, (const Matrix4&) const, Plane), asCALL_THISCALL);
     engine->RegisterObjectMethod("Plane", "Vector4 ToVector4() const", asMETHOD(Plane, ToVector4), asCALL_THISCALL);
     engine->RegisterObjectMethod("Plane", "Vector4 ToVector4() const", asMETHOD(Plane, ToVector4), asCALL_THISCALL);
     engine->RegisterObjectMethod("Plane", "Matrix3x4 get_reflectionMatrix() const", asMETHOD(Plane, ReflectionMatrix), asCALL_THISCALL);
     engine->RegisterObjectMethod("Plane", "Matrix3x4 get_reflectionMatrix() const", asMETHOD(Plane, ReflectionMatrix), asCALL_THISCALL);
     engine->RegisterObjectProperty("Plane", "Vector3 normal", offsetof(Plane, normal_));
     engine->RegisterObjectProperty("Plane", "Vector3 normal", offsetof(Plane, normal_));