flexw said:
@Juliean Thank you for your reply. So for each type of geometry (mesh, skinned mesh, sprite, debug) I would create a base vertex shader this base vertex shader defines an interface. An material can use this interface to inject custom behaviour? Same for the fragment shader. I define a base fragment shader which for example implements phong lightning or pbr and create an interface which client code can use to inject custom behviour?
Yeah, sort of like that. Things like Mesh or SkinnedMesh could be the same base-shader with different options. Lets call those base-shaders a “shader-profile" for now (thats what I use internally and so I don't have to write around describing it every time).
A shader-profile would ideally consist of all the shaders necessary, meaning that you don't have separate vertex/fragment/geometry-shader, but only different shader-profiles that supply all the necessary shader-stages. If you need a profile to act differently depending on the context, lets say forward or deferred rendering, you implement the profile to support both "passes", so to say (and your render-framework should then be able to select the correct path). The difference between forward and deferred then becomes a matter of “Evaluate the material-properties, calculate lighting and write to buffer” (forward) or “Evaluate the material-properties and write them to buffers; then after all are done calculate lighting as a post-pro effect” (deferrred). So your Mesh-profile doesn't need to know anything about rendering a quad for lighting (but you are adviced to have your lighting-calculation as a set of functions that you can invoke in eigther path).
Now for the skinning, I would have this as an option (say a boolean) that the material can request from the profile. If it does, the profile generates code for skinning and gives the material-evaluation function(s) access to the skinnin-parameters. You could probably also make a different profile; but you really want to have as little duplication of shader-code as possible (otherwise introducing new features becomes a nightmare), so I'd go with the configuration-option (this is also very hand for different things like transparency-mode, shading-model, etc…)
flexw said:
A simple idea, that comes to my mind, is that on the creation of the material, the material sends it's custom shader code, with info which base shaders to use, to the renderer. The renderer will then create a concrete shader program based on it's on configuration (forward or deferred).
Yes, sounds like what I'm doing as well. In my case the material consists of a base-profile, the visual shader-code and all the variables/textures. The renderer then supplies a “view” (this is to distinquish between 3D/2D/Gui), and selects specific options (like Forward/Deferred; which the profile has to support), and then you got the final shader-program up and ready.