Browse Source

Reverted earlier shadow split refactoring due to unnecessary shadowcasters being rendered.

Lasse Öörni 13 years ago
parent
commit
50653416da

+ 1 - 1
Engine/Graphics/AnimatedModel.cpp

@@ -259,7 +259,7 @@ void AnimatedModel::GetBatch(Batch& batch, const FrameInfo& frame, unsigned batc
     batch.distance_ = geometryDistances_[batchIndex];
     batch.geometry_ = currentGeometries_[batchIndex];
     batch.geometryType_ = GEOM_SKINNED;
-    batch.worldTransform_ = &GetWorldTransform();
+    batch.worldTransform_ = &node_->GetWorldTransform();
     batch.material_ = materials_[batchIndex];
     
     if (skinMatrices_.Size())

+ 1 - 1
Engine/Graphics/BillboardSet.cpp

@@ -157,7 +157,7 @@ void BillboardSet::GetBatch(Batch& batch, const FrameInfo& frame, unsigned batch
     batch.distance_ = distance_;
     batch.geometry_ = geometry_;
     batch.geometryType_ = GEOM_BILLBOARD;
-    batch.worldTransform_ = &GetWorldTransform();
+    batch.worldTransform_ = &node_->GetWorldTransform();
     batch.material_ = material_;
 }
 

+ 1 - 1
Engine/Graphics/StaticModel.cpp

@@ -166,7 +166,7 @@ void StaticModel::GetBatch(Batch& batch, const FrameInfo& frame, unsigned batchI
 {
     batch.distance_ = geometryDistances_[batchIndex];
     batch.geometry_ = currentGeometries_[batchIndex];
-    batch.worldTransform_ = &GetWorldTransform();
+    batch.worldTransform_ = &node_->GetWorldTransform();
     batch.material_ = materials_[batchIndex];
 }
 

+ 66 - 115
Engine/Graphics/View.cpp

@@ -246,15 +246,6 @@ void ProcessLightWork(const WorkItem* item, unsigned threadIndex)
     view->ProcessLight(*query, threadIndex);
 }
 
-void ProcessShadowSplitWork(const WorkItem* item, unsigned threadIndex)
-{
-    View* view = reinterpret_cast<View*>(item->aux_);
-    LightQueryResult* query = reinterpret_cast<LightQueryResult*>(item->start_);
-    unsigned splitIndex = reinterpret_cast<unsigned>(item->end_);
-    
-    view->ProcessShadowSplit(*query, splitIndex, threadIndex);
-}
-
 void UpdateDrawableGeometriesWork(const WorkItem* item, unsigned threadIndex)
 {
     const FrameInfo& frame = *(reinterpret_cast<FrameInfo*>(item->aux_));
@@ -739,24 +730,15 @@ void View::GetBatches()
             if (query.litGeometries_.Empty())
                 continue;
             
-            // If no shadow casters, the light can be rendered unshadowed. At this point we have not allocated a shadow map yet,
-            // so the only cost has been the shadow camera setup & queries
-            unsigned shadowSplits = query.shadowSplits_.Size();
-            if (shadowSplits)
-            {
-                unsigned totalShadowCasters = 0;
-                for (unsigned i = 0; i < query.shadowSplits_.Size(); ++i)
-                    totalShadowCasters += query.shadowSplits_[i].shadowCasters_.Size();
-                if (!totalShadowCasters)
-                    shadowSplits = 0;
-            }
             
             Light* light = query.light_;
             
             // Per-pixel light
             if (!light->GetPerVertex())
             {
-                // Initialize light queue
+                unsigned shadowSplits = query.numSplits_;
+                
+                // Initialize light queue. Store light-to-queue mapping so that the queue can be found later
                 LightBatchQueue& lightQueue = lightQueues_[usedLightQueues++];
                 light->SetLightQueue(&lightQueue);
                 lightQueue.light_ = light;
@@ -777,20 +759,19 @@ void View::GetBatches()
                 lightQueue.shadowSplits_.Resize(shadowSplits);
                 for (unsigned j = 0; j < shadowSplits; ++j)
                 {
-                    ShadowQueryResult& split = query.shadowSplits_[j];
                     ShadowBatchQueue& shadowQueue = lightQueue.shadowSplits_[j];
-                    Camera* shadowCamera = split.shadowCamera_;
+                    Camera* shadowCamera = query.shadowCameras_[j];
                     shadowQueue.shadowCamera_ = shadowCamera;
-                    shadowQueue.nearSplit_ = split.nearSplit_;
-                    shadowQueue.farSplit_ = split.farSplit_;
+                    shadowQueue.nearSplit_ = query.shadowNearSplits_[j];
+                    shadowQueue.farSplit_ = query.shadowFarSplits_[j];
                     
                     // Setup the shadow split viewport and finalize shadow camera parameters
                     shadowQueue.shadowViewport_ = GetShadowMapViewport(light, j, lightQueue.shadowMap_);
-                    FinalizeShadowCamera(shadowCamera, light, shadowQueue.shadowViewport_, split.shadowCasterBox_);
+                    FinalizeShadowCamera(shadowCamera, light, shadowQueue.shadowViewport_, query.shadowCasterBox_[j]);
                     
                     // Loop through shadow casters
-                    for (PODVector<Drawable*>::ConstIterator k = split.shadowCasters_.Begin(); k != split.shadowCasters_.End();
-                        ++k)
+                    for (PODVector<Drawable*>::ConstIterator k = query.shadowCasters_.Begin() + query.shadowCasterBegin_[j];
+                        k < query.shadowCasters_.Begin() + query.shadowCasterEnd_[j]; ++k)
                     {
                         Drawable* drawable = *k;
                         if (!drawable->IsInView(frame_, false))
@@ -941,7 +922,7 @@ void View::GetBatches()
                         
                         // Allow G-buffer pass instancing only if lightmask matches zone lightmask
                         baseBatch.lightMask_ = GetLightMask(drawable);
-                        FinalizeBatch(baseBatch, tech, pass, baseBatch.lightMask_ == (baseBatch.zone_->GetLightMask() & 0xff));
+                        FinalizeBatch(baseBatch, tech, pass, baseBatch.lightMask_ == (zone->GetLightMask() & 0xff));
                         gbufferQueue_.AddBatch(baseBatch);
                         
                         pass = tech->GetPass(PASS_MATERIAL);
@@ -954,7 +935,7 @@ void View::GetBatches()
                 // Next check for forward base pass
                 if (!pass)
                 {
-                    // Skip if a lit base pass already exists
+                    // Skip if a lit base pass already exists (only in forward rendering)
                     if (j < 32 && drawable->HasBasePass(j))
                         continue;
                     pass = tech->GetPass(PASS_BASE);
@@ -996,6 +977,7 @@ void View::GetBatches()
                         }
                     }
                     
+                    // Check whether batch is opaque or transparent
                     if (pass->GetBlendMode() == BLEND_REPLACE)
                     {
                         if (pass->GetType() != PASS_DEFERRED)
@@ -1020,7 +1002,7 @@ void View::GetBatches()
                     continue;
                 }
                 
-                // If no base pass, finally check for pre-alpha / post-alpha custom passes
+                // If no pass found so far, finally check for pre-alpha / post-alpha custom passes
                 pass = tech->GetPass(PASS_PREALPHA);
                 if (pass)
                 {
@@ -1795,73 +1777,50 @@ void View::ProcessLight(LightQueryResult& query, unsigned threadIndex)
     // If no lit geometries or not shadowed, no need to process shadow cameras
     if (query.litGeometries_.Empty() || !isShadowed)
     {
-        query.shadowSplits_.Clear();
+        query.numSplits_ = 0;
         return;
     }
     
     // Determine number of shadow cameras and setup their initial positions
     SetupShadowCameras(query);
     
-    // Process each split for shadow casters. Divide directional light splits into the work queue
-    if (type == LIGHT_DIRECTIONAL && query.shadowSplits_.Size() > 1)
+    // Process each split for shadow casters
+    query.shadowCasters_.Clear();
+    for (unsigned i = 0; i < query.numSplits_; ++i)
     {
-        WorkQueue* queue = GetSubsystem<WorkQueue>();
+        Camera* shadowCamera = query.shadowCameras_[i];
+        const Frustum& shadowCameraFrustum = shadowCamera->GetFrustum();
+        query.shadowCasterBegin_[i] = query.shadowCasterEnd_[i] = query.shadowCasters_.Size();
         
-        WorkItem item;
-        item.workFunction_ = ProcessShadowSplitWork;
-        item.start_ = &query;
-        item.aux_ = this;
+        // For point light check that the face is visible: if not, can skip the split
+        if (type == LIGHT_POINT && frustum.IsInsideFast(BoundingBox(shadowCameraFrustum)) == OUTSIDE)
+            continue;
         
-        for (unsigned i = 1; i < query.shadowSplits_.Size(); ++i)
+        // For directional light check that the split is inside the visible scene: if not, can skip the split
+        if (type == LIGHT_DIRECTIONAL)
         {
-            item.end_ = (void*)i;
-            queue->AddWorkItem(item);
+            if (sceneViewBox_.min_.z_ > query.shadowFarSplits_[i])
+                continue;
+            if (sceneViewBox_.max_.z_ < query.shadowNearSplits_[i])
+                continue;
         }
         
-        // Process the first split here
-        ProcessShadowSplit(query, 0, threadIndex);
-    }
-    else
-    {
-        for (unsigned i = 0; i < query.shadowSplits_.Size(); ++i)
-            ProcessShadowSplit(query, i, threadIndex);
-    }
-}
-
-void View::ProcessShadowSplit(LightQueryResult& query, unsigned splitIndex, unsigned threadIndex)
-{
-    ShadowQueryResult& split = query.shadowSplits_[splitIndex];
-    Camera* shadowCamera = split.shadowCamera_;
-    split.shadowCasters_.Clear();
-    
-    Light* light = query.light_;
-    LightType type = light->GetLightType();
-    const Frustum& frustum = camera_->GetFrustum();
-    const Frustum& shadowCameraFrustum = shadowCamera->GetFrustum();
-    PODVector<Drawable*>& tempDrawables = tempDrawables_[threadIndex];
-    
-    // For point light check that the face is visible: if not, can skip the split
-    if (type == LIGHT_POINT && frustum.IsInsideFast(BoundingBox(shadowCameraFrustum)) == OUTSIDE)
-        return;
-    
-    // For directional light check that the split is inside the visible scene: if not, can skip the split
-    if (type == LIGHT_DIRECTIONAL)
-    {
-        if (sceneViewBox_.min_.z_ > split.farSplit_)
-            return;
-        if (sceneViewBox_.max_.z_ < split.nearSplit_)
-            return;
-    }
-    
-    // Reuse lit geometry query for all except directional lights
-    if (type == LIGHT_DIRECTIONAL)
-    {
-        ShadowCasterOctreeQuery query(tempDrawables, shadowCameraFrustum, DRAWABLE_GEOMETRY, camera_->GetViewMask());
-        octree_->GetDrawables(query);
+        // Reuse lit geometry query for all except directional lights
+        if (type == LIGHT_DIRECTIONAL)
+        {
+            ShadowCasterOctreeQuery query(tempDrawables, shadowCameraFrustum, DRAWABLE_GEOMETRY,
+                camera_->GetViewMask());
+            octree_->GetDrawables(query);
+        }
+        
+        // Check which shadow casters actually contribute to the shadowing
+        ProcessShadowCasters(query, tempDrawables, i);
     }
     
-    // Check which shadow casters actually contribute to the shadowing
-    ProcessShadowCasters(query, tempDrawables, splitIndex);
+    // If no shadow casters, the light can be rendered unshadowed. At this point we have not allocated a shadow map yet, so the
+    // only cost has been the shadow camera setup & queries
+    if (query.shadowCasters_.Empty())
+        query.numSplits_ = 0;
 }
 
 void View::ProcessShadowCasters(LightQueryResult& query, const PODVector<Drawable*>& drawables, unsigned splitIndex)
@@ -1870,14 +1829,13 @@ void View::ProcessShadowCasters(LightQueryResult& query, const PODVector<Drawabl
     Matrix3x4 lightView;
     Matrix4 lightProj;
     
-    ShadowQueryResult& split = query.shadowSplits_[splitIndex];
-    Camera* shadowCamera = split.shadowCamera_;
+    Camera* shadowCamera = query.shadowCameras_[splitIndex];
     const Frustum& shadowCameraFrustum = shadowCamera->GetFrustum();
     lightView = shadowCamera->GetInverseWorldTransform();
     lightProj = shadowCamera->GetProjection();
     LightType type = light->GetLightType();
     
-    split.shadowCasterBox_.defined_ = false;
+    query.shadowCasterBox_[splitIndex].defined_ = false;
     
     // Transform scene frustum into shadow camera's view space for shadow caster visibility check. For point & spot lights,
     // we can use the whole scene frustum. For directional lights, use the intersection of the scene frustum and the split
@@ -1886,8 +1844,8 @@ void View::ProcessShadowCasters(LightQueryResult& query, const PODVector<Drawabl
     if (type != LIGHT_DIRECTIONAL)
         lightViewFrustum = sceneFrustum_.Transformed(lightView);
     else
-        lightViewFrustum = camera_->GetSplitFrustum(Max(sceneViewBox_.min_.z_, split.nearSplit_),
-            Min(sceneViewBox_.max_.z_, split.farSplit_)).Transformed(lightView);
+        lightViewFrustum = camera_->GetSplitFrustum(Max(sceneViewBox_.min_.z_, query.shadowNearSplits_[splitIndex]),
+            Min(sceneViewBox_.max_.z_, query.shadowFarSplits_[splitIndex])).Transformed(lightView);
     
     BoundingBox lightViewFrustumBox(lightViewFrustum);
      
@@ -1930,15 +1888,17 @@ void View::ProcessShadowCasters(LightQueryResult& query, const PODVector<Drawabl
         {
             // Merge to shadow caster bounding box and add to the list
             if (type == LIGHT_DIRECTIONAL)
-                split.shadowCasterBox_.Merge(lightViewBox);
+                query.shadowCasterBox_[splitIndex].Merge(lightViewBox);
             else
             {
                 lightProjBox = lightViewBox.Projected(lightProj);
-                split.shadowCasterBox_.Merge(lightProjBox);
+                query.shadowCasterBox_[splitIndex].Merge(lightProjBox);
             }
-            split.shadowCasters_.Push(drawable);
+            query.shadowCasters_.Push(drawable);
         }
     }
+    
+    query.shadowCasterEnd_[splitIndex] = query.shadowCasters_.Size();
 }
 
 bool View::IsShadowCasterVisible(Drawable* drawable, BoundingBox lightViewBox, Camera* shadowCamera, const Matrix3x4& lightView,
@@ -2015,7 +1975,7 @@ void View::SetupShadowCameras(LightQueryResult& query)
     Light* light = query.light_;
     
     LightType type = light->GetLightType();
-    unsigned splits = 0;
+    int splits = 0;
     
     if (type == LIGHT_DIRECTIONAL)
     {
@@ -2024,7 +1984,7 @@ void View::SetupShadowCameras(LightQueryResult& query)
         float nearSplit = camera_->GetNearClip();
         float farSplit;
         
-        while (splits < (unsigned)renderer_->GetMaxShadowCascades())
+        while (splits < renderer_->GetMaxShadowCascades())
         {
             // If split is completely beyond camera far clip, we are done
             if (nearSplit > camera_->GetFarClip())
@@ -2034,35 +1994,22 @@ void View::SetupShadowCameras(LightQueryResult& query)
             if (farSplit <= nearSplit)
                 break;
             
-            nearSplit = farSplit;
-            ++splits;
-        }
-        
-        query.shadowSplits_.Resize(splits);
-        
-        for (unsigned i = 0; i < splits; ++i)
-        {
-            nearSplit = camera_->GetNearClip();
-            farSplit = Min(camera_->GetFarClip(), cascade.splits_[i]);
-            
             // Setup the shadow camera for the split
-            ShadowQueryResult& split = query.shadowSplits_[i];
             Camera* shadowCamera = renderer_->GetShadowCamera();
-            split.shadowCamera_ = shadowCamera;
-            split.nearSplit_ = nearSplit;
-            split.farSplit_ = farSplit;
+            query.shadowCameras_[splits] = shadowCamera;
+            query.shadowNearSplits_[splits] = nearSplit;
+            query.shadowFarSplits_[splits] = farSplit;
             SetupDirLightShadowCamera(shadowCamera, light, nearSplit, farSplit);
             
             nearSplit = farSplit;
+            ++splits;
         }
     }
     
     if (type == LIGHT_SPOT)
     {
-        query.shadowSplits_.Resize(1);
-        
         Camera* shadowCamera = renderer_->GetShadowCamera();
-        query.shadowSplits_[0].shadowCamera_ = shadowCamera;
+        query.shadowCameras_[0] = shadowCamera;
         Node* cameraNode = shadowCamera->GetNode();
         
         cameraNode->SetTransform(light->GetWorldPosition(), light->GetWorldRotation());
@@ -2070,16 +2017,16 @@ void View::SetupShadowCameras(LightQueryResult& query)
         shadowCamera->SetFarClip(light->GetRange());
         shadowCamera->SetFov(light->GetFov());
         shadowCamera->SetAspectRatio(light->GetAspectRatio());
+        
+        splits = 1;
     }
     
     if (type == LIGHT_POINT)
     {
-        query.shadowSplits_.Resize(MAX_CUBEMAP_FACES);
-        
         for (unsigned i = 0; i < MAX_CUBEMAP_FACES; ++i)
         {
             Camera* shadowCamera = renderer_->GetShadowCamera();
-            query.shadowSplits_[i].shadowCamera_ = shadowCamera;
+            query.shadowCameras_[i] = shadowCamera;
             Node* cameraNode = shadowCamera->GetNode();
             
             // When making a shadowed point light, align the splits along X, Y and Z axes regardless of light rotation
@@ -2090,7 +2037,11 @@ void View::SetupShadowCameras(LightQueryResult& query)
             shadowCamera->SetFov(90.0f);
             shadowCamera->SetAspectRatio(1.0f);
         }
+        
+        splits = MAX_CUBEMAP_FACES;
     }
+    
+    query.numSplits_ = splits;
 }
 
 void View::SetupDirLightShadowCamera(Camera* shadowCamera, Light* light, float nearSplit, float farSplit)

+ 16 - 20
Engine/Graphics/View.h

@@ -51,21 +51,6 @@ struct GeometryDepthBounds
     float max_;
 };
 
-/// Intermediate shadow map split processing result.
-struct ShadowQueryResult
-{
-    /// Shadow camera.
-    Camera* shadowCamera_;
-    /// Shadow casters.
-    PODVector<Drawable*> shadowCasters_;
-    /// Combined bounding box of the shadow casters in light view or projection space.
-    BoundingBox shadowCasterBox_;
-    /// Directional light shadow near split distance.
-    float nearSplit_;
-    /// Directional light shadow far split distance.
-    float farSplit_;
-};
-
 /// Intermediate light processing result.
 struct LightQueryResult
 {
@@ -73,8 +58,22 @@ struct LightQueryResult
     Light* light_;
     /// Lit geometries.
     PODVector<Drawable*> litGeometries_;
-    /// Shadow map splits.
-    Vector<ShadowQueryResult> shadowSplits_;
+    /// Shadow casters.
+    PODVector<Drawable*> shadowCasters_;
+    /// Shadow cameras.
+    Camera* shadowCameras_[MAX_LIGHT_SPLITS];
+    /// Shadow caster start indices.
+    unsigned shadowCasterBegin_[MAX_LIGHT_SPLITS];
+    /// Shadow caster end indices.
+    unsigned shadowCasterEnd_[MAX_LIGHT_SPLITS];
+    /// Combined bounding box of shadow casters in light view or projection space.
+    BoundingBox shadowCasterBox_[MAX_LIGHT_SPLITS];
+    /// Shadow camera near splits (directional lights only.)
+    float shadowNearSplits_[MAX_LIGHT_SPLITS];
+    /// Shadow camera far splits (directional lights only.)
+    float shadowFarSplits_[MAX_LIGHT_SPLITS];
+    /// Shadow map split count.
+    unsigned numSplits_;
 };
 
 /// 3D rendering view. Includes the main view(s) and any auxiliary views, but not shadow cameras.
@@ -82,7 +81,6 @@ class View : public Object
 {
     friend void CheckVisibilityWork(const WorkItem* item, unsigned threadIndex);
     friend void ProcessLightWork(const WorkItem* item, unsigned threadIndex);
-    friend void ProcessShadowSplitWork(const WorkItem* item, unsigned threadIndex);
     
     OBJECT(View);
     
@@ -139,8 +137,6 @@ private:
     void DrawOccluders(OcclusionBuffer* buffer, const PODVector<Drawable*>& occluders);
     /// Query for lit geometries and shadow casters for a light.
     void ProcessLight(LightQueryResult& query, unsigned threadIndex);
-    /// Process the shadow splits for a light.
-    void ProcessShadowSplit(LightQueryResult& query, unsigned splitIndex, unsigned threadIndex);
     /// Process shadow casters' visibilities and build their combined view- or projection-space bounding box.
     void ProcessShadowCasters(LightQueryResult& query, const PODVector<Drawable*>& drawables, unsigned splitIndex);
     /// %Set up initial shadow camera view(s).