DefaultMaterial

The default material is the approach to centralize basic shader operations, like:

  • vertex transformation
  • displacement mapping
  • handling of multiple light sources
  • handling of different light types: directional, spot or point light
  • texture tiling
  • normal mapping
  • parallax occlusion mapping
  • various shading models: lambert, phong, blinn-phong, PBR
  • plane clipping
  • color clipping
  • color computation by ambient, diffuse, specular and emissive color
  • point sprite rendering (particle effects)
  • fog
  • shadowing: shadow mapping or variant shadow mapping
  • weighted blended order independent transparency
  • reflection, refraction and environment mapping

The simple reason is that those functionality is used in nearly all materials and should not be reinvented each time. Those operations also getting very complex in combination and its hard to keep them still efficient.

Node-Based Shaders

The default material uses a node based memory structure to build shader source code. This means that each shader (vertex- and fragmentshader) holds a nodes hierarchy from which the shader source code is generated from.

Source code getting build by a TGorillaNodeBuilder instance, which each shader provides. The attached nodes are TGorillaNodeEntity instances or inherited from that class. When the shader is getting compiled, the ToString() method is getting called for each node in hierarchy. Depending on the activated defines, the node itself decides how its output code looks like.

This is a very flexible way and allows to modify or replace specific nodes, to produce your own shader code.

On rendering, the source code will automatically be compiled and registered in GPU.

Default Vertex Shader

The default vertex shader is setting up the following node hierarchy.

Root
  * SourceCode [TGorillaCompositeNode]
    - <0> [TGorillaGLSLPragma]
    - Globals [TGorillaGlobalsNode]
      - Constants [TGorillaCompositeNode]
      - Types [TGorillaCompositeNode]
        - <0> [TGorillaGLSLLightType] // DEACTIVATED
        - <1> [TGorillaGLSLTextureType] // DEACTIVATED
        - <2> [TGorillaGLSLMaterialType] // DEACTIVATED
        - <3> [TGorillaGLSLPassDataType]
        - <4> [TGorillaGLSLVertexShaderLocalsStructNode]
      - Attributes [TGorillaCompositeNode]
        - <0> [TGorillaGLSLAttributesNode]
      - Uniforms [TGorillaUniformsNode]
        - <0> [TGorillaGLSLUBOShaderData]
      - Varying [TGorillaCompositeNode]
        - <0> [TGorillaGLSLInOutNode]
      - Functions [TGorillaCompositeNode]
        - <0> [TGorillaGLSLTransformFuncsNode]
        - <1> [TGorillaGLSLGetTextureFuncsNode]
        - <2> [TGorillaVertexShaderFuncNode]
      - Variables [TGorillaCompositeNode]
  -  EntryPoint [TGorillaGLSLMainNode]
    - <0> [TGorillaGLSLVertexShaderLocalsNode]
    - <1> [TGorillaGLSLMatricesOutNode]
    - <2> [TGorillaGLSLGetVertexPositionNode]
    - <3> [TGorillaGLSLDisplacementMappingGetNode]
    - <4> [TGorillaGLSLDisplacementMappingApplyNode]
    - <5> [TGorillaGLSLClippingPlaneGetNode]
    - <6> [TGorillaGLSLVertexShaderOutputNode]
    - <7> [TGorillaGLSLAdjustPointSizeNode]
    - SurfaceShader [TGorillaSurfaceShaderNode]
      - <0> [TGorillaGLSLVertexShaderExec]
      - <1> [TGorillaGLSLVertexPositionOutputNode]

Default Fragment Shader

The default fragment shader is setting up the following node hierarchy.

Root
  * SourcCode [TGorillaCompositeNode]
    - <0> [TGorillaGLSLPragma]
    - Globals [TGorillaGlobalsNode]
      - Constants [TGorillaCompositeNode]
      - Types [TGorillaCompositeNode]
        - <0> [TGorillaGLSLLightType]
        - <1> [TGorillaGLSLTextureType]
        - <2> [TGorillaGLSLMaterialType]
        - <3> [TGorillaGLSLPassDataType]
        - <4> [TGorillaGLSLFragmentShaderLocalsStructNode]
      - Attributes [TGorillaCompositeNode]
      - Uniforms [TGorillaUniformsNode]
        - <0> [TGorillaGLSLUBOShaderData]
      - Varying [TGorillaCompositeNode]
        - <0> [TGorillaGLSLInOutNode]
      - Functions [TGorillaCompositeNode]
        - <0> [TGorillaGLSLPackingFuncsNode]
        - <1> [TGorillaGLSLGetDirLightDirectionFuncNode]
        - <2> [TGorillaGLSLGetPointLightDirectionFuncNode]
        - <3> [TGorillaGLSLGetSpotLightDirectionFuncNode]
        - <4> [TGorillaGLSLGetLightDirectionFuncNode]
        - <5> [TGorillaGLSLGetSpotFalloffFuncNode]
        - <6> [TGorillaGLSLGetLightAttenuationFuncNode]
        - <7> [TGorillaGLSLGetShadingFuncsNode]
        - <8> [TGorillaGLSLGetTextureFuncsNode]
        - <9> [TGorillaGLSLGetTextureAtlasFuncNode]
        - <10> [TGorillaGLSLBasicShadowFuncsNode]
        - <11> [TGorillaGLSLFaketracingShadowFuncsNode] // DEPRECATED
        - <12> [TGorillaGLSLBumpFuncsNode]
        - <13> [TGorillaGLSLPOMFuncsNode]
        - <14> [TGorillaGLSLPBRFuncsNode]
        - <15> [TGorillaGLSLFogFuncNode]
        - <16> [TGorillaSurfaceShaderFuncNode]
      - Variables [TGorillaCompositeNode]
      - <0> [TGorillaGLSLLayoutLocation] (o_Albedo)
      - <1> [TGorillaGLSLLayoutLocation] (o_Alpha)
      - <2> [TGorillaGLSLLayoutLocation] (o_Position)
      - <3> [TGorillaGLSLLayoutLocation] (o_Normals)
      - <4> [TGorillaGLSLLayoutLocation] (o_Components) // DEFERRED_RENDERING ONLY
      - <5> [TGorillaGLSLLayoutLocation] (o_Ambient) // DEFERRED_RENDERING ONLY
      - <6> [TGorillaGLSLLayoutLocation] (o_Emissive) // DEFERRED_RENDERING ONLY
      - <7> [TGorillaGLSLLayoutLocation] (o_Specular) // DEFERRED_RENDERING ONLY
    - EntryPoint [TGorillaGLSLMainNode]
      - <0> [TGorillaGLSLClippingPlaneNode]
      - <1> [TGorillaGLSLMatricesOutNode]
      - <2> [TGorillaGLSLLightingLocalsNode]
      - <3> [TGorillaGLSLSpecularColorNode]
      - <4> [TGorillaGLSLGetTransfVertPosNode]
      - <5> [TGorillaGLSLGetNormalNode]
      - <6> [TGorillaGLSLGetFragViewDirNode]
      - <7> [TGorillaGLSLTextureCoordsNode]
      - <8> [TGorillaGLSLPOMApplyNode]
      - <9> [TGorillaGLSLGetBumpNormalNode]
      - <10> [TGorillaGLSLPBRPrepareNode]
      - <11> [TGorillaGLSLLightsLoopNode]
        - <0> [TGorillaGLSLGetLightShadingNode]
        - <1> [TGorillaGLSLLightingSumNode]
        - <2> [TGorillaGLSLAddShadowNode]
        - <2> [TGorillaGLSLAddFaketracingShadowNode] // DEPRECATED
      - <12> [TGorillaGLSLPBRAmbientNode]
      - SurfaceShader [TGorillaSurfaceShaderNode]
        - <0> [TGorillaGLSLGetBaseColorNode]
        - <1> [TGorillaGLSLSpecularMapNode]
        - <2> [TGorillaGLSLAddEnvironmentNode]
        - <3> [TGorillaGLSLAddSparseVoxelsNode]
        - <4> [TGorillaGLSLAddReflectionNode]
        - <5> [TGorillaGLSLAddRefractionNode]
        - <6> [TGorillaGLSLSurfaceShaderExec]
        - <7> [TGorillaGLSLMergedColorOutputNode]
        - <8> [TGorillaGLSLBrightnessColorNode]
        - <9> [TGorillaGLSLFragColorOutputNode]
        - <10> [TGorillaGLSLColorClipNode]
        - <11> [TGorillaGLSLFogApplyNode]
        - <12> [TGorillaGLSLWeightedBlendedOITNode]

Node Classes

