#############################
Writing Custom Render Shaders
#############################

.. toctree::
    :maxdepth: 1
    :titlesonly:
    :hidden:

    bk_bm_wcr/bk_bm_custom_custom_gpu
    bk_bm_wcr/bk_bm_custom_custom_cpu
    bk_bm_wcr/bk_bm_custom_custom_debug


In addition to the built-in render shaders, HOOPS Luminate allows to completely customize your effects by hand made shader programming.

***********************
Shader Target Selection
***********************

The RED engine is a multi-pass rendering engine. Therefore, a vertex / pixel shader pair may be executed many times for the rendering of a single frame. A simple rendering example with the RED engine uses at least the following workflow as described here: :doc:`/book/subjects/bk_bm/bk_bm_the_shading_pipeline`

    * Pre-lighting pass
    * Lighting passes (1 pass for each active light in the scene)
    * Post-lighting pass

A shader is registered and added to one or many passes in this list. Then inside each pass, a shader may use multiple rendering configurations. We call a 'shader target' the scope of a shader item (variables, programs, binding configuration). Below is the list of valid shader targets for each possible rendering pass. Passes are defined by the ``RED::MATERIAL_PASS`` enumeration.

*Pre-Lighting or Post-Lighting Passes*
======================================

Shader items rendered for these passes have only one single possible shader target:

.. code:: cpp 

    RED_SHAD_TARGET_LIGHT_NO_LIGHT               // Target a not-a-light rendering pass


All parameters, programs, binding information, must use this flag as shader target. Any other target value will cause the faulty item to be ignored during the rendering. This specific target is often referred as the ``RED_L0``.

*Lighting Passes*
=================

Shader items rendered for these passes must specify at least one of the following shader targets:

.. code:: cpp

    RED_SHAD_TARGET_LIGHT_DIRECTIONAL            // Parameter will be available for directional lights only
    RED_SHAD_TARGET_LIGHT_BEAM                   // Parameter will be available for beam lights only
    RED_SHAD_TARGET_LIGHT_POINT                  // Parameter will be available for point lights only
    RED_SHAD_TARGET_LIGHT_AREA                   // Parameter will be available for area lights only
    RED_SHAD_TARGET_LIGHT_POINT_SPOT             // Parameter will be available for point spot lights only
    RED_SHAD_TARGET_LIGHT_AREA_SPOT              // Parameter will be available for area spot lights only


For example, the vertex and pixel shader programs used for a directional light are usually not the same as the programs used for a point light, simply because the lighting calculations differ.

*Ray-Tracer Passes*
===================

Shader items rendered for the ray-tracer must specify at least one of the following shader targets:

.. code:: cpp
        
    RED_SHAD_TARGET_REFLECTION_VECTOR            // Used for the definition of the first ray bounce reflection direction
    RED_SHAD_TARGET_REFRACTION_VECTOR            // Used for the definition of the first ray bounce refraction direction
    RED_SHAD_TARGET_INDIRECT_REFLECTION_VECTOR   // Used for the definition of the second+ ray bounce reflection direction
    RED_SHAD_TARGET_INDIRECT_REFRACTION_VECTOR   // Used for the definition of the second+ ray bounce refraction direction
    RED_SHAD_TARGET_REFLECTION_CUTOFF            // Used for the definition of the first ray bounce reflection cutoff threshold
    RED_SHAD_TARGET_INDIRECT_REFLECTION_CUTOFF   // Used for the definition of the second+ ray bounce reflection cutoff threshold
    RED_SHAD_TARGET_REFRACTION_CUTOFF            // Used for the definition of the first ray bounce refraction cutoff threshold
    RED_SHAD_TARGET_INDIRECT_REFRACTION_CUTOFF   // Used for the definition of the second+ ray bounce refraction cutoff threshold
    RED_SHAD_TARGET_GI_DIFFUSE_COLOR             // Used for the definition of the GI diffusion property of the material
    RED_SHAD_TARGET_GI_REFLECTION_COLOR          // Used for the definition of the GI reflectivity property of the material
    RED_SHAD_TARGET_GI_TRANSMISSION_COLOR        // Used for the definition of the GI transmission property of the material
    RED_SHAD_TARGET_GI_NORMAL                    // Used for the definition of the GI surface normal of the material

These targets are all used within the ``RED::MTL_RAYTRACE`` pass of a material.

****************************************
From Geometry Data to Rendering Programs
****************************************

In this section, we will see how to define the data to be transferred from the mesh geometry to the vertex shader using the ``RED::RenderCode`` class.

A ``RED::RenderShader`` class needs the following minimal set of parameters to work:

    * A vertex shader program (``RED::RenderShader::SetVertexProgramId``)
    * A pixel shader program (``RED::RenderShader::SetPixelProgramId``)
    * A ``RED::RenderCode`` (``RED::RenderShader::SetRenderCode``)

