Shader Generation

Shader generation takes the selected material in the viewer and generate the low level shader code for it and shader reflection data.

Options include being able to choose which shading language target to produce.

Generate Shader Toolbar

The right-hand side contains the set of available options for shader generation. This includes (from left-to-right)

Once a shader is generated once, the options can be used to modify the output shader interactively.

When a new material is chosen then the shader needs to be regenerated. If there is access to modify the text of the MaterialX Document directly then shader regeneration may also be required to reflect the changes.

Source Code Area

The source code area has two text areas. On for the pixel (framgment) shader text and on for the vertex shader text. Vertex shaders only apply to hardware shading languages and will hence be empty for on-hardware languages.

The figure below shows the ESSL output for a given material:

while this figure shows the OSL output for the same material

Note that the generation options have been embedded into the generated shader text as comments. For example for the OSL shader:

//
// Pixel shader for: unlit_surface 
// Generator Target: genosl
// Shader interface: Complete
// Encode sRGB output: false
//

For the sRGB output option, the output function can be seen by scrolling to the botttom of the pixel shaders. When enabled the additional function can be examined.

For example:

   out1 = vec4(mx_srgb_encode(unlit_surface_out.color), 1.0);

versus

  out1 = vec4(unlit_surface_out.color, 1.0);

can be observed.

Shader Reflection

In order to determine how the original MaterialX inputs are mapped to shader inputs this information is "reflected" back to the user.

The shader reflection area shows the list of pixel shader uniforms which are made accessible after code generation in the "Pixel Shader Uniforms" area.

On the left are the shader inputs (or uniforms), the assigned type and assigned values are shown in the middle, and the right shows a remapping to the DAG path of the original MaterialX input.

It is thus possible to modify one and keep the other in sync as desired. The path can be also be used to monitor the original MaterialX document.

Please refer to the Shader Generation documentation for more details on uniform exposure include specially globals uniforms (which begin with u_).

The "Save Reflection Information" button can be used to save the uniform reflection list as well all the shaders in JSON format.

Below is an example of such as file:

