Browse Source

Sort drawable's lights only if necessary (over the maximum light count.)
Handle lights that are converted from per-pixel to per-vertex correctly even if drawable has both opaque & transparent batches.

Lasse Öörni 14 years ago
parent
commit
0804e9d4ec
3 changed files with 28 additions and 32 deletions
  1. 10 19
      Engine/Graphics/Drawable.cpp
  2. 2 2
      Engine/Graphics/Drawable.h
  3. 16 11
      Engine/Graphics/View.cpp

+ 10 - 19
Engine/Graphics/Drawable.cpp

@@ -243,39 +243,30 @@ void Drawable::AddVertexLight(Light* light)
 void Drawable::LimitLights()
 {
     // Maximum lights value 0 means unlimited
-    if (!maxLights_)
+    if (!maxLights_ || lights_.Size() <= maxLights_)
         return;
     
+    // If more lights than allowed, move to vertex lights and cut the list
     const BoundingBox& box = GetWorldBoundingBox();
     for (unsigned i = 0; i < lights_.Size(); ++i)
         lights_[i]->SetIntensitySortValue(box);
     
     Sort(lights_.Begin(), lights_.End(), CompareDrawables);
-    
-    // If more lights than allowed, move to vertex lights and cut the list
-    if (lights_.Size() > maxLights_)
-    {
-        vertexLights_.Insert(vertexLights_.End(), lights_.Begin() + maxLights_, lights_.End());
-        lights_.Resize(maxLights_);
-    }
+    vertexLights_.Insert(vertexLights_.End(), lights_.Begin() + maxLights_, lights_.End());
+    lights_.Resize(maxLights_);
 }
 
-void Drawable::LimitVertexLights(bool removeConvertedLights)
+void Drawable::LimitVertexLights()
 {
+    if (vertexLights_.Size() <= MAX_VERTEX_LIGHTS)
+        return;
+    
     const BoundingBox& box = GetWorldBoundingBox();
     for (unsigned i = vertexLights_.Size() - 1; i < vertexLights_.Size(); --i)
-    {
-        // If necessary (deferred rendering), remove lights that were converted to per-vertex
-        if (removeConvertedLights && !vertexLights_[i]->GetPerVertex())
-            vertexLights_.Erase(i);
-        else
-            vertexLights_[i]->SetIntensitySortValue(box);
-    }
+        vertexLights_[i]->SetIntensitySortValue(box);
     
     Sort(vertexLights_.Begin(), vertexLights_.End(), CompareDrawables);
-    
-    if (vertexLights_.Size() > MAX_VERTEX_LIGHTS)
-        vertexLights_.Resize(MAX_VERTEX_LIGHTS);
+    vertexLights_.Resize(MAX_VERTEX_LIGHTS);
 }
 
 Zone* Drawable::GetZone() const

+ 2 - 2
Engine/Graphics/Drawable.h

@@ -179,10 +179,10 @@ public:
     void AddLight(Light* light);
     /// Add a per-vertex light.
     void AddVertexLight(Light* light);
-    /// Sort and limit per-pixel lights to maximum allowed.
+    /// Sort and limit per-pixel lights to maximum allowed. Convert extra lights into vertex lights.
     void LimitLights();
     /// Sort and limit per-vertex lights to maximum allowed.
-    void LimitVertexLights(bool removeConvertedLights);
+    void LimitVertexLights();
     /// %Set base pass flag for a batch.
     void SetBasePass(unsigned batchIndex) { basePassFlags_ |= (1 << batchIndex); }
     /// Return octree octant.

+ 16 - 11
Engine/Graphics/View.cpp

@@ -523,6 +523,7 @@ void View::GetDrawables()
 void View::GetBatches()
 {
     WorkQueue* queue = GetSubsystem<WorkQueue>();
+    PODVector<Light*> vertexLights;
     
     // Process lit geometries and shadow casters for each light
     {
@@ -713,7 +714,9 @@ void View::GetBatches()
         {
             Drawable* drawable = *i;
             unsigned numBatches = drawable->GetNumBatches();
-            bool vertexLightsProcessed = false;
+            const PODVector<Light*>& drawableVertexLights = drawable->GetVertexLights();
+            if (!drawableVertexLights.Empty())
+                drawable->LimitVertexLights();
             
             for (unsigned j = 0; j < numBatches; ++j)
             {
@@ -770,20 +773,22 @@ void View::GetBatches()
                 if (pass)
                 {
                     // Check for vertex lights (both forward unlit, light pre-pass material pass, and deferred G-buffer)
-                    const PODVector<Light*>& vertexLights = drawable->GetVertexLights();
-                    if (!vertexLights.Empty())
+                    if (!drawableVertexLights.Empty())
                     {
-                        // In deferred modes, check if this is an opaque object that has converted its lights to per-vertex
-                        // due to overflowing the pixel light count. These need to be skipped as the per-pixel accumulation
-                        // already renders the light
-                        /// \todo Sub-geometries might need different interpretation if opaque & alpha are mixed
-                        if (!vertexLightsProcessed)
+                        // For a deferred opaque batch, check if the vertex lights include converted per-pixel lights, and remove
+                        // them to prevent double-lighting
+                        if (renderMode_ != RENDER_FORWARD && pass->GetBlendMode() == BLEND_REPLACE)
                         {
-                            drawable->LimitVertexLights(renderMode_ != RENDER_FORWARD && pass->GetBlendMode() == BLEND_REPLACE);
-                            vertexLightsProcessed = true;
+                            vertexLights.Clear();
+                            for (unsigned i = 0; i < drawableVertexLights.Size(); ++i)
+                            {
+                                if (drawableVertexLights[i]->GetPerVertex())
+                                    vertexLights.Push(drawableVertexLights[i]);
+                            }
                         }
+                        else
+                            vertexLights = drawableVertexLights;
                         
-                        // The vertex light vector possibly became empty, so re-check
                         if (!vertexLights.Empty())
                         {
                             // Find a vertex light queue. If not found, create new