Browse Source

Initial light volume rendering.

Lasse Öörni 14 years ago
parent
commit
c0d05666f8

+ 2 - 0
Engine/Graphics/Batch.h

@@ -300,4 +300,6 @@ struct LightBatchQueue
     Vector<ShadowBatchQueue> shadowSplits_;
     /// Per-vertex lights.
     PODVector<Light*> vertexLights_;
+    /// Light volume draw calls.
+    PODVector<Batch> volumeBatches_;
 };

+ 3 - 0
Engine/Graphics/GraphicsDefs.h

@@ -237,13 +237,16 @@ extern StringHash PSP_SHADOWPROJ;
 enum TextureUnit
 {
     TU_DIFFUSE = 0,
+    TU_DEPTHBUFFER = 0,
     TU_NORMAL = 1,
+    TU_NORMALBUFFER = 1,
     TU_EMISSIVE = 2,
     TU_SPECULAR = 3,
     TU_DETAIL = 4,
     TU_ENVIRONMENT = 5,
     MAX_MATERIAL_TEXTURE_UNITS = 6,
     TU_SHADOWMAP = 6,
+    TU_LIGHTBUFFER = 6,
     TU_LIGHTRAMP = 7,
     TU_LIGHTSHAPE = 8,
     TU_FACESELECT = 9,

+ 8 - 4
Engine/Graphics/Light.cpp

@@ -359,7 +359,7 @@ Frustum Light::GetFrustum() const
 }
 
 
-Matrix3x4 Light::GetDirLightTransform(Camera& camera, bool getNearQuad)
+Matrix3x4 Light::GetDirLightTransform(const Camera& camera, bool getNearQuad)
 {
     Vector3 nearVector, farVector;
     camera.GetFrustumSize(nearVector, farVector);
@@ -379,14 +379,14 @@ Matrix3x4 Light::GetDirLightTransform(Camera& camera, bool getNearQuad)
     return  Matrix3x4(Vector3(0.0f, 0.0f, farVector.z_), Quaternion::IDENTITY, Vector3(farVector.x_, farVector.y_, 1.0f));
 }
 
-const Matrix3x4& Light::GetVolumeTransform()
+const Matrix3x4& Light::GetVolumeTransform(const Camera& camera)
 {
     const Matrix3x4& transform = GetWorldTransform();
     
     switch (lightType_)
     {
-    case LIGHT_POINT:
-        volumeTransform_ = Matrix3x4(transform.Translation(), Quaternion::IDENTITY, range_);
+    case LIGHT_DIRECTIONAL:
+        volumeTransform_ = GetDirLightTransform(camera);
         break;
         
     case LIGHT_SPOT:
@@ -396,6 +396,10 @@ const Matrix3x4& Light::GetVolumeTransform()
             volumeTransform_ = Matrix3x4(transform.Translation(), transform.Rotation(), Vector3(xScale, yScale, range_));
         }
         break;
+        
+    case LIGHT_POINT:
+        volumeTransform_ = Matrix3x4(transform.Translation(), Quaternion::IDENTITY, range_);
+        break;
     }
     
     return volumeTransform_;

+ 2 - 3
Engine/Graphics/Light.h

@@ -242,10 +242,9 @@ public:
     /// %Set sort value based on overall intensity over a bounding box.
     void SetIntensitySortValue(const BoundingBox& box);
     /// Return directional light quad transform for either near or far split.
-    Matrix3x4 GetDirLightTransform(Camera& camera, bool getNearQuad = false);
+    Matrix3x4 GetDirLightTransform(const Camera& camera, bool getNearQuad = false);
     /// Return light volume model transform.
-    const Matrix3x4& GetVolumeTransform();
-
+    const Matrix3x4& GetVolumeTransform(const Camera& camera);
     
     /// %Set ramp texture attribute.
     void SetRampTextureAttr(ResourceRef value);

File diff suppressed because it is too large
+ 1341 - 1343
Engine/Graphics/Renderer.cpp


+ 67 - 10
Engine/Graphics/View.cpp

@@ -179,6 +179,21 @@ bool View::Define(RenderSurface* renderTarget, const Viewport& viewport)
     if (!octree)
         return false;
     
