Module shader

Module shader 

Source
Expand description

Shader is a script for graphics card, it defines how to draw an object. It also defines a set of external resources needed for the rendering.

§Structure

Shader has rigid structure that could be described in this code snipped:

(
	name: "MyShader",

    // A set of resources, the maximum amount of resources is limited by your GPU. The engine
    // guarantees, that there could at least 16 textures and 16 resource groups per shader.
    resources: [
        (
            // Each resource binding must have a name.
            name: "diffuseTexture",

            // Value has limited set of possible variants.
            kind: Texture(kind: Sampler2D, fallback: White),

            binding: 0
        ),
		(
            name: "properties",
            kind: PropertyGroup([
                (
                    name: "diffuseColor",
                    kind: Color(r: 255, g: 255, b: 255, a: 255),
                ),
            ]),
            binding: 0
        ),
        // The following property groups are built-in and provides useful data for each shader.
        (
            name: "fyrox_instanceData",
            kind: PropertyGroup([
                // Autogenerated
            ]),
            binding: 1
        ),
        (
            name: "fyrox_boneMatrices",
            kind: PropertyGroup([
                // Autogenerated
            ]),
            binding: 2
        ),
        (
            name: "fyrox_graphicsSettings",
            kind: PropertyGroup([
                // Autogenerated
            ]),
            binding: 3
        ),
        (
            name: "fyrox_cameraData",
            kind: PropertyGroup([
                // Autogenerated
            ]),
            binding: 4
        ),
        (
            name: "fyrox_lightData",
            kind: PropertyGroup([
                // Autogenerated
            ]),
            binding: 5
        ),
    ],

    // A set of render passes (see a section `Render pass` for more info)
    passes: [
        (
            // Name must match with the name of either standard render pass (see below) or
            // one of your passes.
            name: "Forward",

            // A set of parameters that regulate renderer pipeline state.
            // This is mandatory field of each render pass.
            draw_parameters: DrawParameters(
                // A face to cull. Either Front or Back.
                cull_face: Some(Back),

                // Color mask. Defines which colors should be written to render target.
                color_write: ColorMask(
                    red: true,
                    green: true,
                    blue: true,
                    alpha: true,
                ),

                // Whether to modify depth buffer or not.
                depth_write: true,

                // Whether to use stencil test or not.
                stencil_test: None,

                // Whether to perform depth test when drawing.
                depth_test: Some(Less),

                // Blending options.
                blend: Some(BlendParameters(
                    func: BlendFunc(
                        sfactor: SrcAlpha,
                        dfactor: OneMinusSrcAlpha,
                        alpha_sfactor: SrcAlpha,
                        alpha_dfactor: OneMinusSrcAlpha,
                    ),
                    equation: BlendEquation(
                        rgb: Add,
                        alpha: Add
                    )
                )),

                // Stencil options.
                stencil_op: StencilOp(
                    fail: Keep,
                    zfail: Keep,
                    zpass: Keep,
                    write_mask: 0xFFFF_FFFF,
                ),

                // Scissor box. Could be something like this:
				//
				// scissor_box: Some(ScissorBox(
                //    x: 10,
                //    y: 20,
                //    width: 100,
                //    height: 30
                // ))
                scissor_box: None
            ),

            // Vertex shader code.
            vertex_shader:
                r#"
                layout(location = 0) in vec3 vertexPosition;
                layout(location = 1) in vec2 vertexTexCoord;

                out vec2 texCoord;

                void main()
                {
                    texCoord = vertexTexCoord;
                    gl_Position = fyrox_instanceData.worldViewProjection * vec4(vertexPosition, 1.0);
                }
                "#,

            // Fragment shader code.
            fragment_shader:
                r#"
                out vec4 FragColor;

                in vec2 texCoord;

                void main()
                {
                    FragColor = properties.diffuseColor * texture(diffuseTexture, texCoord);
                }
                "#,
        )
    ],
)

Shader should contain at least one render pass to actually do some job. A shader could not have properties at all. Currently only vertex and fragment programs are supported. Each program mush be written in GLSL. Comprehensive GLSL documentation can be found here

§Render pass

