Sign in to follow this  

few question about the Shader/material implementation

Recommended Posts

I have started with my 3D engine again after a long time. I have some questions 1) How to handle shadowmaps? 2) how to control the bouncing stuff? lets say I have 2 shaders one that will do diffuse lighting and one that do texturing and I need both, this isn't to hard they can go in the same pass. But what if I have one diffuse lighting shader, one specular and one shadowmap shader, normaly the diffuse and specular shader could be done in one pass (could have one shader for this but not in this exampel) When shadowing the shadowmap shader needs to create/update shadowmaps for each light well this is easy just put this in a pass before the other two. BUT now the diffuse and specular lighting needs to be in two different passes (it will probibly go in one pass but lets say the hardware doesn't support what is needed for that) whith some blending too which could be bounced over to a Transparency shader.. but how to know that the in this case Shadowmap shader should be the one that determin which pass the rest goes into? 3) is static passes a must have? is it posible to some way generate nr of passes in some dynamic way. I think some thing like this
class ChunkPass {

 int iPassOrder; // when to render this pass

 VertexBuffer *vb; // pointer to the VB for this pass

 Material *Material; // this would be the material properties for this pass only

then the code would generate a number of chunk passes and put them into the renderqueue sorted depending on the iPassOrder. or would this fail? 4) How to handle objects that will be transparent? I know I would render them after other objecst, but what about shadows and other special effects that they may have? should a transparent object be the same as if it wasn't transparent except that it is rendered with transparency, if so could I have a transparency shader that would be used when object/pass need transparency? EDIT: more questions: 5) The shadowmap shader needs new objects depending on the lights viewport, so should the shadowmap shader be able to collect them by itself and call the renderer with its new temporary shadowmap queue? 6) How does this shader/material implementation work if I create a multithreaded graphics engine?

Share this post

Link to post
Share on other sites

I typed a big ass reply and hit f5 (usualy followed by a enter) cause I'm an nerd and do that in every program after I finish typing something.

So damn I dont wanna type all that again. When I get to work I will have new energy towards not working and will reply what I originaly wrote...

Share this post

Link to post
Share on other sites
Guest Anonymous Poster
I would like to know about the bouncing too

Share this post

Link to post
Share on other sites
There are numerous way of implementing what you are describing. I will give you the way I have choosen for my scenegraph engine.

When redering, the scenegraph is traversed by a visitor ; for each node, i check if it is culled out then use a "node renderer" according to the "node type" (simple look up in an array).

The "node renderer" update the renderer state, create render pass, add render commands to render passes,... Most node renderers for drawable objects use the following design ; they create "geometry render command" and pass them to a "appearance shader" according to the "appearance type" of the drawable.

The "appearance shader" is in charge of defining the render target state of the "geometry render command" (eventually duplicating it as needed for multi pass), asking the geometry render command to map some data channel to render target channels (vertex coordinates, vertex attributes,...), create rendr passes, register render command to passes. Most of the "appearance shader" rely on a "shadow shader" (based on the shadowing technique type tht the light use) when it comes to shading the light behavior.

The "shadow shader" receive the "shaded geometry render command" and as allways is able to create render passes, register render commands,... .

Now, with this design in mind, here are the answer I can give you to your questions ;

1) Shadow maps are handled by the "shadow shader". When it is triggered for the first time, it adds a pass to the main render frame which computes the shadow map. It process the incoming "shaded geometry render command" by applying the needed states for shadow texture depth testing, and register the modifyed shaded depth texture to the "target pass" stored in the "shaded geometry render command".

2) I do not have bouncing problem, since it is the "shadow shader" that register render commands to render passes. This design also lets me the possibility to develop sort of integrated shader that performs all operations for a known set of (node type, appearance type, shadow type).

3) I do not have static passes. When you create a pass, you may specify predecessors / successors. The order rendering of the passes is resolved later on the rendering pipeline. The pass hierarchy is stored in the renderer state allowing me to perform re-rendering of the scene to a sub-pass (for example mirrors, or environnmenent cube map, or shadow map), or to register a render to texture pass that is before all other passes.

4) Transparent objects are just like others. Only when the "appearance shader" process them, it sets there transparency / blending hardware state and they define their target pass to a translucent pass that has the opaque pass as a predecessor.

5) The "shadow shader" has access to the rendering system. In short, in my design, when it need to update its shadow map it will call the following pseudo code ;
create rtt pass for shadow map
rendererState.setRenderFrame(shadow map rtt pass)
rendererState.setFrustum(light frustum)

6) I don't know ; my system is not multithreaded.

That was a bit long. Hopes it will help.

Share this post

Link to post
Share on other sites
Read this article

Yann L's shader implementation description

now to go on with dynamic render pass combination:

