Shader Usage in Candera
Description
This chapter demonstrates how customized shader programs can be used with Candera. Subject of this chapter depicts how to use the Candera classes to set custom shaders for each node, and how to apply shader parameters. Further, it shows how to realize different classes of effects, namely single pass-, local multi pass- and global multi pass effects.
Shader Related Class Usage
This section is about on how the already introduced Candera::Appearance class and its members can be used to realize customized shader effects.
Loading shader programs
First step to realize shader programs is to actually write them. See the GLSL chapter for details on that. For a developer it is recommended to develop using SceneComposer, where the effects can be seen immediately in the Scene Editor window.
This tutorial further focuses on programming with Candera, but the concepts are supported as well in collaboration with SceneComposer. Beside of SceneComposer's shader editor, shader authoring tools like AMD's RenderMonkey can also be used. Benefits from using either SceneComposer or shader authoring tools are syntax highlighting, seeing compiler and linker errors and having a preview scene where the effect can be examined. One unique advantage of using SceneComposer is the support for device dependent shader compilers.
After having finished your shader program you need to load it in your application based on Candera. Use your favorite file I/O libraries among the available ones. It depends on the platform if the underlying OpenGL ES implementation needs the shader source or pre-compiled shader objects. On host you typically load the source of your shader program directly, it will be compiled and linked at runtime by the OpenGL driver invoked by Candera's Upload mechanisms. On targets you might need to provide pre-compiled shader objects, where pre-compiling is done using dedicated shader compile tools. Please refer to the device manufacturers manual.
Using Candera::Shader
Candera::Shader is the class that abstracts from OpenGL ES shader interfaces and manages the shaders handle after creation. For a small description see the tutorial on the Appearance class. See below how to use the class.
First you need to create an instance of the Candera::Shader class using its Create() method.
static MemoryManagement::SharedPointer<Shader> Create();
Next step is to provide the loaded shader sources or objects to the class using the according setters:
bool SetVertexShader(const void* vertexShader, DisposerFn disposerFn); bool SetFragmentShader(const void* fragmentShader, DisposerFn disposerFn);
-
The shaders are passed as void* to ensure that platform dependent representations of the shader program can be passed. The parameter DisposerFn hands over lifetime responsibility of shader passed: If it's set to 0 you'll have to take care of the provided void* by yourself.
Finally, the shader needs to be associated to a node's appearance in order to leave the remaining steps (like Uploading and further Activating) to Candera. Upload takes care of compiling, linking, and retrieving the shaders handle. Vertex attribute binding is done in the appearances activation method, automatically.
The following code snippet demonstrates how a Billboard node with a custom shader can be created.
void Initialize() {
Char* vertexShader = "";
Char* fragmentShader = "";
// Do File I/O here, filling vertexShader and fragmentShader with the read data.
Scene* scene = Scene::Create();
//Do camera setup here, add it to scene graph.
SharedPointer<Shader> shader = Shader::Create();
shader->SetVertexShader(vertexShader, 0); //vertexShader needs to be disposed manually.
shader->SetFragmentShader(fragmentShader, 0); //fragmentShader needs to be disposed manually.
Billboard* billboard = Billboard::Create(2.0f, 2.0f);
billboard->SetAppearance(Appearance::Create());
billboard->GetAppearance()->SetShader(shader); //Here the previously instantiated and configured shader is added.
//Set and configure remaining appearance members.
scene->AddChild(billboard);
scene->UploadAll(); //All nodes, all their Appearance objects and therefore all set shader objects get uploaded.
}
void Render() {
Renderer::RenderAllCameras(); //Here the scene graph gets traversed, for every node the shaders get activated, and the vertex buffers attribute get bound
//to the shaders attributes.
}
Auto Uniforms
Candera::ShaderParamSetter and derived classes are used to set uniform parameters of shaders, they abstract from OpenGL ES's glUniform_ interfaces. They are part of a node's appearance, how to use them is already described in the Appearance Tutorial.
As described the derived class Candera::GenericShaderParamSetter offers to automatically compute and set shader parameters from the configured scene graph. The following table shows which uniforms are reserved for this purpose, what Candera classes they affect and what their semantics are.
- Note:
- The values of reserved variables cannot be edited in SceneComposer, here the Candera::GenericShaderParamSetter has to be used.
The table is structured as follows:
- Column Uniform Variable is the name of the reserved variable.
- Column Data Type describes its data type.
- Column GenericShaderParamSetter Flag describes which properties have to be enabled in Candera::GenericShaderParamSetter in order to compute and set the variable.
- Column Affected Classes describes which classes are used to compute the parameters.
- The last parameter Semantic describes for what purpose this parameter is needed.
-
If no instance of the affected classes exist, the corresponding shader parameters will not be set, even if they are enabled in Candera::GenericShaderParamSetter.
| Uniform Variable | Data Type | GenericShaderParamSetter Flag | Affected Classes | Semantic |
|---|---|---|---|---|
| u_MMatrix3 | Matrix3 | ModelMatrix3Enabled | Candera::Node | Computes the ModelMatrix3 from the Node's transformation data, used to transform 3-component vectors from model to world space. |
| u_MVMatrix3 | Matrix3 | ModelViewMatrix3Enabled | Candera::Node, Candera::Camera | Computes the ModelViewMatrix3 from the Node's transformation data and the currently rendered Camera's ViewMatrix. Used to transform 3-component vectors from model to view space. |
| u_NormalMMatrix3 | Matrix3 | NormalModelMatrix3Enabled | Candera::Node | Computes the NormalModelMatrix3 from the Node's transformation data, used to transform 3-component directional vectors (especially normals) from model to world space. |
| u_NormalMMatrix4 | Matrix4 | NormalModelMatrix4Enabled | Candera::Node | Computes the NormalModelMatrix4 (4×4 normal-transform matrix) from the node’s transform and passes it to the shader. |
| u_NormalMVMatrix3 | Matrix3 | NormalModelViewMatrix3Enabled | Candera::Node, Candera::Camera | Computes the NormalModelViewMatrix3 from the Node's transformation data and the currently rendered Camera's ViewMatrix. Used to transform 3-component directional vectors (especially normals) from model to view space. |
| u_MMatrix | Matrix4 | ModelMatrix4Enabled | Candera::Node | Computes the ModelMatrix from the Node's transformation data, used to transform 4-component vectors from model to world space. |
| u_MVMatrix | Matrix4 | ModelViewMatrix4Enabled | Candera::Node, Candera::Camera | Computes the ModelViewMatrix4 from the Node's transformation data and the currently rendered Camera's ViewMatrix. Used to transform 4-component vectors from model to view space. |
| u_PMatrix | Matrix4 | ProjectionMatrix4Enabled | Candera::Camera | Passes the ProjectionMatrix4 from the active camera to the shader. |
| u_VPMatrix | Matrix4 | ViewProjectionMatrix4Enabled | Candera::Camera | Passes the active camera’s the ViewProjectionMatrix4 (View × Projection) to the shader. |
| u_MVPMatrix | Matrix4 | ModelViewProjectionMatrix4Enabled | Candera::Node, Candera::Camera | Computes the ModelViewProjectionMatrix4 from the Node's transformation data and the currently rendered Camera's ViewProjectionMatrix. Used to transform 4-component vectors from model to homogeneous screen space. |
| u_CamDirection | Vector3 | CameraLookAtVectorEnabled, LightActivationEnabled | Candera::Camera, Candera::Light | Passes the currently rendered Camera's look-at vector in world space to the shader. Transforms it to object space if LightsCoordinateSpace is set to Object. Can be done explicitly, or inside lighting calculations. |
| u_CamPosition | Vector3 | CameraPositionEnabled | Candera::Camera | Passes the currently rendered Camera's position in world space to the shader. |
| u_Size | Float | - | Candera::PointSprite | Passes the size of a Candera::PointSprite node to the shader. This is always done, if node is type of Candera::PointSprite. |
| u_Material.ambient | Vector4 | MaterialActivationEnabled | Candera::Material | Passes the ambient color component of the node's material (member of Appearance, see the section on material.) |
| u_Material.diffuse | Vector4 | MaterialActivationEnabled | Candera::Material | Passes the diffuse color component of the node's material (member of Appearance, see the section on material.) |
| u_Material.emissive | Vector4 | MaterialActivationEnabled | Candera::Material | Passes the emissive color component of the node's material (member of Appearance, see the section on material.) |
| u_Material.specular | Vector4 | MaterialActivationEnabled | Candera::Material | Passes the specular color component of the node's material (member of Appearance, see the section on material.) |
| u_Material.shininess | Float | MaterialActivationEnabled | Candera::Material | Passes the shininess of the node's material (member of Appearance, see the section on material.) |
| u_Texture[i] | Integer | TextureActivationEnabled | Candera::Texture, Candera::BitmapTextureImage, Candera::ProxyTextureImage | Passes the activated textures handle to the shader if the textures Candera::TextureImage is of type Candera::BitmapTextureImage or Candera::ProxyTextureImage(with TextureTargetType Texture2D). i can be from 1 to 7 or nothing (e.g u_Texture, u_Texture1,..). |
| u_CubeMapTexture[i] | Integer | TextureActivationEnabled | Candera::Texture, Candera::CubeMapTextureImage, Candera::ProxyTextureImage | Passes the activated textures handle to the shader if the textures Candera::TextureImage is of type Candera::CubeMapTextureImage or Candera::ProxyTextureImage(with TextureTargetType TextureCubeMap). i can be from 1 to 7 or nothing (e.g u_CubeMapTexture, u_CubeMapTexture1,..). |
| u_Light[i].type | Integer | LightActivationEnabled | Candera::Light | Passes an integer defining the type of light i to the shader, i can range from 0 to 7. |
| u_Light[i].ambient | Vector4 | LightActivationEnabled | Candera::Light | Passes the ambient color component of light i to the shader, i can range from 0 to 7. |
| u_Light[i].diffuse | Vector4 | LightActivationEnabled | Candera::Light | Passes the diffuse color component of light i to the shader, i can range from 0 to 7. |
| u_Light[i].intensity | float | LightActivationEnabled | Candera::Light | Passes the intensity factor applied to the diffuse color of light i to the shader, i can range from 0 to 7. Ignored if the light type is Ambient. |
| u_Light[i].specular | Vector4 | LightActivationEnabled | Candera::Light | Passes the specular color component of light i to the shader, i can range from 0 to 7. |
| u_Light[i].position | Vector4 | LightActivationEnabled | Candera::Light | Passes the position of a point or spotlight i to the shader, i can range from 0 to 7. |
| u_Light[i].direction | Vector3 | LightActivationEnabled | Candera::Light | Passes the direction vector of a directional or spotlight i to the shader, i can range from 0 to 7. |
| u_Light[i].halfplane | Vector3 | LightActivationEnabled | Candera::Light | Passes the halfplane vector of a directional, point or spotlight i to the shader, i can range from 0 to 7. |
| u_Light[i].attenuation | Vector4 | LightActivationEnabled | Candera::Light | Passes the attenuation weights of a point or spotlight i to the shader, i can range from 0 to 7. |
| u_Light[i].spotCosCutoff | Float | LightActivationEnabled | Candera::Light | Passes the cut off angle of a spotlight i to the shader, i can range from 0 to 7. |
| u_Light[i].spotExponent | Float | LightActivationEnabled | Candera::Light | Passes the spot exponent of a directional, point or spotlight i to the shader, i can range from 0 to 7. |
| u_Light[i].range | Float | LightActivationEnabled | Candera::Light | Passes the range of a point or spotlight i to the shader, i can range from 0 to 7. |
| u_Light[i].enabled | Bool | LightActivationEnabled | Candera::Light | Passes whether light i is enabled or not to the shader, i can range from 0 to 7. |
| u_Light[i].cameraLookAtVector | Vector3 | LightActivationEnabled | Candera::Light, Candera::Camera | Computes the look-at vector of the active Camera, and passes it to the shader. Depending on the Light::CoordinateSpace the look-at vector is either in world space or in the object space of the light. |
| u_MorphWeight | Float Array | - | Candera::MorphingMesh | Passes the weights of a Candera::MorphingMesh to the shader. This is always done, if node is type of Candera::MorphingMesh. |
| u_CanvasPivot | Vector2 | CanvasActivationEnabled | Candera::CanvasRenderable | Passes the position of the pivot of a Candera::CanvasRenderable to the shader. |
| u_CanvasSize | Vector2 | CanvasActivationEnabled | Candera::CanvasRenderable | Passes the actual size of a Candera::CanvasRenderable to the shader. |
| ub_Material | Uniform Buffer Object | MaterialActivationEnabled | Candera::Material | Passes all of the material parameters from above in a uniform buffer object to the shader. |
| ub_Lights | Uniform Buffer Object | LightActivationEnabled | Candera::Light, Candera::Camera | Passes all of the light parameters from above in a uniform buffer object to the shader. |
| u_JointMatrices | Matrix4 | SkinningMeshActivationEnable | Candera::SkinningMesh | Passes the Inverse Bind Matrix of a Joint to the shader. |
Attribute Names
Candera uses pre-defined attribute names to bind a vertex buffers attributes. When writing shader programs the following attribute names shall be used:
| Attribute Name | Semantic |
|---|---|
| PositionAttribute[i] | Use this attribute for passing vertex positions (local space). i ranges from 1 to 7 or is nothing (e.g. PositionAttribute, PositionAttribute1,...). |
| PositionTransformedAttribute[i] | Use this attribute for passing transformed vertex positions. i ranges from 1 to 7 or is nothing (e.g. PositionTransformedAttribute, PositionTransformedAttribute1,...). |
| NormalAttribute[i] | Use this attribute for passing the vertices normals. i ranges from 1 to 7 or is nothing (e.g. NormalAttribute, NormalAttribute1,...). |
| TextureCoordinateAttribute[i] | Use this attribute for passing the vertices texture coordinates. i ranges from 1 to 7 or is nothing (e.g. TextureCoordinateAttribute, TextureCoordinateAttribute1,...). |
| ColorAttribute[i] | Use this attribute for passing the vertices colors. i ranges from 1 to 7 or is nothing (e.g. ColorAttribute, ColorAttribute1,...). |
| BlendWeightAttribute[i] | Use this attribute for passing the vertices blend weight attributes. i ranges from 1 to 7 or is nothing (e.g. BlendWeightAttribute, BlendWeightAttribute1,...). |
| BlendIndexAttribute[i] | Use this attribute for passing the vertices blend index attributes. i ranges from 1 to 7 or is nothing (e.g. BlendIndexAttribute, BlendIndexAttribute1,...). |
| PointSizeAttribute[i] | Use this attribute for passing the vertices point sizes. i ranges from 1 to 7 or is nothing (e.g. PositionAttribute, PositionAttribute1,...). |
| TangentAttribute[i] | Use this attribute for passing the vertices tangents. i ranges from 1 to 7 or is nothing (e.g. TangentAttribute, TangentAttribute1,...). |
| BiNormalAttribute[i] | Use this attribute for passing the vertices binormals. i ranges from 1 to 7 or is nothing (e.g. BiNormalAttribute, BiNormalAttribute1,...). |
| TesselationFactorAttribute[i] | Use this attribute for passing the vertices tesselation factors. i ranges from 1 to 7 or is nothing (e.g. TesselationFactorAttribute, TesselationFactorAttribute1,...). |
| FogAttribute[i] | Use this attribute for passing the vertices fog attributes. i ranges from 1 to 7 or is nothing (e.g. FogAttribute, FogAttribute1,...). |
| DepthAttribute[i] | Use this attribute for passing the vertices depth attributes. i ranges from 1 to 7 or is nothing (e.g. DepthAttribute, DepthAttribute1,...). |
| SampleAttribute[i] | Use this attribute for passing the vertices sample attributes. i ranges from 1 to 7 or is nothing (e.g. SampleAttribute, SampleAttribute1,...). |
| CustomAttribute[i] | Use this attribute for passing your custom data per vertex. i ranges from 1 to 7 or is nothing (e.g. CustomAttribute, CustomAttribute1,...). |
Single Pass Effects
Single pass effects can be achieved in one camera pass only. They are simply realized with a single Candera::Appearance attached to a Candera::Node.
Examples for single pass effects can be found in the Special Render Techniques chapter.
Local Multi Pass Effects
Local multi pass effects describe effects with local impact only, thus, they belong to one certain node. They can be realized using Candera::MultiPassAppearance. These appearances are processed in a sequence; for each appearance the node is rendered once and the results are blended together using the different RenderMode settings.
Examples for local multi pass effects can be found in the Special Render Techniques chapter.
Global Multi Pass Effects
Global multi pass (also known as screen-based effects) typically operate on render targets, often they are also referred to as post-processing effects. To realize post-processing effects first images have to be rendered into an offscreen render target. How this is done is presented in Render Targets Tutorial.
The resulting image can further be processed in any desired way.
Examples for global multi pass effects can be found in chapter Special Render Techniques.
Creating Full Screen Effects
You can of course process the resulting texture on any mesh or object you like, but often post processing effects are applied to full screen images. For that purpose a dedicated scene with only a camera and a billboard can be used. The trick is to give the Billboard a size of 1.0 unit in both dimensions.
Billboard* fullScreenBB = Billboard::Create(1.0F, 1.0F);
This causes the billboard to have a vertex buffer with coordinates that match the corners of the window/screen in Canderas viewport space. To draw the billboard full screen you just need to use a vertex shader that doesn't transform the vertex coordinates, use ReferenceShaders\Core\RefViewportSpace.vertp for this purpose. The fragment shader then does the actual post processing. As texture for the billboard you need to use the image provided by the offscreen render target.
RefViewportSpace.vertp takes two float uniforms (u_offsetLeft, u_offsetTop) as inputs, which determine the top left corner of the billboard to render. These values are defined as being in normalized viewport space, where values range from 0.0 to 1.0, where 0.0 is interpreted as the left border respectively top border of the viewport, and 1.0 as the right, respectively bottom border.
The vertex position attribute of a vertex buffer used with this vertex shader is not transformed using a model-view-projection matrix, but simply translated into OpenGL's clip coordinate space with the specified offset applied.
The following examples demonstrate how to use the RefViewportSpace.vert shader in conjunction with the depth-of-field global multi pass effect.
Specify a full screen rectangle:
//Do Shader File I/O here and initialize m_dofCombineShader shader object. Float m_viewportLeft = 1.0F; Float m_vieportTop = 1.0F; m_dofCombineSps = GenericShaderParamSetter::Create(); m_dofCombineSps->SetModelViewProjectionMatrix4Enabled(false); m_dofCombineSps->SetUniform("u_offsetLeft", Shader::Float, &m_viewportLeft); m_dofCombineSps->SetUniform("u_offsetTop", Shader::Float, &m_viewportTop); m_fullScreenQuadDof = Billboard::Create(1.0f,1.0f); m_fullScreenQuadDof->GetAppearance()->SetShader(m_dofCombineShader); m_fullScreenQuadDof->GetAppearance()->SetShaderParamSetter(m_dofCombineSps);
This results in the following image:

