瀏覽代碼

Renamed Camera::GetInverseWorldTransform() to Camera::GetView() as world transform includes scale, but camera view matrix should be unaffected by it.
Fixed spotlight frustum being affected by node scale.
Note: fix is yet incomplete, Node::GetWorldRotation() needs changing to work correctly when parent has nonuniform scale.

Lasse Öörni 12 年之前
父節點
當前提交
26402a255a

+ 1 - 1
Engine/Engine/GraphicsAPI.cpp

@@ -104,7 +104,7 @@ static void RegisterCamera(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Camera", "FillMode get_fillMode() const", asMETHOD(Camera, GetFillMode), asCALL_THISCALL);
     engine->RegisterObjectMethod("Camera", "const Frustum& get_frustum() const", asMETHOD(Camera, GetFrustum), asCALL_THISCALL);
     engine->RegisterObjectMethod("Camera", "const Matrix4& get_projection() const", asMETHODPR(Camera, GetProjection, () const, const Matrix4&), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Camera", "const Matrix3x4& get_inverseWorldTransform() const", asMETHOD(Camera, GetInverseWorldTransform), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Camera", "const Matrix3x4& get_view() const", asMETHOD(Camera, GetView), asCALL_THISCALL);
     engine->RegisterObjectMethod("Camera", "Frustum get_viewSpaceFrustum() const", asMETHOD(Camera, GetViewSpaceFrustum), asCALL_THISCALL);
     engine->RegisterObjectMethod("Camera", "float get_halfViewSize() const", asMETHOD(Camera, GetHalfViewSize), asCALL_THISCALL);
     engine->RegisterObjectMethod("Camera", "Vector3 get_forwardVector() const", asMETHOD(Camera, GetForwardVector), asCALL_THISCALL);

+ 8 - 10
Engine/Graphics/Batch.cpp

@@ -78,7 +78,7 @@ void CalculateShadowMatrix(Matrix4& dest, LightBatchQueue* queue, unsigned split
     const IntRect& viewport = queue->shadowSplits_[split].shadowViewport_;
     
     Matrix3x4 posAdjust(translation, Quaternion::IDENTITY, 1.0f);
-    Matrix3x4 shadowView(shadowCamera->GetInverseWorldTransform());
+    Matrix3x4 shadowView(shadowCamera->GetView());
     Matrix4 shadowProj(shadowCamera->GetProjection());
     Matrix4 texAdjust(Matrix4::IDENTITY);
     
@@ -131,9 +131,7 @@ void CalculateSpotMatrix(Matrix4& dest, Light* light, const Vector3& translation
 {
     Node* lightNode = light->GetNode();
     Matrix3x4 posAdjust(translation, Quaternion::IDENTITY, 1.0f);
-    Matrix3x4 spotView = lightNode->GetWorldTransform();
-    // Remove any scaling
-    spotView.SetRotation(spotView.RotationMatrix());
+    Matrix3x4 spotView = Matrix3x4(lightNode->GetWorldPosition(), lightNode->GetWorldRotation(), 1.0f).Inverse();
     Matrix4 spotProj(Matrix4::ZERO);
     Matrix4 texAdjust(Matrix4::IDENTITY);
     
@@ -153,7 +151,7 @@ void CalculateSpotMatrix(Matrix4& dest, Light* light, const Vector3& translation
     texAdjust.SetScale(Vector3(0.5f, -0.5f, 1.0f));
     #endif
     
-    dest = texAdjust * spotProj * spotView.Inverse() * posAdjust;
+    dest = texAdjust * spotProj * spotView * posAdjust;
 }
 
 void Batch::CalculateSortKey()
@@ -217,7 +215,7 @@ void Batch::Prepare(View* view, bool setModelTransform) const
     if (graphics->NeedParameterUpdate(SP_CAMERA, (void*)cameraHash))
     {
         // Calculate camera rotation just once
-        Matrix3 cameraWorldRotation = cameraNode->GetWorldTransform().RotationMatrix();
+        Matrix3 cameraWorldRotation = cameraNode->GetWorldRotation().RotationMatrix();
         
         graphics->SetShaderParameter(VSP_CAMERAPOS, cameraNode->GetWorldPosition());
         graphics->SetShaderParameter(VSP_CAMERAROT, cameraWorldRotation);
@@ -258,7 +256,7 @@ void Batch::Prepare(View* view, bool setModelTransform) const
         if (overrideView_)
             graphics->SetShaderParameter(VSP_VIEWPROJ, projection);
         else
-            graphics->SetShaderParameter(VSP_VIEWPROJ, projection * camera_->GetInverseWorldTransform());
+            graphics->SetShaderParameter(VSP_VIEWPROJ, projection * camera_->GetView());
         
         graphics->SetShaderParameter(VSP_VIEWRIGHTVECTOR, cameraWorldRotation * Vector3::RIGHT);
         graphics->SetShaderParameter(VSP_VIEWUPVECTOR, cameraWorldRotation * Vector3::UP);
@@ -393,7 +391,7 @@ void Batch::Prepare(View* view, bool setModelTransform) const
     if (light && graphics->NeedParameterUpdate(SP_LIGHT, light))
     {
         Node* lightNode = light->GetNode();
-        Matrix3 lightWorldRotation = lightNode->GetWorldTransform().RotationMatrix();
+        Matrix3 lightWorldRotation = lightNode->GetWorldRotation().RotationMatrix();
         
         graphics->SetShaderParameter(VSP_LIGHTDIR, lightWorldRotation * Vector3::BACK);
         
@@ -430,7 +428,7 @@ void Batch::Prepare(View* view, bool setModelTransform) const
                 
             case LIGHT_POINT:
                 {
-                    Matrix4 lightVecRot(lightNode->GetWorldTransform().RotationMatrix());
+                    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
@@ -485,7 +483,7 @@ void Batch::Prepare(View* view, bool setModelTransform) const
                 
             case LIGHT_POINT:
                 {
-                    Matrix4 lightVecRot(lightNode->GetWorldTransform().RotationMatrix());
+                    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

+ 1 - 2
Engine/Graphics/BillboardSet.cpp

@@ -102,8 +102,7 @@ void BillboardSet::RegisterObject(Context* context)
 void BillboardSet::UpdateBatches(const FrameInfo& frame)
 {
     // Check if position relative to camera has changed, and re-sort in that case
-    const Matrix3x4& worldTransform = node_->GetWorldTransform();
-    Vector3 worldPos = worldTransform.Translation();
+    Vector3 worldPos = node_->GetWorldPosition();
     Vector3 offset = (worldPos - frame.camera_->GetNode()->GetWorldPosition());
     if (offset != previousOffset_)
     {

+ 15 - 15
Engine/Graphics/Camera.cpp

@@ -57,7 +57,7 @@ OBJECTTYPESTATIC(Camera);
 
 Camera::Camera(Context* context) :
     Component(context),
-    inverseWorldDirty_(true),
+    viewDirty_(true),
     projectionDirty_(true),
     frustumDirty_(true),
     orthographic_(false),
@@ -280,7 +280,7 @@ Ray Camera::GetScreenRay(float x, float y) const
         return ret;
     }
 
-    Matrix4 viewProjInverse = (GetProjection(false) * GetInverseWorldTransform()).Inverse();
+    Matrix4 viewProjInverse = (GetProjection(false) * GetView()).Inverse();
 
     // The parameters range from 0.0 to 1.0. Expand to normalized device coordinates (-1.0 to 1.0) & flip Y axis
     x = 2.0f * x - 1.0f;
@@ -295,7 +295,7 @@ Ray Camera::GetScreenRay(float x, float y) const
 
 Vector2 Camera::WorldToScreenPoint(const Vector3& worldPos) const
 {
-    Vector3 eyeSpacePos = GetInverseWorldTransform() * worldPos;
+    Vector3 eyeSpacePos = GetView() * worldPos;
     Vector2 ret;
 
     if(eyeSpacePos.z_ > 0.0f)
@@ -463,12 +463,12 @@ Vector3 Camera::GetForwardVector() const
 
 Vector3 Camera::GetRightVector() const
 {
-    return node_ ? node_->GetWorldTransform().RotationMatrix() * Vector3::RIGHT : Vector3::RIGHT;
+    return node_ ? node_->GetWorldRotation() * Vector3::RIGHT : Vector3::RIGHT;
 }
 
 Vector3 Camera::GetUpVector() const
 {
-    return node_ ? node_->GetWorldTransform().RotationMatrix() * Vector3::UP : Vector3::UP;
+    return node_ ? node_->GetWorldRotation() * Vector3::UP : Vector3::UP;
 }
 
 float Camera::GetDistance(const Vector3& worldPos) const
@@ -479,7 +479,7 @@ float Camera::GetDistance(const Vector3& worldPos) const
         return (worldPos - cameraPos).Length();
     }
     else
-        return Abs((GetInverseWorldTransform() * worldPos).z_);
+        return Abs((GetView() * worldPos).z_);
 }
 
 float Camera::GetDistanceSquared(const Vector3& worldPos) const
@@ -491,7 +491,7 @@ float Camera::GetDistanceSquared(const Vector3& worldPos) const
     }
     else
     {
-        float distance = (GetInverseWorldTransform() * worldPos).z_;
+        float distance = (GetView() * worldPos).z_;
         return distance * distance;
     }
 }
@@ -510,16 +510,16 @@ bool Camera::IsProjectionValid() const
     return farClip_ > GetNearClip();
 }
 
-const Matrix3x4& Camera::GetInverseWorldTransform() const
+const Matrix3x4& Camera::GetView() const
 {
-    if (inverseWorldDirty_)
+    if (viewDirty_)
     {
-        const Matrix3x4& worldTransform = node_ ? node_->GetWorldTransform() : Matrix3x4::IDENTITY;
-        inverseWorld_ = worldTransform.Inverse();
-        inverseWorldDirty_ = false;
+        // Note: view matrix is unaffected by node or parent scale
+        view_ = node_ ? Matrix3x4(node_->GetWorldPosition(), node_->GetWorldRotation(), 1.0f).Inverse() : Matrix3x4::IDENTITY;
+        viewDirty_ = false;
     }
-
-    return inverseWorld_;
+    
+    return view_;
 }
 
 void Camera::OnNodeSet(Node* node)
@@ -531,7 +531,7 @@ void Camera::OnNodeSet(Node* node)
 void Camera::OnMarkedDirty(Node* node)
 {
     frustumDirty_ = true;
-    inverseWorldDirty_ = true;
+    viewDirty_ = true;
 }
 
 }

+ 6 - 7
Engine/Graphics/Camera.h

@@ -109,6 +109,8 @@ public:
     const Matrix4& GetProjection() const;
     /// Return either API-specific or API-independent (D3D convention) projection matrix.
     Matrix4 GetProjection(bool apiSpecific) const;
+    /// Return view matrix.
+    const Matrix3x4& GetView() const;
     /// Return frustum near and far sizes.
     void GetFrustumSize(Vector3& near, Vector3& far) const;
     /// Return half view size.
@@ -144,9 +146,6 @@ public:
     /// Return if projection parameters are valid for rendering and raycasting.
     bool IsProjectionValid() const;
     
-    /// Return inverse world transform, also known as the view matrix.
-    const Matrix3x4& GetInverseWorldTransform() const;
-    
 protected:
     /// Handle node being assigned.
     virtual void OnNodeSet(Node* node);
@@ -154,14 +153,14 @@ protected:
     virtual void OnMarkedDirty(Node* node);
     
 private:
-    /// Cached inverse world transform matrix.
-    mutable Matrix3x4 inverseWorld_;
+    /// Cached view matrix.
+    mutable Matrix3x4 view_;
     /// Cached projection matrix.
     mutable Matrix4 projection_;
     /// Cached frustum.
     mutable Frustum frustum_;
-    /// Inverse world transform dirty flag.
-    mutable bool inverseWorldDirty_;
+    /// View matrix dirty flag.
+    mutable bool viewDirty_;
     /// Projection matrix dirty flag.
     mutable bool projectionDirty_;
     /// Frustum dirty flag.

+ 1 - 1
Engine/Graphics/DebugRenderer.cpp

@@ -70,7 +70,7 @@ void DebugRenderer::SetView(Camera* camera)
     if (!camera)
         return;
 
-    view_ = camera->GetInverseWorldTransform();
+    view_ = camera->GetView();
     projection_ = camera->GetProjection();
     frustum_ = camera->GetFrustum();
 }

+ 8 - 6
Engine/Graphics/Light.cpp

@@ -368,8 +368,9 @@ void Light::SetShapeTexture(Texture* texture)
 
 Frustum Light::GetFrustum() const
 {
-    const Matrix3x4& transform = node_ ? node_->GetWorldTransform() : Matrix3x4::IDENTITY;
-    Matrix3x4 frustumTransform(transform.Translation(), transform.Rotation(), 1.0f);
+    // Note: frustum is unaffected by node or parent scale
+    Matrix3x4 frustumTransform(node_ ? Matrix3x4(node_->GetWorldPosition(), node_->GetWorldRotation(), 1.0f) :
+        Matrix3x4::IDENTITY);
     Frustum ret;
     ret.Define(fov_, aspectRatio_, 1.0f, M_MIN_NEARCLIP, range_, frustumTransform);
     return ret;
@@ -400,8 +401,9 @@ Matrix3x4 Light::GetDirLightTransform(Camera* camera, bool getNearQuad)
 
 const Matrix3x4& Light::GetVolumeTransform(Camera* camera)
 {
-    const Matrix3x4& transform = node_->GetWorldTransform();
-
+    if (!node_)
+        return Matrix3x4::IDENTITY;
+    
     switch (lightType_)
     {
     case LIGHT_DIRECTIONAL:
@@ -412,12 +414,12 @@ const Matrix3x4& Light::GetVolumeTransform(Camera* camera)
         {
             float yScale = tanf(fov_ * M_DEGTORAD * 0.5f) * range_;
             float xScale = aspectRatio_ * yScale;
-            volumeTransform_ = Matrix3x4(transform.Translation(), transform.Rotation(), Vector3(xScale, yScale, range_));
+            volumeTransform_ = Matrix3x4(node_->GetWorldPosition(), node_->GetWorldRotation(), Vector3(xScale, yScale, range_));
         }
         break;
 
     case LIGHT_POINT:
-        volumeTransform_ = Matrix3x4(transform.Translation(), Quaternion::IDENTITY, range_);
+        volumeTransform_ = Matrix3x4(node_->GetWorldPosition(), Quaternion::IDENTITY, range_);
         break;
     }
 

+ 1 - 1
Engine/Graphics/OcclusionBuffer.cpp

@@ -109,7 +109,7 @@ void OcclusionBuffer::SetView(Camera* camera)
     if (!camera)
         return;
     
-    view_ = camera->GetInverseWorldTransform();
+    view_ = camera->GetView();
     projection_ = camera->GetProjection(false);
     viewProj_ = projection_ * view_;
     nearClip_ = camera->GetNearClip();

+ 3 - 3
Engine/Graphics/Renderer.cpp

@@ -819,7 +819,7 @@ Texture2D* Renderer::GetShadowMap(Light* light, Camera* camera, unsigned viewWid
     // Automatically reduce shadow map size when far away
     if (parameters.autoSize_ && type != LIGHT_DIRECTIONAL)
     {
-        const Matrix3x4& view = camera->GetInverseWorldTransform();
+        const Matrix3x4& view = camera->GetView();
         const Matrix4& projection = camera->GetProjection();
         BoundingBox lightBox;
         float lightPixels;
@@ -1318,7 +1318,7 @@ void Renderer::OptimizeLightByStencil(Light* light, Camera* camera)
         }
         
         Geometry* geometry = GetLightGeometry(light);
-        const Matrix3x4& view = camera->GetInverseWorldTransform();
+        const Matrix3x4& view = camera->GetView();
         const Matrix4& projection = camera->GetProjection();
         Vector3 cameraPos = camera->GetNode()->GetWorldPosition();
         float lightDist;
@@ -1384,7 +1384,7 @@ const Rect& Renderer::GetLightScissor(Light* light, Camera* camera)
     if (i != lightScissorCache_.End())
         return i->second_;
     
-    const Matrix3x4& view = camera->GetInverseWorldTransform();
+    const Matrix3x4& view = camera->GetView();
     const Matrix4& projection = camera->GetProjection();
     
     assert(light->GetLightType() != LIGHT_DIRECTIONAL);

+ 3 - 3
Engine/Graphics/View.cpp

@@ -171,7 +171,7 @@ void CheckVisibilityWork(const WorkItem* item, unsigned threadIndex)
     Drawable** start = reinterpret_cast<Drawable**>(item->start_);
     Drawable** end = reinterpret_cast<Drawable**>(item->end_);
     OcclusionBuffer* buffer = view->occlusionBuffer_;
-    const Matrix3x4& viewMatrix = view->camera_->GetInverseWorldTransform();
+    const Matrix3x4& viewMatrix = view->camera_->GetView();
     Vector3 viewZ = Vector3(viewMatrix.m20_, viewMatrix.m21_, viewMatrix.m22_);
     Vector3 absViewZ = viewZ.Abs();
     
@@ -1841,7 +1841,7 @@ void View::ProcessShadowCasters(LightQueryResult& query, const PODVector<Drawabl
     
     Camera* shadowCamera = query.shadowCameras_[splitIndex];
     const Frustum& shadowCameraFrustum = shadowCamera->GetFrustum();
-    const Matrix3x4& lightView = shadowCamera->GetInverseWorldTransform();
+    const Matrix3x4& lightView = shadowCamera->GetView();
     const Matrix4& lightProj = shadowCamera->GetProjection();
     LightType type = light->GetLightType();
     
@@ -2107,7 +2107,7 @@ void View::SetupDirLightShadowCamera(Camera* shadowCamera, Light* light, float n
     }
     
     // Transform frustum volume to light space
-    const Matrix3x4& lightView = shadowCamera->GetInverseWorldTransform();
+    const Matrix3x4& lightView = shadowCamera->GetView();
     frustumVolume.Transform(lightView);
     
     // Fit the frustum volume inside a bounding box. If uniform size, use a sphere instead

+ 2 - 1
Engine/Scene/Node.h

@@ -206,13 +206,14 @@ public:
     /// Return rotation in world space.
     Quaternion GetWorldRotation() const
     {
+        /// \todo This is potentially incorrect if parent has nonuniform scaling
         return GetWorldTransform().Rotation();
     }
 
     /// Return direction in world space.
     Vector3 GetWorldDirection() const
     {
-        return GetWorldTransform().RotationMatrix() * Vector3::FORWARD;
+        return GetWorldRotation() * Vector3::FORWARD;
     }
 
     /// Return scale in world space.