Forward rendering, writing sDepthBuffer

295 views
Skip to first unread message

reat...@gmail.com

unread,
Dec 6, 2013, 8:32:15 AM12/6/13
to urh...@googlegroups.com
Hello,
how can I write the depth buffer texture to be used in the shaders for forward rendering?

Suppose I want to do a softening billboard effect, that is I want to fade out the billboard near the intersection with opaque objects.
I start with the render path ForwardDepth.xml and modify it to bind the depth texture to the alpha scenepass.
In the vertex shader I get the vertex depth with GetDepth(gl_Position) and screen position with GetScreenPosPreDiv(gl_Position).
In the fragment shader I get the depth from the buffer with texture2D(sDepthBuffer, vScreenPos) and compare it with the fragment depth.
This seems to work, but is it efficient? Can I write sDepthBuffer directly from the base scene pass?

Thank you

Lasse Öörni

unread,
Dec 6, 2013, 10:22:58 AM12/6/13
to urh...@googlegroups.com
You could modify the forward ambient pass shaders to write both depth and ambient color at the same time as multiple rendertargets, similar to deferred rendering, which would cut the draw call cost and be more efficient.

The main reason this isn't done in the default shaders is to reduce the number of combinations.

There's also an ineffciency related to the depth buffer handling: the depth pass and the scene color pass will actually use a different depth buffer, due to OpenGL limitations of not being able to render to a texture while using the window depth surface. This could be eliminated by always rendering to an FBO and then only flipping to the window in the very end, but might not be good on eg. mobile devices which are fillrate limited to begin with.

reat...@gmail.com

unread,
Dec 15, 2013, 3:55:17 PM12/15/13
to urh...@googlegroups.com

Thank you Lasse. The best I could do (to render a depth texture with a single pass, instead of the "ForwardDepth.xml") is this:

<renderpath>
   
<rendertarget name="out" rtsizedivisor="1 1" format="rgba" />
   
<rendertarget name="depth" rtsizedivisor="1 1" format="lineardepth" />
   
<command type="clear" color="1 1 1 1" depth="1.0" output="depth" />
   
<command type="clear" color="0 0 0 0" depth="1.0" output="out" />
   
<command type="scenepass" pass="base" vertexlights="true" metadata="base" output="out" />
   
<command type="forwardlights" pass="light" >
       
<output index="0" name="out" />
       
<output index="1" name="depth" />
   
</command>
   
<command type="scenepass" pass="alpha" usescissor="true" vertexlights="true" sort="backtofront" metadata="alpha" output="out">
       
<texture unit="depth" name="depth" />
   
</command>
   
<command type="quad" vs="CopyFramebuffer" ps="CopyFramebuffer" output="viewport">
       
<texture unit="diffuse" name="out" />
   
</command>
</renderpath>

In the fragment LitSolid shaders in the PER_PIXEL section, I write to gl_FragData[0] with color and gl_FragData[1] with depth.
But it is still no good, shadows and ligths aren't working anymore.

In my 3D ignorance, I wanted to do something like this:
 
   <command type="forwardlights" pass="light" >
       
<output index="0" name="viewport" />
       
<output index="1" name="depth" />
   
</command>

but I learned you can't use FBO in that way.

Can you point me some other big errors? Thank you.

A hunch, here:
https://github.com/urho3d/Urho3D/blob/master/Source/Engine/Graphics/OpenGL/OGLGraphics.cpp#L2523
should it be:
int drawBufferIds[MAX_RENDERTARGETS];

Thanks for your help.

Lasse Öörni

unread,
Dec 15, 2013, 4:21:55 PM12/15/13
to urh...@googlegroups.com
You should write depth during the base (ambient) pass. The forward lights pass may be repeated many times per object if there are many per-pixel lights, so that phase shouldn't write depth any more. What makes it more complicated is that the LitSolid shader contains code for both passes, so look for the part that begins with

        // Ambient & per-vertex lighting
        vec3 finalColor = vVertexLight.rgb * diffColor.rgb;

When you do this, the "lit base pass" optimization mechanism (combine base pass and first per-pixel light) cannot be reliably used anymore. This may have some negative impact on performance, but on the other hand it's better for overdraw, as the base pass has already written depth, so you should get early-Z discard for occluded objects. The renderpath should look like

   
<command type="scenepass" pass="base" vertexlights="true" metadata="base">
        <output index="0" name="out" />
       