Class Description
TGorillaNodeEntity The basic node class for all other node classes. The ToString() method returns a source code snippet. The result of all nodes will produce the final shader code.
TGorillaCompositeNode Is the basic node, which can hold sub-nodes and outputs those in the ToString() method
TGorillaUniformsNode Is the basic node for input variables, which is overwritten in the specific shader language
TGorillaGlobalsNode Is the storage point for global variables, constants, attributes, types, inputs, in/out variables and functions
TGorillaDeclarationNode Is the basic node for declaring types or functions
TGorillaTypeNode Is inherited from TGorillaDeclarationNode and represents a type declaration in shader source code
TGorillaStructTypeNode Is inherited from TGorillaTypeNode and represents a structured type declaration in shader source code
TGorillaVariableNode Is inherited from TGorillaDeclarationNode and represents a variable declaration in a type or as global / local.
TGorillaConstantNode Is a simple entity to declare a constant value
TGorillaOperationNode Allows to build mathmatical or logical expressions in node format.
TGorillaStatementNode Basic node to hold a number of operation nodes, which delimits the line on output, f.e. by a semicolon.
TGorillaReferenceNode A node instance with a reference to another node. This is used by syntax nodes to build mathmatical or logical expressions in node format.
TGorillaForLoopNode A node which will output a for-loop statement.
TGorillaSurfaceInputNode Structure type definition node used by the TGorillaSurfaceShaderNode as input parameter.
TGorillaSurfaceOutputNode Structured type definition node used by the TGorillaSurfaceShaderNode as output parameter.
TGorillaVertexShaderFuncNode Defines the empty void VertexShader(inout TLocals DATA){} function declaration for integrating DesignTime Shader functionality
TGorillaSurfaceShaderFuncNode Defines the empty void SurfaceShader(inout TLocals DATA){} function declaration for integrating DesignTime Shader functionality
TGorillaGLSLVertexShaderExec Node to call user specific vertex shader function for DesignTime functionality.
TGorillaGLSLSurfaceShaderExec Node to call user specific fragment shader function for DesignTime functionality.
TGorillaSurfaceShaderNode This node type is intended to be the entry point for user specific source code implementation.
TGorillaEntryPointNode Defines the shader source code entry point. On GLSL this is the main() function (the first function called, when a shader gets executed)

GLSL Node Classes

In the following we list the most common GLSL shader nodes. This should help to understand where you can manipulate or influence shader source code compilation.

Top-Level Nodes

At the top-level of a shader code tree either TGorillaGLSLVertexShader or TGorillaGLSLFragmentShader is attached to the node builder instance.

Class Description
TGorillaGLSLVertexShader The basic vertex shader node builder type
TGorillaGLSLFragmentShader The basic fragment shader node builder type

Second-Level Nodes

Attached to one of those nodes are the following container nodes:

Class Description
TGorillaGLSLPragma Pragma definition node, f.e. to define the GLSL version: #version 310 and float/int precisions.
TGorillaGlobalsNode Containing global declarations, f.e. for variables or functions.
TGorillaGLSLMainNode Containing the main function code for GLSL shaders.

TGorillaGlobalsNode (Globals)

A TGorillaGlobalsNode node automatically provides sub-containers for structuring, f.e. variables, types, functions, …

The following list is showing which node type should be inserted into which sub-container.

Sub-Container Class Description
Constants TGorillaGLSLConstant Create an instance of this class for your own constant declaration and insert it into the Constants sub-container.
- - -
Variables TGorillaGLSLVariable Create an instance of this class for your own global variable declaration and insert it into the Variables sub-container.
- - -
Types TGorillaGLSLStructType Extend this class for your own structure declaration and insert it into the Types sub-container.
Types TGorillaGLSLLightType Defines the internal light structure type. It is not recommend to change it.
Types TGorillaGLSLTextureType Defines the internal texture structure type. It is not recommend to change it.
Types TGorillaGLSLMaterialType Defines the internal material structure type. It is not recommend to change it.
Types TGorillaGLSLPassDataType Defines the internal pass variable structure type. It is not recommend to change it.
Types TGorillaGLSLVertexShaderLocalsStructNode Defines the TLOCALS structure with all pre-defined properties:
  • LOCALS.Position
  • LOCALS.TransfVertexPos
  • LOCALS.WorldViewProjVertPos
  • LOCALS.TexCoord0
  • LOCALS.Color0
  • LOCALS.Normal
  • LOCALS.Tangent
  • LOCALS.Binormal
  • LOCALS.Displace
  • LOCALS.ClippingPlane

Values inside of TLOCALS will be applied at the end of the shader to the varying parameters. It's recommended to modify those values instead of varying values directly (could be overwritten again).

Types TGorillaGLSLFragmentShaderLocalsStructNode Defines the TLOCALS structure with all pre-defined properties:
  • LOCALS.LightDir
  • LOCALS.LightVec
  • LOCALS.LightType
  • LOCALS.LightDist
  • LOCALS.Attenuation
  • LOCALS.SceneAttenuation
  • LOCALS.Ambient
  • LOCALS.Diffuse
  • LOCALS.Specular
  • LOCALS.Emissive
  • LOCALS.TexCoord0
  • LOCALS.TexCoord1
  • LOCALS.TexCoord2
  • LOCALS.TexCoord3
  • LOCALS.TransfVertPos
  • LOCALS.FragDepth
  • LOCALS.Normal
  • LOCALS.FragViewDir
  • LOCALS.SpecularColor
  • LOCALS.BaseColor
  • LOCALS.SumColor
  • LOCALS.Alpha
  • LOCALS.Shading
  • LOCALS.ShadowSum
  • LOCALS.BumpSum

Values inside of TLOCALS will be applied at the end of the shader to the fragment output. It's recommended to modify those values instead of output values directly (could be overwritten again). NOTICE: values getting filled up during computation and are not set at all times.

- - -
Uniforms TGorillaGLSLUBOShaderData Defines the internal uniform buffer object (v3) or variable declaration (v2).
Uniforms TGorillaGLSLUniformsNode Create an instance of this class, if you need additional input variables in your shader
- - -
Attributes TGorillaGLSLAttributesNode Holds the available vertex attributes. It is not recommend to change this node, if you are not sure if the additional attributes are provided by the mesh data.
  • a_Position
  • a_Normal
  • a_Tangent
  • a_Binormal
  • a_TexCoord0
  • a_TexCoord1
  • a_TexCoord2
  • a_TexCoord3
  • a_Color
  • a_Color1
  • a_Color2
  • a_Color3
- - -
Varying TGorillaGLSLInOutNode Holds the input/output variables (varying) used by each shader. On GLES v3+ everything is encapsulated in the INOUT structure accessable by: vars.* Available varying values are:
  • vars.v_VertPos
  • vars.v_TransfVertPos
  • vars.v_WorldViewProjVertPos
  • vars.v_TexCoord0
  • vars.v_Color0
  • vars.v_TBN
  • vars.v_TBN_UT
  • vars.v_ReflProjTextureCoords
  • vars.v_ClipDistance
  • (v_ViewDir deprecated)]
- - -
Functions TGorillaDeclarationNode Extend the declaration node for a user-specific function node and attach it to the Functions property of the Globals node.
Functions TGorillaGLSLTransformFuncsNode Provides functions for vertex transformation:
  • TransformModel()
  • TransformModelViewProjection()
  • TransformModelNormal()
Functions TGorillaGLSLPackingFuncsNode Provides function declarations for packaging / unpackaging:
  • Common_PackNormal()
  • Common_UnpackNormal()
  • Common_UnpackNormalLA()
Functions TGorillaGLSLGetDirLightDirectionFuncNode Providing function declarations for retrieving light direction depending on the supplied light type.
Functions TGorillaGLSLGetPointLightDirectionFuncNode Providing function declarations for retrieving light direction for point lights
Functions TGorillaGLSLGetSpotLightDirectionFuncNode Providing function declarations for retrieving light direction for spot lights
Functions TGorillaGLSLGetLightDirectionFuncNode Providing function declarations for retrieving light direction for directional lights
Functions TGorillaGLSLGetSpotFalloffFuncNode Providing function declarations for computing spot light fall off.
Functions TGorillaGLSLGetLightAttenuationFuncNode Providing function declarations for computing light attenuation depending on the light type.
Functions TGorillaGLSLGetShadingFuncsNode Providing function declarations for computing lambert, phong or blinn-phong shading .
Functions TGorillaGLSLGetTextureFuncsNode Provides function declarations for:
  • tex2D()
  • tex2DProj()
  • tex3D()
  • texCube()
  • Texture_GetNormal()
