Effects, Passes, Shaders and Parameters
As I promised in an earlier post, this is a short overview about shader support in the engine. Currently Merlin3D supports OpenGL and GLSL. DirectX support is not implemented yet.
Merlin3D uses its own effect files, that describes a particular shader set for the different rendering passes (it has some similarities to .fx files in DirectX, but in OpenGL world there is no effect file support at all). Effect files are in XML format. Each visible scene object has exactly one effect required to render the object in different rendering passes. Multiple scene objects can use the same effect. Anyway, it is the recommended way of effect usage, because the engine tries to group objects by the associated effects to reduce OpenGL state changes.
Each effect has shader program definitions for the different passes of the renderer. The renderer supports the following passes: forward, depth, light, transparent pass. Forward pass is for forward shaded rendering and for postprocess effects. Depth pass is for depth pass in deferred rendering mode or depth texture rendering in shadow map generation (this pass is not fully complete yet). Lighting pass is for the lighting pass in deferred rendering, transparency pass is for rendering transparent objects in deferred model, like particle systems or water.
Each shader program definition has one or more vertex and fragment shader source specifier and arbitrary number of shader parameters. Different effects can use the same vertex and fragment shader sources with different parameter configurations. There are three classes of shader parameters. Simple parameters can pass to a specific typed value to the shader. This kind of parameters are coming from the effect files and can be changed from the engine code later. Parameters in the second class are taking values from a console variable. It makes easy to change parameter values interactively because GUI controls can control console variables also via binding, thus it is possible to connect a parameter value to a GUI element without any coding or recompiling. Third class of parameters is the class of built-in variables. These are specified in the effect file as special parameters or in the shader source by using predefined names recognized by the engine. In the latter case the engine checks if the shader parameters have special names and automatically binds the corresponding internal state variable to it. There are many built-in variables like the modelview matrix, the current light source position, and so on.
In the following example, there is a sample effect file for a simple static model. There are two passes in this effect, one for forward rendering and one for depth pass. Passes have own set of shader parameters. The forward pass has the “ObjectColor” parameter that takes value from the “TestColor” console variable. The dollar sign in the value attribute tells the engine that the value is coming from the console variable specified here.
Forward pass shader compiled from one vertex and three fragment shader source files.
<Effect Name="Column"> <Pass Target="ForwardPass"> <Parameters> <ShadowMapTexture Name="shadowMap" /> <Sampler2D Name="texture" Value="column.tga"/> <Color Name="objectColor" Value="$TestColor"/> </Parameters> <VertexShader Source="Data/Shaders/Scene/Concrete1.vert" /> <FragmentShader Source="Data/Shaders/Scene/SkyColor.frag" /> <FragmentShader Source="Data/Shaders/Scene/Shadow.frag" /> <FragmentShader Source="Data/Shaders/Scene/Concrete1.frag" > </FragmentShader> </Pass> <Pass Target="GeometryBufferPass"> <Parameters> <Sampler2D Name="texture" Value="column.tga"/> <Float Name="specular" Value="0.0" /> <Int Name="BRDFIndex" Value="0" /> </Parameters> <VertexShader Source="Data/Shaders/Scene/GenericGeom.vert" /> <FragmentShader Source="Data/Shaders/Scene/GenericGeom.frag" > </FragmentShader> </Pass> </Effect>
This is a sample from one of the corresponding shader sources:
uniform mat4 m3d_ModelViewMatrix; uniform sampler2D texture; uniform vec4 ObjectColor; ....
The first parameter is an automatic built-in variable reference. The engine treats a uniform parameter with name starting with “m3d_” as a built-in variable reference. In this particular case, the engine detects that this name refers to the actual modelview matrix of the renderer and automatically adds an effect parameter to the shader. There is no need to specify this parameter in the effect file or anywhere else. This method also works for multiple shader sources with uniform parameters in each of those. The ‘texture’ and ‘objectColor’ parameters are standard shader parameters specified in the effect file.
It is possible to build and manipulate effects from engine code at run-time also, that makes easy to implement any kind of automatic shader code generation.