I thought about this solution:
a) All shaders are written in Cg
b) at startup I look around what shader combinations are required to reduce the amount of passes
c) look how and if passes can be combined into single passes
d) basic material shader passes and basic material lighting ... can be combined easy

I setup a new shader and merge the Cg shader fragments in the right order
the main routine of the shader is created at runtime and then compiled and assigned whenever this shader combination is required

this allows you to dynamically combine any rendering pass that has to do with meshes and textures

other effects like particles shadows and per pointlight shadowmapping is done seperately and applied at the end of each frame

yann l's shader implementation with dlls will only serve as an implementation that sends the data the actual rendering is done by the code shader system

Share this post

Link to post
Share on other sites
Niwak > it looks like all other shaders are dependent on the shadow shader, what if an object doesn't cast shadows?

Basiror > That thread I have read like 100 times still don't understand a few things. and I don't want to be forced to use CG shaders. and how can the engine be know if two passes can be merged? lets say simple diffuse and specular lighting (using OpenGL built in lighting) can be in one pass when no shadows but has to be split in two passes when using shadowmaps well they can probibly go in one pass if using extensions and other stuff, but how can the engine know this?

is it only alot of testing? like the shadowmap shader request a diffuse lighting shader for pass 1 (shadowmap shader in pass 0) and a specular lighting shader in pass 2 with some blending mode, or should it ask for shader(s) that can do 'diffuse and specular lighting with shadowmap testing' and then the shadersystem resolves either one pass with shaders needed for doing it in one pass or it will resolve two passes with shaders needed in current pass..

BUT how to know if the two shaders can be merged into one pass?

Share this post

Link to post
Share on other sites
Niwak > it looks like all other shaders are dependent on the shadow shader, what if an object doesn't cast shadows?

Not all nodes go through the complete pipe ; it is the choice of each shader to choose wether or not it should use a deeper shader.

An object that does not cast shadow will have its appearance shader deciding to not use any shadow technique.

Yann L's article is very interesting. At first, that was the way I was going. I ended up with the system I have described due to the following problems ;
- I wanted to keep my scenegraph like a very open framework for all my projects. I thought (I may be wrong) that the type of design he described build a scenegraph that is highly dependent on the way it is rendered.
- I did not find a way to design satisfying general bouncing between shaders ; defining bouncing in a very general manner was leading me to restrict the scope a shader would have (i.e. for example, you allow your shader to set texture, set renderer states,... but in my design, they can do anything they want).
- I was thinking that the set up pass was mainly adapted for static scenes which is true in general but requires the scene to be clearly separated between static and dynamic objects.

The design I have described was my choice facing these problems. It is far for perfect. Mainly ;
- it is likely to be less efficient than Yann L's one,
- the bouncing problem is limited by the absence of bouncing - this is not fully satisfying, since it ends up with a missing feature (sort of, since the design provide allow to implement bouncing at a later time).
- there are still dependencies between plugin (each shader is a plugin) since they may require setting the same renderer state ; for example a classic conflict is when the node shader requires vertex program for animation skinning and the appearance shader also require vertex program for example for toon rendering ; in this situation, the situation is logged and the developper needs to create an integrated plugin that handles both the node and the appearance.
- the pre-process pass is replaced by 'optimizers' that can be run at any-time. They still need you to give hint about wether objects are static or dynamic.

BUT how to know if the two shaders can be merged into one pass?

In my design, the shadow shader knows if it can merge with the appearance shader, if the required render target state are not used (a free texture unit, ...).

Share this post

Link to post
Share on other sites
Node shaders (I call them "node render technique") process scenegraph nodes. Here are some examples ;
- I have 2 "node render technique" plugins for the node class "IDrawableMesh", one which use VBO when appropriate and just allocate one VBO per mesh, one which use a dynamic VBO allocation technique (experimental, and not that satisfying).
- I have a node class "KeyFrameDrawableMesh" for interpolated mesh (MD2 style animations), two plugins exists for it : one which performs CPU interpolation, one which use GPU vertex program.
In fact, there are a lot of "node render technique" ; at least one per node class (lights, terrain, transform, group, mesh, bezier patch,...).

"Appearance shaders" are not directly used by the renderer ; "node render technique" use them to shade the appearance of the object they process (texture, reflection, ...). They are just a way of sharing the appearance shading code accross different nodes (for the moment, I use them for IDrawableMesh, IDrawableBezierPatch, FramedNode, KeyFramedMesh, SkinnedMesh and BasicTerrain nodes).

This makes the design highly flexible since the structure of the scenegraph is completely free. This allow me to layer my library (roughly) like this ;
Level 0 : Supporting library (math, geometry, data handling,...)
Level 1 : Scenegraph
Level 2 : Video renderers, Audio renderers, Physic system (planned), Universe management (optimizers, IO library)

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