Modern rendering is a very complex thing that requires drawing an object multiple times with different “scripts”. For example to draw an object with shadows you need to draw an object twice: one directly in a render target, and one in a shadow map. Such stages called render passes.

Binding of shaders to render passes is done via names, each render pass has unique name.

§Predefined passes

There are number of predefined render passes:

  • GBuffer - A pass that fills a set of textures (render targets) with various data about each rendered object (depth, normal, albedo, etc.). These textures then are used for physically-based lighting. Use this pass when you want the standard lighting to work with your objects.

  • Forward - A pass that draws an object directly in a render target. It could be used to render translucent objects.

  • SpotShadow - A pass that emits depth values for an object, later this depth map will be used to render shadows.

  • PointShadow - A pass that emits distance from a fragment to a point light, later this depth map will be used to render shadows.

  • DirectionalShadow - A pass that emits depth values for an object, later this depth map will be used to render shadows for directional cascaded shadows.

§Resources

Each shader requires a specific set of external resources that will be used during the rendering. This set is defined in resources section of the shader and could contain the following resources:

  • Texture - a texture of arbitrary type
  • PropertyGroup - a group of numeric properties.

§Binding points

Shader resource must define a unique (over its type) binding index. The engine will use these points to prepare appropriate resource descriptor sets for GPU. Keep in mind, that binding point indices are unique per each type of resource. This means that a set of texture resource could use the same indices as property groups. The binding points must be unique in its group. If there are more than one resource of a certain type, that shares the same binding point, the engine will refuse to use such shader.

§Built-in resources

There are number of built-in resources, that Fyrox will try to assign automatically if they’re defined in your shader, something like this:

(
    name: "fyrox_instanceData",
    kind: PropertyGroup([
        // Autogenerated
    ]),
    binding: 1
),

The full list of built-in resources is defined below.

§fyrox_instanceData

Property group. Provided for each rendered surface instance.

NameTypeDescription
worldMatrixmat4Local-to-world transformation.
worldViewProjectionmat4Local-to-clip-space transform.
blendShapesCountintTotal amount of blend shapes.
useSkeletalAnimationboolWhether skinned meshes is rendering or not.
blendShapesWeightsvec4[32]Blend shape weights.

§fyrox_boneMatrices

Property group. Provided for each rendered surface, that has skeletal animation.

NameTypeDescription
matricesmat4[256]Bone matrices

§fyrox_cameraData

Property group. Contains camera properties. It contains info not only about scene camera, but also observer info when rendering shadow maps. In other words - it is generic observer properties.

NameTypeDescription
viewProjectionMatrixmat4World-to-clip-space transformation.
positionvec3World-space position of the camera.
upVectorvec3World-space up-vector of the camera.
sideVectorvec3World-space side-vector of the camera.
zNearfloatNear clipping plane location.
zFarfloatFar clipping plane location.
zRangefloatzFar - zNear

§fyrox_lightData

Property group. Available only in shadow passes.

NameTypeDescription
lightPositionvec3World-space light source position. Only for shadow passes.
ambientLightColorvec4Ambient lighting color of the scene.

§fyrox_lightsBlock

Property group. Information about visible light sources

NameTypeDescription
lightCountintTotal amount of light sources visible on screen.
lightsColorRadiusvec4[16]Color (xyz) and radius (w) of light source
lightsParametersvec2[16]Hot-spot cone angle cos (x) and half cone angle cos (y)
lightsPositionvec3[16]World-space light position.
lightsDirectionvec3[16]World-space light direction

§fyrox_graphicsSettings

Property group. Contains graphics options of the renderer.

NameTypeDescription
usePomboolWhether to use parallax occlusion mapping or not.

§fyrox_sceneDepth

Texture. Contains depth values of scene. Available only after opaque geometry is rendered (read - G-Buffer is filled). Typical usage is something like this:

(
    name: "fyrox_sceneDepth",
    kind: Texture(kind: Sampler2D, fallback: White),
    binding: 1
),

§Code generation

Fyrox automatically generates code for resource bindings. This is made specifically to prevent subtle mistakes. For example when you define this set of resources:

