Browse Source

Allow defining depth bias for materials.
Center decal frustum on the decal world position.
Use material depth bias for decals instead of applying the bias to decal geometry.

Lasse Öörni 13 years ago
parent
commit
478a5af9d1

+ 1 - 0
Bin/Data/Materials/UrhoDecal.xml

@@ -2,4 +2,5 @@
     <technique name="Techniques/DiffAdd.xml" />
     <technique name="Techniques/DiffAdd.xml" />
     <texture unit="diffuse" name="Textures/UrhoDecal.dds" />
     <texture unit="diffuse" name="Textures/UrhoDecal.dds" />
     <parameter name="MatDiffColor" value="1 1 0 1" />
     <parameter name="MatDiffColor" value="1 1 0 1" />
+    <depthbias constant="-0.00001" slopescaled="0" />
 </material>
 </material>

+ 2 - 2
Bin/Data/Scripts/TestScene.as

@@ -429,8 +429,8 @@ void HandleMouseButtonDown(StringHash eventType, VariantMap& eventData)
                         decal.maxVertices = 2048;
                         decal.maxVertices = 2048;
                         decal.maxIndices = 4096;
                         decal.maxIndices = 4096;
                     }
                     }
-                    decal.AddDecal(result.drawable, rayHitPos - cameraNode.worldRotation * Vector3(0, 0, 0.5),
-                        cameraNode.worldRotation, 0.5, 1.0, 1.0, Vector2(0, 0), Vector2(1, 1));
+                    decal.AddDecal(result.drawable, rayHitPos, cameraNode.worldRotation, 0.5, 1.0, 1.0, Vector2(0, 0),
+                        Vector2(1, 1));
                 }
                 }
             }
             }
         }
         }

+ 2 - 2
Bin/Data/Scripts/TestSceneOld.as

@@ -542,8 +542,8 @@ void HandleMouseButtonDown(StringHash eventType, VariantMap& eventData)
                         decal.maxVertices = 2048;
                         decal.maxVertices = 2048;
                         decal.maxIndices = 4096;
                         decal.maxIndices = 4096;
                     }
                     }
-                    decal.AddDecal(result.drawable, rayHitPos - cameraNode.worldRotation * Vector3(0, 0, 0.5),
-                        cameraNode.worldRotation, 0.5, 1.0, 1.0, Vector2(0, 0), Vector2(1, 1));
+                    decal.AddDecal(result.drawable, rayHitPos, cameraNode.worldRotation, 0.5, 1.0, 1.0, Vector2(0, 0),
+                        Vector2(1, 1));
                 }
                 }
             }
             }
         }
         }

+ 2 - 1
Docs/Reference.dox

@@ -569,6 +569,7 @@ A material definition looks like this:
     <parameter ... />
     <parameter ... />
     <cull value="cw|ccw|none" />
     <cull value="cw|ccw|none" />
     <shadowcull value="cw|ccw|none" />
     <shadowcull value="cw|ccw|none" />
+    <depthbias constant="x" slopescaled="y" />
 </material>
 </material>
 \endcode
 \endcode
 
 
@@ -584,7 +585,7 @@ When a material defines several techniques for different LOD levels and quality
 
 
 %Material shader parameters can be floats or vectors up to 4 components. Matrix parameters are not supported.
 %Material shader parameters can be floats or vectors up to 4 components. Matrix parameters are not supported.
 
 
-Default culling mode is counterclockwise. The shadowcull element specifies the culling mode to use in the shadow pass.
+Default culling mode is counterclockwise. The shadowcull element specifies the culling mode to use in the shadow pass. Note that material's depth bias settings do not apply in the shadow pass; during shadow rendering the light's depth bias is used instead.
 
 
 \section Materials_Textures Material textures
 \section Materials_Textures Material textures
 
 

+ 25 - 23
Engine/Engine/GraphicsAPI.cpp

@@ -285,8 +285,30 @@ static Material* MaterialClone(const String& cloneName, Material* ptr)
     return clone.Get();
     return clone.Get();
 }
 }
 
 