+    // Check for the render texture being too large
+    if (renderer_->GetLightPrepass() && renderTarget)
+    {
+        if (renderTarget->GetWidth() > graphics_->GetWidth() || renderTarget->GetHeight() > graphics_->GetHeight())
+        {
+            // Display message only once per render target, do not spam each frame
+            if (gBufferErrorDisplayed_.Find(renderTarget) == gBufferErrorDisplayed_.End())
+            {
+                gBufferErrorDisplayed_.Insert(renderTarget);
+                LOGERROR("Render texture is larger than the G-buffer, can not render");
+            }
+            return false;
+        }
+    }
+    
     octree_ = octree;
     camera_ = viewport.camera_;
     renderTarget_ = renderTarget;
@@ -535,6 +550,7 @@ void View::GetBatches()
                 lightQueueMapping_[light] = &lightQueue;
                 lightQueue.light_ = light;
                 lightQueue.litBatches_.Clear();
+                lightQueue.volumeBatches_.Clear();
                 
                 // Allocate shadow map now
                 lightQueue.shadowMap_ = 0;
@@ -610,6 +626,24 @@ void View::GetBatches()
                     else
                         maxLightsDrawables_.Insert(drawable);
                 }
+                
+                // In light pre-pass mode, store the light volume batch now
+                if (prepass)
+                {
+                    /// \todo Handle SM2 multiple batches for shadowed directional lights
+                    Batch volumeBatch;
+                    volumeBatch.geometry_ = renderer_->GetLightGeometry(light);
+                    volumeBatch.worldTransform_ = &light->GetVolumeTransform(*camera_);
+                    volumeBatch.overrideView_ = light->GetLightType() == LIGHT_DIRECTIONAL;
+                    volumeBatch.camera_ = camera_;
+                    volumeBatch.lightQueue_ = &lightQueue;
+                    volumeBatch.distance_ = light->GetDistance();
+                    volumeBatch.material_ = 0;
+                    volumeBatch.pass_ = 0;
+                    volumeBatch.zone_ = 0;
+                    renderer_->SetLightVolumeShaders(volumeBatch);
+                    lightQueue.volumeBatches_.Push(volumeBatch);
+                }
             }
             // Per-vertex light
             else
@@ -997,11 +1031,21 @@ void View::RenderBatchesLightPrepass()
     // Render the G-buffer
     Texture2D* normalBuffer = renderer_->GetNormalBuffer();
     Texture2D* depthBuffer = renderer_->GetDepthBuffer();
+    RenderSurface* depthStencil = 0;
     