<output index="1" name="depth" />
   
</command>
    <command type="forwardlights" pass="light" uselitbase="false" output="out" />


reat...@gmail.com

unread,
Dec 24, 2013, 3:13:36 PM12/24/13
to urh...@googlegroups.com
Thanks Lasse, that uselitbase="false" was the key.

I've done a little OpenGL example for this soft billboards effect, it is not Urho quality, but at least it should work. The effect simply fades out the billboards near opaque objects or near the camera. If anyone could find it useful it is attached.

In the meanwhile I was trying to add support for int and IntVector2 uniforms to Urho. Permorfance aside, for prototyping shaders I find it useful to have some int to use bitwise to enable/disable things.
By adding an XML attribute 'type' in the parameter of the material I was successful on OpenGL, but not on Direct3D. My knowledge of DirectX is terrible. I think bitwise operator are not supported in SM3, but I wasn't able to make them work even with "if (cMyInt)", also booleans does not work (you wrote a TODO note that they may do nothing in Direct3D 9). I tried "uniform int cMyInt" and then specifying the registry c0 or using the [branch/flatten] on the "if".
Do you think uniform ints can be done in Direct3D?

Completely unrelated, I also have attached a patch for adding an orbital camera to the editor, it uses the middle mouse button. I find it useful to highlight materials properties. While orbiting the post render is skipped to hide debug geometries. Discard it with no comments if it is not useful.


SoftBillboards_OpenGL_example.zip
orbital-camera.patch

Lasse Öörni

unread,
Dec 24, 2013, 3:40:43 PM12/24/13
to urh...@googlegroups.com
I'm not sure about integer constants. There's the API to set them, but similarly as with booleans, the register space is different than for floats. Microsoft's documentation on them in Direct3D9 context is quite poor.

Can you make a pull request of the orbit camera? That way your name will be directly attributed to the commit.

reat...@gmail.com

unread,
Dec 24, 2013, 4:08:08 PM12/24/13
to urh...@googlegroups.com

Very poor indeed. I've used SetVertexShaderConstantI:
http://msdn.microsoft.com/en-us/library/windows/desktop/bb174468(v=vs.85).aspx
Starting from SetShaderParameter() for float and Vector2, it was as easy as replacing SetVertexShaderConstantF with SetVertexShaderConstantI, but it was not good.
Something on the billboard who use the shader with the bool/int uniform you see all the textures in memory (included the correct one) cycling in a random manner.
I'll do some more checks, thanks.

About the pull request, I really don't need my name on it, but in this way you can't blame me....
Give me some time to do some tests before I messed up everything (git noob here).


Lasse Öörni

unread,
Dec 25, 2013, 7:37:14 AM12/25/13
to
One thing that might be messing up on our side can be the assumption of a single register space. When switching shaders, D3DGraphics.cpp caches what shader parameters are in which register index. But if eg. an int constant and float constant both occupy register index 0 they could end up "fighting" and overwriting each other. I'll have to check this code.

Hm, from gamedev.net:

In SM2.0 and SM3.0, all of your standard constant registers (c0 through c255) are float4's. You can only set floats in them, no exceptions. To do that you use SetVertexShaderConstantF/SetPixelShaderConstantF, or you use a D3DX helper that calls it for you. In SM3.0 you also have 16 constant integer registers (i0 through i15) that can only be used for loop control. These are set with SetVertexShaderConstantI/SetPixelShaderConstantI.

You can't use integers for general-purpose constants, since there's no registers for it and because all the shaders can only do floating-point math. I'm not 100% sure, but I think that ID3DXConstantTable will convert integers to floating-point if you try to set an integer for a value mapped to a constant register. In SM4.0 and above native integer instructions and constants are available, but that's only for D3D10+.

Lasse Öörni

unread,
Dec 25, 2013, 7:49:57 AM12/25/13
to urh...@googlegroups.com
Checked the code that tracks parameters in use, the mapping is from names to registers, so as long as names are unique having both a float constant at 0 and an int constant at 0 shouldn't be a problem.