Specify a centered rectangle with half viewport resolution:
//Do Shader File I/O here and initialize m_dofCombineShader shader object. Float m_viewportLeft = 0.25F; Float m_vieportTop = 0.25F; m_dofCombineSps = GenericShaderParamSetter::Create(); m_dofCombineSps->SetModelViewProjectionMatrix4Enabled(false); m_dofCombineSps->SetUniform("u_offsetLeft", Shader::Float, &m_viewportLeft); m_dofCombineSps->SetUniform("u_offsetTop", Shader::Float, &m_viewportTop); m_fullScreenQuadDof = Billboard::Create(0.5f,0.5f); m_fullScreenQuadDof->GetAppearance()->SetShader(m_dofCombineShader); m_fullScreenQuadDof->GetAppearance()->SetShaderParamSetter(m_dofCombineSps);
This results in the following image:

Specify a rectangle in bottom right corner with quarter viewport resolution:
//Do Shader File I/O here and initialize m_dofCombineShader shader object. Float m_viewportLeft = 0.75F; Float m_vieportTop = 0.75F; m_dofCombineSps = GenericShaderParamSetter::Create(); m_dofCombineSps->SetModelViewProjectionMatrix4Enabled(false); m_dofCombineSps->SetUniform("u_offsetLeft", Shader::Float, &m_viewportLeft); m_dofCombineSps->SetUniform("u_offsetTop", Shader::Float, &m_viewportTop); m_fullScreenQuadDof = Billboard::Create(0.25f,0.25f); m_fullScreenQuadDof->GetAppearance()->SetShader(m_dofCombineShader); m_fullScreenQuadDof->GetAppearance()->SetShaderParamSetter(m_dofCombineSps);
This results in the following image:

-
Overlapping Billboards (in screen space) would produce depth-fighting artifacts. Disabling depth test and using render order as well as using depth bias can be used to avoid them.
m_fullScreenQuadDof->GetAppearance()->SetRenderMode(RenderMode::Create()); m_fullScreenQuadDof->GetAppearance()->GetRenderMode()->SetDepthBias(0.1F);
For details on how to use render order please refer to Tutorial 3.