+    if (graphics_->GetFallback())
+    {
+        graphics_->SetRenderTarget(0, normalBuffer);
+        graphics_->SetDepthStencil(depthStencil);
+        graphics_->SetViewport(screenRect_);
+        graphics_->Clear(CLEAR_COLOR | CLEAR_DEPTH | CLEAR_STENCIL, Color(0.5f, 0.5f, 1.0f, 1.0f));
+    }
     if (graphics_->GetHardwareDepthSupport())
     {
+        depthStencil = depthBuffer->GetRenderSurface();
+        
         graphics_->SetRenderTarget(0, normalBuffer);
-        graphics_->SetDepthStencil(depthBuffer);
+        graphics_->SetDepthStencil(depthStencil);
         graphics_->SetViewport(screenRect_);
         // Clear depth and stencil only
         graphics_->Clear(CLEAR_DEPTH | CLEAR_STENCIL);
@@ -1009,7 +1053,7 @@ void View::RenderBatchesLightPrepass()
     else
     {
         graphics_->SetRenderTarget(0, depthBuffer);
-        graphics_->ResetDepthStencil();
+        graphics_->SetDepthStencil(depthStencil);
         graphics_->SetViewport(screenRect_);
         // Clear the depth render target to far depth
         graphics_->Clear(CLEAR_COLOR | CLEAR_DEPTH | CLEAR_STENCIL, Color::WHITE);
@@ -1024,12 +1068,17 @@ void View::RenderBatchesLightPrepass()
         RenderBatchQueue(gbufferQueue_);
     }
     
+    // Clear the light accumulation buffer
+    Texture2D* lightBuffer = renderer_->GetLightBuffer();
     graphics_->ResetRenderTarget(1);
+    graphics_->SetRenderTarget(0, lightBuffer);
+    graphics_->SetDepthStencil(depthStencil);
+    graphics_->SetViewport(screenRect_);
+    graphics_->Clear(CLEAR_COLOR);
     
-    /*
     if (!lightQueues_.Empty())
     {
-        // Render shadow maps + opaque objects' shadowed additive lighting
+        // Render shadow maps + light volumes
         PROFILE(RenderLights);
         
         for (List<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
@@ -1038,20 +1087,26 @@ void View::RenderBatchesLightPrepass()
             if (renderer_->GetReuseShadowMaps() && i->shadowMap_)
             {
                 RenderShadowMap(*i);
-                graphics_->SetRenderTarget(0, renderTarget_);
-                graphics_->SetDepthStencil(depthStencil_);
+                graphics_->SetRenderTarget(0, lightBuffer);
+                graphics_->SetDepthStencil(depthStencil);
                 graphics_->SetViewport(screenRect_);
             }
             
-            RenderLightBatchQueue(i->litBatches_, i->light_);
+            graphics_->SetTexture(TU_DEPTHBUFFER, depthBuffer);
+            graphics_->SetTexture(TU_NORMALBUFFER, normalBuffer);
+            
+            for (unsigned j = 0; j < i->volumeBatches_.Size(); ++j)
+            {
+                SetupLightBatch(i->volumeBatches_[j]);
+                i->volumeBatches_[j].Draw(graphics_, renderer_);
+            }
         }
     }
-    */
     
     graphics_->SetScissorTest(false);
     graphics_->SetStencilTest(false);
     graphics_->SetRenderTarget(0, renderTarget_);
-    graphics_->SetDepthStencil(depthStencil_);
+    graphics_->SetDepthStencil(depthStencil);
     graphics_->SetViewport(screenRect_);
     graphics_->Clear(CLEAR_COLOR, farClipZone_->GetFogColor());
     
@@ -1060,6 +1115,8 @@ void View::RenderBatchesLightPrepass()
         // Render opaque objects with deferred lighting result
         PROFILE(RenderBase);
         
+        graphics_->SetTexture(TU_LIGHTBUFFER, lightBuffer);
+        
         RenderBatchQueue(baseQueue_);
     }
     
@@ -1466,7 +1523,7 @@ void View::OptimizeLightByStencil(Light* light)
         graphics_->SetStencilTest(true, CMP_ALWAYS, OP_REF, OP_KEEP, OP_KEEP, lightStencilValue_);
         graphics_->SetShaders(renderer_->GetStencilVS(), renderer_->GetStencilPS());
         graphics_->SetShaderParameter(VSP_VIEWPROJ, projection * view);
-        graphics_->SetShaderParameter(VSP_MODEL, light->GetVolumeTransform());
+        graphics_->SetShaderParameter(VSP_MODEL, light->GetVolumeTransform(*camera_));
         
         geometry->Draw(graphics_);
         

+ 2 - 0
Engine/Graphics/View.h

@@ -249,6 +249,8 @@ private:
     PODVector<GeometryDepthBounds> geometryDepthBounds_;
     /// Lights.
     PODVector<Light*> lights_;
+    /// Render surfaces for which a G-buffer size error has already been logged, to prevent log spam.
+    HashSet<RenderSurface*> gBufferErrorDisplayed_;
     /// Drawables that limit their maximum light count.
     HashSet<Drawable*> maxLightsDrawables_;
     /// Lookup map for the processed lights' light queues.

+ 2 - 2
SourceAssets/HLSLShaders/Samplers.hlsl

@@ -17,8 +17,8 @@ samplerCUBE sFaceSelectCubeMap : register(S9);
 samplerCUBE sIndirectionCubeMap : register(S10);
 
 // Deferred buffer samplers
-sampler2D sNormalBuffer : register(S0);
-sampler2D sDepthBuffer : register(S1);
+sampler2D sDepthBuffer : register(S0);
+sampler2D sNormalBuffer : register(S1);
 sampler2D sLightBuffer : register(S6);
 
 float4 Sample(sampler2D map, float2 texCoord)

Some files were not shown because too many files changed in this diff