Sfoglia il codice sorgente

Allow also scenepass & forwardlights commands to define shader parameters.

Lasse Öörni 9 anni fa
parent
commit
05c0e7741b

+ 11 - 4
Docs/Reference.dox

@@ -1504,12 +1504,14 @@ The available commands are:
 
 - clear: Clear any of color, depth and stencil. Color clear can optionally use the fog color from the Zone visible at the far clip distance.
 - scenepass: Render scene objects whose \ref Materials "material technique" contains the specified pass. Will either be front-to-back ordered with state sorting, or back-to-front ordered with no state sorting. For deferred rendering, object lightmasks can be optionally marked to the stencil buffer. Vertex lights can optionally be handled during a pass, if it has the necessary shader combinations. Textures global to the pass can be bound to free texture units; these can either be the viewport, a named rendertarget, or a texture resource identified with its pathname.
-- quad: Render a viewport-sized quad using the specified shaders and compilation defines. Textures can be bound and additionally shader parameters and the blend mode (default=replace) can be specified.
+- quad: Render a viewport-sized quad using the specified shaders. The blend mode (default=replace) can be optionally specified.
 - forwardlights: Render per-pixel forward lighting for opaque objects with the specified pass name. Shadow maps are also rendered as necessary.
 - lightvolumes: Render deferred light volumes using the specified shaders. G-buffer textures can be bound as necessary.
 - renderui: Render the UI into the output rendertarget. Using this will cause the default %UI render to the backbuffer to be skipped.
 - sendevent: Send an event with a specified string parameter ("event name"). This can be used to call custom code,typically custom low-level rendering, in the middle of the renderpath execution.
 
+Scenepass, quad, forwardlights and lightvolumes commands all allow command-global shader compilation defines, shader parameters and textures to be defined. For example in deferred rendering, the lightvolumes command would bind the G-buffer textures to be able to calculate the lighting. Note that when binding command-global textures, these are (for optimization) bound only once in the beginning of the command. If the texture binding is overwritten by an object's material, it is "lost" until the end of the command. Therefore the command-global textures should be in units that are not used by materials.
+
 A render path can be loaded from a main XML file by calling \ref RenderPath::Load "Load()", after which other XML files (for example one for each post-processing effect) can be appended to it by calling \ref RenderPath::Append "Append()". Rendertargets and commands can be enabled or disabled by calling \ref RenderPath::SetEnabled "SetEnabled()" to switch eg. a post-processing effect on or off. To aid in this, both can be identified by tag names, for example the bloom effect uses the tag "Bloom" for all of its rendertargets and commands.
 
 It is legal to both write to the destination viewport and sample from it during the same command: pingpong copies of its contents will be made automatically. If the viewport has hardware multisampling on, the multisampled backbuffer will be resolved to a texture before sampling it.
@@ -1522,19 +1524,24 @@ The render path XML definition looks like this:
         format="rgb|rgba|r32f|rgba16|rgba16f|rgba32f|rg16|rg16f|rg32f|lineardepth|readabledepth" filter="true|false" srgb="true|false" persistent="true|false"
         multisample="x" autoresolve="true|false" />
     <command type="clear" tag="TagName" enabled="true|false" color="r g b a|fog" depth="x" stencil="y" output="viewport|RTName" face="0|1|2|3|4|5" depthstencil="DSName" />
-    <command type="scenepass" pass="PassName" sort="fronttoback|backtofront" marktostencil="true|false" vertexlights="true|false" metadata="base|alpha|gbuffer" depthstencil="DSName">
+    <command type="scenepass" pass="PassName" vsdefines="DEFINE1 DEFINE2" psdefines="DEFINE3 DEFINE4" sort="fronttoback|backtofront" marktostencil="true|false" vertexlights="true|false" metadata="base|alpha|gbuffer" depthstencil="DSName">
         <output index="0" name="RTName1" face="0|1|2|3|4|5" />
         <output index="1" name="RTName2" />
         <output index="2" name="RTName3" />
         <texture unit="unit" name="viewport|RTName|TextureName" />
+        <parameter name="ParameterName" value="x y z w" />
     </command>
     <command type="quad" vs="VertexShaderName" ps="PixelShaderName" vsdefines="DEFINE1 DEFINE2" psdefines="DEFINE3 DEFINE4" blend="replace|add|multiply|alpha|addalpha|premulalpha|invdestalpha|subtract|subtractalpha" output="viewport|RTName" depthstencil="DSName" />
         <texture unit="unit" name="viewport|RTName|TextureName" />
         <parameter name="ParameterName" value="x y z w" />
     </command>
