- Qt 6.5
- Qt Quick 3D
- Shadergen Tool
- Qt Quick 3D | Commercial or GPLv3

# Shadergen Tool

The shadergen tool is a command line application that is part of Qt Quick 3D's asset conditioning pipeline. It can be enable per project or run manually from the command line. Pre-generating the material shaders can have a significant impact on the start-up time and/or avoid unwanted stalls at run-time, as the processes of creating a material shader at run-time can be costly.

Note: This tool is experimental and under development, but most common use-cases should work already.

One of the biggest obstacles for the offline shader generator is the amount of different materials that can be generated, not only based on the material properties themeself but also how the rest of the scene is set-up; for example, light count, light type, shadows, etc. all affect the generated shader(s). When we also take dynamic properties into account, the share amount of material shader permutations can very quickly make it unfeasible to generate them all at build-time. To limit the amount of shaders the tool needs to generate, the tool tries to only generate the shaders it think the application needs. The heuristics used in the tool might not always be able to detect which materials should be generate, this is espcecially true for properties that change at run-time. To verify that the material shaders were successfully, and correctly, generated, the tool should have generated a .qsbc file which can be inspected to verify that the content matches the material used by the application. It's also possible to verify that the material was loaded from the pre-built cache by setting the environment variable QT_RHI_SHADER_DEBUG=1 and looking at the debug output for mentions of the engine loading the pregenerated shader successfully.

Known limitations are:

- Scenes with more then one View3D.
- Dynamically adding or removing lights are not supported when using generating materials.
- The generated shaders are strictly tied to the Qt version used due to its dependency on the internals of the renderer. Compatibility of the generated shaders can therefore not be guaranteed between versions.

## Usage

To enable offline generation of material shaders in your project, add the following to your project file:

CMake:

     qt6_add_materials(offlineshaders "shaders"
         PREFIX
             "/"
         FILES
             ${qml_resource_files}
     )

Alternatively the shadergen tool can be invoked manually from the command line, like this:

     shadergen main.qml Material.qml

Normally the shadergen tool should be run from your application's project folder, but it's also possible to instruct the tool to change its current working directory through the `-C` argument.

If no output path is provided then the tool will write the generated files to the current directory. The output path can be changed with the `-o` option.

Note that for the tool to generate the expected materials it will need to know about the whole scene and not just the material(s), for example the number of lights in the scene does also affect how the materials get generated, so all relevant qml files should be added to the list of files the tool needs to process.

### Command line arguments

Short | Full | Description
--- | --- | ---
-C <PATH> | –directory <PATH> | Changes the current directory to `<PATH>`. This argument is optional.
-o <PATH> | –output-dir <PATH> | Sets the output path to <PATH>. This is the location where the files generated by the tool will be placed under. If no path is given the path is current directory.
-r <NAME> | –resource-file <NAME> | Changes the name of the generated resource file to `<NAME>`. This argument is optional.
-l <FILE> | –list-qsbc <FILE> | List the content of the qsbc file.

## Generated content

The shadergen tools main output file is a .qsbc file. The .qsbc file contains a collection of .qsb files plus some meta-data about the various material shaders, like the unique property string for each material.

The .qsbc file can be inspected by calling the shadergen tool with the `-d` argument:

     shadergen -d qtappshaders.qsbc

## Dynamic properties

Since the tool is run at build-time it has limited ability to reason about which properties might change at run-time. Properties where a value is only changing within the properties range, for example the roughness value, will not have any affect on the generated material shader, but properties that are either on or off, e.g., setting an image map at run-time, would require a different type of material to be generated. It is therefore recommended that all variants of a material, which enables or disables features in the material, or the scene, are declared as individual components, this will help the tool to generated the correct material shaders.

The following example shows a contrived example of a material where we want to add a base color map to a material at run-time. Note that the component `MaterialRedExtended` is never used in the example, it's purely defined to help the shadergen tool generate the shaders needed to dynamically set the `baseColorMap` at run-time.

MaterialRed.qml

     PrincipledMaterial {
         baseColor: "red"
         lighting: PrincipledMaterial.NoLighting
     }

MaterialRedExtended.qml

     MaterialRed {
         baseColorMap: Texture {
             source: "maps/metallic/basecolor.jpg"
         }
     }

main.qml

     Model {
         position: Qt.vector3d(0, -30, 0)
         scale: Qt.vector3d(4, 4, 4)
         source: "#Sphere"
         materials: MaterialRed {
             id: redMaterial
         }
     MouseArea {
         anchors.fill: parent
         onClicked: {
         if (redMaterial.baseColorMap === null)
             redMaterial.baseColorMap = baseColorMap
         else
             redMaterial.baseColorMap = null
         }
     }

See also QtShaderTools.