Skip to main content

Custom Shader for 2D Effects on 3D Devices

2D Effects on 3D devices are realized by usage of shader in the RenderDevice2D for implementation of 2D over 3D.
Several times, available effects just for this device have been enhanced (see "Open GL" Effects).

For more flexibility and the option, to write custom 2D effects with a custom shader, the API has been enhanced:

  • It is possible to provide a custom shader source from an effect implementation
  • It is also possible to transfer uniforms (definition and value) from an effect implementation

The API is:

Candera::Internal::Context2DOver3DDevicePool::SetCustomProgram
Candera::Internal::Context2DOver3DDevicePool::ResetCustomProgram
Candera::Internal::Context2DOver3DDevicePool::HasCustomProgram

The API is internal and shall only be used by experienced users!

Furthermore, the RenderDevice2D API has been enhanced to set a second surface (texture).

A new effect, GlMultiTextureBrushBlend, has been added with the purpose to demonstrate the usage of the new API.

This effect uses the following shader code in its implementation:

static const Char* s_vertexShader = {
    "#ifndef GL_ES\n"
    "#define lowp\n"
    "#define mediump\n"
    "#define highp\n"
    "#define precision\n"
    "#endif\n"
    "precision highp float;\n"

    "attribute vec4 a_Position;\n"
    "attribute vec4 a_TextureCoordinate;\n"

    "uniform mat4 u_Transform;\n"
    "uniform mat4 u_TexTransform;\n"

    "varying vec2 v_TexCoord;\n"

    "void main(void)                                               \n"
    "{\n"
    "   gl_Position = a_Position * u_Transform;                    \n"
    "   v_TexCoord.xy = (a_TextureCoordinate * u_TexTransform).xy; \n"
    "}\n"
};

static const Char* s_fragmentShader = {
    "#ifndef GL_ES\n"
    "#define lowp\n"
    "#define mediump\n"
    "#define highp\n"
    "#define precision\n"
    "#endif\n"
    "precision highp float;\n"

    "uniform sampler2D u_Texture;\n"
    "uniform sampler2D u_Texture2;\n"
    "uniform vec4 u_ConstTexColor;\n"
    "uniform float u_TexturesBlendFactor;\n"

    "varying vec2 v_TexCoord;\n"

    "void main(void)\n"
    "{                                                                                      \n"
    "    vec4 color = u_ConstTexColor;                                                      \n"
    "    vec4 texCol = texture2D(u_Texture, v_TexCoord) * u_TexturesBlendFactor;            \n"
    "    vec4 texCol2 = texture2D(u_Texture2, v_TexCoord) * (1.0F - u_TexturesBlendFactor); \n"
    "    gl_FragColor = color * (texCol + texCol2);                                         \n"
    "}\n"
};

The shader code here is written for OpenGL ES 2.0 on purpose! The sample effect shall run also on devices supporting only this version.

The core functionality inside the GlMultiTextureBrushBlend::Render method:

static_cast<void>(ActivateSecondaryImage(output));

Internal::Context2DOver3DDevicePool& pool = Internal::Context2DOver3DDevicePool::GetInstance();
FeatStd::Internal::Guid guid("8D86313D-47B2-49BD-89C3-DBD24E23A5A1");

Float texturesBlendFactor = m_texturesBlendFactor.Get();
texturesBlendFactor = (texturesBlendFactor < 0.0F) ? 0.0F : texturesBlendFactor;
texturesBlendFactor = (texturesBlendFactor > 1.0F) ? 1.0F : texturesBlendFactor;

Internal::Context2DOver3DDevicePool::CustomUniform customUniforms[1] = {
	{ Internal::Context2DOver3DDeviceProgram::FloatUniform, "u_TexturesBlendFactor", texturesBlendFactor }
};

pool.SetCustomProgram(s_vertexShader, s_fragmentShader, customUniforms, 1, guid);

m_bitmapBrush.Render(input, inputArea, transform, node, output, outputArea);
if (pool.HasCustomProgram()) {
	pool.ResetCustomProgram();
}

success = DeactivateSecondaryImage(output) && success;

Parameters for the shader are provided as uniforms. For the user, the parameters are exposed as Effect properties!