Browse Source

Added function to get API-independent projection matrix.
Preallocate light queues once per frame instead of resizing the light queue container multiple times.

Lasse Öörni 13 years ago
parent
commit
66f3fd4097

+ 1 - 1
Engine/Engine/GraphicsAPI.cpp

@@ -87,7 +87,7 @@ static void RegisterCamera(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Camera", "void set_viewOverrideFlags(uint)", asMETHOD(Camera, SetViewOverrideFlags), asCALL_THISCALL);
     engine->RegisterObjectMethod("Camera", "void set_viewOverrideFlags(uint)", asMETHOD(Camera, SetViewOverrideFlags), asCALL_THISCALL);
     engine->RegisterObjectMethod("Camera", "uint get_viewOverrideFlags() const", asMETHOD(Camera, GetViewOverrideFlags), asCALL_THISCALL);
     engine->RegisterObjectMethod("Camera", "uint get_viewOverrideFlags() const", asMETHOD(Camera, GetViewOverrideFlags), asCALL_THISCALL);
     engine->RegisterObjectMethod("Camera", "const Frustum& get_frustum()", asMETHOD(Camera, GetFrustum), asCALL_THISCALL);
     engine->RegisterObjectMethod("Camera", "const Frustum& get_frustum()", asMETHOD(Camera, GetFrustum), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Camera", "const Matrix4& get_projection()", asMETHOD(Camera, GetProjection), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Camera", "const Matrix4& get_projection()", asMETHODPR(Camera, GetProjection, (), const Matrix4&), asCALL_THISCALL);
     engine->RegisterObjectMethod("Camera", "Frustum get_viewSpaceFrustum() const", asMETHOD(Camera, GetViewSpaceFrustum), 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", "float get_halfViewSize() const", asMETHOD(Camera, GetHalfViewSize), asCALL_THISCALL);
     engine->RegisterObjectMethod("Camera", "Vector3 get_forwardVector()", asMETHOD(Camera, GetForwardVector), asCALL_THISCALL);
     engine->RegisterObjectMethod("Camera", "Vector3 get_forwardVector()", asMETHOD(Camera, GetForwardVector), asCALL_THISCALL);

+ 64 - 44
Engine/Graphics/Camera.cpp

@@ -242,19 +242,13 @@ Ray Camera::GetScreenRay(float x, float y)
         return ret;
         return ret;
     }
     }
     
     
-    Matrix4 viewProjInverse = (GetProjection() * GetInverseWorldTransform()).Inverse();
+    Matrix4 viewProjInverse = (GetProjection(false) * GetInverseWorldTransform()).Inverse();
     
     
     // The parameters range from 0.0 to 1.0. Expand to normalized device coordinates (-1.0 to 1.0) & flip Y axis
     // 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;
     x = 2.0f * x - 1.0f;
     y = 1.0f - 2.0f * y;
     y = 1.0f - 2.0f * y;
-    
-    #ifdef USE_OPENGL
-    Vector3 near(x, y, -1.0f);
-    Vector3 far(x, y, 1.0f);
-    #else
     Vector3 near(x, y, 0.0f);
     Vector3 near(x, y, 0.0f);
     Vector3 far(x, y, 1.0f);
     Vector3 far(x, y, 1.0f);
-    #endif
     
     
     ret.origin_ = viewProjInverse * near;
     ret.origin_ = viewProjInverse * near;
     ret.direction_ = ((viewProjInverse * far) - ret.origin_).Normalized();
     ret.direction_ = ((viewProjInverse * far) - ret.origin_).Normalized();
