Shaders and parameters
Some time ago I fired off a resource thread and this thread is along those lines but not exactly. Because of this I started a new thread and also just to let the old one die.
For those of you working with shaders I have an important question. How in the world are you rendering with these when:
- Each shader can and will require different parameters.
- Each shader is for a different 'effect' and may also require several textures
For example, I have a shader manager that handles the actual shader objects. I have a central rendering system that, when created, takes all of the objects from my object manager and examines their shader ID. It groups objects with the same shader IDs into lists. These lists simply contain the ID of the object in the game object list. Later during rendering I start with the first shader and render all objects in the first shader list and continue this until all lists are rendered.
In order to speed up rendering and culling each list is culled and placed into a master list. The number of objects per shader is stored so that the rendering system knows when to switch shaders.
This is all fine and well until I attempt to set the parameters of shaders. My default ambient, diffuse, specular shader requires a material containing 3 4D vectors used as color values for light properties. The specular component also contains a specular power factor that must be set. The world/projection matrix must also be sent to the shader as well as textures.
Now I can do some type of checking in the shader to determine if or how many textures are being used up to a maximum of 5 textures. I do not, however, have a way of specifying how each texture stage should be blended together and since you cannot use the output of one shader as the input for another without re-rendering the geometry I'm sort of stuck. How the Direct3D fixed function pipeline created stages for blending is beyond me and perhaps it's not possible with the current shader models.
What I'm lost on is how do I specify that shader X requires certain params and shader Y requires other params? This is quite confusing. All I can come up with is this:
I just send all the parameters to the shader. Or try to anyway. If the current shader doesn't use the parameter then it doesn't have any effect anyway.
For example, I have two versions of my phong lighting shader; one with normal mapping, and one without. Because all my objects store a normal map anyway, I set it and send it to the shader. If i'm using a shader that doesn't use normal mapping, then that texture I sent becomes useless.
I'm sure this is inefficient, since i'm wasting a texture unit when ever I set a shader that doesn't make use of normal mapping. But I haven't yet come up with any other way.
I'm working on multiple passes in Direct3D effect files. Some of my effects require 2 passes which gives a bit more functionality to the engine.
I've come up with a way to set light color states, matrix states, and light type states using the OR to combine fields. The shader manager then examines the dwLightColor, dwLightType, and dwMatrices DWORD to see if they contain any of the pre-defined states. If they do then the manager class sets the correct values in the shaders. This means of course that in all shaders there must be a universal naming scheme for certain matrices and lights.
The only other way I can think of is to employ scripting which is not what I want to do.
I have several ideas to try out once the system is up and running:
- Glow mapping
- Adaptive glare
- Steerable streak filters
- GPU based blur kernel
- Shadow mapping
- Water effects
- Real time atmosphere effects (updated sky shader)
For shadow mapping I'm going to try something a bit different. I'm going to render the shadowing object from the direction of the light - or what it would look like if the camera was at the light position and orientation. This will be rendered, filtered, and then I will perform a projective texture map onto the surface surrounding the object in the direction of the light rays. This won't do self-shadowing but it is a cheap shadow effect.
Even though I can add multiple textures in a single pass the operations between each step are fixed and hard-coded which is not what I want. In order to gain Direct3D 9.0c FFP functionality I would have to write multiple passes for each texture and re-render the geometry to get the effect. I don't like this approach so I'm creating shaders for up to 5 texture blends with operations specified in matrices. The problem with using this approach is that it makes my shaders use VS 3.0 and PS 3.0 which some cards do not support. I will provide a fallback approach for pre 3.0 cards.