-    <command type="forwardlights" pass="PassName" uselitbase="true|false" output="viewport|RTName" depthstencil="DSName" />
-    <command type="lightvolumes"  vs="VertexShaderName" ps="PixelShaderName" output="viewport|RTName" depthstencil="DSName" />
+    <command type="forwardlights" pass="PassName" vsdefines="DEFINE1 DEFINE2" psdefines="DEFINE3 DEFINE4" uselitbase="true|false" output="viewport|RTName" depthstencil="DSName">
         <texture unit="unit" name="viewport|RTName|TextureName" />
+        <parameter name="ParameterName" value="x y z w" />
+    </command
+    <command type="lightvolumes"  vs="VertexShaderName" ps="PixelShaderName" vsdefines="DEFINE1 DEFINE2" psdefines="DEFINE3 DEFINE4" output="viewport|RTName" depthstencil="DSName" />
+        <texture unit="unit" name="viewport|RTName|TextureName" />
+        <parameter name="ParameterName" value="x y z w" />
     </command>
     <command type="renderui" output="viewport|RTName" depthstencil="DSName" />
     <command type="sendevent" name="EventName" />

+ 15 - 16
Source/Urho3D/Graphics/RenderPath.cpp

@@ -165,24 +165,11 @@ void RenderPathCommand::Load(const XMLElement& element)
     case CMD_QUAD:
         vertexShaderName_ = element.GetAttribute("vs");
         pixelShaderName_ = element.GetAttribute("ps");
-        vertexShaderDefines_ = element.GetAttribute("vsdefines");
-        pixelShaderDefines_ = element.GetAttribute("psdefines");
 
-        if (type_ == CMD_QUAD)
+        if (type_ == CMD_QUAD && element.HasAttribute("blend"))
         {
-            if (element.HasAttribute("blend"))
-            {
-                String blend = element.GetAttributeLower("blend");
-                blendMode_ = ((BlendMode)GetStringListIndex(blend.CString(), blendModeNames, BLEND_REPLACE));
-            }
-
-            XMLElement parameterElem = element.GetChild("parameter");
-            while (parameterElem)
-            {
-                String name = parameterElem.GetAttribute("name");
-                shaderParameters_[name] = Material::ParseShaderParameterValue(parameterElem.GetAttribute("value"));
-                parameterElem = parameterElem.GetNext("parameter");
-            }
+            String blend = element.GetAttributeLower("blend");
+            blendMode_ = ((BlendMode)GetStringListIndex(blend.CString(), blendModeNames, BLEND_REPLACE));
         }
         break;
 
@@ -218,6 +205,18 @@ void RenderPathCommand::Load(const XMLElement& element)
         outputElem = outputElem.GetNext("output");
     }
 
+    // Shader compile flags & parameters
+    vertexShaderDefines_ = element.GetAttribute("vsdefines");
+    pixelShaderDefines_ = element.GetAttribute("psdefines");
+    XMLElement parameterElem = element.GetChild("parameter");
+    while (parameterElem)
+    {
+        String name = parameterElem.GetAttribute("name");
+        shaderParameters_[name] = Material::ParseShaderParameterValue(parameterElem.GetAttribute("value"));
+        parameterElem = parameterElem.GetNext("parameter");
+    }
+
+    // Texture bindings
     XMLElement textureElem = element.GetChild("texture");
     while (textureElem)
     {

+ 42 - 4
Source/Urho3D/Graphics/View.cpp

@@ -301,7 +301,8 @@ View::View(Context* context) :
     farClipZone_(0),
     occlusionBuffer_(0),
     renderTarget_(0),
-    substituteRenderTarget_(0)
+    substituteRenderTarget_(0),
+    passCommand_(0)
 {
     // Create octree query and scene results vector for each thread
     unsigned numThreads = GetSubsystem<WorkQueue>()->GetNumThreads() + 1; // Worker threads + main thread
@@ -760,6 +761,17 @@ void View::SetCameraShaderParameters(Camera* camera)
 #endif
 
     graphics_->SetShaderParameter(VSP_VIEWPROJ, projection * camera->GetView());
+
+    // If in a scene pass and the command defines shader parameters, set them now
+    if (passCommand_)
+        SetCommandShaderParameters(*passCommand_);
+}
+
+void View::SetCommandShaderParameters(const RenderPathCommand& command)
+{
+    const HashMap<StringHash, Variant>& parameters = command.shaderParameters_;
+    for (HashMap<StringHash, Variant>::ConstIterator k = parameters.Begin(); k != parameters.End(); ++k)
+        graphics_->SetShaderParameter(k->first_, k->second_);
 }
 
 void View::SetGBufferShaderParameters(const IntVector2& texSize, const IntRect& viewRect)
@@ -1454,6 +1466,7 @@ void View::ExecuteRenderPathCommands()
         // Set for safety in case of empty renderpath
         currentRenderTarget_ = substituteRenderTarget_ ? substituteRenderTarget_ : renderTarget_;
         currentViewportTexture_ = 0;
+        passCommand_ = 0;
 
         bool viewportModified = false;
         bool isPingponging = false;
@@ -1571,7 +1584,18 @@ void View::ExecuteRenderPathCommands()
                         bool allowDepthWrite = SetTextures(command);
                         graphics_->SetClipPlane(camera_->GetUseClipping(), camera_->GetClipPlane(), camera_->GetView(),
                             camera_->GetGPUProjection());
+
+                        if (command.shaderParameters_.Size())
+                        {
+                            // If pass defines shader parameters, reset parameter sources now to ensure they all will be set
+                            // (will be set after camera shader parameters)
+                            graphics_->ClearParameterSources();
+                            passCommand_ = &command;
+                        }
+
                         queue.Draw(this, camera_, command.markToStencil_, false, allowDepthWrite);
+
+                        passCommand_ = 0;
                     }
                 }
                 break;