+static void ConstructBiasParameters(BiasParameters* ptr)
+{
+    new(ptr) BiasParameters(0.0f, 0.0f);
+}
+
+static void ConstructBiasParametersCopy(BiasParameters& parameters, BiasParameters* ptr)
+{
+    new(ptr) BiasParameters(parameters);
+}
+
+static void ConstructBiasParametersInit(float constantBias, float slopeScaledBias, BiasParameters* ptr)
+{
+    new(ptr) BiasParameters(constantBias, slopeScaledBias);
+}
+
 static void RegisterMaterial(asIScriptEngine* engine)
 static void RegisterMaterial(asIScriptEngine* engine)
 {
 {
+    engine->RegisterObjectType("BiasParameters", sizeof(BiasParameters), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_C);
+    engine->RegisterObjectBehaviour("BiasParameters", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructBiasParameters), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectBehaviour("BiasParameters", asBEHAVE_CONSTRUCT, "void f(const BiasParameters&in)", asFUNCTION(ConstructBiasParametersCopy), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectBehaviour("BiasParameters", asBEHAVE_CONSTRUCT, "void f(float, float)", asFUNCTION(ConstructBiasParametersInit), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectProperty("BiasParameters", "float constantBias", offsetof(BiasParameters, constantBias_));
+    engine->RegisterObjectProperty("BiasParameters", "float slopeScaledBias", offsetof(BiasParameters, slopeScaledBias_));
+    
     engine->RegisterEnum("TextureUnit");
     engine->RegisterEnum("TextureUnit");
     engine->RegisterEnumValue("TextureUnit", "TU_DIFFUSE", TU_DIFFUSE);
     engine->RegisterEnumValue("TextureUnit", "TU_DIFFUSE", TU_DIFFUSE);
     engine->RegisterEnumValue("TextureUnit", "TU_NORMAL", TU_NORMAL);
     engine->RegisterEnumValue("TextureUnit", "TU_NORMAL", TU_NORMAL);
@@ -367,6 +389,8 @@ static void RegisterMaterial(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Material", "CullMode get_cullMode() const", asMETHOD(Material, GetCullMode), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "CullMode get_cullMode() const", asMETHOD(Material, GetCullMode), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "void set_shadowCullMode(CullMode)", asMETHOD(Material, SetShadowCullMode), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "void set_shadowCullMode(CullMode)", asMETHOD(Material, SetShadowCullMode), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "CullMode get_shadowCullMode() const", asMETHOD(Material, GetShadowCullMode), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "CullMode get_shadowCullMode() const", asMETHOD(Material, GetShadowCullMode), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Material", "void set_depthBias(const BiasParameters&in)", asMETHOD(Material, SetDepthBias), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Material", "const BiasParameters& get_depthBias() const", asMETHOD(Material, GetDepthBias), asCALL_THISCALL);
 }
 }
 
 
 static PostProcess* PostProcessClone(PostProcess* ptr)
 static PostProcess* PostProcessClone(PostProcess* ptr)
@@ -440,21 +464,6 @@ static void RegisterDrawable(asIScriptEngine* engine)
     RegisterDrawable<Drawable>(engine, "Drawable");
     RegisterDrawable<Drawable>(engine, "Drawable");
 }
 }
 
 
-static void ConstructBiasParameters(BiasParameters* ptr)
-{
-    new(ptr) BiasParameters(0.0f, 0.0f);
-}
-
-static void ConstructBiasParametersCopy(BiasParameters& parameters, BiasParameters* ptr)
-{
-    new(ptr) BiasParameters(parameters);
-}
-
-static void ConstructBiasParametersInit(float constantBias, float slopeScaledBias, BiasParameters* ptr)
-{
-    new(ptr) BiasParameters(constantBias, slopeScaledBias);
-}
-
 static void ConstructCascadeParameters(CascadeParameters* ptr)
 static void ConstructCascadeParameters(CascadeParameters* ptr)
 {
 {
     new(ptr) CascadeParameters(0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
     new(ptr) CascadeParameters(0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
@@ -492,13 +501,6 @@ static void RegisterLight(asIScriptEngine* engine)
     engine->RegisterEnumValue("LightType", "LIGHT_SPOT", LIGHT_SPOT);
     engine->RegisterEnumValue("LightType", "LIGHT_SPOT", LIGHT_SPOT);
     engine->RegisterEnumValue("LightType", "LIGHT_POINT", LIGHT_POINT);
     engine->RegisterEnumValue("LightType", "LIGHT_POINT", LIGHT_POINT);
     
     
-    engine->RegisterObjectType("BiasParameters", sizeof(BiasParameters), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_C);
-    engine->RegisterObjectBehaviour("BiasParameters", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructBiasParameters), asCALL_CDECL_OBJLAST);
-    engine->RegisterObjectBehaviour("BiasParameters", asBEHAVE_CONSTRUCT, "void f(const BiasParameters&in)", asFUNCTION(ConstructBiasParametersCopy), asCALL_CDECL_OBJLAST);
-    engine->RegisterObjectBehaviour("BiasParameters", asBEHAVE_CONSTRUCT, "void f(float, float)", asFUNCTION(ConstructBiasParametersInit), asCALL_CDECL_OBJLAST);
-    engine->RegisterObjectProperty("BiasParameters", "float constantBias", offsetof(BiasParameters, constantBias_));
-    engine->RegisterObjectProperty("BiasParameters", "float slopeScaledBias", offsetof(BiasParameters, slopeScaledBias_));
-    
     engine->RegisterObjectType("CascadeParameters", sizeof(CascadeParameters), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_C);
     engine->RegisterObjectType("CascadeParameters", sizeof(CascadeParameters), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_C);
     engine->RegisterObjectBehaviour("CascadeParameters", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructCascadeParameters), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectBehaviour("CascadeParameters", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructCascadeParameters), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectBehaviour("CascadeParameters", asBEHAVE_CONSTRUCT, "void f(const CascadeParameters&in)", asFUNCTION(ConstructCascadeParametersCopy), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectBehaviour("CascadeParameters", asBEHAVE_CONSTRUCT, "void f(const CascadeParameters&in)", asFUNCTION(ConstructCascadeParametersCopy), asCALL_CDECL_OBJLAST);
@@ -756,7 +758,7 @@ static void RegisterParticleEmitter(asIScriptEngine* engine)
 static void RegisterDecalSet(asIScriptEngine* engine)
 static void RegisterDecalSet(asIScriptEngine* engine)
 {
 {
     RegisterDrawable<DecalSet>(engine, "DecalSet");
     RegisterDrawable<DecalSet>(engine, "DecalSet");
-    engine->RegisterObjectMethod("DecalSet", "bool AddDecal(Drawable@+, const Vector3&in, const Quaternion&in, float, float, float, const Vector2&in, const Vector2&in, float timeToLive = 0.0, float normalCutoff = 0.1, float depthBias = 0.001, uint subGeometry = 0xffffffff)", asMETHOD(DecalSet, AddDecal), asCALL_THISCALL);
+    engine->RegisterObjectMethod("DecalSet", "bool AddDecal(Drawable@+, const Vector3&in, const Quaternion&in, float, float, float, const Vector2&in, const Vector2&in, float timeToLive = 0.0, float normalCutoff = 0.1, uint subGeometry = 0xffffffff)", asMETHOD(DecalSet, AddDecal), asCALL_THISCALL);
     engine->RegisterObjectMethod("DecalSet", "void RemoveDecals(uint)", asMETHOD(DecalSet, RemoveDecals), asCALL_THISCALL);
     engine->RegisterObjectMethod("DecalSet", "void RemoveDecals(uint)", asMETHOD(DecalSet, RemoveDecals), asCALL_THISCALL);
     engine->RegisterObjectMethod("DecalSet", "void RemoveAllDecals()", asMETHOD(DecalSet, RemoveAllDecals), asCALL_THISCALL);
     engine->RegisterObjectMethod("DecalSet", "void RemoveAllDecals()", asMETHOD(DecalSet, RemoveAllDecals), asCALL_THISCALL);
     engine->RegisterObjectMethod("DecalSet", "void set_material(Material@+)", asMETHOD(DecalSet, SetMaterial), asCALL_THISCALL);
     engine->RegisterObjectMethod("DecalSet", "void set_material(Material@+)", asMETHOD(DecalSet, SetMaterial), asCALL_THISCALL);

+ 10 - 4
Engine/Graphics/Batch.cpp

@@ -26,7 +26,7 @@
 #include "Geometry.h"
 #include "Geometry.h"
 #include "Graphics.h"
 #include "Graphics.h"
 #include "GraphicsImpl.h"
 #include "GraphicsImpl.h"
-#include "Light.h"
+#include "Material.h"
 #include "Node.h"
 #include "Node.h"
 #include "Renderer.h"
 #include "Renderer.h"
 #include "Profiler.h"
 #include "Profiler.h"
@@ -67,7 +67,7 @@ static void SortFrontToBack2Pass(PODVector<Batch*>& batches)
     Sort(batches.Begin(), batches.End(), CompareBatchesFrontToBack);
     Sort(batches.Begin(), batches.End(), CompareBatchesFrontToBack);
     
     
     // Then rewrite distances so that different states will be ordered front to back, and sort again.
     // Then rewrite distances so that different states will be ordered front to back, and sort again.
-    // Do not do this on mobile devices as they likely use a tiled deferred approach, with which 
+    // Do not do this on mobile devices as they likely use a tiled deferred approach, with which
     // front-to-back sorting is irrelevant
     // front-to-back sorting is irrelevant
     #ifndef GL_ES_VERSION_2_0
     #ifndef GL_ES_VERSION_2_0
     float lastDistance;
     float lastDistance;
@@ -205,9 +205,15 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
     // Set pass / material-specific renderstates
     // Set pass / material-specific renderstates
     if (pass_ && material_)
     if (pass_ && material_)
     {
     {
+        bool isShadowPass = pass_->GetType() == PASS_SHADOW;
+        
         graphics->SetBlendMode(pass_->GetBlendMode());
         graphics->SetBlendMode(pass_->GetBlendMode());
-        renderer->SetCullMode(pass_->GetType() != PASS_SHADOW ? material_->GetCullMode() : material_->GetShadowCullMode(),
-            camera_);
+        renderer->SetCullMode(isShadowPass ? material_->GetShadowCullMode() : material_->GetCullMode(), camera_);
+        if (!isShadowPass)
+        {
+            const BiasParameters& depthBias = material_->GetDepthBias();
+            graphics->SetDepthBias(depthBias.constantBias_, depthBias.slopeScaledBias_);
+        }
         graphics->SetDepthTest(pass_->GetDepthTestMode());
         graphics->SetDepthTest(pass_->GetDepthTestMode());
         graphics->SetDepthWrite(pass_->GetDepthWrite());
         graphics->SetDepthWrite(pass_->GetDepthWrite());
     }
     }

+ 1 - 0
Engine/Graphics/BillboardSet.cpp

@@ -29,6 +29,7 @@
 #include "Geometry.h"
 #include "Geometry.h"
 #include "Graphics.h"
 #include "Graphics.h"
 #include "IndexBuffer.h"
 #include "IndexBuffer.h"
+#include "Material.h"
 #include "MemoryBuffer.h"
 #include "MemoryBuffer.h"
 #include "Node.h"
 #include "Node.h"
 #include "Profiler.h"
 #include "Profiler.h"

+ 38 - 30
Engine/Graphics/DecalSet.cpp

@@ -31,6 +31,7 @@
 #include "Graphics.h"
 #include "Graphics.h"
 #include "IndexBuffer.h"
 #include "IndexBuffer.h"
 #include "Log.h"
 #include "Log.h"
+#include "Material.h"
 #include "MemoryBuffer.h"
 #include "MemoryBuffer.h"
 #include "Node.h"
 #include "Node.h"
 #include "Profiler.h"
 #include "Profiler.h"
@@ -276,7 +277,7 @@ void DecalSet::SetMaxIndices(unsigned num)
 
 
 bool DecalSet::AddDecal(Drawable* target, const Vector3& worldPosition, const Quaternion& worldRotation, float size,
 bool DecalSet::AddDecal(Drawable* target, const Vector3& worldPosition, const Quaternion& worldRotation, float size,
     float aspectRatio, float depth, const Vector2& topLeftUV, const Vector2& bottomRightUV, float timeToLive, float normalCutoff,
     float aspectRatio, float depth, const Vector2& topLeftUV, const Vector2& bottomRightUV, float timeToLive, float normalCutoff,
-    float depthBias, unsigned subGeometry)
+    unsigned subGeometry)
 {
 {
     PROFILE(AddDecal);
     PROFILE(AddDecal);
     
     
@@ -298,6 +299,8 @@ bool DecalSet::AddDecal(Drawable* target, const Vector3& worldPosition, const Qu
         bufferSizeDirty_ = true;
         bufferSizeDirty_ = true;
     }
     }
     
     
+    // Center the decal frustum on the world position
+    Vector3 adjustedWorldPosition = worldPosition - 0.5f * depth * (worldRotation * Vector3::FORWARD);
     Matrix3x4 targetTransform = target->GetNode()->GetWorldTransform().Inverse();
     Matrix3x4 targetTransform = target->GetNode()->GetWorldTransform().Inverse();
     
     
     // For an animated model, adjust the decal position back to the bind pose
     // For an animated model, adjust the decal position back to the bind pose
@@ -316,9 +319,9 @@ bool DecalSet::AddDecal(Drawable* target, const Vector3& worldPosition, const Qu
                 continue;
                 continue;
             
             
             // Represent the decal as a sphere, try to find the biggest colliding bone
             // Represent the decal as a sphere, try to find the biggest colliding bone
-            Sphere decalSphere(bone->node_->GetWorldTransform().Inverse() * (worldPosition + worldRotation * (0.5f * depth *
-                Vector3::FORWARD)), 0.5f * size / bone->node_->GetWorldScale().Length());
-            float distance = (worldPosition - bone->node_->GetWorldPosition()).Length();
+            Sphere decalSphere(bone->node_->GetWorldTransform().Inverse() * adjustedWorldPosition, 0.5f * size /
+                bone->node_->GetWorldScale().Length());
+            float distance = (adjustedWorldPosition - bone->node_->GetWorldPosition()).Length();
             
             
             if (bone->collisionMask_ & BONECOLLISION_BOX)
             if (bone->collisionMask_ & BONECOLLISION_BOX)
             {
             {
@@ -350,10 +353,9 @@ bool DecalSet::AddDecal(Drawable* target, const Vector3& worldPosition, const Qu
     
     
     // Build the decal frustum
     // Build the decal frustum
     Frustum decalFrustum;
     Frustum decalFrustum;
-    Matrix3x4 frustumTransform = targetTransform * Matrix3x4(worldPosition, worldRotation, 1.0f);
+    Matrix3x4 frustumTransform = targetTransform * Matrix3x4(adjustedWorldPosition, worldRotation, 1.0f);
     decalFrustum.DefineOrtho(size, aspectRatio, 1.0, 0.0f, depth, frustumTransform);
     decalFrustum.DefineOrtho(size, aspectRatio, 1.0, 0.0f, depth, frustumTransform);
     
     
-    Vector3 biasVector = targetTransform * Vector4(worldRotation * (Vector3::BACK * depthBias), 0.0f);
     Vector3 decalNormal = (targetTransform * Vector4(worldRotation * Vector3::BACK, 0.0f)).Normalized();
     Vector3 decalNormal = (targetTransform * Vector4(worldRotation * Vector3::BACK, 0.0f)).Normalized();
     
     
     decals_.Resize(decals_.Size() + 1);
     decals_.Resize(decals_.Size() + 1);
@@ -425,10 +427,18 @@ bool DecalSet::AddDecal(Drawable* target, const Vector3& worldPosition, const Qu
         return false;
         return false;
     }
     }
     
     
-    // Finally transform vertices to this node's local space
+    // Calculate UVs
+    Matrix4 projection(Matrix4::ZERO);
+    projection.m11_ = (1.0f / (size * 0.5f));
+    projection.m00_ = projection.m11_ / aspectRatio;
+    projection.m22_ = 1.0f / depth;
+    projection.m33_ = 1.0f;
+    
+    CalculateUVs(newDecal, frustumTransform.Inverse(), projection, topLeftUV, bottomRightUV);
+    
+    // Transform vertices to this node's local space and generate tangents
     Matrix3x4 decalTransform = node_->GetWorldTransform().Inverse() * target->GetNode()->GetWorldTransform();
     Matrix3x4 decalTransform = node_->GetWorldTransform().Inverse() * target->GetNode()->GetWorldTransform();
-    CalculateUVs(newDecal, frustumTransform.Inverse(), size, aspectRatio, depth, topLeftUV, bottomRightUV);
-    TransformVertices(newDecal, skinned_ ? Matrix3x4::IDENTITY : decalTransform, biasVector);
+    TransformVertices(newDecal, skinned_ ? Matrix3x4::IDENTITY : decalTransform);
     GenerateTangents(&newDecal.vertices_[0], sizeof(DecalVertex), &newDecal.indices_[0], sizeof(unsigned short), 0,
     GenerateTangents(&newDecal.vertices_[0], sizeof(DecalVertex), &newDecal.indices_[0], sizeof(unsigned short), 0,
         newDecal.indices_.Size(), offsetof(DecalVertex, normal_), offsetof(DecalVertex, texCoord_), offsetof(DecalVertex,
         newDecal.indices_.Size(), offsetof(DecalVertex, normal_), offsetof(DecalVertex, texCoord_), offsetof(DecalVertex,
         tangent_));
         tangent_));
@@ -782,15 +792,26 @@ void DecalSet::GetFace(Vector<PODVector<DecalVertex> >& faces, Drawable* target,
     const Vector3& v0 = *((const Vector3*)(&positionData[i0 * positionStride]));
     const Vector3& v0 = *((const Vector3*)(&positionData[i0 * positionStride]));
     const Vector3& v1 = *((const Vector3*)(&positionData[i1 * positionStride]));
     const Vector3& v1 = *((const Vector3*)(&positionData[i1 * positionStride]));
     const Vector3& v2 = *((const Vector3*)(&positionData[i2 * positionStride]));
     const Vector3& v2 = *((const Vector3*)(&positionData[i2 * positionStride]));
-    const Vector3& n0 = hasNormals ? *((const Vector3*)(&normalData[i0 * normalStride])) : Vector3::ZERO;
-    const Vector3& n1 = hasNormals ? *((const Vector3*)(&normalData[i1 * normalStride])) : Vector3::ZERO;
-    const Vector3& n2 = hasNormals ? *((const Vector3*)(&normalData[i2 * normalStride])) : Vector3::ZERO;
+    
+    // Calculate unsmoothed face normals if no normal data
+    Vector3 faceNormal = Vector3::ZERO;
+    if (!hasNormals)
+    {
+        Vector3 dist1 = v1 - v0;
+        Vector3 dist2 = v2 - v0;
+        faceNormal = (dist1.CrossProduct(dist2)).Normalized();
+    }
+    
+    const Vector3& n0 = hasNormals ? *((const Vector3*)(&normalData[i0 * normalStride])) : faceNormal;
+    const Vector3& n1 = hasNormals ? *((const Vector3*)(&normalData[i1 * normalStride])) : faceNormal;
+    const Vector3& n2 = hasNormals ? *((const Vector3*)(&normalData[i2 * normalStride])) : faceNormal;
+    
     const unsigned char* s0 = hasSkinning ? &skinningData[i0 * skinningStride] : (const unsigned char*)0;
     const unsigned char* s0 = hasSkinning ? &skinningData[i0 * skinningStride] : (const unsigned char*)0;
     const unsigned char* s1 = hasSkinning ? &skinningData[i1 * skinningStride] : (const unsigned char*)0;
     const unsigned char* s1 = hasSkinning ? &skinningData[i1 * skinningStride] : (const unsigned char*)0;
     const unsigned char* s2 = hasSkinning ? &skinningData[i2 * skinningStride] : (const unsigned char*)0;
     const unsigned char* s2 = hasSkinning ? &skinningData[i2 * skinningStride] : (const unsigned char*)0;
     
     
     // Check if face is too much away from the decal normal
     // Check if face is too much away from the decal normal
-    if (hasNormals && decalNormal.DotProduct((n0 + n1 + n2) / 3.0f) < normalCutoff)
+    if (decalNormal.DotProduct((n0 + n1 + n2) / 3.0f) < normalCutoff)
         return;
         return;
     
     
     // Check if face is culled completely by any of the planes
     // Check if face is culled completely by any of the planes
@@ -915,22 +936,9 @@ bool DecalSet::GetBones(Drawable* target, unsigned batchIndex, const float* blen
     return true;
     return true;
 }
 }
 
 
-void DecalSet::CalculateUVs(Decal& decal, const Matrix3x4& view, float size, float aspectRatio, float depth,
-    const Vector2& topLeftUV, const Vector2& bottomRightUV)
+void DecalSet::CalculateUVs(Decal& decal, const Matrix3x4& view, const Matrix4& projection, const Vector2& topLeftUV,
+    const Vector2& bottomRightUV)
 {
 {
-    Matrix4 projection(Matrix4::ZERO);
-    
-    float h = (1.0f / (size * 0.5f));
-    float w = h / aspectRatio;
-    float q = 1.0f / depth;
-    float r = 0.0f;
-    
-    projection.m00_ = w;
-    projection.m11_ = h;
-    projection.m22_ = q;
-    projection.m23_ = r;
-    projection.m33_ = 1.0f;
-    
     Matrix4 viewProj = projection * view;
     Matrix4 viewProj = projection * view;
     
     
     for (PODVector<DecalVertex>::Iterator i = decal.vertices_.Begin(); i != decal.vertices_.End(); ++i)
     for (PODVector<DecalVertex>::Iterator i = decal.vertices_.Begin(); i != decal.vertices_.End(); ++i)
@@ -943,11 +951,11 @@ void DecalSet::CalculateUVs(Decal& decal, const Matrix3x4& view, float size, flo
     }
     }
 }
 }
 
 
-void DecalSet::TransformVertices(Decal& decal, const Matrix3x4& transform, const Vector3& biasVector)
+void DecalSet::TransformVertices(Decal& decal, const Matrix3x4& transform)
 {
 {
     for (PODVector<DecalVertex>::Iterator i = decal.vertices_.Begin(); i != decal.vertices_.End(); ++i)
     for (PODVector<DecalVertex>::Iterator i = decal.vertices_.Begin(); i != decal.vertices_.End(); ++i)
     {
     {
-        i->position_ = transform * (i->position_ + biasVector);
+        i->position_ = transform * i->position_;
         i->normal_ = (transform * i->normal_).Normalized();
         i->normal_ = (transform * i->normal_).Normalized();
     }
     }
 }
 }

+ 3 - 3
Engine/Graphics/DecalSet.h

@@ -126,7 +126,7 @@ class DecalSet : public Drawable
     /// %Set maximum number of decal vertex indices.
     /// %Set maximum number of decal vertex indices.
     void SetMaxIndices(unsigned num);
     void SetMaxIndices(unsigned num);
     /// Add a decal at world coordinates, using an existing drawable's geometry for reference. Return true if successful.
     /// Add a decal at world coordinates, using an existing drawable's geometry for reference. Return true if successful.
-    bool AddDecal(Drawable* target, const Vector3& worldPosition, const Quaternion& worldRotation, float size, float aspectRatio, float depth, const Vector2& topLeftUV, const Vector2& bottomRightUV, float timeToLive = 0.0f, float normalCutoff = 0.1f, float depthBias = 0.001f, unsigned subGeometry = M_MAX_UNSIGNED);
+    bool AddDecal(Drawable* target, const Vector3& worldPosition, const Quaternion& worldRotation, float size, float aspectRatio, float depth, const Vector2& topLeftUV, const Vector2& bottomRightUV, float timeToLive = 0.0f, float normalCutoff = 0.1f, unsigned subGeometry = M_MAX_UNSIGNED);
     /// Remove n oldest decals.
     /// Remove n oldest decals.
     void RemoveDecals(unsigned num);
     void RemoveDecals(unsigned num);
     /// Remove all decals.
     /// Remove all decals.
@@ -168,9 +168,9 @@ private:
     /// Get bones referenced by skinning data and remap the skinning indices. Return true if successful.
     /// Get bones referenced by skinning data and remap the skinning indices. Return true if successful.
     bool GetBones(Drawable* target, unsigned batchIndex, const float* blendWeights, const unsigned char* blendIndices, unsigned char* newBlendIndices);
     bool GetBones(Drawable* target, unsigned batchIndex, const float* blendWeights, const unsigned char* blendIndices, unsigned char* newBlendIndices);
     /// Calculate UV coordinates for the decal.
     /// Calculate UV coordinates for the decal.
-    void CalculateUVs(Decal& decal, const Matrix3x4& view, float size, float aspectRatio, float depth, const Vector2& topLeftUV, const Vector2& bottomRightUV);
+    void CalculateUVs(Decal& decal, const Matrix3x4& view, const Matrix4& projection, const Vector2& topLeftUV, const Vector2& bottomRightUV);
     /// Transform decal's vertices from the target geometry to the decal set local space.
     /// Transform decal's vertices from the target geometry to the decal set local space.
-    void TransformVertices(Decal& decal, const Matrix3x4& transform, const Vector3& biasVector);
+    void TransformVertices(Decal& decal, const Matrix3x4& transform);
     /// Remove a decal by iterator and return iterator to the next decal.
     /// Remove a decal by iterator and return iterator to the next decal.
     List<Decal>::Iterator RemoveDecal(List<Decal>::Iterator i);
     List<Decal>::Iterator RemoveDecal(List<Decal>::Iterator i);
     /// Mark decals and the bounding box dirty.
     /// Mark decals and the bounding box dirty.

+ 1 - 1
Engine/Graphics/Direct3D9/D3D9Graphics.cpp

@@ -33,8 +33,8 @@
 #include "GraphicsEvents.h"
 #include "GraphicsEvents.h"
 #include "GraphicsImpl.h"
 #include "GraphicsImpl.h"
 #include "IndexBuffer.h"
 #include "IndexBuffer.h"
-#include "Light.h"
 #include "Log.h"
 #include "Log.h"
+#include "Material.h"
 #include "Octree.h"
 #include "Octree.h"
 #include "ParticleEmitter.h"
 #include "ParticleEmitter.h"
 #include "ProcessUtils.h"
 #include "ProcessUtils.h"

+ 16 - 1
Engine/Graphics/Drawable.cpp

@@ -25,7 +25,7 @@
 #include "Camera.h"
 #include "Camera.h"
 #include "Context.h"
 #include "Context.h"
 #include "DebugRenderer.h"
 #include "DebugRenderer.h"
-#include "Light.h"
+#include "Material.h"
 #include "Octree.h"
 #include "Octree.h"
 #include "Scene.h"
 #include "Scene.h"
 #include "Sort.h"
 #include "Sort.h"
@@ -35,6 +35,21 @@
 
 
 static const Vector3 DOT_SCALE(1 / 3.0f, 1 / 3.0f, 1 / 3.0f);
 static const Vector3 DOT_SCALE(1 / 3.0f, 1 / 3.0f, 1 / 3.0f);
 
 
+SourceBatch::SourceBatch() :
+    distance_(0.0f),
+    geometry_(0),
+    worldTransform_(&Matrix3x4::IDENTITY),
+    shaderData_(0),
+    shaderDataSize_(0),
+    geometryType_(GEOM_STATIC),
+    overrideView_(false)
+{
+}
+
+SourceBatch::~SourceBatch()
+{
+}
+
 OBJECTTYPESTATIC(Drawable);
 OBJECTTYPESTATIC(Drawable);
 
 
 Drawable::Drawable(Context* context) :
 Drawable::Drawable(Context* context) :

+ 4 - 11
Engine/Graphics/Drawable.h

@@ -26,7 +26,6 @@
 #include "BoundingBox.h"
 #include "BoundingBox.h"
 #include "Component.h"
 #include "Component.h"
 #include "GraphicsDefs.h"
 #include "GraphicsDefs.h"
-#include "Material.h"
 
 
 static const unsigned DRAWABLE_GEOMETRY = 0x1;
 static const unsigned DRAWABLE_GEOMETRY = 0x1;
 static const unsigned DRAWABLE_LIGHT = 0x2;
 static const unsigned DRAWABLE_LIGHT = 0x2;
@@ -42,6 +41,7 @@ static const int MAX_VERTEX_LIGHTS = 4;
 class Camera;
 class Camera;
 class Geometry;
 class Geometry;
 class Light;
 class Light;
+class Material;
 class OcclusionBuffer;
 class OcclusionBuffer;
 class Octant;
 class Octant;
 class RayOctreeQuery;
 class RayOctreeQuery;
@@ -74,16 +74,9 @@ struct FrameInfo
 struct SourceBatch
 struct SourceBatch
 {
 {
     /// Construct with defaults.
     /// Construct with defaults.
-    SourceBatch() :
-        distance_(0.0f),
-        geometry_(0),
-        worldTransform_(&Matrix3x4::IDENTITY),
-        shaderData_(0),
-        shaderDataSize_(0),
-        geometryType_(GEOM_STATIC),
-        overrideView_(false)
-    {
-    }
+    SourceBatch();
+    /// Destruct.
+    ~SourceBatch();
     
     
     /// Distance from camera.
     /// Distance from camera.
     float distance_;
     float distance_;

+ 2 - 2
Engine/Graphics/Light.cpp

@@ -56,8 +56,8 @@ static const char* typeNames[] =
 
 
 void BiasParameters::Validate()
 void BiasParameters::Validate()
 {
 {
-    constantBias_ = Clamp(constantBias_, 0.0f, 1.0f);
-    slopeScaledBias_ = Clamp(slopeScaledBias_, 0.0f, 16.0f);
+    constantBias_ = Clamp(constantBias_, -1.0f, 1.0f);
+    slopeScaledBias_ = Clamp(slopeScaledBias_, -16.0f, 16.0f);
 }
 }
 
 
 void CascadeParameters::Validate()
 void CascadeParameters::Validate()

+ 17 - 1
Engine/Graphics/Material.cpp

@@ -95,9 +95,10 @@ OBJECTTYPESTATIC(Material);
 
 
 Material::Material(Context* context) :
 Material::Material(Context* context) :
     Resource(context),
     Resource(context),
-    auxViewFrameNumber_(0),
     cullMode_(CULL_CCW),
     cullMode_(CULL_CCW),
     shadowCullMode_(CULL_CCW),
     shadowCullMode_(CULL_CCW),
+    depthBias_(BiasParameters(0.0f, 0.0f)),
+    auxViewFrameNumber_(0),
     occlusion_(true)
     occlusion_(true)
 {
 {
     SetNumTechniques(1);
     SetNumTechniques(1);
@@ -202,6 +203,10 @@ bool Material::Load(Deserializer& source)
     if (shadowCullElem)
     if (shadowCullElem)
         SetShadowCullMode((CullMode)GetStringListIndex(shadowCullElem.GetAttribute("value"), cullModeNames, CULL_CCW));
         SetShadowCullMode((CullMode)GetStringListIndex(shadowCullElem.GetAttribute("value"), cullModeNames, CULL_CCW));
     
     
+    XMLElement depthBiasElem = rootElem.GetChild("depthbias");
+    if (depthBiasElem)
+        SetDepthBias(BiasParameters(depthBiasElem.GetFloat("constant"), depthBiasElem.GetFloat("slopescaled")));
+    
     // Calculate memory use
     // Calculate memory use
     unsigned memoryUse = sizeof(Material);
     unsigned memoryUse = sizeof(Material);
     
     
@@ -260,6 +265,11 @@ bool Material::Save(Serializer& dest)
     XMLElement shadowCullElem = materialElem.CreateChild("shadowcull");
     XMLElement shadowCullElem = materialElem.CreateChild("shadowcull");
     shadowCullElem.SetString("value", cullModeNames[shadowCullMode_]);
     shadowCullElem.SetString("value", cullModeNames[shadowCullMode_]);
     
     
+    // Write depth bias
+    XMLElement depthBiasElem = materialElem.CreateChild("depthbias");
+    depthBiasElem.SetFloat("constant", depthBias_.constantBias_);
+    depthBiasElem.SetFloat("slopescaled", depthBias_.slopeScaledBias_);
+    
     return xml->Save(dest);
     return xml->Save(dest);
 }
 }
 
 
@@ -340,6 +350,12 @@ void Material::SetShadowCullMode(CullMode mode)
     shadowCullMode_ = mode;
     shadowCullMode_ = mode;
 }
 }
 
 
+void Material::SetDepthBias(const BiasParameters& parameters)
+{
+    depthBias_ = parameters;
+    depthBias_.Validate();
+}
+
 void Material::RemoveShaderParameter(const String& name)
 void Material::RemoveShaderParameter(const String& name)
 {
 {
     shaderParameters_.Erase(StringHash(name));
     shaderParameters_.Erase(StringHash(name));

+ 9 - 2
Engine/Graphics/Material.h

@@ -25,6 +25,7 @@
 
 
 #include "GraphicsDefs.h"
 #include "GraphicsDefs.h"
 #include "HashMap.h"
 #include "HashMap.h"
+#include "Light.h"
 #include "Resource.h"
 #include "Resource.h"
 #include "Vector4.h"
 #include "Vector4.h"
 
 
@@ -95,6 +96,8 @@ public:
     void SetCullMode(CullMode mode);
     void SetCullMode(CullMode mode);
     /// %Set culling mode for shadows.
     /// %Set culling mode for shadows.
     void SetShadowCullMode(CullMode mode);
     void SetShadowCullMode(CullMode mode);
+    /// %Set depth bias.
+    void SetDepthBias(const BiasParameters& parameters);
     /// Remove shader parameter.
     /// Remove shader parameter.
     void RemoveShaderParameter(const String& name);
     void RemoveShaderParameter(const String& name);
     /// Reset all shader pointers.
     /// Reset all shader pointers.
@@ -126,6 +129,8 @@ public:
     CullMode GetCullMode() const { return cullMode_; }
     CullMode GetCullMode() const { return cullMode_; }
     /// Return culling mode for shadows.
     /// Return culling mode for shadows.
     CullMode GetShadowCullMode() const { return shadowCullMode_; }
     CullMode GetShadowCullMode() const { return shadowCullMode_; }
+    /// Return depth bias.
+    const BiasParameters& GetDepthBias() const { return depthBias_; }
     /// Return last auxiliary view rendered frame number.
     /// Return last auxiliary view rendered frame number.
     unsigned GetAuxViewFrameNumber() const { return auxViewFrameNumber_; }
     unsigned GetAuxViewFrameNumber() const { return auxViewFrameNumber_; }
     /// Return whether should render occlusion.
     /// Return whether should render occlusion.
@@ -148,12 +153,14 @@ private:
     SharedPtr<Texture> textures_[MAX_MATERIAL_TEXTURE_UNITS];
     SharedPtr<Texture> textures_[MAX_MATERIAL_TEXTURE_UNITS];
     /// %Shader parameters.
     /// %Shader parameters.
     HashMap<StringHash, MaterialShaderParameter> shaderParameters_;
     HashMap<StringHash, MaterialShaderParameter> shaderParameters_;
-    /// Last auxiliary view rendered frame number.
-    unsigned auxViewFrameNumber_;
     /// Normal culling mode.
     /// Normal culling mode.
     CullMode cullMode_;
     CullMode cullMode_;
     /// Culling mode for shadow rendering.
     /// Culling mode for shadow rendering.
     CullMode shadowCullMode_;
     CullMode shadowCullMode_;
+    /// Depth bias parameters.
+    BiasParameters depthBias_;
+    /// Last auxiliary view rendered frame number.
+    unsigned auxViewFrameNumber_;
     /// Render occlusion flag.
     /// Render occlusion flag.
     bool occlusion_;
     bool occlusion_;
     /// Specular lighting flag.
     /// Specular lighting flag.

+ 1 - 1
Engine/Graphics/OpenGL/OGLGraphics.cpp

@@ -34,8 +34,8 @@
 #include "GraphicsEvents.h"
 #include "GraphicsEvents.h"
 #include "GraphicsImpl.h"
 #include "GraphicsImpl.h"
 #include "IndexBuffer.h"
 #include "IndexBuffer.h"
-#include "Light.h"
 #include "Log.h"
 #include "Log.h"
+#include "Material.h"
 #include "Mutex.h"
 #include "Mutex.h"
 #include "Octree.h"
 #include "Octree.h"
 #include "ParticleEmitter.h"
 #include "ParticleEmitter.h"

+ 0 - 1
Engine/Graphics/Renderer.cpp

@@ -30,7 +30,6 @@
 #include "GraphicsEvents.h"
 #include "GraphicsEvents.h"
 #include "GraphicsImpl.h"
 #include "GraphicsImpl.h"
 #include "IndexBuffer.h"
 #include "IndexBuffer.h"
-#include "Light.h"
 #include "Log.h"
 #include "Log.h"
 #include "Material.h"
 #include "Material.h"
 #include "OcclusionBuffer.h"
 #include "OcclusionBuffer.h"

+ 1 - 0
Engine/Graphics/StaticModel.cpp

@@ -27,6 +27,7 @@
 #include "Context.h"
 #include "Context.h"
 #include "Geometry.h"
 #include "Geometry.h"
 #include "Log.h"
 #include "Log.h"
+#include "Material.h"
 #include "Model.h"
 #include "Model.h"
 #include "OcclusionBuffer.h"
 #include "OcclusionBuffer.h"
 #include "OctreeQuery.h"
 #include "OctreeQuery.h"

+ 1 - 20
Engine/Graphics/TerrainPatch.cpp

@@ -26,6 +26,7 @@
 #include "Context.h"
 #include "Context.h"
 #include "Geometry.h"
 #include "Geometry.h"
 #include "IndexBuffer.h"
 #include "IndexBuffer.h"
+#include "Material.h"
 #include "Node.h"
 #include "Node.h"
 #include "OcclusionBuffer.h"
 #include "OcclusionBuffer.h"
 #include "OctreeQuery.h"
 #include "OctreeQuery.h"
@@ -278,26 +279,6 @@ Terrain* TerrainPatch::GetOwner() const
     return owner_;
     return owner_;
 }
 }
 
 
-TerrainPatch* TerrainPatch::GetNorthPatch() const
-{
-    return north_;
-}
-
-TerrainPatch* TerrainPatch::GetSouthPatch() const
-{
-    return south_;
-}
-
-TerrainPatch* TerrainPatch::GetWestPatch() const
-{
-    return west_;
-}
-
-TerrainPatch* TerrainPatch::GetEastPatch() const
-{
-    return east_;
-}
-
 void TerrainPatch::OnWorldBoundingBoxUpdate()
 void TerrainPatch::OnWorldBoundingBoxUpdate()
 {
 {
     worldBoundingBox_ = boundingBox_.Transformed(node_->GetWorldTransform());
     worldBoundingBox_ = boundingBox_.Transformed(node_->GetWorldTransform());

+ 4 - 4
Engine/Graphics/TerrainPatch.h

@@ -77,13 +77,13 @@ public:
     /// Return owner terrain.
     /// Return owner terrain.
     Terrain* GetOwner() const;
     Terrain* GetOwner() const;
     /// Return north neighbor patch.
     /// Return north neighbor patch.
-    TerrainPatch* GetNorthPatch() const;
+    TerrainPatch* GetNorthPatch() const { return north_; }
     /// Return south neighbor patch.
     /// Return south neighbor patch.
-    TerrainPatch* GetSouthPatch() const;
+    TerrainPatch* GetSouthPatch() const { return south_; }
     /// Return west neighbor patch.
     /// Return west neighbor patch.
-    TerrainPatch* GetWestPatch() const;
+    TerrainPatch* GetWestPatch() const { return west_; }
     /// Return east neighbor patch.
     /// Return east neighbor patch.
-    TerrainPatch* GetEastPatch() const;
+    TerrainPatch* GetEastPatch() const { return east_; }
     /// Return local-space bounding box.
     /// Return local-space bounding box.
     const BoundingBox& GetBoundingBox() const { return boundingBox_; }
     const BoundingBox& GetBoundingBox() const { return boundingBox_; }
     /// Return patch coordinates.
     /// Return patch coordinates.

+ 4 - 2
Engine/Graphics/View.cpp

@@ -27,8 +27,8 @@
 #include "Geometry.h"
 #include "Geometry.h"
 #include "Graphics.h"
 #include "Graphics.h"
 #include "GraphicsImpl.h"
 #include "GraphicsImpl.h"
-#include "Light.h"
 #include "Log.h"
 #include "Log.h"
+#include "Material.h"
 #include "OcclusionBuffer.h"
 #include "OcclusionBuffer.h"
 #include "Octree.h"
 #include "Octree.h"
 #include "Renderer.h"
 #include "Renderer.h"
@@ -475,9 +475,10 @@ void View::Render()
     camera_->SetFlipVertical(false);
     camera_->SetFlipVertical(false);
     #endif
     #endif
     
     
-    graphics_->SetViewTexture(0);
+    graphics_->SetDepthBias(0.0f, 0.0f);
     graphics_->SetScissorTest(false);
     graphics_->SetScissorTest(false);
     graphics_->SetStencilTest(false);
     graphics_->SetStencilTest(false);
+    graphics_->SetViewTexture(0);
     graphics_->ResetStreamFrequencies();
     graphics_->ResetStreamFrequencies();
     
     
     // Run post-processes or framebuffer blitting now
     // Run post-processes or framebuffer blitting now
@@ -2433,6 +2434,7 @@ void View::SetupLightVolumeBatch(Batch& batch)
     
     
     // Use replace blend mode for the first pre-pass light volume, and additive for the rest
     // Use replace blend mode for the first pre-pass light volume, and additive for the rest
     graphics_->SetBlendMode(renderMode_ == RENDER_PREPASS && light == lightQueues_.Front().light_ ? BLEND_REPLACE : BLEND_ADD);
     graphics_->SetBlendMode(renderMode_ == RENDER_PREPASS && light == lightQueues_.Front().light_ ? BLEND_REPLACE : BLEND_ADD);
+    graphics_->SetDepthBias(0.0f, 0.0f);
     graphics_->SetDepthWrite(false);
     graphics_->SetDepthWrite(false);
     
     
     if (type != LIGHT_DIRECTIONAL)
     if (type != LIGHT_DIRECTIONAL)