Browse Source

Removed convenience GetWorldTransform() from Component to make it explicit that an indirection to the parent node is being made.
Added inverse transform caching to Zone.
Added light nullcheck to Batch.

Lasse Öörni 13 years ago
parent
commit
e6fe0d6cf0

+ 2 - 0
Docs/ScriptAPI.dox

@@ -1919,6 +1919,7 @@ Properties:<br>
 - uint maxLights
 - BoundingBox& worldBoundingBox (readonly)
 - BoundingBox& boundingBox
+- Matrix3x4& inverseWorldTransform (readonly)
 - Color& ambientColor
 - Color& ambientStartColor (readonly)
 - Color& ambientEndColor (readonly)
@@ -2309,6 +2310,7 @@ Properties:<br>
 - bool hardwareDepthSupport (readonly)
 - bool hardwareShadowSupport (readonly)
 - bool hiresShadowSupport (readonly)
+- bool compressedTextureSupport (readonly)
 - bool forceSM2
 - IntVector2[]@ resolutions (readonly)
 - int[]@ multiSampleLevels (readonly)

+ 3 - 2
Engine/Audio/SoundSource3D.cpp

@@ -24,6 +24,7 @@
 #include "Precompiled.h"
 #include "Audio.h"
 #include "Context.h"
+#include "Node.h"
 #include "Sound.h"
 #include "SoundSource3D.h"
 #include "XMLElement.h"
@@ -95,9 +96,9 @@ void SoundSource3D::CalculateAttenuation()
         return;
     
     float interval = farDistance_ - nearDistance_;
