• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
lipsryme

Dynamic branching in shader not working. Keeps jumping out.

10 posts in this topic

I'm trying to implement a branching inside my uber shader to achieve different material types using deferred shading but keep getting problems with the branching.

Now this is where it seems to cause the problem:
[CODE]

float4 PS_Directional(VSO input) : SV_TARGET
{
float4 output = float4(0.0f, 0.0f, 0.0f, 1.0f);

// Get Material ID
float materialID = tex2D(AlbedoBuffer, input.UV).a;

// Get Normals
half4 encodedNormal = tex2D(NormalBuffer, input.UV);
half3 Normal = mul(normalize(decode(encodedNormal)), inverseView);


if(materialID == 0.02f)
{
output = 1.0f;
}


return output;
}

[/CODE]

As you can see I'm doing an if on the materialID to set a pixel color specifically for each objects material.
Now when I run this I just get a black screen, as it's (output) initialized at the beginning.
Running this in PIX I can see him going inside the if statement, setting output to the correct color and then going back to the if statement and returning 0.0f again.
What is going on here ? Why does it set the correct color and jump back afterwards to undo it ?? Edited by lipsryme
0

Share this post


Link to post
Share on other sites
First of all try to avoid doing dynamic branching like this, and look into less naive approaches for rendering multiple materials in a deferred setup. This thread has some good ideas for such approaches: [url="http://www.gamedev.net/topic/625023-branching-picking-lighting-technique-in-a-deferred-renderer/"]http://www.gamedev.n...erred-renderer/[/url]
Have a look at hodgman's post about using a material mask to reduce branching to an absolute minimum (I've built a variant of this technique which does deferred rendering with 3 different BRDFs myself)

Second, I believe your issue here has to do with floating point error. Due to the way floating point values are stored in memory you can never assume a statement like 'materialId == 0.02f' to return true, because the actual value of your floating point number would probably be something lower than 0.02f
Always use a small delta range for checking equality between floating point numbers Edited by Radikalizm
1

Share this post


Link to post
Share on other sites
Radikalzm is most likely correct.

An easy way to find out would be:
float materialID = tex2D(AlbedoBuffer, input.UV).a;
double d = materialID;

Check the value of 'd'. It'll be something like 0.019999999552965164
2

Share this post


Link to post
Share on other sites
I'm not so sure about the advice to avoid dynamic branching at all costs here. Not so long ago I would have been, and would have given much the same advice, but times change and more info comes in.

The key thing is that the HLSL code you write does not necessarily need to bear any relationship to the code generated by the shader compiler. It's incredibly instructive to look at the generated asm code in PIX or another shader debugging tool - you may find that the HLSL code with branching has been converted into code that has no branching whatsoever. The D3D shader compiler is [i]extremely[/i] good at doing this, and the whole experience can be quite an eye-opener (not to mention changing your attitude towards shader branching).
2

Share this post


Link to post
Share on other sites
I see that is quite an interesting solution there @Radikalizm.
On topic: You are right I just tried dividing the materialID by 10 and multiplying it by 10 again after reading it back and it suddenly works.
0

Share this post


Link to post
Share on other sites
[quote name='mhagain' timestamp='1341167382' post='4954600']
I'm not so sure about the advice to avoid dynamic branching at all costs here. Not so long ago I would have been, and would have given much the same advice, but times change and more info comes in.

The key thing is that the HLSL code you write does not necessarily need to bear any relationship to the code generated by the shader compiler. It's incredibly instructive to look at the generated asm code in PIX or another shader debugging tool - you may find that the HLSL code with branching has been converted into code that has no branching whatsoever. The D3D shader compiler is [i]extremely[/i] good at doing this, and the whole experience can be quite an eye-opener (not to mention changing your attitude towards shader branching).
[/quote]

In this simple case with just a really small amount of branches I agree with you that it won't really have an impact (on more modern GPUs that is), however when it comes to a setup which can support a lot of materials it will become a problem. I believe pixel shaders get executed in some sort of thread groups (terminology?), and as long as all the pixels in such a group take the same path of the branch there won't be much of a problem. This does become a problem however when multiple paths are executed, since the pixel shader will run through all the options and pick the right result afterwards for all pixels in said group (please do correct me if I'm wrong here, my knowledge of the matter isn't completely solid).

IMO it's still best to avoid use of branching, some small branches here and there won't hurt, but for things like lighting calculations I believe it'd be best to find an alternative when it comes to a greater amount of branch options. Edited by Radikalizm
0

Share this post


Link to post
Share on other sites
Ugh now I'm having a new problem.

Using code like this:
[CODE]
if(materialID < 2.1f &amp;&amp; materialID > 1.9f)
{
return float4(1.0f, 0.0f, 0.0f, 1.0f);
}
else if(materialID < 1.1f &amp;&amp; materialID > 0.9f)
{
return 1.0f;
}
[/CODE]

gives me the object in the right color (red) but with a white border...

I guess it comes back to the same problem with precision, right ?
What value range would I use to define this more clearly for the pixel shader ?
PIX tells me the pixel of the white border uses a materialID of 1.0 Edited by lipsryme
0

Share this post


Link to post
Share on other sites
Could you maybe provide a screenshot of the problem? Could be a problem with texture filtering when sampling your texture for a material ID, or maybe your material ID isn't being written to your g-buffer correctly
0

Share this post


Link to post
Share on other sites
Looks like this: [url="http://cl.ly/082u1i2O3s3X43391x0W"]http://cl.ly/082u1i2O3s3X43391x0W[/url]

I think it's the overlapping materialID values that cause this.
Using a greater distance between one and another e.g. 0-1 (ID 1) and 2-3 (ID 2) seems to work.

edit: You might be right, haven't thought of the idea that the linear filtering might interpolate those materialID values quite a bit.

[b]Update: It was indeed the texture filtering that was causing this precision issue. Using point clamp works perfectly.[/b] Edited by lipsryme
1

Share this post


Link to post
Share on other sites
I think conditional branching in shaders only provides a performance hit if each SIMD instance might take a unique branch. If so, you will get a SIMD 'stall'. The shared branch instances will execute in the current active working set, then the other branch set will execute, and then eventually they will 'sync' up afer all branch sets and once again grinf away efficiently as SIMD across the entire working set.

But just because you take a hit doesn't mean you can't do it. Just be aware there is a hit. Instrument and measure the hit, compare normal cases with extremes. It might not be so bad, that totally depends on the logic.

This issue becomes more front and center with openCL but it also applies to shaders.
2

Share this post


Link to post
Share on other sites
I'm dying to really see how well modern hardware handles true branches when you can disregard old hardware, because we work extra hard to flatten our shaders and build custom permutations for all of them in order to minimuze shader ALU processing.
0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0