DefaultMaterial

The default material is the approach to centralize basic shader operations like vertex transformation, multiple light computation, shadow casting, normal mapping and much more.

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 number of nodes (in tree structure) to compile their source code from.

Source code is built by a TGorillaNodeBuilder instance, which each shader provides. The attached nodes are TGorillaNodeEntity instances or inherited from that class.

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

Node Classes

Class Description
TGorillaNodeEntity The basic node class for all other node classes. The ToString() method returns 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.
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

We will list in the following the most important GLSL shader nodes, to understand where you can manipulate or influence shader source code compilation.

Class Description
TGorillaGLSLVertexShader The basic vertex shader node builder type
TGorillaGLSLFragmentShader The basic fragment shader node builder type
TGorillaGLSLPragma Pragma definition node, f.e. to define the GLSL version: #version 330
TGorillaGLSLConstant Extends TGorillaConstantNode for GLSL compatibility
TGorillaGLSLVariable Extends TGorillaVariableNode for GLSL compatibility
TGorillaGLSLStructType Extends TGorillaStructTypeNode for GLSL compatibility
TGorillaGLSLLightType Defines the internal light structure type. It is not recommend to change it
TGorillaGLSLTextureType Defines the internal texture structure type. It is not recommend to change it
TGorillaGLSLMaterialType Defines the internal material structure type. It is not recommend to change it
TGorillaGLSLPassDataType Defines the internal pass variable structure type. It is not recommend to change it
TGorillaGLSLUBOShaderData Defines the internal uniform buffer object (v3) or variable declaration (v2).
TGorillaGLSLUniformsNode Create this node, if you need additional input variables in your shader
TGorillaGLSLLocalsNode Holds the local variables defined at the beginning of the main() function
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
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: v_VertPos, v_WorldVertPos, v_Normal, v_TexCoord0, v_Color0, v_EyeVertPos [, v_ReflProjTextureCoords, v_RefrProjTextureCoords]
TGorillaGLSLTextureUniformNode You don't have to instanciate this type of node, simply use DoAddBitmapToPool() function provided by the material class. Internal available texture uniforms: _Texture0, _NormalMapTexture, _SpecularMapTexture, _DepthTexture, _DisplacementMapTexture, _ReflectionTexture, _RefractionTexture (Depending on the activated definitions in the node builder.
TGorillaGLSLForLoopNode Extends TGorillaForLoopNode for GLSL compatibility
TGorillaGLSLLightingLocalsNode Declares the local variables for lighting computation: l_Ambient, l_Diffuse, l_Specular By iterating all light source these values will be filled and representing light information only.
TGorillaGLSLSpecularColorNode Node to set local specular color variable (l_SpecularColor)
TGorillaGLSLTextureCoordsNode Node to set local texture coordinate variable (l_TexCoord0). It will automatically apply tiling information.
TGorillaGLSLGetBaseColorNode Node to set local base color and base alpha value (l_BaseColor, l_Alpha)
TGorillaGLSLMergedColorOutputNode Node to merge all color variables together to the local variable (l_SumColor)
TGorillaGLSLVertexPositionOutputNode Node to set vertex shader output (gl_Position) by the local transformed position variable (l_Position)
TGorillaGLSLFragColorOutputNode Node to merge summarized color (l_SumColor) and alpha value (l_Alpha) and set fragment shader output color (gl_FragColor)

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_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 Activates faketracing shadow casting. The GORILLA_GLSL_DEFINE_SHADOW needs to be activated too.
GORILLA_GLSL_DEFINE_REFLECTION Activates reflection handling.
GORILLA_GLSL_DEFINE_REFRACTION Activates refraction handling.
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_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_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.
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.
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 Enables OpenGL es v2 support. This define manages backwards compatibility
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

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.

Adding individual input variables

Register the variable in firemonkey

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

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 declared our user specific function, we want to call it in the shader. For that we do again need a new node type. Here the easiest 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 “l_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 “l_BaseColor” value. So we need to remove it and insert ours at this point, to ensure the correct order of operations.

type
  TGorillaGLSLCallGetTextureColorNode = class(TGorillaNodeEntity)
    protected
    public
      function ToString() : String; override;
  end;
 
function TGorillaGLSLCallGetTextureColorNode.ToString() : String;
begin
  Result := 'l_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;

Globally available variables

Attributes

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

Only available in GLES v3!

Name Delphi-Type GLSL-Type Description
_ModelViewMatrix TMatrix3D mat4 model matrix with translation, scaling and rotation
_ModelViewProjectionMatrix TMatrix3D mat4 model * view * projection multiplied matrix
_ModelNormalMatrix TMatrix3D mat4 inverse transposed model * view multiplied matrix
_ViewMatrix TMatrix3D mat4 view / camera matrix
_ProjectionMatrix TMatrix3D mat4 projection matrix
_ShadowMatrix TMatrix3D mat4 shadow mapping matrix
_TimeInfo TVector3D vec4 x = starting time, y = current time, z = previous time, w = delta time
_ViewDir TPoint3D vec3 camera view direction
_ShadingModel FixedInt int used shading model: 0 = lambert, 1 = phong, 2 = blinnphong
_Material[0] TGorillaShaderMaterial struct Material material values
_Lights[x] Array of TGorillaShaderLight struct Lights[…] light values
_LightsCount FixedInt int number of available lights in lights-array
_BoundaryMin TVector3D vec4 3D minimum corner of scene bounds
_BoundaryMax TVector3D vec4 3D maximum corner of scene bounds
_ViewSize TVector3D vec4 viewport resolution (X, Y) and near / far values (Z, W)
_PassData[0] TGorillaShaderPassData struct PassData pass information values