The ``RED::RenderCode`` performs the association between mesh data channels and vertex shader channels. Vertex shaders have 16 generic input attributes that can be used. Meshes have 16 generic channels that can store various data.

.. figure:: bk_bm_custom_custom_geom_01.png
    :align: center
    
    **The RED::RenderCode swizzles mesh channels to setup the vertex shader**

A mesh data channel may be replicated using the ``RED::RenderCode`` at the vertex shader's entrance. A mesh data channel may although be ignored if it's not needed for the shader in the rendered configuration. But a valid ``RED::RenderCode`` is mandatory to fill the shader's inputs.

The ``RED::RenderCode::BindChannel`` function gives the ability to define which mesh channel will be connected to the shader inputs. Two enumerations are generally used to define the mesh channels and vertex inputs: ``RED::MESH_CHANNEL`` and ``RED_VSH_INPUT``.

Note that the RED engine uses the generic naming for all vertex shader input attributes. Therefore, a vertex shader must use the vertex.attrib syntax defined by the ARB vertex program extension. It can't use the vertex.position, vertex.texcoord syntax, as the engine provides generic inputs, and does not use any conventional input channel name.

The ``RED::RenderCode`` object exposes several other options like sending the model or the view matrix to the shader using the functions ``RED::RenderCode::SetModelMatrix`` and ``RED::RenderCode::SetViewMatrix``, or to normalize a channel (``RED::RenderCode::SetNormalizedChannel``).

*****************
Shader Parameters
*****************

Shader parameters are inserted in the rendering workflow as detailed on the figure below:

.. figure:: bk_bm_custom_custom_param_01.png
    :align: center
    
    **View of the full shader pipeline**

*Values*
========

The ``RED::RenderShaderParameter`` class enumerates all possible values that can be made available to a shader program:

    * ``RED::Vector`` (4 floats)
    * ``RED::Color`` (RGBA, 4 floats)
    * ``RED::Matrix`` (4x4 homogeneous matrices, floats)
    * Image (2D, composite, cube)

These values are bound by the specification of three items:

    * The shader program targeted by the parameter: vertex or pixel
    * The name of the parameter: a ``RED::String`` that identify the parameter for later searches from the shader API
    * The binding position of the parameter

The binding position is understood in a way that is specific for each kind of parameter:

    * ``RED::Vector``: Number of the program.local constant that receive the vector
    * ``RED::Color``: Number of the program.local constant that receive the color
    * ``RED::Matrix``: Numbers of the program.local constants that receive the matrix. 4 consecutive constants are used at the specified binding position. If we bind at the 4th constant, the parameter will use program.local[4, 5, 6, 7]. A matrix is bound using the line major convention: e.g. program.local[4] matches the first matrix row in our example
    * Image: Texture channel bound to the texture. We've at least 16 texture channels available

*References*
============

References are HOOPS Luminate specific shader parameters whose values are automatically computed by the engine based on the current rendering pass. Refer to the ``RED::RenderShaderParameter::TYPE`` enumeration for a list of all possible references.

If we consider for example a shader using the dimensions of the viewport, then if we use this shader in two different windows, the shader will be called twice, each time with the corresponding viewport parameters. The same applies for all lights parameters: if we have more than one light in a scene, then all positions, directions, textures, colors of the light change during each lighting pass, hence the need for references. References are specified within the ``RED::RenderShaderParameter``, indicating the enumerated value for the corresponding wished reference. 

.. note:: 
    
    A reference uses one of the possible values of a shader parameter: a reference may be a ``RED::Color``, a ``RED::Vector``, an image (``RED::Object``), a ``RED::Matrix``.


*Camera Level Parameters*
=========================

Sometimes, defining global parameters that are common to all materials in the context of a scene graph can be very useful. HOOPS Luminate provides such a mechanism by defining camera shader parameters.

The ``RED::IViewpoint::AddRenderShaderParameter`` is used to define shader parameters at the camera level. It defines global parameters for all the render shaders contained in the viewpoint scene graph.

The two shader parameter functions ``RED::RenderShaderParameter::SetCameraParameterValue`` and ``RED::RenderShaderParameter::GetCameraParameterValue`` could then be called to define which global parameter must be used by the shader in the scene graph during the rendering phase. The shader parameter stores the reference to the camera parameter, it is of type ``RED::RenderShaderParameter::REF_CAMERA_PARAMETER``.

.. figure:: API_CameraLevelParameters.png
    :align: center
    
    **The camera level parameters model**

Each camera in the scene has a parameter storing a color: yellow for the first camera, blue for the second camera. During the rendering of each camera scene graph, the geometry shading will look for the referenced parameter in the list of parameters available from the camera.

.. include:: /tasks/ta_ca/ta_ca_material/tk_adding_shader_parameter.rst