Functions TGorillaGLSLGetTextureAtlasFuncNode Providing function declarations for extracting specific frames from texture atlas.
Functions TGorillaGLSLBasicShadowFuncsNode Providing shadow computation functions for shadow mapping or variance shadow mapping depending on the material settings.
Functions TGorillaGLSLFaketracingShadowFuncsNode DEPRECATED: A bad approach for better shadow computation.
Functions TGorillaGLSLBumpFuncsNode Providing function declarations for bump mapping and normal mapping.
Functions TGorillaGLSLPOMFuncsNode Providing function declaration for parallax occlusion mapping functionality
Functions TGorillaGLSLPBRFuncsNode Providing function declaration for physically based rendering functionality.
Functions TGorillaGLSLFogFuncNode Provididing fog computation function declarations.
Functions TGorillaVertexShaderFuncNode By default it's providing an empty function: void VertexShader(inout TLocals DATA){} which can be filled up by users at designtime or runtime.
Functions TGorillaSurfaceShaderFuncNode By default it's providing an empty function: void SurfaceShader(inout TLocals DATA){} which can be filled up by users at designtime or runtime.
- - -
- TGorillaGLSLLayoutLocation Defines a layout location for render target output. This node is only available for modern OpenGL 4.3+ or OpenGLES 3.1+ syntax. In the default fragment shader the following layouts are automatically registered:
  • o_Albedo
  • o_Alpha
  • o_Position
  • o_Normals
  • o_Components (Deferred Rendering Only)
  • o_Ambient (Deferred Rendering Only)
  • o_Emissive (Deferred Rendering Only)
  • o_Specular (Deferred Rendering Only)

TGorillaGLSLMainNode (EntryPoint)

Vertex Shader

Class Description
- TGorillaGLSLVertexShaderLocalsNode Empty node. Variable declaration was moved to TGorillaGLSLVertexShaderLocalsStructNode.
- TGorillaGLSLMatricesOutNode DEPRECATED: Pushes all transformation matrices to varying parameters (OpenGLES v2):
  • v_ModelMatrix
  • v_ModelViewProjectionMatrix
  • v_ModelNormalMatrix
  • v_ViewMatrix
  • v_ProjectionMatrix
  • v_ShadowMatrix

. While in modern OpenGL (GLES v3.1+) everything is already stored in the uniform buffer.

- TGorillaGLSLGetVertexPositionNode Automatically sets the following LOCALS properties by attributes and uniforms: LOCALS.Position, LOCALS.ClippingPlane and LOCALS.Displace
- TGorillaGLSLDisplacementMappingGetNode Requests LOCALS.Displace value from _DisplacementMapTexture.
- TGorillaGLSLDisplacementMappingApplyNode Adds LOCALS.Displace to LOCALS.Position for vertex displacement.
- TGorillaGLSLClippingPlaneGetNode Sets the locals value for LOCALS.ClippingPlane.
- TGorillaGLSLVertexShaderOutputNode Automatically sets the following locals and varying parameters
  • LOCALS.Position
  • LOCALS.TransfVertexPos
  • LOCALS.WorldViewProjVertPos
  • LOCALS.TexCoord0
  • LOCALS.TexCoord1
  • LOCALS.TexCoord2
  • LOCALS.TexCoord3
  • LOCALS.Color0
  • LOCALS.Normal
  • LOCALS.Tangent
  • LOCALS.Binormal
  • LOCALS.Displace
  • LOCALS.ClippingPlane
  • vars.v_TBN
  • vars.v_TBN_UT
- TGorillaGLSLAdjustPointSizeNode Computes sprite distance and sets gl_PointSize value.
- TGorillaSurfaceShaderNode Sets up a container node SurfaceShader for surface computation, where further sub-nodes are attached to (TGorillaGLSLVertexShaderExec, TGorillaGLSLVertexPositionOutputNode).
- - -
SurfaceShader TGorillaGLSLVertexShaderExec Calls VertexShader(LOCALS);.
SurfaceShader TGorillaGLSLVertexPositionOutputNode Sets varying values from TLOCALS structure for:
  • vars.v_VertPos
  • vars.v_TransfVertPos
  • vars.v_WorldViewProjVertPos
  • vars.v_TexCoord0
  • vars.v_Color0
  • vars.v_ClipDistance
  • vars.v_TBN
  • vars.v_TBN_UT
  • gl_Position

Fragment Shader

Class Description
- TGorillaGLSLClippingPlaneNode If GORILLA_GLSL_DEFINE_CLIPPINGPLANE is activated, it checks if clipping plane is activated and discards the fragment in case of clipping.
- TGorillaGLSLMatricesOutNode Empty node and only compiled for vertex shader.
- TGorillaGLSLLightingLocalsNode Empty node. Source code was moved to TGorillaGLSLFragmentShaderLocalsStructNode.
- TGorillaGLSLSpecularColorNode If GORILLA_GLSL_DEFINE_USE_SPECULAR is activated, it sets LOCALS.SpecularColor from Material.Specular settings, otherwise the value is set to zero.
- TGorillaGLSLGetTransfVertPosNode Sets LOCALS.TransfVertPos from vars.v_TransfVertPos and LOCALS.FragDepth from gl_FragCoord.z
- TGorillaGLSLGetNormalNode If GORILLA_GLSL_DEFINE_BUMP is activated, it sets LOCALS.Normal from vars.v_TBN[2]
- TGorillaGLSLGetFragViewDirNode Computes LOCALS.FragViewDir from direction between camera position and transformed vertex position.
- TGorillaGLSLTextureCoordsNode If GORILLA_GLSL_DEFINE_USE_TEXTURE is activated, it sets LOCALS.TexCoord0 from vars.v_TexCoord0 and automatically applies tiling from first texture in material settings.
- TGorillaGLSLPOMApplyNode If GORILLA_GLSL_DEFINE_POM is activated, it computes LOCALS.TexCoord0 by ParallaxOcclusionMapping() function.
- TGorillaGLSLGetBumpNormalNode If GORILLA_GLSL_DEFINE_LIGHTING, GORILLA_GLSL_DEFINE_NORMALMAP and GORILLA_GLSL_DEFINE_BUMP are activated, it computes LOCALS.Normal by CalcBumpedNormal() function.
- TGorillaGLSLPBRPrepareNode If GORILLA_GLSL_DEFINE_LIGHTING and GORILLA_GLSL_DEFINE_PBR are activated, it prepares values for physically based rendering.
- TGorillaGLSLLightsLoopNode Sets up a loop for all available light sources inside of _Light[x]. Further node will be attached to it. Those subnodes will be executed for each light source.
LightsLoop TGorillaGLSLGetLightShadingNode If GORILLA_GLSL_DEFINE_LIGHTING is activated the node will compute shading depending on the shading model: lambert, phong, blinn-phong or PBR.
LightsLoop TGorillaGLSLLightingSumNode If GORILLA_GLSL_DEFINE_LIGHTING is activated the node will sum up lighting. If GORILLA_GLSL_DEFINE_PBR is activated it will output no code. If GORILLA_GLSL_DEFINE_USE_SPECULAR is activated, it will also apply specular lighting.
LightsLoop TGorillaGLSLAddShadowNode If GORILLA_GLSL_DEFINE_LIGHTING and GORILLA_GLSL_DEFINE_SHADOW are activated, it will calculate LOCALS.ShadowSum depending on the GORILLA_GLSL_DEFINE_SHADOW_SM or GORILLA_GLSL_DEFINE_SHADOW_VSM define.
LightsLoop TGorillaGLSLAddFaketracingShadowNode DEPRECATED: This node is deprecated and should not be used anymore.
- - -
- TGorillaGLSLPBRAmbientNode If GORILLA_GLSL_DEFINE_LIGHTING and GORILLA_GLSL_DEFINE_PBR are activated, it will set LOCALS.Ambient and LOCALS.Specular from albedo, AO and specular settings.
- TGorillaSurfaceShaderNode Is a container node for the final surface color computation.
SurfaceShader TGorillaGLSLGetBaseColorNode It will compute LOCALS.BaseColor and LOCALS.Alpha depending on GORILLA_GLSL_DEFINE_BUMP, GORILLA_GLSL_DEFINE_PBR, GORILLA_GLSL_DEFINE_USE_TEXTURE_ATLAS, GORILLA_GLSL_DEFINE_USE_POINTSPRITE, GORILLA_GLSL_DEFINE_LIGHTING , GORILLA_GLSL_DEFINE_USE_TEXTURE and GORILLA_GLSL_DEFINE_USE_VERTEXCOLOR defines. The node is way to complex to explain it's functionality here.
SurfaceShader TGorillaGLSLSpecularMapNode If GORILLA_GLSL_DEFINE_SPECULARMAP is activated, it computes LOCALS.SpecularColor from _SpecularMapTexture.
SurfaceShader TGorillaGLSLAddEnvironmentNode If GORILLA_GLSL_DEFINE_ENVIRONMENT is activated, it computes LOCALS.BaseColor and LOCALS.Ambient values from _EnvironmentTexture
SurfaceShader TGorillaGLSLAddReflectionNode If GORILLA_GLSL_DEFINE_REFLECTION is activated, it merges _ReflectionTexture with LOCALS.BaseColor.
SurfaceShader TGorillaGLSLAddRefractionNode If GORILLA_GLSL_DEFINE_REFRACTION is activated, it merges _RefractionTexture with LOCALS.BaseColor.
SurfaceShader TGorillaGLSLSurfaceShaderExec Calls SurfaceShader(LOCALS);
SurfaceShader TGorillaGLSLMergedColorOutputNode It will compute the final LOCALS.SumColor depending if GORILLA_GLSL_DEFINE_LIGHTING, GORILLA_GLSL_DEFINE_SPECULARMAP, GORILLA_GLSL_DEFINE_SHADOW or GORILLA_GLSL_DEFINE_PBR are activated.
SurfaceShader TGorillaGLSLBrightnessColorNode It will multiply _Brightness value with LOCALS.SumColor (since v0.8.4.2322)
SurfaceShader TGorillaGLSLFragColorOutputNode It will apply material alpha value to LOCALS.Alpha and finally write vec4(LOCALS.SumColor, LOCALS.Alpha) to o_Albedo render target.
SurfaceShader TGorillaGLSLColorClipNode If GORILLA_GLSL_DEFINE_USE_COLORCLIP is activated, it will discard the fragment if threshold was reached.
SurfaceShader TGorillaGLSLFogApplyNode It will compute fog value by calling computeFog() and modify the o_Albedo render target.
SurfaceShader TGorillaGLSLWeightedBlendedOITNode It will perform WBOIT value computation and sets all other render target outputs
  • o_Position
  • o_Normals
  • o_Alpha
  • o_Components (Deferred Rendering only)
  • o_Ambient (Deferred Rendering only)
  • o_Emissive (Deferred Rendering only)
  • o_Specular (Deferred Rendering only)