{
  "element_path": "unlit_surface",
  "shader_generator": "essl",
  "generator_interface": "complete",
  "srgb_out_injection": false,
  "shader_uniforms": [
    [
      "type",
      "integer",
      null,
      ""
    ],
    [
      "emission",
      "float",
      "1",
      ""
    ],
    [
      "transmission",
      "float",
      "0",
      ""
    ],
    [
      "transmission_color",
      "color3",
      "1, 1, 1",
      ""
    ],
    [
      "opacity",
      "float",
      "1",
      ""
    ],
    [
      "default_gooch_warm_color",
      "color3",
      "0.8, 0.8, 0.7",
      "default_gooch/warm_color"
    ],
    [
      "default_gooch_cool_color",
      "color3",
      "0.3, 0.3, 0.8",
      "default_gooch/cool_color"
    ],
    [
      "default_gooch_specular_intensity",
      "float",
      "1",
      "default_gooch/specular_intensity"
    ],
    [
      "default_gooch_shininess",
      "float",
      "64",
      "default_gooch/shininess"
    ],
    [
      "default_gooch_light_direction",
      "vector3",
      "1, -0.5, -0.5",
      "default_gooch/light_direction"
    ],
    [
      "u_envMatrix",
      "matrix44",
      "-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1",
      ""
    ],
    [
      "u_envRadiance",
      "filename",
      null,
      ""
    ],
    [
      "u_envLightIntensity",
      "float",
      "1",
      ""
    ],
    [
      "u_envRadianceMips",
      "integer",
      "1",
      ""
    ],
    [
      "u_envRadianceSamples",
      "integer",
      "16",
      ""
    ],
    [
      "u_envIrradiance",
      "filename",
      null,
      ""
    ],
    [
      "u_refractionTwoSided",
      "boolean",
      null,
      ""
    ],
    [
      "u_viewPosition",
      "vector3",
      null,
      ""
    ]
  ],
  "vertex": "#version 300 es\n\nprecision mediump float;\n\n// Uniform block: PrivateUniforms\nuniform mat4 u_worldMatrix;\nuniform mat4 u_viewProjectionMatrix;\nuniform mat4 u_worldInverseTransposeMatrix;\n\n// Inputs block: VertexInputs\nin vec3 i_position;\nin vec3 i_normal;\n\nout vec3 normalWorld;\nout vec3 positionWorld;\n\nvoid main()\n{\n    vec4 hPositionWorld = u_worldMatrix * vec4(i_position, 1.0);\n    gl_Position = u_viewProjectionMatrix * hPositionWorld;\n    normalWorld = normalize((u_worldInverseTransposeMatrix * vec4(i_normal, 0.0)).xyz);\n    positionWorld = hPositionWorld.xyz;\n}\n\n",
  "pixel": "//\n// Pixel shader for: unlit_surface \n// Generator Target: essl\n// Shader interface: Complete\n// Encode sRGB output: false\n//\n#version 300 es\n\nprecision mediump float;\n\nstruct BSDF { vec3 response; vec3 throughput; };\n#define EDF vec3\nstruct surfaceshader { vec3 color; vec3 transparency; };\nstruct volumeshader { vec3 color; vec3 transparency; };\nstruct displacementshader { vec3 offset; float scale; };\nstruct lightshader { vec3 intensity; vec3 direction; };\n#define material surfaceshader\n\n// Uniform block: PublicUniforms\nuniform float emission;\nuniform float transmission;\nuniform vec3 transmission_color;\nuniform float opacity;\nuniform vec3 default_gooch_warm_color;\nuniform vec3 default_gooch_cool_color;\nuniform float default_gooch_specular_intensity;\nuniform float default_gooch_shininess;\nuniform vec3 default_gooch_light_direction;\n\n// Uniform block: PrivateUniforms\nuniform mat4 u_envMatrix;\nuniform sampler2D u_envRadiance;\nuniform float u_envLightIntensity;\nuniform int u_envRadianceMips;\nuniform int u_envRadianceSamples;\nuniform sampler2D u_envIrradiance;\nuniform bool u_refractionTwoSided;\nuniform vec3 u_viewPosition;\n\nin vec3 normalWorld;\nin vec3 positionWorld;\n\n// Pixel shader outputs\nout vec4 out1;\n\n#define M_FLOAT_EPS 1e-8\n\nfloat mx_square(float x)\n{\n    return x*x;\n}\n\nvec2 mx_square(vec2 x)\n{\n    return x*x;\n}\n\nvec3 mx_square(vec3 x)\n{\n    return x*x;\n}\n\nvec3 mx_srgb_encode(vec3 color)\n{\n    bvec3 isAbove = greaterThan(color, vec3(0.0031308));\n    vec3 linSeg = color * 12.92;\n    vec3 powSeg = 1.055 * pow(max(color, vec3(0.0)), vec3(1.0 / 2.4)) - 0.055;\n    return mix(linSeg, powSeg, isAbove);\n}\n\nvoid NG_reflect_vector3(vec3 in1, vec3 normal, out vec3 out1)\n{\n    float NdotI_out = dot(normal, in1);\n    const float NdotI_2_in2_tmp = 2.000000;\n    float NdotI_2_out = NdotI_out * NdotI_2_in2_tmp;\n    vec3 NdotI_N_2_out = normal * NdotI_2_out;\n    vec3 reflection_vector_out = in1 - NdotI_N_2_out;\n    out1 = reflection_vector_out;\n}\n\nvoid NG_gooch_shade(vec3 warm_color, vec3 cool_color, float specular_intensity, float shininess, vec3 light_direction, out vec3 out1)\n{\n    vec3 normal_out = normalize(normalWorld);\n    vec3 unit_lightdir_out = normalize(light_direction);\n    vec3 viewdir_out = normalize(positionWorld - u_viewPosition);\n    vec3 unit_normal_out = normalize(normal_out);\n    const float invert_lightdir_in2_tmp = -1.000000;\n    vec3 invert_lightdir_out = unit_lightdir_out * invert_lightdir_in2_tmp;\n    vec3 unit_viewdir_out = normalize(viewdir_out);\n    float NdotL_out = dot(unit_normal_out, unit_lightdir_out);\n    vec3 view_reflect_out = vec3(0.0);\n    NG_reflect_vector3(unit_viewdir_out, unit_normal_out, view_reflect_out);\n    const float one_plus_NdotL_in1_tmp = 1.000000;\n    float one_plus_NdotL_out = one_plus_NdotL_in1_tmp + NdotL_out;\n    float VdotR_out = dot(invert_lightdir_out, view_reflect_out);\n    const float cool_intensity_in2_tmp = 2.000000;\n    float cool_intensity_out = one_plus_NdotL_out / cool_intensity_in2_tmp;\n    const float VdotR_nonnegative_in2_tmp = 0.000000;\n    float VdotR_nonnegative_out = max(VdotR_out, VdotR_nonnegative_in2_tmp);\n    vec3 diffuse_out = mix(warm_color, cool_color, cool_intensity_out);\n    float specular_highlight_out = pow(VdotR_nonnegative_out, shininess);\n    float specular_out = specular_highlight_out * specular_intensity;\n    vec3 final_color_out = diffuse_out + specular_out;\n    out1 = final_color_out;\n}\n\nvoid main()\n{\n    vec3 default_gooch_out = vec3(0.0);\n    NG_gooch_shade(default_gooch_warm_color, default_gooch_cool_color, default_gooch_specular_intensity, default_gooch_shininess, default_gooch_light_direction, default_gooch_out);\n    surfaceshader unlit_surface_out = surfaceshader(vec3(0.0),vec3(0.0));\n    unlit_surface_out.color = emission * default_gooch_out;\n    unlit_surface_out.transparency = transmission * transmission_color;\n    unlit_surface_out.color *= opacity;\n    unlit_surface_out.transparency = mix(vec3(1.0), unlit_surface_out.transparency, opacity);\n    out1 = vec4(unlit_surface_out.color, 1.0);\n}\n\n"
}