@@ -1607,6 +1631,12 @@ void View::ExecuteRenderPathCommands()
                         graphics_->SetClipPlane(camera_->GetUseClipping(), camera_->GetClipPlane(), camera_->GetView(),
                             camera_->GetGPUProjection());
 
+                        if (command.shaderParameters_.Size())
+                        {
+                            graphics_->ClearParameterSources();
+                            passCommand_ = &command;
+                        }
+
                         // Draw base (replace blend) batches first
                         i->litBaseBatches_.Draw(this, camera_, false, false, allowDepthWrite);
 
@@ -1618,6 +1648,8 @@ void View::ExecuteRenderPathCommands()
                                 renderer_->OptimizeLightByStencil(i->light_, camera_);
                             i->litBatches_.Draw(this, camera_, false, true, allowDepthWrite);
                         }
+
+                        passCommand_ = 0;
                     }
 
                     graphics_->SetScissorTest(false);
@@ -1643,11 +1675,19 @@ void View::ExecuteRenderPathCommands()
 
                         SetTextures(command);
 
+                        if (command.shaderParameters_.Size())
+                        {
+                            graphics_->ClearParameterSources();
+                            passCommand_ = &command;
+                        }
+
                         for (unsigned j = 0; j < i->volumeBatches_.Size(); ++j)
                         {
                             SetupLightVolumeBatch(i->volumeBatches_[j]);
                             i->volumeBatches_[j].Draw(this, camera_, false);
                         }
+
+                        passCommand_ = 0;
                     }
 
                     graphics_->SetScissorTest(false);
@@ -1838,9 +1878,7 @@ void View::RenderQuad(RenderPathCommand& command)
     }
 
     // Set command's shader parameters last to allow them to override any of the above
-    const HashMap<StringHash, Variant>& parameters = command.shaderParameters_;
-    for (HashMap<StringHash, Variant>::ConstIterator k = parameters.Begin(); k != parameters.End(); ++k)
-        graphics_->SetShaderParameter(k->first_, k->second_);
+    SetCommandShaderParameters(command);
 
     graphics_->SetBlendMode(command.blendMode_);
     graphics_->SetDepthTest(CMP_ALWAYS);

+ 4 - 0
Source/Urho3D/Graphics/View.h

@@ -184,6 +184,8 @@ public:
     void SetGlobalShaderParameters();
     /// Set camera-specific shader parameters. Called by Batch and internally by View.
     void SetCameraShaderParameters(Camera* camera);
+    /// Set command's shader parameters if any. Called internally by View.
+    void SetCommandShaderParameters(const RenderPathCommand& command);
     /// Set G-buffer offset and inverse size shader parameters. Called by Batch and internally by View.
     void SetGBufferShaderParameters(const IntVector2& texSize, const IntRect& viewRect);
 
@@ -425,6 +427,8 @@ private:
     unsigned litAlphaPassIndex_;
     /// Pointer to the light volume command if any.
     const RenderPathCommand* lightVolumeCommand_;
+    /// Pointer to the current commmand if it contains shader parameters to be set for a render pass.
+    const RenderPathCommand* passCommand_;
     /// Flag for scene being resolved from the backbuffer.
     bool usedResolve_;
 };