Using Defines

Not all nodes are enabled by default, so you have to unlock them by using the define management of the node builder. The following defines are provided in the default material:

Define Notice
GORILLA_GLSL_DEFINE_VERTEXSHADER Defines the specific nodebuilder as vertex shader source code
GORILLA_GLSL_DEFINE_FRAGMENTSHADER Defines the specific nodebuilder as fragment shader source code
GORILLA_GLSL_DEFINE_DEPTH Activates the depth map functionality. Nevertheless a depth render pass needs to be attached to the material
GORILLA_GLSL_DEFINE_DEFERRED NOT IMPLEMENTATED YET. DO NOT USE!
GORILLA_GLSL_DEFINE_SHADOW Activates shadow casting. The GORILLA_GLSL_DEFINE_DEPTH needs to be activated too.
GORILLA_GLSL_DEFINE_SHADOW_SM Activates simple shadow mapping. The GORILLA_GLSL_DEFINE_SHADOW needs to be activated too.
GORILLA_GLSL_DEFINE_SHADOW_VSM Activates variance shadow mapping. The GORILLA_GLSL_DEFINE_SHADOW needs to be activated too.
GORILLA_GLSL_DEFINE_SHADOW_FT DEPRECATED! DO NOT USE ANYMORE!
GORILLA_GLSL_DEFINE_REFLECTION Activates reflection handling.
GORILLA_GLSL_DEFINE_REFRACTION Activates refraction handling.
GORILLA_GLSL_DEFINE_ENVIRONMENT Activates enviroment mapping for reflection and refraction. Do not combine with GORILLA_GLSL_DEFINE_REFLECTION or GORILLA_GLSL_DEFINE_REFRACTION
GORILLA_GLSL_DEFINE_CLIPPINGPLANE Activates clipping plane handling.
GORILLA_GLSL_DEFINE_NORMALMAP Activates normal mapping functionality.
GORILLA_GLSL_DEFINE_BUMP Activates bump mapping functionality in combination with GORILLA_GLSL_DEFINE_NORMALMAP
GORILLA_GLSL_DEFINE_POM Activates parallax occlusion mapping computation
GORILLA_GLSL_DEFINE_POM_DISCARD Activates discarding edge fragments during parallax occlusion mapping. GORILLA_GLSL_DEFINE_POM needs to be activated.
GORILLA_GLSL_DEFINE_SPECULARMAP Allows to supply a specular texture for model specific specular color computation.
GORILLA_GLSL_DEFINE_DISPLACEMENT Enables the displacement mapping functionality in the vertex shader.
GORILLA_GLSL_DEFINE_LIGHTING Enables lighting computation with lambert, phong or blinnphong algorithm.
GORILLA_GLSL_DEFINE_PHONG Enables phong shading source code for the material
GORILLA_GLSL_DEFINE_BLINNPHONG Enables blinn-phong shading source code for the material
GORILLA_GLSL_DEFINE_PBR Enables physically based rendering source code for the material.
GORILLA_GLSL_DEFINE_PBR_TEXTURE0 Activates usage of _Texture0 in shader. If not activated, it expects LOCALS.BaseColor to be already set
GORILLA_GLSL_DEFINE_PBR_TEXTURES Enables usage of all PBR textures (Metalness, Roughness, AmbientOcclusion). Otherwise the bias values will be used *MetallicBias* and *RoughnessBias*
GORILLA_GLSL_DEFINE_USE_SPECULAR Enables specular light computation.
GORILLA_GLSL_DEFINE_USE_VERTEXCOLOR Enables to use the color of each vertex.
GORILLA_GLSL_DEFINE_USE_TEXTURE Enables general texture functionality (tex2D, tex2DProj, … methods)
GORILLA_GLSL_DEFINE_USE_TEXTURE0 Enables the Texture0 handling in the material
GORILLA_GLSL_DEFINE_USE_TEXTURE_ATLAS Declares texture atlas mapping functionality: GetTextureAtlasColor()
GORILLA_GLSL_DEFINE_USE_POINTSPRITE In combination with GORILLA_GLSL_DEFINE_USE_TEXTURE_ATLAS the Texture0 will be used as atlas and mapped onto each vertex point: GetTextureAtlasColor()
GORILLA_GLSL_DEFINE_PACKED_NORMAL Enables packed normals
GORILLA_GLSL_DEFINE_INOUTVARS Enables in/out variables for GLSLv3+
GORILLA_GLSL_DEFINE_VARYINGSTRUCTS Enables varying structs. This define manages backwards compatibility
GORILLA_GLSL_DEFINE_DEPRECATED DO NOT USE ANYMORE!
GORILLA_GLSL_DEFINE_INTEL Automatically set by the system, in case of an Intel graphics card.
GORILLA_GLSL_DEFINE_AMD Automatically set by the system, in case of an AMD graphics card.
GORILLA_GLSL_DEFINE_NVIDIA Automatically set by the system, in case of an NVidia graphics card.
GORILLA_GLSL_DEFINE_GEFORCE Automatically set by the system, in case of an GeForce graphics card.
GORILLA_GLSL_DEFINE_RADEON Automatically set by the system, in case of an Radeon graphics card.
GORILLA_GLSL_DEFINE_HDGRAPHICS Automatically set by the system, in case of an HDGraphics graphics card.

To enable a shader section call: AddDefine(GORILLA_GLSL_DEFINE_*)

To disable a shader section call: RemoveDefine(GORILLA_GLSL_DEFINE_*)

In most cases definitions need to be applied to vertex- and fragmentshader, because in both shaders functionality is available.

The DefaultMaterial defines the following sections by default:

Shader Defines
VertexShader GORILLA_GLSL_DEFINE_VERTEXSHADER, GORILLA_GLSL_DEFINE_CLIPPINGPLANE
FragmentShader GORILLA_GLSL_DEFINE_FRAGMENTSHADER, GORILLA_GLSL_DEFINE_CLIPPINGPLANE

Globals

As already mentioned in the sections above, the default shader declares attributes, types, constants and variables automatically.

Those entities can be used inside the shader and can of course be modified.

In the following we list the available presets.

Attributes

Each vertex provides further information besides the position of it.

But depending on the mesh data given, not all of those properties may be available.

Nevertheless the shader defines a fixed set of attributes, even if they are not filled by the mesh data.

Name Delphi-Type GLSL-Type
a_Position TPoint3D vec3
a_Normal TPoint3D vec3
a_Tangent TPoint3D vec3
a_Binormal TPoint3D vec3
a_TexCoord0 TPointF vec2
a_TexCoord1 TPointF vec2
a_TexCoord2 TPointF vec2
a_TexCoord3 TPointF vec2
a_Color TAlphaColorF vec4
a_Color1 TAlphaColorF vec4
a_Color2 TAlphaColorF vec4
a_Color3 TAlphaColorF vec4

Uniform Buffer

In the current implementation of the default material a uniform buffer is used to submit settings as block to the shaders. While in previous implementations each variable was submitted separately, it became very inefficient on the large number of settings.

The default material allows to register multiple uniform buffers, but by default only the TGorillaShaderData structure is registered.

Notice: Structures inside of Delphi need a fixed alignment to OpenGL's std140 layout. You might have recognized a few “Reserved” fields. Those are marking a memory alignment inside of the structure.

Read more about OpenGL memory alignment here: https://www.khronos.org/opengl/wiki/Interface_Block_(GLSL)

TGorillaShaderData

The TGorillaDefaultMaterial therefore registers a packed record as exchanging buffer.

Having a closer look at the structure below, it's showing further sub structures for lights, material, textures and render pass data. Those sub structures are automatically submitted to shaders too.

