polygoff wrote:
2. All of my textures require a time uniform of some sort for animations. Let's say I have 64 materials. Is it really necessary that I cycle through all these materials every frame to update their individual uniform timer with h3dSetMaterialUniform()?
There was some talk about changing this before - is there something planned (or was already done)?
As DarkAngel pointed out, you can use the pipeline to reference/apply "global" materials.
In our setup, we use the following setup:
Code:
<Pipeline>
<CommandQueue>
<Stage id="Geometry" link="scene01/pipelines/globalSettings.material.xml">
<!-- normal drawing follows here like DrawGeometry-->
<DrawGeometry context="AMBIENT" class="~Translucent" order="STATECHANGES"/>
</Stage>
</CommandQueue>
</Pipeline>
The globalSettings.material.xml itself looks like this:
Code:
<Material link="$EngineGlobals">
<Sampler name="ambientMap" map="scene01/models/cubemaps/ambientMap.dds" />
</Material>
This means, that all Shaders which have "ambientMap" as sampler, use the texture defined in globalSettings.material.xml.
If you want to change the ambientMap for all materials, just do it here.
As Material linking is recursive, we added a link called "$EngineGlobals" (we use the dollar sign to denote that this material is created in C++ code).
Our $EngineGlobals looks like this (simplified):
Code:
const char* gGlobalMaterialXML =
"<Material>\n"
" <Uniform name=\"g_TimeParams\" a=\".0\" b=\".0\" c=\".0\" d=\".0\" />\n" // a=CurTime
" <Uniform name=\"g_ZBufferParams\" a=\".0\" b=\".0\" c=\".0\" d=\".0\" />\n" // a=near b=far c=(1-far/near)/2 d=(1+far/near)/2
"</Material>\n"
In C++ we create an instance of it like this:
Code:
gGlobalMatRes = ::h3dAddResource(H3DResTypes::Material, "$EngineGlobals", 0);
::h3dLoadResource(gGlobalMatRes, gGlobalMaterialXML, strlen(gGlobalMaterialXML)+1));
Each frame we update the material like this:
Code:
::h3dSetMaterialUniform(gGlobalMatRes, "g_TimeParams", getCurrentTime(), 0.0f, 0.0f, 0.0f);
Additionally we set the ZBufferParams (used for Depth reconstruction, for example).
In your shader code, you need to define the $EngineGlobals (sadly, this has to be done in every shader, as there is no include for the setup-section for shaders) like this:
Code:
float4 g_ZBufferParams;
float4 g_TimeParams;
As a side-note: if you use commands in your stage like
Code:
<DrawQuad material="scene01/pipelines/postFX.material.xml" context="TRANSFER" />
and your stage has no link to the "$EngineGlobals", make sure you add a link to the "$EngineGlobals" material inside the postFX.material.xml as well, otherwise the uniforms/samplers will not be picked up.
I agree, that global or per-instance uniforms would come handy.
Also, the order of material linking is important: once a uniform/sample is set in a link, you cannot override it locally (if I remember correctly), e.g. you cannot assign a different texture in your shader's material for the ambientMap example above. The globalSettings.material.xml will always override it.
Hope this helps.