@@ -280,58 +274,84 @@ const Matrix4& Camera::GetProjection()
 {
 {
     if (projectionDirty_)
     if (projectionDirty_)
     {
     {
-        projection_ = Matrix4::ZERO;
+        projection_ = GetProjection(true);
+        projectionDirty_ = false;
+    }
+    
+    return projection_;
+}
+
+Matrix4 Camera::GetProjection(bool apiSpecific) const
+{
+    Matrix4 ret(Matrix4::ZERO);
+    
+    if (!orthographic_)
+    {
+        float nearClip = GetNearClip();
+        float h = (1.0f / tanf(fov_ * M_DEGTORAD * 0.5f)) * zoom_;
+        float w = h / aspectRatio_;
+        float q, r;
         
         
-        if (!orthographic_)
+        if (apiSpecific)
         {
         {
-            float nearClip = GetNearClip();
-            float h = (1.0f / tanf(fov_ * M_DEGTORAD * 0.5f)) * zoom_;
-            float w = h / aspectRatio_;
             #ifdef USE_OPENGL
             #ifdef USE_OPENGL
-            float q = (farClip_ + nearClip) / (farClip_ - nearClip);
-            float r = -2.0f * farClip_ * nearClip / (farClip_ - nearClip);
+            q = (farClip_ + nearClip) / (farClip_ - nearClip);
+            r = -2.0f * farClip_ * nearClip / (farClip_ - nearClip);
             #else
             #else
-            float q = farClip_ / (farClip_ - nearClip);
-            float r = -q * nearClip;
+            q = farClip_ / (farClip_ - nearClip);
+            r = -q * nearClip;
             #endif
             #endif
-            
-            projection_.m00_ = w;
-            projection_.m02_ = projectionOffset_.x_ * 2.0f;
-            projection_.m11_ = h;
-            projection_.m12_ = projectionOffset_.y_ * 2.0f;
-            projection_.m22_ = q;
-            projection_.m23_ = r;
-            projection_.m32_ = 1.0f;
         }
         }
         else
         else
         {
         {
-            // Disregard near clip, because it does not affect depth precision as with perspective projection
-            float h = (1.0f / (orthoSize_ * 0.5f)) * zoom_;
-            float w = h / aspectRatio_;
+            q = farClip_ / (farClip_ - nearClip);
+            r = -q * nearClip;
+        }
+        
+        ret.m00_ = w;
+        ret.m02_ = projectionOffset_.x_ * 2.0f;
+        ret.m11_ = h;
+        ret.m12_ = projectionOffset_.y_ * 2.0f;
+        ret.m22_ = q;
+        ret.m23_ = r;
+        ret.m32_ = 1.0f;
+    }
+    else
+    {
+        // Disregard near clip, because it does not affect depth precision as with perspective projection
+        float h = (1.0f / (orthoSize_ * 0.5f)) * zoom_;
+        float w = h / aspectRatio_;
+        float q, r;
+        
+        if (apiSpecific)
+        {
             #ifdef USE_OPENGL
             #ifdef USE_OPENGL
-            float q = 2.0f / farClip_;
-            float r = -1.0f;
+            q = 2.0f / farClip_;
+            r = -1.0f;
             #else
             #else
-            float q = 1.0f / farClip_;
-            float r = 0.0f;
+            q = 1.0f / farClip_;
+            r = 0.0f;
             #endif
             #endif
-            
-            projection_.m00_ = w;
-            projection_.m03_ = projectionOffset_.x_ * 2.0f;
-            projection_.m11_ = h;
-            projection_.m13_ = projectionOffset_.y_ * 2.0f;
-            projection_.m22_ = q;
-            projection_.m23_ = r;
-            projection_.m33_ = 1.0f;
+        }
+        else
+        {
+            q = 1.0f / farClip_;
+            r = 0.0f;
         }
         }
         
         
-        if (flipVertical_)
-            projection_ = flipMatrix * projection_;
-        
-        projectionDirty_ = false;
+        ret.m00_ = w;
+        ret.m03_ = projectionOffset_.x_ * 2.0f;
+        ret.m11_ = h;
+        ret.m13_ = projectionOffset_.y_ * 2.0f;
+        ret.m22_ = q;
+        ret.m23_ = r;
+        ret.m33_ = 1.0f;
     }
     }
     
     
-    return projection_;
+    if (flipVertical_)
+        ret = flipMatrix * ret;
+    
+    return ret;
 }
 }
 
 
 void Camera::GetFrustumSize(Vector3& near, Vector3& far) const
 void Camera::GetFrustumSize(Vector3& near, Vector3& far) const

+ 3 - 1
Engine/Graphics/Camera.h

@@ -99,8 +99,10 @@ public:
     bool GetAutoAspectRatio() const { return autoAspectRatio_; }
     bool GetAutoAspectRatio() const { return autoAspectRatio_; }
     /// Return frustum in world space.
     /// Return frustum in world space.
     const Frustum& GetFrustum();
     const Frustum& GetFrustum();
-    /// Return projection matrix.
+    /// Return API-specific projection matrix.
     const Matrix4& GetProjection();
     const Matrix4& GetProjection();
+    /// Return either API-specific or API-independent (D3D convention) projection matrix.
+    Matrix4 GetProjection(bool apiSpecific) const;
     /// Return frustum near and far sizes.
     /// Return frustum near and far sizes.
     void GetFrustumSize(Vector3& near, Vector3& far) const;
     void GetFrustumSize(Vector3& near, Vector3& far) const;
     /// Return half view size.
     /// Return half view size.