Notice: Modified since v1.1

  TGorillaShaderData = packed record
    /// <summary>
    /// Defines the multiplied model, view and projection matrix.
    /// </summary>
    ModelViewProjectionMatrix : TMatrix3D;
    /// <summary>
    /// Defines the view / camera matrix.
    /// </summary>
    ViewMatrix : TMatrix3D;
    /// <summary>
    /// Defines the projection matrix.
    /// </summary>
    ProjectionMatrix : TMatrix3D;
    /// <summary>
    /// Provides information about start, current, previous and delta time
    /// X - Starting time
    /// Y - Current time
    /// Z - Previous time
    /// W - Delta time
    /// </summary>
    TimeInfo : TVector3D;
    /// <summary>
    /// The absolute camera position.
    /// </summary>
    EyePos : TVector3D;
    /// <summary>
    /// The camera view direction.
    /// </summary>
    ViewDir : TPoint3D;
    /// <summary>
    /// Defines the used shading model: lambert (default), phong, blinnphong, pbr, ...
    /// </summary>
    ShadingModel : FixedInt; {TGorillaShadingModel}
    /// <summary>
    /// Defines material properties, like diffuse, specular, ambient, emissive
    /// color or information about uniform textures.
    /// </summary>
    Material : Array[0..0] of TGorillaShaderMaterial;
    /// <summary>
    /// Defines activated light sources with their properties.
    /// </summary>
    Lights : Array[0..GORILLA_MATERIAL_DEFAULT_LIGHTS-1] of TGorillaShaderLight;
    /// <summary>
    /// Defines the number of lights used in the fix-sized lights array above,
    /// beginning at 0.
    /// </summary>
    LightsCount : FixedInt;
    /// <summary>
    /// Shader specific options.
    /// </summary>
    Options : FixedInt;
 
    /// <summary>
    /// Defines how much shading is applied to diffuse and specular color.
    /// </summary>
    ShadingIntensity : Single;
    /// <summary>
    /// Defines the brightness factor applied to the diffuse color.
    /// </summary>
    Brightness : Single;
 
    /// <summary>
    /// FogMode contains information about the algorithm to be used and if
    /// fog is enabled or not.
    /// </summary>
    FogMode : FixedInt; // $01 enabled, $02 - linear, $04 - exp, $08 - exp2
    /// <summary>
    /// Defines the density of fog, used for exp and exp2 algorithm
    /// </summary>
    FogDensity : Single; // default = 0.001
    /// <summary>
    /// Defines the eye-vertex distance where fog begins.
    /// </summary>
    FogStart : Single; // default = 100.0
    /// <summary>
    /// Defines the eye-vertex distance where fog ends.
    /// </summary>
    FogEnd : Single; // default = 500.0
    /// <summary>
    /// Define the fog color used for computation.
    /// </summary>
    FogColor : TAlphaColorF; // default = vec4(0, 0, 0, 1);
 
    /// <summary>
    /// Provides the camera frustum bounding box top-left-near corner.
    /// </summary>
    FrustumMin : TVector3D;
    /// <summary>
    /// Provides the camera frustum bounding box bottom-right-far corner.
    /// </summary>
    FrustumMax : TVector3D;
    /// <summary>
    /// Provides the top-left-near corner of the scenery bounds.
    /// </summary>
    SceneMin : TVector3D;
    /// <summary>
    /// Provides the bottom-right-far corner of the scenery bounds.
    /// </summary>
    SceneMax : TVector3D;
    /// <summary>
    /// Provides the top-left-near corner of the scenery bounds.
    /// </summary>
    BoundaryMin : TVector3D;
    /// <summary>
    /// Provides the bottom-right-far corner of the scenery bounds.
    /// </summary>
    BoundaryMax : TVector3D;
 
    /// <summary>
    /// Current viewport rendering size and near / far limitation.
    /// </summary>
    /// <remarks>
    /// <para>
    /// X - viewport width
    /// </para>
    /// <para>
    /// Y - viewport height
    /// </para>
    /// <para>
    /// Z - camera frustum near
    /// </para>
    /// <para>
    /// W - camera frustum far
    /// </para>
    /// </remarks>
    ViewSize : TVector3D;
    /// <summary>
    /// You can define a single clipping plane for discarding fragments below.
    /// </summary>
    ClippingPlane : TVector3D;
 
    /// <summary>
    /// Defines some pass data information, f.e. for raytracing, reflection and refraction.
    /// </summary>
    PassData : Array[0..0] of TGorillaShaderPassData;
 
    class function Create() : TGorillaShaderData; static;
  end;

NOTICE: Properties in uniform structures need to be accessed in OpenGL shaders by prefixing those witth an underscore (“_”), even for sub-properties of sub-structures.

You can access a top-level property inside of TShaderData in OpenGL shader, like:

vars.v_Position *= _ModelMatrix;

TGorillaShaderMaterial

The material property inside of the TGorillaShaderData struct defines a sub structure.

Notice: Even the material is defined as array, there is only a single material structure available.

Material : Array[0..0] of TGorillaShaderMaterial;

And the Delphi implementation of this structure is represented by the following packed record.

  TGorillaShaderMaterial = packed record
    /// <summary>
    /// Emissive color value.
    /// </summary>
    Emissive : TAlphaColorF;
    /// <summary>
    /// Ambient color value.
    /// </summary>
    Ambient : TAlphaColorF;
    /// <summary>
    /// Diffuse color value.
    /// </summary>
    Diffuse : TAlphaColorF;
    /// <summary>
    /// Specular color value.
    /// </summary>
    Specular : TAlphaColorF;
    /// <summary>
    /// Clipping color value. R/G/B is the color value, A is the tolerance.
    /// </summary>
    Clipping : TAlphaColorF;
 
    /// <summary>
    /// Alpha cutoff value: (X > 0.01) == enabled, (Y == tolerated value)
    /// </summary>
    AlphaCutoff : TPointF;
    /// <summary>
    /// Tonemapping exposure value
    /// </summary>
    ToneMapExp  : Single;
    Reserve     : Single;
 
    /// <summary>
    /// Displacement factor to scale the influence of a displacement map.
    /// Default value is set to vec4(0.1, 0.1, 0.1, 1.0)
    /// </summary>
    /// <remarks>
    /// <para>
    /// (x, y, z) are the extension factors applied to the vertex normal.
    /// </para>
    /// <para>
    /// w - is the extension direction, while -1 means shrinking
    /// but +1 means model extrusion.
    /// </para>
    /// </remarks>
    Displacement : TVector3D;
 
    /// <summary>
    /// X - Current object opacity value.
    /// Y - reserved for future values
    /// Z - reserved for future values
    /// W - reserved for future values
    /// </summary>
    Features : TVector3D;
 
    /// <summary>
    /// Specular shining factor. If the value is <= 1.0, shading is deativated.
    /// </summary>
    Shininess : Single;
    /// <summary>
    /// Number of all textures
    /// </summary>
    Textures : FixedInt;
    /// <summary>
    /// The index of the first pool texture to find in texture settings:
    /// _Material[0]._Texture[_Material[0]._PoolTexturesOffset]
    /// </summary>
    PoolTexturesOffset : FixedInt;
    /// <summary>
    /// Number of total pool textures.
    /// </summary>
    PoolTextures : FixedInt;
 
    /// <summary>
    /// Fixed array of texture settings.
    /// </summary>
    Texture : TGorillaShaderTextures;
 
    class function Create() : TGorillaShaderMaterial; static;
  end;

You can access material settings in OpenGL shader, f.e. by:

LOCALS.Ambient = _Material[0]._Ambient;

TGorillaShaderTexture

Each material structure TGorillaShaderMaterial supports a set of max. 16 texture structures.

// type TGorillaShaderTextures = Array[0..GORILLA_SHADER_TEXTURES_MAX - 1] of TGorillaShaderTexture;
Texture : TGorillaShaderTextures;

This allows to texture specific settings like transition values (for terrain material) or tile settings.

  TGorillaShaderTexture = packed record
    /// <summary>
    /// for terrain textures we need information about height and transition
    /// between textures - those we put inside of a vec4
    /// MinHeight, MaxHeight, LowTransition, HighTransition : Single
    /// </summary>
    Feature : TVector3D;
    /// <summary>
    /// Texture repeating value
    /// </summary>
    Tiling : TPointF;
  {$IFDEF GL_ES_VERSION_3_0}
    /// <summary>
    /// Due to memory alignment in gpu - we have to adjust memory here by
    /// some dummy bytes.
    /// </summary>
    Reserved1   : Array[0..7] of Byte;
  {$ENDIF}
  end;

You can access those settings in OpenGL shader, like:

LOCALS.Tiling.xy = _Material[0]._Texture[0]._Tiling.xy;

TGorillaShaderLight

The default material supports multiple light sources, which are submitted inside the TGorillaShaderData uniform structure as array of TGorillaShaderLight structure.

Lights : Array[0..GORILLA_MATERIAL_DEFAULT_LIGHTS-1] of TGorillaShaderLight;

The size of that array is platform dependent.