(
    name: "MyShader",

    resources: [
        (
            name: "diffuseTexture",
            kind: Texture(kind: Sampler2D, fallback: White),
            binding: 0
        ),
        (
            name: "normalTexture",
            kind: Texture(kind: Sampler2D, fallback: Normal),
            binding: 1
        ),
        (
            name: "properties",
            kind: PropertyGroup([
                (
                    name: "texCoordScale",
                    kind: Vector2((1.0, 1.0)),
                ),
                (
                    name: "diffuseColor",
                    kind: Color(r: 255, g: 255, b: 255, a: 255),
                ),
            ]),
            binding: 0
        ),
    ]
)

The engine generates the following code and adds it to source code of every shader of every pass automatically:

uniform sampler2D diffuseTexture;
uniform sampler2D normalTexture;
struct Tproperties {
    vec2 texCoordScale;
    vec4 diffuseColor;
};
layout(std140) uniform Uproperties { Tproperties properties; }

The most important thing is that the engine keeps properties in the struct Tproperties in correct order and forces std140 layout on the generated uniform block. Since the engine knows the layout of the properties from their definition section, it could easily form a memory block with all required alignments and paddings that could be uploaded to GPU. The next important thing is that the engine batches all the data needed into a large chunks of data and uploads them all at once, which is much faster.

§Drawing parameters

Drawing parameters defines which GPU functions to use and at which state. For example, to render transparent objects you need to enable blending with specific blending rules. Or you need to disable culling to draw objects from both sides. This is when draw parameters comes in handy.

There are relatively large list of drawing parameters, and it could confuse a person who didn’t get used to work with graphics. The following list should help you to use drawing parameters correctly.

  • cull_face

  • color_write:

    • Defines which components of color should be written to a render target
    • Possible values: ColorMask(…)
  • depth_write:

    • Whether to modify depth buffer or not.
    • Possible values: true/false
  • stencil_test:

    • Whether to use stencil test or not.
    • Possible values:
  • depth_test:

    • Whether to perform depth test when drawing.
    • Possible values: true/false
  • blend:

    • Blending options.
    • Possible values:
  • stencil_op:

    • Stencil options.
    • Possible values: StencilOp

§Standard shader

By default, Fyrox uses standard material for rendering, it covers 95% of uses cases and it is very flexible. To get standard shader instance, use ShaderResource::standard


let standard_shader = ShaderResource::standard();

Usually you don’t need to get this shader manually, using of Material::standard is enough.

Modules§

loader
Shader loader.

Structs§

RenderPassDefinition
A render pass definition. See ShaderResource docs for more info about render passes.
Shader
Internal state of the shader.
ShaderDefinition
A definition of the shader.
ShaderResourceDefinition
Shader resource definition.

Enums§

SamplerFallback
A fallback value for the sampler.
ShaderError
A set of possible error variants that can occur during shader loading.
ShaderResourceKind
Shader property with default value.

Constants§

STANDARD_2D_SHADER_NAME
A name of the standard 2D shader.
STANDARD_2D_SHADER_SRC
A source code of the standard 2D shader.
STANDARD_PARTICLE_SYSTEM_SHADER_NAME
A name of the standard particle system shader.
STANDARD_PARTICLE_SYSTEM_SHADER_SRC
A source code of the standard particle system shader.
STANDARD_SHADER_NAME
A name of the standard shader.
STANDARD_SHADER_NAMES
A list of names of standard shaders.
STANDARD_SHADER_SOURCES
A list of source code of standard shaders.
STANDARD_SHADER_SRC
A source code of the standard shader.
STANDARD_SPRITE_SHADER_NAME
A name of the standard sprite shader.
STANDARD_SPRITE_SHADER_SRC
A source code of the standard sprite shader.
STANDARD_TERRAIN_SHADER_NAME
A name of the standard terrain shader.
STANDARD_TERRAIN_SHADER_SRC
A source code of the standard terrain shader.
STANDARD_TILE_SHADER_NAME
A name of the standard tile shader.
STANDARD_TWOSIDES_SHADER_NAME
A name of the standard two-sides shader.
STANDARD_TWOSIDES_SHADER_SRC
A source code of the standard two-sides shader.

Traits§

ShaderResourceExtension
Extension trait for shader resources.

Type Aliases§

ShaderResource
Type alias for shader resources.