+ 1 - 1
Engine/Graphics/OcclusionBuffer.cpp

@@ -107,7 +107,7 @@ void OcclusionBuffer::SetView(Camera* camera)
         return;
         return;
     
     
     view_ = camera->GetInverseWorldTransform();
     view_ = camera->GetInverseWorldTransform();
-    projection_ = camera->GetProjection();
+    projection_ = camera->GetProjection(false);
     viewProj_ = projection_ * view_;
     viewProj_ = projection_ * view_;
     nearClip_ = camera->GetNearClip();
     nearClip_ = camera->GetNearClip();
     farClip_ = camera->GetFarClip();
     farClip_ = camera->GetFarClip();

+ 2 - 2
Engine/Graphics/Renderer.cpp

@@ -538,9 +538,9 @@ unsigned Renderer::GetNumShadowMaps(bool allViews) const
     
     
     for (unsigned i = 0; i < lastView; ++i)
     for (unsigned i = 0; i < lastView; ++i)
     {
     {
-        const List<LightBatchQueue>& lightQueues = views_[i]->GetLightQueues();
+        const Vector<LightBatchQueue>& lightQueues = views_[i]->GetLightQueues();
         
         
-        for (List<LightBatchQueue>::ConstIterator i = lightQueues.Begin(); i != lightQueues.End(); ++i)
+        for (Vector<LightBatchQueue>::ConstIterator i = lightQueues.Begin(); i != lightQueues.End(); ++i)
         {
         {
             if (i->shadowMap_)
             if (i->shadowMap_)
                 ++numShadowMaps;
                 ++numShadowMaps;

+ 20 - 9
Engine/Graphics/View.cpp

@@ -689,9 +689,21 @@ void View::GetBatches()
         maxLightsDrawables_.Clear();
         maxLightsDrawables_.Clear();
         lightQueueMapping_.Clear();
         lightQueueMapping_.Clear();
         
         
+        // Preallocate light queues: per-pixel lights which have lit geometries
+        unsigned numLightQueues = 0;
+        unsigned usedLightQueues = 0;
+        for (Vector<LightQueryResult>::ConstIterator i = lightQueryResults_.Begin(); i != lightQueryResults_.End(); ++i)
+        {
+            if (!i->light_->GetPerVertex() && i->litGeometries_.Size())
+                ++numLightQueues;
+        }
+        
+        lightQueues_.Resize(numLightQueues);
+        
         for (Vector<LightQueryResult>::ConstIterator i = lightQueryResults_.Begin(); i != lightQueryResults_.End(); ++i)
         for (Vector<LightQueryResult>::ConstIterator i = lightQueryResults_.Begin(); i != lightQueryResults_.End(); ++i)
         {
         {
             const LightQueryResult& query = *i;
             const LightQueryResult& query = *i;
+            
             // If light has no affected geometries, no need to process further
             // If light has no affected geometries, no need to process further
             if (query.litGeometries_.Empty())
             if (query.litGeometries_.Empty())
                 continue;
                 continue;
@@ -706,8 +718,7 @@ void View::GetBatches()
                 unsigned shadowSplits = query.numSplits_;
                 unsigned shadowSplits = query.numSplits_;
                 
                 
                 // Initialize light queue. Store light-to-queue mapping so that the queue can be found later
                 // Initialize light queue. Store light-to-queue mapping so that the queue can be found later
-                lightQueues_.Resize(lightQueues_.Size() + 1);
-                LightBatchQueue& lightQueue = lightQueues_.Back();
+                LightBatchQueue& lightQueue = lightQueues_[usedLightQueues++];
                 lightQueueMapping_[light] = &lightQueue;
                 lightQueueMapping_[light] = &lightQueue;
                 lightQueue.light_ = light;
                 lightQueue.light_ = light;
                 lightQueue.litBatches_.Clear();
                 lightQueue.litBatches_.Clear();
@@ -1015,7 +1026,7 @@ void View::UpdateGeometries()
         item.start_ = &postAlphaQueue_;
         item.start_ = &postAlphaQueue_;
         queue->AddWorkItem(item);
         queue->AddWorkItem(item);
         
         
-        for (List<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
+        for (Vector<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
         {
         {
             item.workFunction_ = SortLightQueueWork;
             item.workFunction_ = SortLightQueueWork;
             item.start_ = &(*i);
             item.start_ = &(*i);
@@ -1145,7 +1156,7 @@ void View::RenderBatchesForward()
     {
     {
         PROFILE(RenderShadowMaps);
         PROFILE(RenderShadowMaps);
         
         
-        for (List<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
+        for (Vector<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
         {
         {
             if (i->shadowMap_)
             if (i->shadowMap_)
                 RenderShadowMap(*i);
                 RenderShadowMap(*i);
@@ -1169,7 +1180,7 @@ void View::RenderBatchesForward()
     {
     {
         PROFILE(RenderLights);
         PROFILE(RenderLights);
         
         
-        for (List<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
+        for (Vector<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
         {
         {
             // If reusing shadowmaps, render each of them before the lit batches
             // If reusing shadowmaps, render each of them before the lit batches
             if (renderer_->GetReuseShadowMaps() && i->shadowMap_)
             if (renderer_->GetReuseShadowMaps() && i->shadowMap_)
@@ -1233,7 +1244,7 @@ void View::RenderBatchesDeferred()
     {
     {
         PROFILE(RenderShadowMaps);
         PROFILE(RenderShadowMaps);
         
         
-        for (List<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
+        for (Vector<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
         {
         {
             if (i->shadowMap_)
             if (i->shadowMap_)
                 RenderShadowMap(*i);
                 RenderShadowMap(*i);
@@ -1303,7 +1314,7 @@ void View::RenderBatchesDeferred()
     {
     {
         PROFILE(RenderLights);
         PROFILE(RenderLights);
         
         
-        for (List<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
+        for (Vector<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
         {
         {
             // If reusing shadowmaps, render each of them before the lit batches
             // If reusing shadowmaps, render each of them before the lit batches
             if (renderer_->GetReuseShadowMaps() && i->shadowMap_)
             if (renderer_->GetReuseShadowMaps() && i->shadowMap_)
@@ -2344,7 +2355,7 @@ void View::PrepareInstancingBuffer()
     if (renderMode_ != RENDER_FORWARD)
     if (renderMode_ != RENDER_FORWARD)
         totalInstances += gbufferQueue_.GetNumInstances(renderer_);
         totalInstances += gbufferQueue_.GetNumInstances(renderer_);
     
     
-    for (List<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
+    for (Vector<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
     {
     {
         for (unsigned j = 0; j < i->shadowSplits_.Size(); ++j)
         for (unsigned j = 0; j < i->shadowSplits_.Size(); ++j)
             totalInstances += i->shadowSplits_[j].shadowBatches_.GetNumInstances(renderer_);
             totalInstances += i->shadowSplits_[j].shadowBatches_.GetNumInstances(renderer_);
@@ -2364,7 +2375,7 @@ void View::PrepareInstancingBuffer()
             if (renderMode_ != RENDER_FORWARD)
             if (renderMode_ != RENDER_FORWARD)
                 gbufferQueue_.SetTransforms(renderer_, lockedData, freeIndex);
                 gbufferQueue_.SetTransforms(renderer_, lockedData, freeIndex);
             
             
-            for (List<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
+            for (Vector<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
             {
             {
                 for (unsigned j = 0; j < i->shadowSplits_.Size(); ++j)
                 for (unsigned j = 0; j < i->shadowSplits_.Size(); ++j)
                     i->shadowSplits_[j].shadowBatches_.SetTransforms(renderer_, lockedData, freeIndex);
                     i->shadowSplits_[j].shadowBatches_.SetTransforms(renderer_, lockedData, freeIndex);

+ 2 - 2
Engine/Graphics/View.h

@@ -110,7 +110,7 @@ public:
     /// Return lights.
     /// Return lights.
     const PODVector<Light*>& GetLights() const { return lights_; }
     const PODVector<Light*>& GetLights() const { return lights_; }
     /// Return light batch queues.
     /// Return light batch queues.
-    const List<LightBatchQueue>& GetLightQueues() const { return lightQueues_; }
+    const Vector<LightBatchQueue>& GetLightQueues() const { return lightQueues_; }
     
     
 private:
 private:
     /// Query the octree for drawable objects.
     /// Query the octree for drawable objects.
@@ -257,7 +257,7 @@ private:
     /// Intermediate light processing results.
     /// Intermediate light processing results.
     Vector<LightQueryResult> lightQueryResults_;
     Vector<LightQueryResult> lightQueryResults_;
     /// Per-pixel light queues.
     /// Per-pixel light queues.
-    List<LightBatchQueue> lightQueues_;
+    Vector<LightBatchQueue> lightQueues_;
     /// Per-vertex light queues.
     /// Per-vertex light queues.
     HashMap<unsigned long long, LightBatchQueue> vertexLightQueues_;
     HashMap<unsigned long long, LightBatchQueue> vertexLightQueues_;
     /// Material quality level.
     /// Material quality level.