While on Windows platforms it is limited to 32, on Android it is limited to max. 8 lights.

  TGorillaShaderLight = packed record
    LightType   : FixedInt; {TLightType}
  {$IFDEF GL_ES_VERSION_3_0}
    // due to memory alignment in gpu - we have to adjust
    Reserved1   : Array[0..11] of Byte;
  {$ENDIF}
    Position    : TVector3D;
    Direction   : TVector3D;
    Ambient     : TAlphaColorF;
    Diffuse     : TAlphaColorF;
    Specular    : TAlphaColorF;
 
    /// <summary>
    /// Light-Scattering settings are compressed into a single vec4 value, with
    /// the following structure:
    /// x=intensity, y=exposure, z=decay, w=density
    /// </summary>
    Scattering : TVector3D;    
 
    SpotCutoff    : Single;
    SpotCosCutoff : Single;
    SpotExponent  : Single;
 
    ConstantAttenuation  : Single;
    LinearAttenuation    : Single;
    QuadraticAttenuation : Single;
 
    Intensity : Single;
    Enabled   : FixedInt;
 
    constructor Create(ALight : TLightDescription);
  end;

You can access light settings in OpenGL shader, like:

LOCALS.BaseColor = _Light[0]._Diffuse;

TGorillaShaderPassData

In case you have run a render pass like reflections in a previous stage, some additional settings might be needed, like ReflectTextureMatrix or ReflectionPower.

So the PassData structure was introduced to group those settings in one place. Even if it is defined as an array, there is only a single pass data structure available.

PassData : Array[0..0] of TGorillaShaderPassData;

For more compressed data and less memory size, we merged various settings into this single structure. It might seem to be a little bit messed up, but it reduces memory usage in general.

Notice: We might refactor this structure in future, due to this confusing setup.

  TGorillaShaderPassData = packed record
    ShadowMapMatrix : Array[0..7] of TMatrix3D;
 
    ReflectTextureMatrix : TMatrix3D;
    RefractTextureMatrix : TMatrix3D;
 
    ReflectionPower : Single;
    RefractionPower : Single;
 
    TranslucentDistance : Single;
    /// <summary>
    /// A factor that is applied on the normal vector in
    /// bump mapping / normal mapping / parallax occlusion mapping.
    /// </summary>
    NormalIntensity : Single;
    /// <summary>
    /// Define the number raytracing levels during parallax occlusion mapping.
    /// Allowed values are between 4 and 256.
    /// More levels meaning less performance due to more intense gpu usage.
    /// </summary>
    ParallaxLevels : FixedInt;
 
    /// <summary>
    /// Metallic value for controlling metalness of physically based rendering output.
    /// </summary>
    PBRMetallic : Single;
    /// <summary>
    /// Roughness value for controlling noise computation of physically based rendering output.
    /// </summary>
    PBRRoughness : Single;
    /// <summary>
    /// Ambient occlusion value for controlling ambient intensity of physically based rendering output.
    /// </summary>
    PBRAO : Single;
  end;

The PassData can be access in OpenGL shader like:

LOCALS.BaseColor.xyz *= _PassData[0]._ReflectionPower;

Varying values

We will not go into detail about shader stages. For further reading, please have a look at: https://www.khronos.org/opengl/wiki/Rendering_Pipeline_Overview.

But simply said, the vertex shader is computed at first and already modifies vertex position or precomputes some values, we might use in our final fragment shader.

To supply those data, we need some kind of an exchange structure. This is called varying parameter, which is represented in GLSL by the _ _ INOUT _ _ struct, accessable by the “vars.” prefix.

Because the size of this structure is limited, we can only support a restricted number of properties.

It is not recommended to extend this structure, because exceeding those limits, might have unexpected effects!

The following list shows which properties are already defined:

Name Delphi-Type GLSL-Type Description
vars.v_VertPos TVector3D vec4 untransformed vertex position
vars.v_TransfVertPos TPoint3D vec3 transformed vertex position
vars.v_WorldVertPos TVector3D vec4 MVP transformed vertex position
vars.v_TBN TMatrix mat3 Array of three vectors for tangent, binormal and normal transformed by the model matrix.
vars.v_TBN_UT TMatrix mat3 Array of three vectors for tangent, binormal and normal untransformed (UT).
vars.v_TexCoord0 TPointF vec2 vertex texture coordinate for first texture
vars.v_Color0 TAlphaColorF vec4 first vertex color information (may be black if not provided)
vars.v_ReflProjTextureCoords TVector3D vec4 when reflection is active, these are the transformed coordinates for reflection texture
vars.v_RefrProjTextureCoords TVector3D vec4 when refraction is active, these are the transformed coordinates for refraction texture

Default Textures

Name GLSL-Type Description
_DisplacementMapTexture VertexShader sampler2D If GORILLA_GLSL_DEFINE_DISPLACEMENT is activated.
_Texture0 FragmentShader sampler2D / samplerCube / sampler3D (depending on the material used) If GORILLA_GLSL_DEFINE_USE_TEXTURE is activated.
_NormalMapTexture FragmentShader sampler2D If GORILLA_GLSL_DEFINE_NORMALMAP is activated.
_SpecularMapTexture FragmentShader sampler2D If GORILLA_GLSL_DEFINE_USE_SPECULAR is activated.
_EmissiveTexture FragmentShader sampler2D If GORILLA_GLSL_DEFINE_USE_EMISSIVE is activated.
_DepthTexture FragmentShader sampler2D If GORILLA_GLSL_DEFINE_DEPTH is activated.
_EnvironmentTexture FragmentShader samplerCube If GORILLA_GLSL_DEFINE_ENVIRONMENT is activated.
_ReflectionTexture FragmentShader sampler2D If GORILLA_GLSL_DEFINE_REFLECTION is activated.
_RefractionTexture FragmentShader sampler2D If GORILLA_GLSL_DEFINE_REFRACTION is activated.

Render Targets

The default material is using a multiple render target approach in fragment shaders.

This means it outputs values to multiple destination buffers.

Render Target Defines Description
o_Albedo - o_Albedo = LOCALS.SumColor
o_Alpha - o_Alpha = LOCALS.Alpha
o_Position - o_Position = vec4(LOCALS.TransfVertPos.xyz, LOCALS.FragDepth)
o_Normals - o_Normals = LOCALS.Normal.xyz
o_Components GORILLA_GLSL_DEFINE_DEFERRED o_Components = vec4(TexCoord0.xy, 1.0, 1.0)
o_Ambient GORILLA_GLSL_DEFINE_DEFERRED o_Ambient = LOCALS.Ambient.xyz
o_Emissive GORILLA_GLSL_DEFINE_DEFERRED o_Emissive = LOCALS.Emissive.xyz
o_Specular GORILLA_GLSL_DEFINE_DEFERRED o_Specular = LOCALS.Specular.xyz

Properties

Default material component provides a few easy-to-use properties for automatic defines settings. By using the following properties in your default material, you can setup the necessary defines, your shaders need for computation.

PropertyDescription
UseLighting Enable or disable lighting shading model computation in shader
UseTexturing Enable or disable texturing functionality (using tex2D and tex2DProj in shader)
UseTexture0 Enable or disable “_Texture0” uniform variable and accessing Texture property.
UseVertexColor Enable or disable to use vertex color rendering.
constructor TMyMaterial.Create(const ASource : TGorillaDefaultMaterialSource);
begin
  inherited;
 
  UseTexturing := true;
  UseTexture0 := true;
  UseLighting := true;
  UseVertexColor := false;
end;

NOTICE: Deactivating “UseTexture0” will remove “Texture” property availability! You can no longer use a Texture0 in your shader. Deactivate this property if you just want to use the diffuse color as base color.

Material Behaviours

Since v1.1 (Rev. 2724) we provide the material behaviour functionality.

Material Behaviours are a way to encapsulate shader functionality into building blocks. These building blocks can then be reused across multiple TGorillaDefaultMaterialSource components. This makes it easy to keep your shaders organized and maintainable.

NOTICE: Material behaviours are not compatible with embedded Firemonkey material sources, like TLightMaterialSource or TColorMaterialSourcce!

Apply a single material behaviour to multiple material sources, but the place to edit parameters of your behaviour stay centralized. This makes it very easy to manage complex shading behaviour.

Read more about Material Behaviour

Extending the default material

Here is a quick example for extending the default material to setup your own shader material to create a vertex color material.

Gorilla.Material.VertexColor.pas
unit Gorilla.Material.VertexColor;
 
interface
 
uses
  System.SysUtils,
  System.Classes,
  FMX.Types,
  FMX.Types3D,
  FMX.Materials,
  FMX.MaterialSources,
  Gorilla.Material.Default;
 
type
  TGorillaVertexColorMaterial = class(TGorillaDefaultMaterial)
    protected
      procedure DoCreateVertexShader(); override;
      procedure DoCreateFragmentShader(); override;
 
    public
  end;
 
  TGorillaVertexColorMaterialSource = class(TGorillaDefaultMaterialSource)
    protected
      function CreateMaterial() : TMaterial; override;
 
    public
  end;
 