-    if (interval > 0.0f)
+    if (interval > 0.0f && node_)
     {
-        Vector3 relativePos(audio_->GetListenerRotation().Inverse() * (GetWorldPosition() - audio_->GetListenerPosition()));
+        Vector3 relativePos(audio_->GetListenerRotation().Inverse() * (node_->GetWorldPosition() - audio_->GetListenerPosition()));
         float distance = Clamp(relativePos.Length() - nearDistance_, 0.0f, interval);
         float attenuation = powf(1.0f - distance / interval, rolloffFactor_);
         float panning = relativePos.Normalized().x_;

+ 1 - 0
Engine/Engine/GraphicsAPI.cpp

@@ -553,6 +553,7 @@ static void RegisterZone(asIScriptEngine* engine)
     RegisterDrawable<Zone>(engine, "Zone");
     engine->RegisterObjectMethod("Zone", "void set_boundingBox(const BoundingBox&in)", asMETHOD(Zone, SetBoundingBox), asCALL_THISCALL);
     engine->RegisterObjectMethod("Zone", "const BoundingBox& get_boundingBox() const", asMETHOD(Zone, GetBoundingBox), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Zone", "const Matrix3x4& get_inverseWorldTransform() const", asMETHOD(Zone, GetInverseWorldTransform), asCALL_THISCALL);
     engine->RegisterObjectMethod("Zone", "void set_ambientColor(const Color&in)", asMETHOD(Zone, SetAmbientColor), asCALL_THISCALL);
     engine->RegisterObjectMethod("Zone", "const Color& get_ambientColor() const", asMETHOD(Zone, GetAmbientColor), asCALL_THISCALL);
     engine->RegisterObjectMethod("Zone", "const Color& get_ambientStartColor()", asMETHOD(Zone, GetAmbientStartColor), asCALL_THISCALL);

+ 1 - 1
Engine/Graphics/AnimatedModel.cpp

@@ -814,7 +814,7 @@ void AnimatedModel::OnMarkedDirty(Node* node)
 void AnimatedModel::OnWorldBoundingBoxUpdate()
 {
     if (!skeleton_.GetNumBones())
-        worldBoundingBox_ = boundingBox_.Transformed(GetWorldTransform());
+        worldBoundingBox_ = boundingBox_.Transformed(node_->GetWorldTransform());
     else
     {
         // If has bones, update world bounding box based on them

+ 129 - 119
Engine/Graphics/Batch.cpp

@@ -122,8 +122,9 @@ void CalculateShadowMatrix(Matrix4& dest, LightBatchQueue* queue, unsigned split
 
 void CalculateSpotMatrix(Matrix4& dest, Light* light, const Vector3& translation)
 {
+    Node* lightNode = light->GetNode();
     Matrix3x4 posAdjust(translation, Quaternion::IDENTITY, 1.0f);
-    Matrix3x4 spotView(light->GetWorldPosition(), light->GetWorldRotation(), 1.0f);
+    Matrix3x4 spotView(lightNode->GetWorldPosition(), lightNode->GetWorldRotation(), 1.0f);
     Matrix4 spotProj(Matrix4::ZERO);
     Matrix4 texAdjust(Matrix4::IDENTITY);
     
@@ -163,6 +164,8 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
     if (!vertexShader_ || !pixelShader_)
         return;
     
+    Node* cameraNode = camera_ ? camera_->GetNode() : 0;
+    
     // Set pass / material-specific renderstates
     if (pass_ && material_)
     {
@@ -183,10 +186,10 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
     
     // Set viewport and camera shader parameters
     if (graphics->NeedParameterUpdate(VSP_CAMERAPOS, camera_))
-        graphics->SetShaderParameter(VSP_CAMERAPOS, camera_->GetWorldPosition());
+        graphics->SetShaderParameter(VSP_CAMERAPOS, cameraNode->GetWorldPosition());
     
     if (graphics->NeedParameterUpdate(VSP_CAMERAROT, camera_))
-        graphics->SetShaderParameter(VSP_CAMERAROT, camera_->GetWorldTransform().RotationMatrix());
+        graphics->SetShaderParameter(VSP_CAMERAROT, cameraNode->GetWorldTransform().RotationMatrix());
     
     if (graphics->NeedParameterUpdate(VSP_DEPTHMODE, camera_))
     {
@@ -287,7 +290,7 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
             Matrix3x4 adjust(Matrix3x4::IDENTITY);
             adjust.SetScale(Vector3(1.0f / boxSize.x_, 1.0f / boxSize.y_, 1.0f / boxSize.z_));
             adjust.SetTranslation(Vector3(0.5f, 0.5f, 0.5f));
-            Matrix3x4 zoneTransform = adjust * zone_->GetWorldTransform().Inverse();
+            Matrix3x4 zoneTransform = adjust * zone_->GetInverseWorldTransform();
             
             graphics->SetShaderParameter(VSP_ZONE, zoneTransform);
         }
@@ -333,58 +336,6 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
         light = lightQueue_->light_;
         shadowMap = lightQueue_->shadowMap_;
         
-        if (graphics->NeedParameterUpdate(VSP_LIGHTDIR, light))
-            graphics->SetShaderParameter(VSP_LIGHTDIR, light->GetWorldRotation() * Vector3::BACK);
-        
-        if (graphics->NeedParameterUpdate(VSP_LIGHTPOS, light))
-        {
-            float atten = 1.0f / Max(light->GetRange(), M_EPSILON);
-            graphics->SetShaderParameter(VSP_LIGHTPOS, Vector4(light->GetWorldPosition(), atten));
-        }
-        
-        if (graphics->NeedParameterUpdate(VSP_LIGHTMATRICES, light))
-        {
-            switch (light->GetLightType())
-            {
-            case LIGHT_DIRECTIONAL:
-                {
-                    Matrix4 shadowMatrices[MAX_CASCADE_SPLITS];
-                    unsigned numSplits = lightQueue_->shadowSplits_.Size();
-                    for (unsigned i = 0; i < numSplits; ++i)
-                        CalculateShadowMatrix(shadowMatrices[i], lightQueue_, i, renderer, Vector3::ZERO);
-                    
-                    graphics->SetShaderParameter(VSP_LIGHTMATRICES, shadowMatrices[0].Data(), 16 * numSplits);
-                }
-                break;
-                
-            case LIGHT_SPOT:
-                {
-                    Matrix4 shadowMatrices[2];
-                    
-                    CalculateSpotMatrix(shadowMatrices[0], light, Vector3::ZERO);
-                    bool isShadowed = shadowMap && graphics->NeedTextureUnit(TU_SHADOWMAP);
-                    if (isShadowed)
-                        CalculateShadowMatrix(shadowMatrices[1], lightQueue_, 0, renderer, Vector3::ZERO);
-                    
-                    graphics->SetShaderParameter(VSP_LIGHTMATRICES, shadowMatrices[0].Data(), isShadowed ? 32 : 16);
-                }
-                break;
-                
-            case LIGHT_POINT:
-                {
-                    Matrix4 lightVecRot(light->GetWorldRotation().RotationMatrix());
-                    // HLSL compiler will pack the parameters as if the matrix is only 3x4, so must be careful to not overwrite
-                    // the next parameter
-                    #ifdef USE_OPENGL
-                    graphics->SetShaderParameter(VSP_LIGHTMATRICES, lightVecRot.Data(), 16);
-                    #else
-                    graphics->SetShaderParameter(VSP_LIGHTMATRICES, lightVecRot.Data(), 12);
-                    #endif
-                }
-                break;
-            }
-        }
-        
         if (graphics->NeedParameterUpdate(VSP_VERTEXLIGHTS, lightQueue_))
         {
             Vector4 vertexLights[MAX_VERTEX_LIGHTS * 3];
@@ -393,6 +344,7 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
             for (unsigned i = 0; i < lights.Size(); ++i)
             {
                 Light* vertexLight = lights[i];
+                Node* vertexLightNode = vertexLight->GetNode();
                 LightType type = vertexLight->GetLightType();
                 
                 // Attenuation
@@ -425,37 +377,138 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
                 vertexLights[i * 3] = Vector4(color.r_, color.g_, color.b_, invRange);
                 
                 // Direction
-                vertexLights[i * 3 + 1] = Vector4(-(vertexLight->GetNode()->GetWorldDirection()), cutoff);
+                vertexLights[i * 3 + 1] = Vector4(-(vertexLightNode->GetWorldDirection()), cutoff);
                 
                 // Position
-                vertexLights[i * 3 + 2] = Vector4(vertexLight->GetWorldPosition(), invCutoff);
+                vertexLights[i * 3 + 2] = Vector4(vertexLightNode->GetWorldPosition(), invCutoff);
             }
             
             if (lights.Size())
                 graphics->SetShaderParameter(VSP_VERTEXLIGHTS, vertexLights[0].Data(), lights.Size() * 3 * 4);
         }
         
-        if (graphics->NeedParameterUpdate(PSP_LIGHTCOLOR, light))
+        if (light)
         {
-            float fade = 1.0f;
-            float fadeEnd = light->GetDrawDistance();
-            float fadeStart = light->GetFadeDistance();
+            Node* lightNode = light->GetNode();
             
-            // Do fade calculation for light if both fade & draw distance defined
-            if (light->GetLightType() != LIGHT_DIRECTIONAL && fadeEnd > 0.0f && fadeStart > 0.0f && fadeStart < fadeEnd)
-                fade = Min(1.0f - (light->GetDistance() - fadeStart) / (fadeEnd - fadeStart), 1.0f);
+            if (graphics->NeedParameterUpdate(VSP_LIGHTDIR, light))
+                graphics->SetShaderParameter(VSP_LIGHTDIR, lightNode->GetWorldRotation() * Vector3::BACK);
             
-            graphics->SetShaderParameter(PSP_LIGHTCOLOR, Vector4(light->GetColor().RGBValues(),
-                light->GetSpecularIntensity()) * fade);
-        }
-        
-        if (graphics->NeedParameterUpdate(PSP_LIGHTDIR, light))
-            graphics->SetShaderParameter(PSP_LIGHTDIR, light->GetWorldRotation() * Vector3::BACK);
-        
-        if (graphics->NeedParameterUpdate(PSP_LIGHTPOS, light))
-        {
-            float atten = 1.0f / Max(light->GetRange(), M_EPSILON);
-            graphics->SetShaderParameter(PSP_LIGHTPOS, Vector4(light->GetWorldPosition() - camera_->GetWorldPosition(), atten));
+            if (graphics->NeedParameterUpdate(VSP_LIGHTPOS, light))
+            {
+                float atten = 1.0f / Max(light->GetRange(), M_EPSILON);
+                graphics->SetShaderParameter(VSP_LIGHTPOS, Vector4(lightNode->GetWorldPosition(), atten));
+            }
+            
+            if (graphics->NeedParameterUpdate(VSP_LIGHTMATRICES, light))
+            {
+                switch (light->GetLightType())
+                {
+                case LIGHT_DIRECTIONAL:
+                    {
+                        Matrix4 shadowMatrices[MAX_CASCADE_SPLITS];
+                        unsigned numSplits = lightQueue_->shadowSplits_.Size();
+                        for (unsigned i = 0; i < numSplits; ++i)
+                            CalculateShadowMatrix(shadowMatrices[i], lightQueue_, i, renderer, Vector3::ZERO);
+                        
+                        graphics->SetShaderParameter(VSP_LIGHTMATRICES, shadowMatrices[0].Data(), 16 * numSplits);
+                    }
+                    break;
+                    
+                case LIGHT_SPOT:
+                    {
+                        Matrix4 shadowMatrices[2];
+                        
+                        CalculateSpotMatrix(shadowMatrices[0], light, Vector3::ZERO);
+                        bool isShadowed = shadowMap && graphics->NeedTextureUnit(TU_SHADOWMAP);
+                        if (isShadowed)
+                            CalculateShadowMatrix(shadowMatrices[1], lightQueue_, 0, renderer, Vector3::ZERO);
+                        
+                        graphics->SetShaderParameter(VSP_LIGHTMATRICES, shadowMatrices[0].Data(), isShadowed ? 32 : 16);
+                    }
+                    break;
+                    
+                case LIGHT_POINT:
+                    {
+                        Matrix4 lightVecRot(lightNode->GetWorldRotation().RotationMatrix());
+                        // HLSL compiler will pack the parameters as if the matrix is only 3x4, so must be careful to not overwrite
+                        // the next parameter
+                        #ifdef USE_OPENGL
+                        graphics->SetShaderParameter(VSP_LIGHTMATRICES, lightVecRot.Data(), 16);
+                        #else
+                        graphics->SetShaderParameter(VSP_LIGHTMATRICES, lightVecRot.Data(), 12);
+                        #endif
+                    }
+                    break;
+                }
+            }
+            
+            if (graphics->NeedParameterUpdate(PSP_LIGHTCOLOR, light))
+            {
+                float fade = 1.0f;
+                float fadeEnd = light->GetDrawDistance();
+                float fadeStart = light->GetFadeDistance();
+                
+                // Do fade calculation for light if both fade & draw distance defined
+                if (light->GetLightType() != LIGHT_DIRECTIONAL && fadeEnd > 0.0f && fadeStart > 0.0f && fadeStart < fadeEnd)
+                    fade = Min(1.0f - (light->GetDistance() - fadeStart) / (fadeEnd - fadeStart), 1.0f);
+                
+                graphics->SetShaderParameter(PSP_LIGHTCOLOR, Vector4(light->GetColor().RGBValues(),
+                    light->GetSpecularIntensity()) * fade);
+            }
+            
+            if (graphics->NeedParameterUpdate(PSP_LIGHTDIR, light))
+                graphics->SetShaderParameter(PSP_LIGHTDIR, lightNode->GetWorldRotation() * Vector3::BACK);
+            
+            if (graphics->NeedParameterUpdate(PSP_LIGHTPOS, light))
+            {
+                float atten = 1.0f / Max(light->GetRange(), M_EPSILON);
+                graphics->SetShaderParameter(PSP_LIGHTPOS, Vector4(lightNode->GetWorldPosition() -
+                    cameraNode->GetWorldPosition(), atten));
+            }
+            
+            if (graphics->NeedParameterUpdate(PSP_LIGHTMATRICES, light))
+            {
+                switch (light->GetLightType())
+                {
+                case LIGHT_DIRECTIONAL:
+                    {
+                        Matrix4 shadowMatrices[MAX_CASCADE_SPLITS];
+                        unsigned numSplits = lightQueue_->shadowSplits_.Size();
+                        for (unsigned i = 0; i < numSplits; ++i)
+                            CalculateShadowMatrix(shadowMatrices[i], lightQueue_, i, renderer, cameraNode->GetWorldPosition());
+                        
+                        graphics->SetShaderParameter(PSP_LIGHTMATRICES, shadowMatrices[0].Data(), 16 * numSplits);
+                    }
+                    break;
+                    
+                case LIGHT_SPOT:
+                    {
+                        Matrix4 shadowMatrices[2];
+                        
+                        CalculateSpotMatrix(shadowMatrices[0], light, cameraNode->GetWorldPosition());
+                        bool isShadowed = lightQueue_->shadowMap_ != 0;
+                        if (isShadowed)
+                            CalculateShadowMatrix(shadowMatrices[1], lightQueue_, 0, renderer, cameraNode->GetWorldPosition());
+                        
+                        graphics->SetShaderParameter(PSP_LIGHTMATRICES, shadowMatrices[0].Data(), isShadowed ? 32 : 16);
+                    }
+                    break;
+                    
+                case LIGHT_POINT:
+                    {
+                        Matrix4 lightVecRot(lightNode->GetWorldRotation().RotationMatrix());
+                        // HLSL compiler will pack the parameters as if the matrix is only 3x4, so must be careful to not overwrite
+                        // the next parameter
+                        #ifdef USE_OPENGL
+                        graphics->SetShaderParameter(PSP_LIGHTMATRICES, lightVecRot.Data(), 16);
+                        #else
+                        graphics->SetShaderParameter(PSP_LIGHTMATRICES, lightVecRot.Data(), 12);
+                        #endif
+                    }
+                    break;
+                }
+            }
         }
         
         // Set shadow mapping shader parameters
@@ -537,49 +590,6 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
                 graphics->SetShaderParameter(PSP_SHADOWSPLITS, lightSplits);
             }
         }
-        
-        if (graphics->NeedParameterUpdate(PSP_LIGHTMATRICES, light))
-        {
-            switch (light->GetLightType())
-            {
-            case LIGHT_DIRECTIONAL:
-                {
-                    Matrix4 shadowMatrices[MAX_CASCADE_SPLITS];
-                    unsigned numSplits = lightQueue_->shadowSplits_.Size();
-                    for (unsigned i = 0; i < numSplits; ++i)
-                        CalculateShadowMatrix(shadowMatrices[i], lightQueue_, i, renderer, camera_->GetWorldPosition());
-                    
-                    graphics->SetShaderParameter(PSP_LIGHTMATRICES, shadowMatrices[0].Data(), 16 * numSplits);
-                }
-                break;
-                
-            case LIGHT_SPOT:
-                {
-                    Matrix4 shadowMatrices[2];
-                    
-                    CalculateSpotMatrix(shadowMatrices[0], light, camera_->GetWorldPosition());
-                    bool isShadowed = lightQueue_->shadowMap_ != 0;
-                    if (isShadowed)
-                        CalculateShadowMatrix(shadowMatrices[1], lightQueue_, 0, renderer, camera_->GetWorldPosition());
-                    
-                    graphics->SetShaderParameter(PSP_LIGHTMATRICES, shadowMatrices[0].Data(), isShadowed ? 32 : 16);
-                }
-                break;
-                
-            case LIGHT_POINT:
-                {
-                    Matrix4 lightVecRot(light->GetWorldRotation().RotationMatrix());
-                    // HLSL compiler will pack the parameters as if the matrix is only 3x4, so must be careful to not overwrite
-                    // the next parameter
-                    #ifdef USE_OPENGL
-                    graphics->SetShaderParameter(PSP_LIGHTMATRICES, lightVecRot.Data(), 16);
-                    #else
-                    graphics->SetShaderParameter(PSP_LIGHTMATRICES, lightVecRot.Data(), 12);
-                    #endif
-                }
-                break;
-            }
-        }
     }
     
     // Set material-specific shader parameters and textures

+ 1 - 1
Engine/Graphics/BillboardSet.cpp

@@ -94,7 +94,7 @@ void BillboardSet::UpdateDistance(const FrameInfo& frame)
 {
     // Check if position relative to camera has changed, and re-sort in that case
     const Vector3& worldPos = node_->GetWorldPosition();
-    Vector3 offset = (worldPos - frame.camera_->GetWorldPosition());
+    Vector3 offset = (worldPos - frame.camera_->GetNode()->GetWorldPosition());
     if (offset != previousOffset_)
     {
         previousOffset_ = offset;

+ 15 - 9
Engine/Graphics/Camera.cpp

@@ -203,15 +203,16 @@ Frustum Camera::GetSplitFrustum(float nearClip, float farClip) const
 {
     Frustum ret;
     
+    const Matrix3x4& worldTransform = node_ ? node_->GetWorldTransform() : Matrix3x4::IDENTITY;
     nearClip = Max(nearClip, GetNearClip());
     farClip = Min(farClip, farClip_);
     if (farClip < nearClip)
         farClip = nearClip;
     
     if (!orthographic_)
-        ret.Define(fov_, aspectRatio_, zoom_, nearClip, farClip, GetWorldTransform());
+        ret.Define(fov_, aspectRatio_, zoom_, nearClip, farClip, worldTransform);
     else
-        ret.DefineOrtho(orthoSize_, aspectRatio_, zoom_, nearClip, farClip, GetWorldTransform());
+        ret.DefineOrtho(orthoSize_, aspectRatio_, zoom_, nearClip, farClip, worldTransform);
     
     return ret;
 }
@@ -252,7 +253,7 @@ Ray Camera::GetScreenRay(float x, float y)
     // If projection is invalid, just return a ray pointing forward
     if (!IsProjectionValid())
     {
-        ret.origin_ = GetWorldPosition();
+        ret.origin_ = node_ ? node_->GetWorldPosition() : Vector3::ZERO;
         ret.direction_ = GetForwardVector();
         return ret;
     }
@@ -274,10 +275,11 @@ const Frustum& Camera::GetFrustum() const
 {
     if (frustumDirty_)
     {
+        const Matrix3x4& worldTransform = node_ ? node_->GetWorldTransform() : Matrix3x4::IDENTITY;
         if (!orthographic_)
-            frustum_.Define(fov_, aspectRatio_, zoom_, GetNearClip(), farClip_, GetWorldTransform());
+            frustum_.Define(fov_, aspectRatio_, zoom_, GetNearClip(), farClip_, worldTransform);
         else
-            frustum_.DefineOrtho(orthoSize_, aspectRatio_, zoom_, GetNearClip(), farClip_, GetWorldTransform());
+            frustum_.DefineOrtho(orthoSize_, aspectRatio_, zoom_, GetNearClip(), farClip_, worldTransform);
         
         frustumDirty_ = false;
     }
@@ -406,17 +408,20 @@ float Camera::GetHalfViewSize() const
 
 Vector3 Camera::GetForwardVector()
 {
-    return GetWorldTransform().RotationMatrix() * Vector3::FORWARD;
+    Quaternion worldRotation = node_ ? node_->GetWorldRotation() : Quaternion::IDENTITY;
+    return worldRotation * Vector3::FORWARD;
 }
 
 Vector3 Camera::GetRightVector()
 {
-    return GetWorldTransform().RotationMatrix() * Vector3::RIGHT;
+    Quaternion worldRotation = node_ ? node_->GetWorldRotation() : Quaternion::IDENTITY;
+    return worldRotation * Vector3::RIGHT;
 }
 
 Vector3 Camera::GetUpVector()
 {
-    return GetWorldTransform().RotationMatrix() * Vector3::UP;
+    Quaternion worldRotation = node_ ? node_->GetWorldRotation() : Quaternion::IDENTITY;
+    return worldRotation * Vector3::UP;
 }
 
 float Camera::GetDistance(const Vector3& worldPos) const
@@ -462,7 +467,8 @@ const Matrix3x4& Camera::GetInverseWorldTransform() const
 {
     if (inverseWorldDirty_)
     {
-        inverseWorld_ = GetWorldTransform().Inverse();
+        const Matrix3x4& worldTransform = node_ ? node_->GetWorldTransform() : Matrix3x4::IDENTITY;
+        inverseWorld_ = worldTransform.Inverse();
         inverseWorldDirty_ = false;
     }
     

+ 3 - 3
Engine/Graphics/Light.cpp

@@ -184,7 +184,7 @@ void Light::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResul
     case RAY_OBB:
         if (lightType_ != LIGHT_DIRECTIONAL)
         {
-            Matrix3x4 inverse(GetWorldTransform().Inverse());
+            Matrix3x4 inverse(node_->GetWorldTransform().Inverse());
             Ray localRay(inverse * query.ray_.origin_, inverse * Vector4(query.ray_.direction_, 0.0f));
             float distance = localRay.HitDistance(GetWorldBoundingBox());
             if (distance <= query.maxDistance_)
@@ -256,7 +256,7 @@ void Light::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
             break;
             
         case LIGHT_POINT:
-            debug->AddSphere(Sphere(GetWorldPosition(), range_), GetColor(), depthTest);
+            debug->AddSphere(Sphere(node_->GetWorldPosition(), range_), GetColor(), depthTest);
             break;
         }
     }
@@ -375,7 +375,7 @@ void Light::SetShapeTexture(Texture* texture)
 
 Frustum Light::GetFrustum() const
 {
-    const Matrix3x4& transform = GetWorldTransform();
+    const Matrix3x4& transform = node_ ? node_->GetWorldTransform() : Matrix3x4::IDENTITY;
     Matrix3x4 frustumTransform(transform.Translation(), transform.Rotation(), 1.0f);
     Frustum ret;
     ret.Define(fov_, aspectRatio_, 1.0f, M_MIN_NEARCLIP, range_, frustumTransform);

+ 4 - 3
Engine/Graphics/Renderer.cpp

@@ -769,7 +769,7 @@ Texture2D* Renderer::GetShadowMap(Light* light, Camera* camera, unsigned viewWid
         if (type == LIGHT_POINT)
         {
             // Calculate point light pixel size from the projection of its diagonal
-            Vector3 center = view * light->GetWorldPosition();
+            Vector3 center = view * light->GetNode()->GetWorldPosition();
             float extent = 0.58f * light->GetRange();
             lightBox.Define(center + Vector3(extent, extent, extent), center - Vector3(extent, extent, extent));
         }
@@ -1251,12 +1251,13 @@ void Renderer::OptimizeLightByStencil(Light* light, Camera* camera)
         Geometry* geometry = GetLightGeometry(light);
         const Matrix3x4& view = camera->GetInverseWorldTransform();
         const Matrix4& projection = camera->GetProjection();
+        Vector3 cameraPos = camera->GetNode()->GetWorldPosition();
         float lightDist;
         
         if (type == LIGHT_POINT)
-            lightDist = Sphere(light->GetWorldPosition(), light->GetRange() * 1.25f).Distance(camera->GetWorldPosition());
+            lightDist = Sphere(light->GetNode()->GetWorldPosition(), light->GetRange() * 1.25f).Distance(cameraPos);
         else
-            lightDist = light->GetFrustum().Distance(camera->GetWorldPosition());
+            lightDist = light->GetFrustum().Distance(cameraPos);
         
         // If the camera is actually inside the light volume, do not draw to stencil as it would waste fillrate
         if (lightDist < M_EPSILON)

+ 2 - 2
Engine/Graphics/Skybox.cpp

@@ -62,8 +62,8 @@ void Skybox::GetBatch(Batch& batch, const FrameInfo& frame, unsigned batchIndex)
     StaticModelBatch& srcBatch = batches_[batchIndex];
     
     // Follow only the camera rotation, not position
-    Matrix3x4 customView(Vector3::ZERO, frame.camera_->GetWorldRotation().Inverse(), Vector3::ONE);
-    customWorldTransform_ = customView * GetWorldTransform();
+    Matrix3x4 customView(Vector3::ZERO, frame.camera_->GetNode()->GetWorldRotation().Inverse(), Vector3::ONE);
+    customWorldTransform_ = customView * node_->GetWorldTransform();
     
     batch.distance_ = 0.0f;
     batch.geometry_ = srcBatch.geometry_;

+ 4 - 4
Engine/Graphics/StaticModel.cpp

@@ -85,7 +85,7 @@ void StaticModel::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQuer
         
     case RAY_OBB:
         {
-            Matrix3x4 inverse(GetWorldTransform().Inverse());
+            Matrix3x4 inverse(node_->GetWorldTransform().Inverse());
             Ray localRay(inverse * query.ray_.origin_, inverse * Vector4(query.ray_.direction_, 0.0f));
             float distance = localRay.HitDistance(boundingBox_);
             if (distance <= query.maxDistance_)
@@ -103,7 +103,7 @@ void StaticModel::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQuer
     case RAY_TRIANGLE:
         {
             // Do a pretest using the OBB
-            Matrix3x4 inverse(GetWorldTransform().Inverse());
+            Matrix3x4 inverse(node_->GetWorldTransform().Inverse());
             Ray localRay(inverse * query.ray_.origin_, inverse * Vector4(query.ray_.direction_, 0.0f));
             float distance = localRay.HitDistance(boundingBox_);
             if (distance <= query.maxDistance_)
@@ -249,7 +249,7 @@ bool StaticModel::DrawOcclusion(OcclusionBuffer* buffer)
         unsigned indexCount = geom->GetIndexCount();
         
         // Draw and check for running out of triangles
-        if (!buffer->Draw(GetWorldTransform(), vertexData, vertexSize, indexData, indexSize, indexStart, indexCount))
+        if (!buffer->Draw(node_->GetWorldTransform(), vertexData, vertexSize, indexData, indexSize, indexStart, indexCount))
             success = false;
         
         if (!success)
@@ -361,7 +361,7 @@ const ResourceRefList& StaticModel::GetMaterialsAttr() const
 
 void StaticModel::OnWorldBoundingBoxUpdate()
 {
-    worldBoundingBox_ = boundingBox_.Transformed(GetWorldTransform());
+    worldBoundingBox_ = boundingBox_.Transformed(node_->GetWorldTransform());
 }
 
 void StaticModel::ResetLodLevels()

+ 24 - 20
Engine/Graphics/View.cpp

@@ -315,7 +315,7 @@ bool View::Define(RenderSurface* renderTarget, Viewport* viewport)
 {
     Scene* scene = viewport->GetScene();
     Camera* camera = viewport->GetCamera();
-    if (!scene || !camera)
+    if (!scene || !camera || !camera->GetNode())
         return false;
     
     // If scene is loading asynchronously, it is incomplete and should not be rendered
@@ -329,6 +329,7 @@ bool View::Define(RenderSurface* renderTarget, Viewport* viewport)
     renderMode_ = renderer_->GetRenderMode();
     octree_ = octree;
     camera_ = camera;
+    cameraNode_ = camera->GetNode();
     renderTarget_ = renderTarget;
     
     // Get active post-processing effects on the viewport
@@ -522,7 +523,7 @@ void View::GetDrawables()
     
     highestZonePriority_ = M_MIN_INT;
     int bestPriority = M_MIN_INT;
-    Vector3 cameraPos = camera_->GetWorldPosition();
+    Vector3 cameraPos = cameraNode_->GetWorldPosition();
     
     // Get default zone first in case we do not have zones defined
     Zone* defaultZone = renderer_->GetDefaultZone();
@@ -554,7 +555,7 @@ void View::GetDrawables()
     cameraZoneOverride_ = cameraZone_->GetOverride();
     if (!cameraZoneOverride_)
     {
-        Vector3 farClipPos = cameraPos + camera_->GetNode()->GetWorldDirection() * Vector3(0.0f, 0.0f, camera_->GetFarClip());
+        Vector3 farClipPos = cameraPos + cameraNode_->GetWorldDirection() * Vector3(0.0f, 0.0f, camera_->GetFarClip());
         bestPriority = M_MIN_INT;
         
         for (PODVector<Zone*>::Iterator i = zones_.Begin(); i != zones_.End(); ++i)
@@ -660,7 +661,7 @@ void View::GetDrawables()
     for (unsigned i = 0; i < lights_.Size(); ++i)
     {
         Light* light = lights_[i];
-        light->SetIntensitySortValue(camera_->GetDistance(light->GetWorldPosition()));
+        light->SetIntensitySortValue(camera_->GetDistance(light->GetNode()->GetWorldPosition()));
         light->SetLightQueue(0);
     }
     
@@ -1633,7 +1634,7 @@ void View::UpdateOccluders(PODVector<Drawable*>& occluders, Camera* camera)
     float occluderSizeThreshold_ = renderer_->GetOccluderSizeThreshold();
     float halfViewSize = camera->GetHalfViewSize();
     float invOrthoSize = 1.0f / camera->GetOrthoSize();
-    Vector3 cameraPos = camera->GetWorldPosition();
+    Vector3 cameraPos = camera->GetNode()->GetWorldPosition();
     
     for (PODVector<Drawable*>::Iterator i = occluders.Begin(); i != occluders.End();)
     {
@@ -1742,7 +1743,7 @@ void View::ProcessLight(LightQueryResult& query, unsigned threadIndex)
         
     case LIGHT_POINT:
         {
-            SphereOctreeQuery octreeQuery(tempDrawables, Sphere(light->GetWorldPosition(), light->GetRange()),
+            SphereOctreeQuery octreeQuery(tempDrawables, Sphere(light->GetNode()->GetWorldPosition(), light->GetRange()),
                 DRAWABLE_GEOMETRY, camera_->GetViewMask());
             octree_->GetDrawables(octreeQuery);
             for (unsigned i = 0; i < tempDrawables.Size(); ++i)
@@ -1989,8 +1990,9 @@ void View::SetupShadowCameras(LightQueryResult& query)
         Camera* shadowCamera = renderer_->GetShadowCamera();
         query.shadowCameras_[0] = shadowCamera;
         Node* cameraNode = shadowCamera->GetNode();
+        Node* lightNode = light->GetNode();
         
-        cameraNode->SetTransform(light->GetWorldPosition(), light->GetWorldRotation());
+        cameraNode->SetTransform(lightNode->GetWorldPosition(), lightNode->GetWorldRotation());
         shadowCamera->SetNearClip(light->GetShadowNearFarRatio() * light->GetRange());
         shadowCamera->SetFarClip(light->GetRange());
         shadowCamera->SetFov(light->GetFov());
@@ -2008,7 +2010,7 @@ void View::SetupShadowCameras(LightQueryResult& query)
             Node* cameraNode = shadowCamera->GetNode();
             
             // When making a shadowed point light, align the splits along X, Y and Z axes regardless of light rotation
-            cameraNode->SetPosition(light->GetWorldPosition());
+            cameraNode->SetPosition(light->GetNode()->GetWorldPosition());
             cameraNode->SetDirection(directions[i]);
             shadowCamera->SetNearClip(light->GetShadowNearFarRatio() * light->GetRange());
             shadowCamera->SetFarClip(light->GetRange());
@@ -2024,14 +2026,15 @@ void View::SetupShadowCameras(LightQueryResult& query)
 
 void View::SetupDirLightShadowCamera(Camera* shadowCamera, Light* light, float nearSplit, float farSplit)
 {
-    Node* cameraNode = shadowCamera->GetNode();
+    Node* shadowCameraNode = shadowCamera->GetNode();
+    Node* lightNode = light->GetNode();
     float extrusionDistance = camera_->GetFarClip();
     const FocusParameters& parameters = light->GetShadowFocus();
     
     // Calculate initial position & rotation
-    Vector3 lightWorldDirection = light->GetWorldRotation() * Vector3::FORWARD;
-    Vector3 pos = camera_->GetWorldPosition() - extrusionDistance * lightWorldDirection;
-    cameraNode->SetTransform(pos, light->GetWorldRotation());
+    Vector3 lightWorldDirection = lightNode->GetWorldRotation() * Vector3::FORWARD;
+    Vector3 pos = cameraNode_->GetWorldPosition() - extrusionDistance * lightWorldDirection;
+    shadowCameraNode->SetTransform(pos, lightNode->GetWorldRotation());
     
     // Calculate main camera shadowed frustum in light's view space
     farSplit = Min(farSplit, camera_->GetFarClip());
@@ -2147,7 +2150,7 @@ void View::FinalizeShadowCamera(Camera* shadowCamera, Light* light, const IntRec
 void View::QuantizeDirLightShadowCamera(Camera* shadowCamera, Light* light, const IntRect& shadowViewport,
     const BoundingBox& viewBox)
 {
-    Node* cameraNode = shadowCamera->GetNode();
+    Node* shadowCameraNode = shadowCamera->GetNode();
     const FocusParameters& parameters = light->GetShadowFocus();
     float shadowMapWidth = (float)(shadowViewport.right_ - shadowViewport.left_);
     
@@ -2179,20 +2182,20 @@ void View::QuantizeDirLightShadowCamera(Camera* shadowCamera, Light* light, cons
     shadowCamera->SetOrthoSize(viewSize);
     
     // Center shadow camera to the view space bounding box
-    Vector3 pos(shadowCamera->GetWorldPosition());
-    Quaternion rot(shadowCamera->GetWorldRotation());
+    Vector3 pos(shadowCameraNode->GetWorldPosition());
+    Quaternion rot(shadowCameraNode->GetWorldRotation());
     Vector3 adjust(center.x_, center.y_, 0.0f);
-    cameraNode->Translate(rot * adjust);
+    shadowCameraNode->Translate(rot * adjust);
     
     // If the shadow map viewport is known, snap to whole texels
     if (shadowMapWidth > 0.0f)
     {
-        Vector3 viewPos(rot.Inverse() * cameraNode->GetWorldPosition());
+        Vector3 viewPos(rot.Inverse() * shadowCameraNode->GetWorldPosition());
         // Take into account that shadow map border will not be used
         float invActualSize = 1.0f / (shadowMapWidth - 2.0f);
         Vector2 texelSize(viewSize.x_ * invActualSize, viewSize.y_ * invActualSize);
         Vector3 snap(-fmodf(viewPos.x_, texelSize.x_), -fmodf(viewPos.y_, texelSize.y_), 0.0f);
-        cameraNode->Translate(rot * snap);
+        shadowCameraNode->Translate(rot * snap);
     }
 }
 
@@ -2407,6 +2410,7 @@ void View::SetupLightVolumeBatch(Batch& batch)
 {
     Light* light = batch.lightQueue_->light_;
     LightType type = light->GetLightType();
+    Vector3 cameraPos = cameraNode_->GetWorldPosition();
     float lightDist;
     
     // Use replace blend mode for the first pre-pass light volume, and additive for the rest
@@ -2417,9 +2421,9 @@ void View::SetupLightVolumeBatch(Batch& batch)
     if (type != LIGHT_DIRECTIONAL)
     {
         if (type == LIGHT_POINT)
-            lightDist = Sphere(light->GetWorldPosition(), light->GetRange() * 1.25f).Distance(camera_->GetWorldPosition());
+            lightDist = Sphere(light->GetNode()->GetWorldPosition(), light->GetRange() * 1.25f).Distance(cameraPos);
         else
-            lightDist = light->GetFrustum().Distance(camera_->GetWorldPosition());
+            lightDist = light->GetFrustum().Distance(cameraPos);
         
         // Draw front faces if not inside light volume
         if (lightDist < camera_->GetNearClip() * 2.0f)

+ 2 - 0
Engine/Graphics/View.h

@@ -185,6 +185,8 @@ private:
     Octree* octree_;
     /// Camera to use.
     Camera* camera_;
+    /// Camera's scene node.
+    Node* cameraNode_;
     /// Zone the camera is inside, or default zone if not assigned.
     Zone* cameraZone_;
     /// Zone at far clip plane.

+ 22 - 9
Engine/Graphics/Zone.cpp

@@ -41,14 +41,15 @@ OBJECTTYPESTATIC(Zone);
 
 Zone::Zone(Context* context) :
     Drawable(context),
+    inverseWorldDirty_(true),
+    override_(false),
+    ambientGradient_(false),
     boundingBox_(DEFAULT_BOUNDING_BOX_MIN, DEFAULT_BOUNDING_BOX_MAX),
     ambientColor_(DEFAULT_AMBIENT_COLOR),
     fogColor_(DEFAULT_FOG_COLOR),
     fogStart_(DEFAULT_FOG_START),
     fogEnd_(DEFAULT_FOG_END),
-    priority_(0),
-    override_(false),
-    ambientGradient_(false)
+    priority_(0)
 {
     drawableFlags_ =  DRAWABLE_ZONE;
 }
@@ -95,7 +96,7 @@ void Zone::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
 void Zone::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
 {
     if (debug)
-        debug->AddBoundingBox(boundingBox_, GetWorldTransform(), Color::GREEN, depthTest);
+        debug->AddBoundingBox(boundingBox_, node_->GetWorldTransform(), Color::GREEN, depthTest);
 }
 
 void Zone::SetBoundingBox(const BoundingBox& box)
@@ -153,6 +154,18 @@ void Zone::SetAmbientGradient(bool enable)
     MarkNetworkUpdate();
 }
 
+const Matrix3x4& Zone::GetInverseWorldTransform() const
+{
+    if (inverseWorldDirty_ && node_)
+    {
+        const Matrix3x4& worldTransform = node_ ? node_->GetWorldTransform() : Matrix3x4::IDENTITY;
+        inverseWorld_ = worldTransform.Inverse();
+        inverseWorldDirty_ = false;
+    }
+    
+    return inverseWorld_;
+}
+
 const Color& Zone::GetAmbientStartColor()
 {
     if (!ambientGradient_)
@@ -175,11 +188,10 @@ const Color& Zone::GetAmbientEndColor()
     return ambientEndColor_;
 }
 
-bool Zone::IsInside(const Vector3& point)
+bool Zone::IsInside(const Vector3& point) const
 {
     // Use an oriented bounding box test
-    Matrix3x4 inverse(GetWorldTransform().Inverse());
-    Vector3 localPoint(inverse * point);
+    Vector3 localPoint(GetInverseWorldTransform() * point);
     return boundingBox_.IsInside(localPoint) != OUTSIDE;
 }
 
@@ -213,11 +225,12 @@ void Zone::OnMarkedDirty(Node* node)
     lastWorldBoundingBox_ = GetWorldBoundingBox();
     lastAmbientStartZone_.Reset();
     lastAmbientEndZone_.Reset();
+    inverseWorldDirty_ = true;
 }
 
 void Zone::OnWorldBoundingBoxUpdate()
 {
-    worldBoundingBox_ = boundingBox_.Transformed(GetWorldTransform());
+    worldBoundingBox_ = boundingBox_.Transformed(node_->GetWorldTransform());
 }
 
 void Zone::UpdateAmbientGradient()
@@ -230,7 +243,7 @@ void Zone::UpdateAmbientGradient()
     
     if (octant_)
     {
-        const Matrix3x4& worldTransform = GetWorldTransform();
+        const Matrix3x4& worldTransform = node_->GetWorldTransform();
         Vector3 center = boundingBox_.Center();
         Vector3 minZPosition = worldTransform * Vector3(center.x_, center.y_, boundingBox_.min_.z_);
         Vector3 maxZPosition = worldTransform * Vector3(center.x_, center.y_, boundingBox_.max_.z_);

+ 15 - 9
Engine/Graphics/Zone.h

@@ -63,6 +63,8 @@ public:
     
     /// Return bounding box.
     const BoundingBox& GetBoundingBox() const { return boundingBox_; }
+    /// Return inverse world transform.
+    const Matrix3x4& GetInverseWorldTransform() const;
     /// Return zone's own ambient color, disregarding gradient mode.
     const Color& GetAmbientColor() const { return ambientColor_; }
     /// Return ambient start color.
@@ -83,7 +85,7 @@ public:
     bool GetAmbientGradient() const { return ambientGradient_; }
     
     /// Check whether a point is inside.
-    virtual bool IsInside(const Vector3& point);
+    bool IsInside(const Vector3& point) const;
     
 protected:
     /// Transform has changed. Clear cached zone of any contained drawables.
@@ -93,10 +95,14 @@ protected:
     /// Recalculate the ambient gradient colors from neighbor zones.
     void UpdateAmbientGradient();
     
-    /// Last zone used for ambient gradient start color.
-    WeakPtr<Zone> lastAmbientStartZone_;
-    /// Last zone used for ambient gradient end color.
-    WeakPtr<Zone> lastAmbientEndZone_;
+    /// Cached inverse world transform matrix.
+    mutable Matrix3x4 inverseWorld_;
+    /// Inverse transform dirty flag.
+    mutable bool inverseWorldDirty_;
+    /// Override mode flag.
+    bool override_;
+    /// Ambient gradient mode flag.
+    bool ambientGradient_;
     /// Bounding box.
     BoundingBox boundingBox_;
     /// Last world-space bounding box.
@@ -115,8 +121,8 @@ protected:
     float fogEnd_;
     /// Zone priority.
     int priority_;
-    /// Override mode flag.
-    bool override_;
-    /// Ambient gradient mode flag.
-    bool ambientGradient_;
+    /// Last zone used for ambient gradient start color.
+    WeakPtr<Zone> lastAmbientStartZone_;
+    /// Last zone used for ambient gradient end color.
+    WeakPtr<Zone> lastAmbientEndZone_;
 };

+ 0 - 5
Engine/Scene/Component.cpp

@@ -85,11 +85,6 @@ Scene* Component::GetScene() const
     return node_ ? node_->GetScene() : 0;
 }
 
-const Matrix3x4& Component::GetWorldTransform() const
-{
-    return node_ ? node_->GetWorldTransform() : Matrix3x4::IDENTITY;
-}
-
 void Component::AddReplicationState(ComponentReplicationState* state)
 {
     if (!networkState_)

+ 0 - 8
Engine/Scene/Component.h

@@ -63,14 +63,6 @@ public:
     Node* GetNode() const { return node_; }
     /// Return the scene the node belongs to.
     Scene* GetScene() const;
-    /// Return parent node's transform matrix in world space.
-    const Matrix3x4& GetWorldTransform() const;
-    /// Return parent node's position in world space.
-    Vector3 GetWorldPosition() const { return GetWorldTransform().Translation(); }
-    /// Return parent node's rotation in world space.
-    Quaternion GetWorldRotation() const { return GetWorldTransform().Rotation(); }
-    /// Return parent node's scale in world space.
-    Vector3 GetWorldScale() const { return GetWorldTransform().Scale(); }
     /// Return components in the same scene node by type.
     void GetComponents(PODVector<Component*>& dest, ShortStringHash type) const;
     /// Return component in the same scene node by type. If there are several, returns the first.