Skip to content

Effects

tobspr edited this page Apr 26, 2016 · 22 revisions

The effects system was introduced to make creating custom shaders easier. An effect file uses builtin templates and injects shader code at predefined "hooks". That way the effects are compatible with different pipeline versions, even if the template code changes.

Writing Effects

Each effect is a yaml file, containing information which shader templates to use and shader code to be injected into the hooks.

There are 2 sections, containing the definition for the vertex and fragment shader. The vertex shader section is started with the vertex: keyword, and the fragment shader section starts with the fragment: keyword.

Specifying additional requirements

For each stage, you can list additional requirements, like additional inputs or outputs, and includes. For example, you could modify the vertex stage of your effect to something like this:

vertex:
    dependencies:
        - includes/some_requirement.inc.glsl
    inout: |
        uniform vec3 myCustomInput;
        in vec4 p3d_Tangent;
        out vec3 myCustomPerVertexOutput;

That way you can include other glsl files, and add in- and outputs.

Injecting custom code

Each template defines several hooks, where you can inject code. Lets have a look at some part of the default fragment shader template (you can find it here)

    MaterialShaderOutput m;
    // ...
        m.normal = material_nrm;
        m.metallic = mInput.metallic;
        m.specular_ior = blend_ior(mInput.specular_ior, sampled_ior);
        m.roughness = mInput.roughness * sampled_roughness;
        m.shading_model_param0 = mInput.arbitrary0;
    #endif

    %MATERIAL%

    render_material(m);

You can see there is a hook defined named "material", and that's where you can inject your custom code for example. If you, for example, would like to set the materials roughness and specular ior value to some fixed value, you could do so using this effect:

fragment:
    material: |       # <-- The '|' is required since we use multiline strings
        m.roughness = 0.123;
        m.specular_ior = 1.456;

The code specified at that section gets inserted into the template, to build the final shader.

Debugging the created shaders

If you get a shader error for example, or want to see how your effects gets translated into a shader, you can have a look at the temporary generated files. First, you have to make sure that you set a physical write path (see Mount Manager). Then, while the pipeline is running, head over to that temporary path. You will see a lot of generated shader files, including the shader file generated for your effect. If you look at that file, you will see a lot of comments, telling the line numbers, and whether the line was generated from the template or the effect file. For example, the effect from the previous section got translated to:

                 ...
/* T 0026 */     Material m;
                 ...
/* T 0031 */     m.specular = specular;
/* T 0032 */     m.roughness = roughness;

/* Hook material */
/* E 0000 */     m.roughness = 0.123;
/* E 0001 */     m.specular = 0.456;

/* T 0036 */     render_material(m);
/* T 0037 */ }

As you can see, T specifies a line from the template, and E specifies a line inserted from the effect.

Using Effects

To apply an effect to a NodePath, use:

render_pipeline.set_effect(my_node_path, "effects/my_effect.yaml", {
        "render_gbuffer": True,
        "render_shadow": True,
        "alpha_testing": False,
        "normal_mapping": True
        # Further options ...
})

There are several effect options:

render_gbuffer: This controls whether the object will be rendered in the main rendering pass

render_shadow: This controls whether the object casts shadows.

render_voxel: This controls whether the object will be rendered when voxelizing the scene. This has an effect when Global Illumination is enabled.

render_forward: This controls whether the object should be rendered with the forward renderer. In case you activate this, you shold disable the render_gbuffer option.

render_envmap: This controls whether the object will be rendered when capturing environment maps.

alpha_testing: If enabled, the alpha channel of the diffuse texture will be used for binary alpha testing.

normal_mapping: If enabled, normal mapping will be enabled. Your objects should have a normal map applied, and also a bump factor greater than 0. See [Exporting from Blender](Exporting from Blender) on how to use a normal map.

parallax_mapping: Enables parallax mapping, your models should have a displacement texture assigned for that