implementation
 
uses
  Gorilla.Material.Default.GLSL;
 
{ TGorillaVertexColorMaterial }
 
procedure TGorillaVertexColorMaterial.DoCreateVertexShader();
begin
  inherited;
 
  VertexShaderNode.AddDefine(GORILLA_GLSL_DEFINE_USE_COLOR);
  VertexShaderNode.RemoveDefine(GORILLA_GLSL_DEFINE_USE_TEXTURE);
end;
 
procedure TGorillaVertexColorMaterial.DoCreateFragmentShader();
begin
  inherited;
 
  FragmentShaderNode.AddDefine(GORILLA_GLSL_DEFINE_USE_COLOR);
  FragmentShaderNode.RemoveDefine(GORILLA_GLSL_DEFINE_USE_TEXTURE);
end;
 
{ TGorillaVertexColorMaterialSource }
 
function TGorillaVertexColorMaterialSource.CreateMaterial() : TMaterial;
begin
  Result := TGorillaVertexColorMaterial.Create(Self);
end;
 
end.

Register a user-specific UniformBuffer

The default material allows to register more than one uniform buffer in shaders.

To create a new user-specific uniform buffer, you will need a representation of that structure in your default material class.

Notice: Structures inside of Delphi need a fixed alignment to OpenGL's std140 layout. Read more about OpenGL memory alignment here: https://www.khronos.org/opengl/wiki/Interface_Block_(GLSL)

At first we define a packed record structure inside of Delphi.

  PMyParams = ^TMyParams;
  TMyParams = packed record
    MyValue : Single;
    Reserved0 : Array[0..2] of Single; // taking care of memory alignment in TVector3D blocks.
 
    Point : TPoint3D;
    Reserved1 : Single; // taking care of memory alignment in TVector3D blocks.
  end;

The example above shows a structure declaration with memory alignment (Reserved0 + Reserved1). It should help to understand, how OpenGL aligns memory in std140 layout.

But in this exact case, we can optimize the record!

Because MyValue and Point fields fit into a single 4 * 4 Byte memory block of std140 alignment.

  PMyParams = ^TMyParams;
  TMyParams = packed record    
    Point : TPoint3D;
    MyValue : Single;
  end;

In GLSL the structure will appear as:

layout (binding=1, std140) uniform MyParams{
  vec3 _Point;
  float _MyValue;
};

In the next step, create a field inside of your material to store TMyParams.

TMyMaterial = class(TGorillaDefaultMaterial)
    protected
      FMyParams : TMyParams;
 
      /// override the update shader uniform buffers method to register our record in GPU.
      procedure DoUpdateShaderUniformBuffers(const Context: TContext3D;
        AProgram : TShaderProgram); override;
end;

And prepare values for shader:

constructor TMyMaterial.Create(const ASource : TGorillaDefaultMaterialSource);
begin
  inherited Create(ASource);
 
  FMyParams.MyValue := 0.25;
  FMyParams.Point := Point3D(1, -10, -1);
end;

Afterwards we implement our register function:

procedure TMyMaterial.DoUpdateShaderUniformBuffers(const Context: TContext3D;
  AProgram : TShaderProgram);
begin
  if not Assigned(AProgram) then
    Exit;
 
  inherited;
 
  /// let's register it in GPU shader.
  AProgram.RegisterUniformBuffer('MyParams', @FMyParams, SizeOf(FMyParams));
end;

In case we have dynamic values and need to modify the record values, we can use the DoApply() method. Because the memory is directly linked to the GPU, we can simply modify any value in our record and it will automatically be updated in shader.

procedure TGorillaWaterMaterial.DoApply(const Context: TContext3D);
begin
  inherited;
 
  FMyParams.MyValue := Random(100) / 100;
end;

Register a texture variable

Registering textures in shader is a little but different, but quite easy.

Because the default material manages a pool of textures, we only have to add a texture to it, and the component will do the rest for us.

Working further with our TMyMaterial, we need also a TMyMaterialSource to overwrite the protected DoCreateDefaultBitmaps() method.

type
  TMyMaterialSource = class(TGorillaMaterialSource)
    protected
      procedure DoCreateDefaultBitmaps(); override;
  end;
 
[...]
 
procedure TMyMaterialSource.DoCreateDefaultBitmaps();
var LEntry: TGorillaBitmapPoolEntry;
begin  
  ///
  /// adding new textures before calling "inherited"
  ///
  LEntry := DoAddOrUpdateBitmapToPool("MYTEXTURE0",
    TPixelFormatEx.RGBA8, TPixelFormatEx.RGBA, GORILLA_DEFAULT_TEXTURE_DATATYPE,
    false, true, true);
 
  /// in case you need to, modify the wrapping and filtering settings
  if Assigned(LEntry) then
    LEntry.SetExtendedProperties(
      TGorillaTextureWrap.Repeated, TGorillaTextureWrap.Repeated, TGorillaTextureWrap.Repeated,
      TTextureFilter.Linear, TTextureFilter.Linear);
 
  inherited;
 
  ///
  /// modifying default (existing) textures after calling "inherited".
  ///
  LEntry := Self.FindBitmapEntryByName(GORILLA_MATERIAL_TEXTURE_NORMALMAP);
  if Assigned(LEntry) then
    LEntry.SetExtendedProperties(
      TGorillaTextureWrap.Repeated, TGorillaTextureWrap.Repeated, TGorillaTextureWrap.Repeated,
      TTextureFilter.Linear, TTextureFilter.Linear);
end;

Register a single variable

To add individual variables to the shaders you need to override the shader setup method.

Warning: This way adds a single variable to the shader and does not modify the uniform buffer!

Warning: Do not use this way to register texture variables! (Read more about in the section above.)

Shader Function
VertexShader DoSetupVertexShader();
FragmentShader DoSetupFragmentShader();

Then simply use the AddVariables() routine of the shader source:

Shader Function
VertexShader FVSShaderSource.AddVariables([]);
FragmentShader FFSShaderSource.AddVariables([]);

Because variables need an incrementing index on registration, you need to supply the shader source specific variable:

Shader Field
VertexShader FVSVarIndex
FragmentShader FFSVarIndex

Here is a short example:

procedure TGorillaMyMaterial.DoSetupFragmentShader();
begin
  inherited;
 
  // use the fragment shader source to add a new variable
  FFSShaderSource.AddVariables(
    [
    TContextShaderVariable.Create('MyPointF',
      TContextShaderVariableKind.Float2, FFSVarIndex, 0)
    ]);
 
  inc(FFSVarIndex, 1);
end;

Declare the variable in GLSL source code

In the next step you need to add a new uniforms node in the specific shader. To access the node builder in the material, use one of the following variables:

Shader Field
VertexShader VertexShaderNode
FragmentShader FragmentShaderNode

We add the new uniform node in the global uniform section of the node-tree to ensure, that is available anywhere in the code.

Take care to declare the variable name with the prefix “_”!

(Due to Firemonkey framework all uniform variables are declared by a leading underscore.)

procedure TGorillaMyMaterial.DoCreateFragmentShader();
var LUniform : TGorillaGLSLUniformsNode;
begin
  inherited;
 
  LUniform := TGorillaGLSLUniformsNode.Create(FragmentShaderNode);
  LUniform.AddDeclaration('_MyPointF', TGorillaShaderNodeVariableType.stVec2);
  FragmentShaderNode.Globals.Uniforms.Add(LUniform);
end;

You are allowed to add more than one variable in the uniforms node. There is no need to declare a single node for each variable.

Adding individual functions

To include a user specific function in shader source code, you need to declare a new node class inherited from TGorillaDeclarationNode. Then simply override the ToString() method and return your function declaration in shader language format.

In the DoCreateVertexShader() or DoCreateFragmentShader() function you create an instance of your declared node type and add it to the global function section of the node builder.

type
  TGorillaGLSLGetTextureColorFuncNode = class(TGorillaDeclarationNode)
    protected
    public
      function ToString() : String; override;
  end;
 
function TGorillaGLSLGetTextureColorFuncNode.ToString() : String;
begin
  Result := 'vec4 GetTextureColor(in sampler2D p_Texture, in vec2 p_TexCoord0){'#13#10 +
    '  return texture2D(p_Texture, p_TexCoord0);'#13#10 +
    '}'#13#10;
end;  
 
procedure TGorillaMyMaterial.DoCreateFragmentShader();
var LNode   : TGorillaNodeEntity;
begin
  // FragmentShaderNode is the fragment shader node builder
  LNode := TGorillaGLSLGetTextureColorFuncNode.Create(FragmentShaderNode);
  FragmentShaderNode.Globals.Functions.Add(LNode);
end;

Calling an individual functions

After we've declared our user specific function, we want to call it in the shader. For that we need a new node. Here the basic class TGorillaNodeEntity is quite perfect for the job.

Afterwards we have to attach the node to the node-builder again. The insert point depends on the job to do, of course.

