variable multipass shaders

Started by
10 comments, last by _DarkWIng_ 19 years, 4 months ago
Hi. I have material/shader implementation working in for most things, but there is one thing I just can't find elegant solution to. How do you create a shader that has variable number of passes. I have no trouble with shaders that use bouncing to other shaders but this is something different. Lets take PPL shader for example. And for simplicity let's say I can do 1 light in one pass and I want up to 4 lights per chunk. So I need to loop this shader 1-4 times or a no-light shader once, based on number of lights in area. I really can't find elegant solution to this. I've tried number of things but all end up breaking the whole shader system or end-up being major performance problem. I would really like to know how you guys handle this type of problems.
You should never let your fears become the boundaries of your dreams.
Advertisement
One soulution could be to send to the shader the actual state,where it can find, for example, the first 4 light near.
With this approach,the shader take the decision if to render all in one pass or render with multiple pass or take only one light and skip the other three light.

Davide
Took me a while to solve this too, however I think my shader system is quite different ( I went the script route rather than the plugin DLL route ). Anyway, this is what I do:

As an input to my shader script ( similar to an fx file, but not ), I have a variable array of light positions or vectors. I then define different paths to take ( to different cg programs - shaders in the classical sense ) depending on the hardware available and the number of lights. So, for instance, say you had 3 lights coming in. If the graphics card could cope with 2 lights per pass, the shader would have coded a path for 2 lights, and a path for one light. At runtime, the engine would split the render operation up into two parts, one renders two lights, one renders one, and adds them both to the render queue. So essentially I have a number of shaders that can each do a number of lights per pass, and I bounce around them to render however many I require.

I don't know how you'd do it in a plugin system, but with a script it's easy.
If at first you don't succeed, redefine success.
davidino79: I don't have a problem how to select ligts and so on. I have a problem how to handle then in elegant maner.

Hi python_regious. I had similar system as one of possibilitys. So you create one shader chain (list of shaders) for each number of lights and select the right one each frame of what? Or do you select shader with max possible lights and somehow ignore the rest. In your example. You create shader for 3 lights: what happens if 2 of lights move out of range?

Could anyone else please explain how they handle this.
You should never let your fears become the boundaries of your dreams.
What about having a part at the end of your shader that tells the engine what shader it should run next. This can be a reference to the shader for the next pass in the overall shader (could be the same shader again), or that the shader is finished. Also this ending part indicates what parameters to pass to the next shader, which could include the pass number. The pass number can be used to figure out when to finish the shader.
[s] [/s]
I can see the fnords.
Quote:Original post by DudeMiester
What about having a part at the end of your shader that tells the engine what shader it should run next. This can be a reference to the shader for the next pass in the overall shader (could be the same shader again), or that the shader is finished. Also this ending part indicates what parameters to pass to the next shader, which could include the pass number. The pass number can be used to figure out when to finish the shader.


This wont work, shaders should be sorted to minimize state changes so going to a different shader like that is a bad idea. I use the same principals in my system as the thread but it is quite different in the implementation then what was proposed.

I have run into the problem you speak of and right now haven't implementated a solution, beside proxy shaders that do nothing and just act to chain others together. This is just for debugging.

What about just adding another function to the shader, GetCallBack() that would either return a bool for a call to be placed back to the shader or an integer that would tell you how many calls you need (just loop it then).

Anyway, very interested in hearing what you come up with to solve this problem
Quote:Original post by nts
What about just adding another function to the shader, GetCallBack() that would either return a bool for a call to be placed back to the shader or an integer that would tell you how many calls you need (just loop it then).

This is simmilar to the method that I have as my best option so far. Shader has a function that returns info how many times it needs to be looped. But the problem is that you have to disable blending for 1st pass and enable it for all the rest. And blending state switch is not very cheap as far as I can remember. I might just implement this and test it... probably tomorrow.
You should never let your fears become the boundaries of your dreams.
I know of engines that simply use different shaders for different light counts (I think Source does this). Which is basically what was described above. Either pre-build shaders that do 1 light, 2 lights, ... up to some maximum. Or have a system to dynamically build the shaders based on the number of lights requested (with some caching, etc...). That last approach is becoming fairly common, I think - especially as it's not that hard to paste together HLSL or something similar at run-time and run it through the shader compiler/assembler.
Quote:Original post by _DarkWIng_
Quote:Original post by nts
What about just adding another function to the shader, GetCallBack() that would either return a bool for a call to be placed back to the shader or an integer that would tell you how many calls you need (just loop it then).

This is simmilar to the method that I have as my best option so far. Shader has a function that returns info how many times it needs to be looped. But the problem is that you have to disable blending for 1st pass and enable it for all the rest. And blending state switch is not very cheap as far as I can remember. I might just implement this and test it... probably tomorrow.


I'm thinking of going this route aswell. My engine isn't as advanced yet and i'm not familiar with the cost associated with each state change (except that its best to minimize them :p) but what about implementing the shader as multipass then, with the first base shader and the rest of the blend passes in another i'm sure you though about this already too :)

Lemme know how it works for you, dunno when i'll have the time to implement it
Quote:Original post by _DarkWIng_
Hi python_regious. I had similar system as one of possibilitys. So you create one shader chain (list of shaders) for each number of lights and select the right one each frame of what? Or do you select shader with max possible lights and somehow ignore the rest. In your example. You create shader for 3 lights: what happens if 2 of lights move out of range?


If two lights moved out of range, then only the one-light-per-pass shader would be added to the render queue. If 5 lights were in range, then the 2 lights per pass shader would be added twice, and the 1 light per pass shader would be added once.
If at first you don't succeed, redefine success.

This topic is closed to new replies.

Advertisement