Varying values in fragment shader

GLES v3
Name Delphi-Type GLSL-Type Description
vars.v_VertPos TVector3D vec4 untransformed vertex position
vars.v_WorldVertPos TVector3D vec4 MVP transformed vertex position
vars.v_Normal TPoint3D vec3 vertex normal vector
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_EyeVertPos TVector3D vec4 modelmatrix transformed vertex position (in translation, scaling and rotation)
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
GLES v2

When compiled for GLES v2, due to compatibility, more varying values are provided:

Name Delphi-Type GLSL-Type Description
v_VertPos TVector3D vec4 untransformed vertex position
v_WorldVertPos TVector3D vec4 MVP transformed vertex position
v_Normal TPoint3D vec3 vertex normal vector
v_TexCoord0 TPointF vec2 vertex texture coordinate for first texture
v_Color0 TAlphaColorF vec4 first vertex color information (may be black if not provided)
v_EyeVertPos TVector3D vec4 model view space transformed vertex position
v_ReflProjTextureCoords TVector3D vec4 when reflection is active, these are the transformed coordinates for reflection texture
v_RefrProjTextureCoords TVector3D vec4 when refraction is active, these are the transformed coordinates for refraction texture
v_ModelViewMatrix TMatrix3D mat4 model * view multiplied matrix
v_ModelViewProjectionMatrix TMatrix3D mat4 model * view * projection multiplied matrix
v_ModelNormalMatrix TMatrix3D mat4 inverse transposed model * view multiplied matrix
v_ViewMatrix TMatrix3D mat4 view matrix
v_ProjectionMatrix TMatrix3D mat4 projection matrix
v_ShadowMatrix TMatrix3D mat4 when shadows are activated this will contain the shadow map transformation matrix
v_ViewDir TPoint3D vec3 view direction vector
v_ViewSize TVector3D vec4 viewport resolution (X, Y) and near / far values (Z, W)

Available Textures

Name GLSL-Type Description
_Texture0 sampler2D If GORILLA_GLSL_DEFINE_USE_TEXTURE is activated.
_NormalMapTexture sampler2D If GORILLA_GLSL_DEFINE_NORMALMAP is activated.
_SpecularMapTexture sampler2D If GORILLA_GLSL_DEFINE_USE_SPECULAR is activated.
_DepthTexture sampler2D If GORILLA_GLSL_DEFINE_DEPTH is activated.
_DisplacementMapTexture sampler2D If GORILLA_GLSL_DEFINE_DISPLACEMENT is activated.
_ReflectionTexture sampler2D If GORILLA_GLSL_DEFINE_REFLECTION is activated.
_RefractionTexture sampler2D If GORILLA_GLSL_DEFINE_REFRACTION is activated.
_GeometryTexture0, _GeometryTexture1, _GeometryTexture2, _GeometryTexture3, _GeometryTexture4, _GeometryTexture5 sampler3D If GORILLA_GLSL_DEFINE_RAYTRACING is activated

Shader Locals

VertexShader
Name Type Shader Description
l_Position vec4 VS MVP transformed vertex position
l_Displace vec3 VS Raw disposition value from displacement map. Use TGorillaGLSLDisplacementMappingGetNode and TGorillaGLSLDisplacementMappingApplyNode to manipulate displacement
FragmentShader
Name Type Shader Description
l_Ambient vec3 FS Ambient light color (only in lights loop)
l_Diffuse vec3 FS Diffuse light color (only in lights loop)
l_Specular vec3 FS Specular light color (only in lights loop)
l_SpecularColor vec3 FS Specular material color (from texture or computed)
l_TexCoord0 vec2 FS transformed and tiled first texture coordinate
l_Tiling0 vec2 FS Tiling information for texture 0.
l_Shading vec2 FS Multiple light combined value
l_LightDir vec4 FS Direction of light (only in lights loop)
l_LightVec vec3 FS Light vector (only in lights loop)
l_LightType int FS Type of light (point, direction or spot light) (only in lights loop)
l_LightDist float FS Distance to light source (only in lights loop)
l_Attenuation float FS Computed light attenuation (only in lights loop)
l_BumpSum vec2 FS Bump-Mapping for each light source
l_BaseColor vec4 FS Diffuse texture color / vertex color / computed color
l_Alpha float FS Final alpha output value - combine with l_SumColor
l_SumColor vec3 FS Final RGB output value - combine with l_Alpha

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;