In our example we've written a function that returns the current texture color. This is called base-color. The default shader declares a local variable “LOCALS.BaseColor” for that. If we set this, it will automatically be used in the color-light-summary.

The entry point for this node operation is the surface-shader node in the fragment shader: “FragmentShaderNode.SurfaceShader”.

Caution: The problem here is, that there is already a node (TGorillaGLSLGetBaseColorNode) that computes the “LOCALS.BaseColor” value. So we need to replace it with our node. But we have to ensure the correct position in node hierarchy for a valid shader code output.

type
  TGorillaGLSLCallGetTextureColorNode = class(TGorillaNodeEntity)
    protected
    public
      function ToString() : String; override;
  end;
 
function TGorillaGLSLCallGetTextureColorNode.ToString() : String;
begin
  Result := 'LOCALS.BaseColor = GetTextureColor(_Texture0, l_TexCoord0);'#13#10;
end;
 
procedure TGorillaMyMaterial.DoCreateFragmentShader();
var LNode   : TGorillaNodeEntity;
    LOldIdx : Integer;
begin
  [...]
 
  LNode := TGorillaGLSLCallGetTextureColorNode.Create(FragmentShaderNode);
 
  /// replace base color request
  LOldIdx := FragmentShaderNode.SurfaceShader.IndexOf(TGorillaGLSLGetBaseColorNode, '');
  if (LOldIdx > -1) then
  begin
    /// remove old basecolor node
    FragmentShaderNode.SurfaceShader.Delete(LOldIdx);
    FragmentShaderNode.SurfaceShader.Insert(LOldIdx, LNode);
  end
  else FragmentShaderNode.SurfaceShader.Insert(0, LNode);
end;

Changing Shaders at DesignTime

Since 0.8.4 it's possible to modify your default shader at designtime, by using published properties *VertexShader* or *SurfaceShader*.

Simply select your default material source, go to object inspector and open the text editor of the property. An empty GLSL function should be visible depending on the shader used.

For VertexShader:

void VertexShader(inout TLocals DATA){
 
}

For SurfaceShader (Fragment/Pixel-Shader):

void SurfaceShader(inout TLocals DATA){
 
}

You can then modify or extend the shader functionality. Please have a look a the section Shader-Variables for the available fields in TLocals structure.

NOTICE: Modifying the vertex position in vertex-shader all 3 fields “DATA.Position”, “DATA.TransfVertexPos” and “DATA.WorldViewProjVertPos” need to be modified. Otherwise their basis might not be equal which leads to unexpected effects!

In the following example we've created a wobbling effect in the vertex shader:

vec2 DELPHI_HASH2(vec2 n){ 
    return fract(sin(n)*1399763.5453123);
}
 
float DELPHI_NOISE(vec2 st){
    vec2 i = floor(st);
    vec2 f = fract(st);
 
    vec2 u = f * f * (3.0 - 2.0 * f);
 
    float a = dot(DELPHI_HASH2(i + vec2(0.0,0.0)), f - vec2(0.0, 0.0));
    float b = dot(DELPHI_HASH2(i + vec2(1.0,0.0)), f - vec2(1.0, 0.0));
    float c = dot(DELPHI_HASH2(i + vec2(0.0,1.0)), f - vec2(0.0, 1.0));
    float d = dot(DELPHI_HASH2(i + vec2(1.0,1.0)), f - vec2(1.0, 1.0));
 
    return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
}
 
vec3 DELPHI_WOBBLE(vec3 pos, float time, float intensity){
    return vec3(pos.x, pos.y + (DELPHI_NOISE(vec2(pos.x, pos.z) + time) * intensity), pos.z);
}
 
void VertexShader(inout TLocals DATA){
  DATA.Position.xyz = DELPHI_WOBBLE(DATA.Position.xyz, _TimeInfo.y, 0.5);
 
  DATA.TransfVertexPos = a_ModelMatrix * DATA.Position;
  DATA.WorldViewProjVertPos = _ModelViewProjectionMatrix * DATA.Position;
}

Another example of a fragment shader to render an animated spritesheet with 3 x 3 rows and columns in a texture. The DefaultMaterial property “MeasureTime” needs to be set to TRUE.

Add a spritesheet texture to the material in the “Texture” property.

The shader discards fragments with a low alpha value for transparency. If you set <TControl3D>.Opaque to false, the alpha channel will be used for transparency, otherwise discarding a fragment is the correct way.

void SurfaceShader(inout TLocals DATA){
    float SPRITE_COLUMNS = 3.0;
    float SPRITE_ROWS = 3.0;
    uint NUM_OF_SPRITES = 9;
 
    float t = _TimeInfo.y;
 
    uint sprite_idx = int(abs(sin(t) * (NUM_OF_SPRITES - 1))) % NUM_OF_SPRITES;
    vec2 pos = vec2(sprite_idx % int(SPRITE_COLUMNS), int(sprite_idx / SPRITE_COLUMNS));
 
    DATA.BaseColor = tex2D(_Texture0, vec2((DATA.TexCoord0.x / SPRITE_COLUMNS) + pos.x * (1.0 / SPRITE_COLUMNS),
        (DATA.TexCoord0.y / SPRITE_ROWS) + pos.y * (1.0 / SPRITE_ROWS)));
    DATA.Alpha = DATA.BaseColor.a;
 
    if(DATA.Alpha < 0.04) discard;
}

Read more about TLocals structure in VertexShader/SurfaceShader in section TGorillaGlobalsNode at TGorillaGLSLVertexShaderLocalsStructNode and TGorillaGLSLFragmentShaderLocalsStructNode.

To modify the “SurfaceShader” or “VertexShader” property at runtime, you have to work with a temporary TStrings component. Otherwise the shader code is not getting updated after modifying the user-code:

procedure TForm1.SetMyShaderCode();
var LStr : TStringList;
begin
  /// Create a temporary stringlist component for our source code
  LStr := TStringList.Create();
  try
    LStr.Text :=
      'void SurfaceShader(inout TLocals DATA){'#13#10 +
      /// make everything green
      '  DATA.BaseColor.xyz = vec3(0.0, 1.0, 0.0);'#13#10 +
      '}';
 
    // Apply the temporary stringlist to the material
    // This will assign it to the internal stringlist and update the shader code
    // automatically.
    GorillaLambertMaterialSource1.SurfaceShader := LStr;
  finally
    FreeAndNil(LStr);
  end;
end;

Adding new Textures at DesignTime

Besides the possibility of adding textures by code at runtime, you can also add new textures at designtime.

Move inside the object inspector to the specific material source (inherited from TGorillaDefaultMaterialSource).

Steps:

  • Open the design editor of the “Bitmaps” property
  • Add a new item
  • Input a name for the texture
  • Choose where the texture will be available: PixelShader or VertexShader

NOTICE: The name will be important to access the texture in your shader!

Due to Firemonkey implementation, you will access your texture with the prefix “_”. So for example, if you name your texture “MyTexture”, you will access it by “_MyTexture”.

When you choose the shader your texture will be available, you can access it also at design time in the corresponding property:

ShaderKindProperty
PixelShader<TGorillaDefaultMaterialSource>.SurfaceShader
VertexShader<TGorillaDefaultMaterialSource>.VertexShader

In the collection item you can configure further properties of your texture and you can of course load the image data itself.

NOTICE: Not all of the properties are fully restorable at runtime, because there are some automatisms which can't be overwritten by Gorilla3D. Use the “ProtectFormatSettings” property to at least try to protect those properties from implicit modification.

WARNING: When adding new texture always add them at the end of the collection, to not intercept default textures.

Availabled Properties

PropertyDescr
BitmapImage data loadable from BMP, PNG or JPEG
BorderColorDefines a texture border color.
DataTypeDefines the data type of the internal texture format. See OpenGL specification for further information.
FormatDefines the general texture format. See OpenGL specification for further information.
IgnoreInArrayInternally arrays of textures are used for specific topics (shadows), where the name of the texture becomes obsolete.
InternalFormatDefines the internal texture format. See OpenGL specification for further information.
IsDynamicThe texture will automatically retrieve its image data from a renderpass or other dynamic source. It's not recommended to use this with user specific textures.
MagFilterDefines the magnification texture filtering in combination with the MinFilter property.
MinFilterDefines the minification texture filtering in combination with the MagFilter property.
NameA name for the texture will always be needed! Access the texture in shaders with the prefix “_”
ProtoectFormatSettingsTRUE/FALSE to protect the texture from implicit modification on re-init during runtime.
ShaderKindDefines where the texture will be available. In PixelShader or VertexShader.
TextureKindKind of the texture: 2D, 3D, CubeMap, 2DArray (recommened: only 2D)
TilingXTiling of the texture on x-axis (2D)
TilingYTiling of the texture on y-axis (2D)
WrapRTexture wrapping on R-axis (for 3D textures)
WrapSTexture wrapping on S-axis
WrapTTexture wrapping on T-axis