reat...@gmail.com

unread,
Dec 29, 2013, 7:42:18 AM12/29/13
to urh...@googlegroups.com

Here are my findings on uniforms and DirectX 9.

1. Native int and bitwise operators are supported only from SM4.0
Source: https://en.wikipedia.org/wiki/High-level_shader_language and MJP from gamedev (much more solid).
In SM2.0 there are the Constant Integer Registers i#, but they are used only by loop - ps and rep - ps.
Source: http://msdn.microsoft.com/en-us/library/windows/desktop/bb219858%28v=vs.85%29.aspx

2. In SM2 and 3 you can use common modulo operator % with ints but it not very fast and it is better to do it with floats.
Source: http://msdn.microsoft.com/en-us/library/windows/desktop/bb509631(v=vs.85).aspx

3. Float, int and bool uniforms are all stored in the Constant Float Registers c#. Each of these registers consists in 4 floats (x,y,z,w).
Source: some tests with Microsoft PIX on a Nvidia card and AMD ShaderAnalyzer.

4. As said, bools are also stored in c# and not in the b# registers.
b# are the Constant Boolean Registers, they exist also in SM2.0, they are "a collection of bits used in static flow control
instructions (for example, if bool - ps - else - ps - endif - ps). They can be set using defb - ps or SetPixelShaderConstantB."
Source: http://msdn.microsoft.com/en-us/library/windows/desktop/bb219856%28v=vs.85%29.aspx
Now I see a problem: does 'SetPixelShaderConstantB' declare these bools as 'defb' does ? If so, then I don't have
to declare them in my shader, but if I use these bools and don't declare them, how can I can compile the shader?
So I think that these b# can be used only in HLSL assembly (maybe).
Also, you cannot specify a registry b# for an uniform bool like this:
 uniform bool cMyBool : registry(b0);
because here the b# are the Constant buffer registers, they are different things from the Constant Boolean Registers.
Source: http://msdn.microsoft.com/en-us/library/windows/desktop/dd607359%28v=vs.85%29.aspx
Anyway, this isn't a problem since an uniform bool is stored in a c# register.

5. In Urho to set a bool shader parameter we use "void Graphics::SetShaderParameter(StringHash param, bool value)".
Here it uses SetPixelShaderConstantB which works only on b#, so to make the bools work we could use SetPixelShaderConstantF to write
on c#, something like this:
void Graphics::SetShaderParameter(StringHash param, bool value)
{
    SetShaderParameter(param, (float)value);
}

This works (c# = (value > 0.0) ? 1.0 : 0.0), but...

6. Sometimes when there is an uniform bool in the shader code, the compiler (D3DCompile) nukes all the uniforms (even the ones in
Uniforms.hlsl and I think also some code). To be sure this doesn't happen I found two ways (but I could not understand why):

- specify a registry c# for the bool, for example:
uniform bool cMyBool : registry(c0);
void PS(...)
{
    ...
    if (cMyBool)
    ...
}


- specify the attribute 'flatten' on the 'if':
uniform bool cMyBool;
void PS(...)
{
    ...
    [flatten] if (cMyBool)
    ...
}


7. Similary, int uniforms can be set with 'SetPixelShaderConstantF', you cannot use 'SetPixelShaderConstantI' because it is for i# registers only.

8. I've also noticed that the ID3DXEffectPool interface (the one you get with D3DXCreateEffectFromFile) works with no problems with:
effect->SetFloat(), effect->SetInt(), effect->SetBool(), so I think that maybe inside it uses 'SetPixelShaderConstantF'.

Conclusions:
- Adding support for int and IntVector2 shader uniforms can be done on OpenGL and DirectX9 (with a little modify on the material XML), but it
adds nothing to DirectX9 (and they are slow), better to use floats; on OpenGl it can be useful for prototyping (and they should be fast).
- To make uniform bools work on DirectX9 the Set___ShaderConstantB could be replaced with Set___ShaderConstantF, this works but it seems
an hack, and their use can create problems difficult to pinpoint (point 6).

These notes are not much trustworthy, there is no experience behind only a few tests done last week.
I think it is better for Urho to leave it as it is now: few gains to face problems not fully understood.


Reply all
Reply to author
Forward
0 new messages