Skip to content
On this page

Compute Casting

Compute casting is an alternate way to cast material compared to using traditional casters and shading networks. The following diagram provides an overview of the compute casting workflow and the major component involved.

Compute Casting Overview
Compute Casting Overview

Compute Casting as the name suggest uses a compute shader and Vulkan backend to cast textures. The Vulkan backend can either be a GPU or a CPU fallback API (e.g SwiftShader). Like other caster compute caster takes in MappingImage, Materials and Textures for the casting processing. Unlike other caster you also need to provide MaterialEvaluationShader and a user-defined shader block.

Dependencies

Before you get started with compute casting in your pipeline the following dependencies should be installed on machines where you intend to use the feature.

  • VulkanSDK (Version 1.2+) Simplygon uses a Vulkan-based compute casting processor, and needs the VulkanSDK shader compilation tools:
    • glslc.exe for compiling GLSL shaders. glslc.exe is part of the VulkanSDK distro, so if you install VulkanSDK, Simplygon should be able to find glslc.exe automatically. If not, please make sure it is available in the Windows PATH environment variable.
    • dxc.exe for compiling HLSL shaders. dxc.exe and all needed Spir-V support tools are part of the VulkanSDK distro, so if you install VulkanSDK, Simplygon should be able to find dxc.exe automatically. If not, please make sure it is available in the Windows PATH environment variable. (Please note! This is not the standard dxc.exe which is included with Visual Studio and compiles DXIL code, but a version which is able to output and compile Spir-V for Vulkan.)
  • A Vulkan-compatible GPU, with latest drives, -or-
  • Swift Shader (Optional: CPU based fallback Vulkan API implementation)

Material Evaluation Shader and user-defined shader block

Material Evaluation Shader

This object is meta data that is attached to the Material object. This meta data along with the user defined shader block is used by the compute caster to generate a compute shader for the casting process. The ShaderLanguage attribute/property is required.

MaterialEvaluationShader can be defined by either creating API object programmatically or by deserializing a XML file. See Material Evaluation Shader for more info. The following are the main components required for MaterialEvaluationShader.

Attributes

MaterialEvaluationShaderAttribute object declare a buffer resource that is setup during compute shader generation phase. The buffer refers to a field in the source GeometryData used in the user-defined shader block(e.g Texcoords, Coords, Normals, Tangents and custom fields). The Name property refers to the variable or buffer name in the shader. The GeometryFieldType refers to the field type in GeometryData. See EGeometryFieldType. The AttributeFormat refers to the data type(e.g F32vec2,U32 and etc). See EAttributeFormat. Geometry fields like Texcoords, Colors, UserCornerField, UserVertexField , UserTriangleField allow the user to provide a name. These are user named fields. The FieldName property can be used to refer to these user named fields in GeometryData.

IMPORTANT NOTE

If the user named field has no FieldName the first available field would be selected. For example if there is a MaterialEvaluationShaderAttribute with GeometryFieldType as Texcoords and no FieldName setup. The generator will go through all available Texcoords and select the first available one.

IMPORTANT NOTE

If a user named field is not present in the GeometryData and the frequency is known (e.g Triangle, Vertex, Corner) a zero initialized buffer is created for use by the generated compute shader.See Material Evaluation Shader Attribute for more information.

Evaluation Functions

ShaderEvaluationFunction object declare a mapping between MaterialChannel and a method in user defined shader block to use for casting. At least one ShaderEvaluationFunction object is required. (e.g Diffuse, Basecolor, Normals, Roughness and etc.). See Shader Evaluation Function. The EntryPoint is the name of the function in user defined shader block. Channel property should refer to MaterialChannel on the Material object.

Shader Parameters

The shader parameters are parameter used to setup the generated shader. ShaderParameter is the base class. The following are the concrete types:

Textures

ShaderParameterTexture and ShaderParameterTextureArray objects are used to define texture references, which can be sampled using a texture sampler (defined below). The ShaderParameterTexture object creates a single texture reference in the shader code, and the ShaderParameterTextureArray creates an array of texture references, which can be indexed in the shader code.

ShaderParameterTexture object has a TextureName property which must refer to an existing Texture in the TextureTable. ShaderParameterTextureArray contains a StringArray parameter, which holds the names and indices of all the textures in the texture array.

ShaderParameterTexture object has a TextureFormat property which is used to specify the type and packing of texture data. Following are valid formats.

EAttributeFormat (value)Bit Per PixelColor spaceVulkan FormatRange
U8vec48LinearVK_FORMAT_R8G8B8A8_UINT
S8vec48LinearVK_FORMAT_R8G8B8A8_SINT
U8vec48LinearVK_FORMAT_R8G8B8A8_UNORM
U8vec48sRGBVK_FORMAT_R8G8B8A8_SRGB
U16vec416LinearVK_FORMAT_R16G16B16A16_SINT
S16vec416LinearVK_FORMAT_R16G16B16A16_UINT
F32vec216LinearVK_FORMAT_R16G16B16A16_UNORMTwo Half-precision floating point numbers
F32vec432LinearVK_FORMAT_R32G32B32A32_SFLOAT (Default)Single-precision floating point number

Samplers

ShaderParameterSampler object declare a texture sampler that is generated by the compute caster. A ShaderParameterSampler object per Texture is required(referred in user-defined shader block). ShaderParameterSampler object has an optional TextureName property which should refer to a Texture in the TextureTable. If the TextureName property is set, the sampler is a combined texture and sampler, and bound to one slot. Each ShaderParameterSampler object can use a default state. Users can override sampler state by declaring a ShaderParameterSamplerState object. The SamplerState property can be used to refer to the name of the ShaderParameterSamplerState object to use. If SamplerState property is not set a default SamplerState is used. See Shader Parameter Sampler

Samplers States

The ShaderParameterSamplerState object declare the behavior of a sampler like filtering and addressing modes. See ESamplerAddressMode, ESamplerFilter and Shader Parameter Sampler state. This shader parameter type is optional. To refer to ShaderParameterSampler object. The SamplerState property on ShaderParameterSampler object should refer to the Name of the ShaderParameterSamplerState object to use.

Note: Since HLSL and GLSL handle sampler states a bit differently, samplers in GLSL are automatically applied to each sampler, while in HLSL, the samplers are explicitly selected in the shader. For HLSL, it is recommended to specify samplers and textures separately, to be able to defined the names of the objects specifically.

Default Samplers State

PropertyDefault
MagFilterLinear
MinFilterLinear
AddressModeURepeat
AddressModeVRepeat
AddressModeWRepeat
UnnormalizedCoordinatesfalse

Buffers

The ShaderParameterBuffer declare a custom buffer as input binding to be used during compute casting. The custom buffer can be used to bind custom data to the shader. For example you can pass in a custom struct containing GBuffer data. ShaderParameterBuffer can be setup through the API or from XML. The FieldName is used to refer custom field name either on GeometryData or CasterSource. The Type property is the user-specified type in the shader. The type is shader-specific and must be declared in the shader header. You can either setup a CustomField on GeometryData. When setting it up from XML you can specify an external .bin file.

IMPORTANT NOTE

ShaderParameterBuffer is always added as UnsignedCharArray and EAttributeFormat is U8

Following is an example of a custom shader type setup as custom buffer from XML:

hlsl
struct TintAndMultiplyField
{
	float4 color;
	float multiplier;
};
xml
<?xml version="1.0" encoding="UTF-8"?>
<Scene>
<!-- 
The CustomFields element lists any additional custom fields which should be added to the Scene (as AddCustomField).
Note that since the user is responsible for alignment and packing, all fields are added as UnsignedCharArrays, with 
a tuple size of 1. 

Fields can either reference external files, as shown below (TintAndMultiplyField.bin), or be embedded in the .xml
as a base64 encoded field.

In the example field below, we encode one 20 byte struct per material, so the input .bin file is 8 * 20 = 160 bytes
-->

<CustomFields>
   <CustomField Name="TintAndMultiplyField" FilePath="TintAndMultiplyField.bin"/>
</CustomFields>

<Material>
   <MaterialEvaluationShader>
   <!-- 
		Example of referencing a custom field in the scene.
		This is used in the shader to modify the color value of the Diffuse color 
		-->
	<ShaderParameterBuffer Name="TintAndMultiplyStructBuffer" FieldName="TintAndMultiplyField" Type="SgTintAndMultiplier"/>
		
   </MaterialEvaluationShader>
</Material>
</Scene>

Preprocessor Defines

MaterialEvaluationShaderDefine object can be used to declare a preprocessor define in the generated compute shader before the user block begins. The define is undefined after the user block ends. The Name property is required. The Value property is optional.

Built-in values

Some values are always defined in the generated shader file. These have specific properties, and can be used by the shader code to modify behaviour etc. The values are listed below.

ValueTypeDescription
sg_MaterialIdFilter#define (unsigned value)The Id of the current material being compiled
sg_TriangleIdintThe triangle Id of the current triangle
sg_BCoord0floatThe barycentric coordinate of the current sample in the current triangle, value 0
sg_BCoord1floatThe barycentric coordinate of the current sample in the current triangle, value 1
sg_BCoord2floatThe barycentric coordinate of the current sample in the current triangle, value 2
sg_WorldCoord3d vectorThe projected world coordinate of the current sample
sg_HasPreviousValueboolWhen there are multiple layers, this is set to true if there are previous values to blend with. Note: Layers are blended back-to-front
sg_PreviousValue4d vectorIf there is a previous layer data (sg_HasPreviousValue == true), this is the accumulated value
sg_DiscardValueboolSet to true when the value should be discarded. Useful if the casting is based on a pixel/fragment shader with a discard/clip call and you want the same behaviour in the compute shader
sg_DestinationWorldCoord3d vectorThe projected world coordinate of the destination sample, on the destination mesh
sg_DestinationTangent3d vectorThe tangent basis tangent vector of the destination sample, on the destination mesh
sg_DestinationBitangent3d vectorThe tangent basis bitangent vector of the destination sample, on the destination mesh
sg_DestinationNormal3d vectorThe tangent basis normal vector of the destination sample, on the destination mesh

Setting up Material Evaluation Shader and Exporting the XML

If you have access to the Simplygon API prefer creating MaterialEvaluationShader object over XML. In case your shader export module can not take a dependency on you can export an XML using any XML writer for ingestion into your LOD generation module.

The following code example shows how to setup a MaterialEvaluationShader object. Load a shader from disk and export it as an XML. This is mainly to validate what kind of XML is read by Simplygon and deserialized. You can adapt your XML writer to export similarly.

cpp
void SetupMaterialEusevaluationShaderAndExportXML( const std::string& xmlPath, const std::string& shaderFilePath )
{
    
 auto materialEvaluationShader = sg->CreateMaterialEvaluationShader();

 //create a texcoord attribute
 auto texCoordAttribute = sg->CreateMaterialEvaluationShaderAttribute();
 
 //reference name used inside the shader
 texCoordAttribute
     ->SetName( "TEXCOORD0" );
 
 //type of field (spGeometryData)
 texCoordAttribute
     ->SetFieldType(Simplygon::EGeometryDataFieldType::TexCoords);
 
 //type of data the field contains
 texCoordAttribute
     ->SetFieldFormat(Simplygon::EAttributeFormat::F32vec2);
 
 //name of the field (spGeometryData). (i.e if read from FBX or if you  
 texCoordAttribute
     ->SetFieldName( "UVMap1" );

 //add attributes to the attribute table
 materialEvaluationShader->GetMaterialEvaluationShaderAttributeTable()->AddAttribute(texCoordAttribute);

 //create an evaluation function
 auto baseColorEvalFunction = sg->CreateShaderEvaluationFunction();
 baseColorEvalFunction
     ->SetName( "EvalFunction" );
 //the channel name that is present in the spMaterial
 baseColorEvalFunction->SetChannel( SG_MATERIAL_CHANNEL_BASECOLOR );

 //the name of the method that is in the shader
 baseColorEvalFunction->SetEntryPoint( "EvaluateBaseColor" );

 materialEvaluationShader->GetShaderEvaluationFunctionTable()->AddShaderEvaluationFunction(baseColorEvalFunction);
 
 //create a samplersate
 auto samplerStateParameter = sg->CreateShaderParameterSamplerState();
 samplerStateParameter->SetName( "LinearRepeat" );
 samplerStateParameter->SetAddressU( Simplygon::ESamplerAddressMode::MirrorRepeat);
 samplerStateParameter->SetAddressV( Simplygon::ESamplerAddressMode::MirrorRepeat);
 samplerStateParameter->SetAddressW( Simplygon::ESamplerAddressMode::MirrorRepeat);
 samplerStateParameter->SetMagFilter( Simplygon::ESamplerFilter::Linear);
 samplerStateParameter->SetMinFilter( Simplygon::ESamplerFilter::Linear);
 samplerStateParameter->SetUnNormalizedCoordinates( false );

 //create a sampler
 auto sampler = sg->CreateShaderParameterSampler();

 //reference of the sampler used in the shader
 sampler->SetName( "BaseColorTexture" );

 //reference the sampler sate created above.
 sampler->SetSamplerState( "LinearRepeat" );

 //name of the texture in the Scene's(spScene) texture table (spTextureTable)
 sampler->SetTextureName( "wood_D" );

 //add to table
 materialEvaluationShader->GetShaderParameterTable()->AddShaderParameter(samplerStateParameter);
 materialEvaluationShader->GetShaderParameterTable()->AddShaderParameter(sampler);
 materialEvaluationShader->SetShaderLanguage(Simplygon::EShaderLanguage::GLSL);

 //add a shader define to flip the uv values in baking process. See the user code block 
 auto shaderDefine = sg->CreateMaterialEvaluationShaderDefine();
    shaderDefine->SetName( "FLIP_UV" );

 //add to table
    materialEvaluationShader->GetMaterialEvaluationShaderDefineTable()->AddMaterialEvaluationShaderDefine(shaderDefine);

 //load shader (optionally you can set the shader string with SetShaderCode
 materialEvaluationShader->LoadShaderFromFilePath( shaderFilePath.c_str() );

 auto materialEvaluationShaderSerializer = sg->CreateMaterialEvaluationShaderSerializer();       
 
 materialEvaluationShaderSerializer->SaveMaterialEvaluationShaderToFile( xmlPath.c_str(), materialEvaluationShader );
}
csharp
void SetupMaterialEvaluationShaderAndExportXML(string xmlPath, string shaderFilePath)
{
    var materialEvaluationShader = sg.CreateMaterialEvaluationShader();

 //create a texcoord attribute
 var texCoordAttribute = sg.CreateMaterialEvaluationShaderAttribute();
 
 //reference name used inside the shader
 texCoordAttribute.SetName( "TEXCOORD0" );
 
 //type of field (spGeometryData)
 texCoordAttribute.SetFieldType(Simplygon::EGeometryDataFieldType::TexCoords);
 
 //type of data the field contains
 texCoordAttribute.SetFieldFormat(Simplygon::EAttributeFormat::F32vec2);
 
 //name of the field (spGeometryData). (i.e if read from FBX or if you  
 texCoordAttribute.SetFieldName( "UVMap1" );

 //add attributes to the attribute table
 materialEvaluationShader.GetMaterialEvaluationShaderAttributeTable().AddAttribute(texCoordAttribute);

 //create an evaluation function
 var baseColorEvalFunction = sg.CreateShaderEvaluationFunction();
 baseColorEvalFunction.SetName( "EvalFunction" );
 //the channel name that is present in the spMaterial
 baseColorEvalFunction.SetChannel( Simplygon.Simplygon.SG_MATERIAL_CHANNEL_BASECOLOR );

 //the name of the method that is in the shader
 baseColorEvalFunction.SetEntryPoint( "EvaluateBaseColor" );

 materialEvaluationShader.GetShaderEvaluationFunctionTable().AddShaderEvaluationFunction(baseColorEvalFunction);
 
 //create a samplersate
 var samplerStateParameter = sg.CreateShaderParameterSamplerState();
 samplerStateParameter.SetName( "LinearRepeat" );
 samplerStateParameter.SetAddressU( Simplygon.Simplygon.ESamplerAddressMode,MirrorRepeat);
 samplerStateParameter.SetAddressV( Simplygon.Simplygon.ESamplerAddressMode.MirrorRepeat);
 samplerStateParameter.SetAddressW( Simplygon.Simplygon.ESamplerAddressMode.MirrorRepeat);
 samplerStateParameter.SetMagFilter( Simplygon.Simplygon.ESamplerFilter.Linear);
 samplerStateParameter.SetMinFilter( Simplygon.Simplygon.ESamplerFilter.Linear);
 samplerStateParameter.SetUnNormalizedCoordinates( false );

 //create a sampler
 var sampler = sg.CreateShaderParameterSampler();

 //reference of the sampler used in the shader
 sampler.SetName( "BaseColorTexture" );

 //reference the sampler sate created above.
 sampler.SetSamplerState( "LinearRepeat" );

 //name of the texture in the Scene's(spScene) texture table (spTextureTable)
 sampler.SetTextureName( "wood_D" );

 //add to table
 materialEvaluationShader.GetShaderParameterTable().AddShaderParameter(samplerStateParameter);
 materialEvaluationShader.GetShaderParameterTable().AddShaderParameter(sampler);
 materialEvaluationShader.SetShaderLanguage(Simplygon.Simplygon.EShaderLanguage.GLSL);

 //add a shader define to flip the uv values in baking process. See the user code block 
 var shaderDefine = sg.CreateMaterialEvaluationShaderDefine();
    shaderDefine.SetName( "FLIP_UV" );

 // add to table
    materialEvaluationShader.GetMaterialEvaluationShaderDefineTable().AddMaterialEvaluationShaderDefine(shaderDefine);
 
 //load shader (optionally you can set the shader string with SetShaderCode
 materialEvaluationShader.LoadShaderFromFilePath( shaderFilePath );

 var materialEvaluationShaderSerializer = sg.CreateMaterialEvaluationShaderSerializer();       
 
 materialEvaluationShaderSerializer.SaveMaterialEvaluationShaderToFile( xmlPath, materialEvaluationShader );
}
python
def SetupMaterialEvaluationShaderAndExportXML( xmlPath, shaderFilePath ):
 materialEvaluationShader = sg.CreateMaterialEvaluationShader()
 
 #create a texcoord attribute
 texCoordAttribute = sg.CreateMaterialEvaluationShaderAttribute()
 
 #reference name used inside the shader
 texCoordAttribute.SetName( "TEXCOORD0" )
 
 #type of field (spGeometryData)
 texCoordAttribute.SetFieldType(Simplygon::EGeometryDataFieldType::TexCoords)
 
 #type of data the field contains
 texCoordAttribute.SetFieldFormat(Simplygon::EAttributeFormat::F32vec2)
 
 #name of the field (spGeometryData). (i.e if read from FBX or if you  
 texCoordAttribute.SetFieldName( "UVMap1" )

 #add attributes to the attribute table
 materialEvaluationShader.GetMaterialEvaluationShaderAttributeTable().AddAttribute(texCoordAttribute)

 #create an evaluation function
 baseColorEvalFunction = sg.CreateShaderEvaluationFunction()
 baseColorEvalFunction.SetName( "EvalFunction" )
 #the channel name that is present in the spMaterial
 baseColorEvalFunction.SetChannel( Simplygon.Simplygon.SG_MATERIAL_CHANNEL_BASECOLOR )

 #the name of the method that is in the shader
 baseColorEvalFunction.SetEntryPoint( "EvaluateBaseColor" )

 materialEvaluationShader.GetShaderEvaluationFunctionTable().AddShaderEvaluationFunction(baseColorEvalFunction)
 
 #create a samplersate
 samplerStateParameter = sg.CreateShaderParameterSamplerState()
 samplerStateParameter.SetName( "LinearRepeat" )
 samplerStateParameter.SetAddressU( Simplygon.Simplygon.ESamplerAddressMode,MirrorRepeat)
 samplerStateParameter.SetAddressV( Simplygon.Simplygon.ESamplerAddressMode.MirrorRepeat)
 samplerStateParameter.SetAddressW( Simplygon.Simplygon.ESamplerAddressMode.MirrorRepeat)
 samplerStateParameter.SetMagFilter( Simplygon.Simplygon.ESamplerFilter.Linear)
 samplerStateParameter.SetMinFilter( Simplygon.Simplygon.ESamplerFilter.Linear)
 samplerStateParameter.SetUnNormalizedCoordinates( false )

 #create a sampler
 sampler = sg.CreateShaderParameterSampler()

 #reference of the sampler used in the shader
 sampler.SetName( "BaseColorTexture" )

 #reference the sampler sate created above.
 sampler.SetSamplerState( "LinearRepeat" )

 #name of the texture in the Scene's(spScene) texture table (spTextureTable)
 sampler.SetTextureName( "wood_D" )

 #add to table
 materialEvaluationShader.GetShaderParameterTable().AddShaderParameter(samplerStateParameter)
 materialEvaluationShader.GetShaderParameterTable().AddShaderParameter(sampler)
 materialEvaluationShader.SetShaderLanguage(Simplygon.Simplygon.EShaderLanguage.GLSL)

 #add a shader define to flip the uv values in baking process. See the user code block 
 var shaderDefine = sg.CreateMaterialEvaluationShaderDefine()
    shaderDefine.SetName( "FLIP_UV" )

 #add to table
    materialEvaluationShader.GetMaterialEvaluationShaderDefineTable().AddMaterialEvaluationShaderDefine(shaderDefine)
 
 #load shader (optionally you can set the shader string with SetShaderCode
 materialEvaluationShader.LoadShaderFromFilePath( shaderFilePath )

 materialEvaluationShaderSerializer = sg.CreateMaterialEvaluationShaderSerializer()
 
 materialEvaluationShaderSerializer.SaveMaterialEvaluationShaderToFile( xmlPath, materialEvaluationShader )

It is also possieble to export all material evaluation shaders, along with their material mapping and used textures, by using the SaveSceneMaterialEvaluationShadersToFile call. This will output an extended XML.

Example Material Evaluation Shader XML

The following is a an example XML what can be deserialized into a MaterialEvaluationShader object. The following XML was generated using the above sample code. ShaderLanguage attribute is required for appropriate shader bindings generation by compute caster.

xml
<?xml version="1.0" encoding="UTF-8"?>
<MaterialEvaluationShader Version="1.0" ShaderLanguage="GLSL">
    <!-- This attribute defines that from source geometry we want to use a named TexCoord field named UVMap -->
    <Attribute Name="TEXCOORD0" FieldType="TexCoords" FieldName="UVMap1" FieldFormat="F32vec2"/>

    <!-- A method called CastDiffuse will be used to cast to diffuse channel -->
    <EvaluationFunction Channel="Basecolor" EntryPoint="EvaluateBaseColor"/>
    <!-- A non default sampler state -->
    <ShaderParameterSamplerState Name="LinearRepeat" MinFilter="Linear" MagFilter="Linear" AddressU="MirrorRepeat" AddressV="MirrorRepeat" AddressW="MirrorRepeat" UnNormalizedCoordinates="true"/>
    <!-- A sampler using non default sampler state called LinearRepeat which is used to sample wood_D texture -->
    <ShaderParameterSampler Name="BaseColorTexture" TextureName="wood_D" SamplerState="LinearRepeat"/>
 <!-- A Shader define that would be declared in generated code-->
 <Define Name="FLIP_UV"/>
    <!-- If SetShaderCode or LoadShaderFromFile is used the shader is embedded as cdata -->
    <Shader><![CDATA[
vec4 EvaluateBaseColor() 
{ 
#ifdef FLIP_UV 
 return vec4(TEXCOORD0.y,TEXCOORD0.x,0,1); 
#else 
 return vec4(TEXCOORD0.x,TEXCOORD0.y,0,1); 
#endif 
}]]></Shader>
</MaterialEvaluationShader>

Below is an example of the extended XML which also maps the evaluation shader into a material called "wood_material", and also adds the texture "wood_D" (filename: "wood.png") into the texture table. Note that if the material and texture exists in the current scene, their data is replaced. If the material or texture does not exist in the scene, they are added.

xml
<?xml version="1.0" encoding="UTF-8"?>
<Scene>
   <TextureTable>
      <Texture Name="wood_D" FilePath="wood.png" ColorSpace="Linear"/>
   </TextureTable>
   <MaterialTable>
      <Material Name="wood_material">
         <MaterialEvaluationShader Version="1.0" ShaderLanguage="GLSL">
            <!-- This attribute defines that from source geometry we want to use a named TexCoord field named UVMap -->
            <Attribute Name="TEXCOORD0" FieldType="TexCoords" FieldName="UVMap1" FieldFormat="F32vec2"/>

            <!-- A method called CastDiffuse will be used to cast to diffuse channel -->
            <EvaluationFunction Channel="Basecolor" EntryPoint="EvaluateBaseColor"/>
            <!-- A non default sampler state -->
            <ShaderParameterSamplerState Name="LinearRepeat" MinFilter="Linear" MagFilter="Linear" AddressU="MirrorRepeat" AddressV="MirrorRepeat" AddressW="MirrorRepeat" UnNormalizedCoordinates="true"/>
            <!-- A sampler using non default sampler state called LinearRepeat which is used to sample wood_D texture -->
            <ShaderParameterSampler Name="BaseColorTexture" TextureName="wood_D" SamplerState="LinearRepeat"/>
         <!-- A Shader define that would be declared in generated code-->
         <Define Name="FLIP_UV"/>
            <!-- If SetShaderCode or LoadShaderFromFile is used the shader is embedded as cdata -->
            <Shader><![CDATA[
         vec4 EvaluateBaseColor() 
         { 
         #ifdef FLIP_UV 
         return vec4(TEXCOORD0.y,TEXCOORD0.x,0,1); 
         #else 
         return vec4(TEXCOORD0.x,TEXCOORD0.y,0,1); 
         #endif 
         }]]></Shader>
         </MaterialEvaluationShader>
      </Material>
   </MaterialTable>
</Scene>

XML Elements & Evaluation Shader Setup

XML ElementAPI Object*Additional Info
MaterialEvaluationShaderMaterialEvaluationShaderRoot
EvaluationFunctionShaderEvaluationFunctionRequired
AttributeMaterialEvaluationShaderAttributeOptional
ShaderParameterBufferShaderParameterBufferOptional. (Is a ShaderParameter)
ShaderParameterSamplerStateShaderParameterSamplerStateOptional. (Is a ShaderParameter)
ShaderParameterSamplerShaderParameterSamplerOptional. (Is a ShaderParameter)
ShaderParameterTextureShaderParameterTextureOptional. (Is a ShaderParameter)
ShaderParameterTextureArrayShaderParameterTextureArrayOptional. (Is a ShaderParameter)
DefineMaterialEvaluationShaderDefineOptional
Shader-Optional user (GLSL/HLSL) block as CDATA. Requires ShaderLanguage attribute be set on MaterialEvaluationShader element. Or use LoadMaterialEvaluationShaderFromFile(MaterialEvaluationShader) to load from file.

User-defined shader block

User defined shader block define how to evaluate the pixel for the baked texture. It is a block of GLSL code. Its is a partial code block that is injected into the final compute shader generated by the compute caster. Any resources (i.e textures, geometry data fields from source geometry are define by the MaterialEvaluationShader object.

IMPORTANT NOTE

The output data fromm the compute shader is expected to be RGBA. So make sure to sanatize the output from you user block as vec4/float4. Otherwise components that are not used can have any value.

glsl
vec4 AlphaOffset(in sampler2D alphaMask, vec2 uv, vec4 offset)
{
 vec4 alphaMaks = texture(alphaMask, uv);
 vec4 maskOffset = alphaMaks - offset;
 vec4 clampOffset = clamp(maskOffset,0.0,1.0);
 return ceil(clampOffset);
}

vec4 BlendTextures(in sampler2D primary, in sampler2D secondary,vec2 UV,vec4 alphaMasks)
{
 vec4 allOnes = vec4(1);
 
 vec4 primaryColor = texture(primary,UV);
 vec4 secondaryColor = texture(secondary,UV);

    vec4 oneMinus = allOnes-alphaMasks;

 vec4 filterPrimary =  oneMinus*primaryColor;
 vec4 filterSecondary =  alphaMasks*secondaryColor;
 return filterPrimary+filterSecondary;
}

// The Evaluation Function in XML as referenced in
// TEXCOORD0 DiffuseA, DiffuseB & Mask are also referenced in the XML
// These are the samplers and buffer resources that will be bound to the generated compute shader
vec4 CastDiffuse()
{
 vec4 diffuseColor;
 vec4 alphaMasks = AlphaOffset(Mask,TEXCOORD0,vec4(0.10));
 diffuseColor = BlendTextures(DiffuseA,DiffuseB, TEXCOORD0, alphaMasks);
 return diffuseColor;
}

Loading Shader block and XML Example

The following code snippet on how users can use the serializer to deserialize the XML to and MaterialEvaluationShader object and assign it to the Material.

cpp
void SetupMaterialEvaluationShaderForMaterial(spMaterial material, const std::string& assetPath)
{
    auto materialName = material->GetName();
    
    // each material has material evaluation shader xml. Note this can be shared between material as long as the surface is evaluated in the same way.
    const auto evaluationShaderXml = assetPath + "\\" + materilaName + ".xml";

    // Create the serializer object
 spMaterialEvaluationShaderSerializer serializer = 
    sg->CreateMaterialEvaluationShaderSerializer();

    // deserialize xml to material evaluation shader object
 auto evaluationShader = serializer->LoadMaterialEvaluationShaderFromFile( evaluationShaderXml.c_str() );

    //load GLSL file from disk . This is the user-defined shader block
    const auto evaluationShaderGlsl = assetPath + "\\" + materilaName + ".glsl";
    evaluationShader->LoadShaderFromFilePath(evaluationShaderGlsl.c_str());

    // set material evaluation shader on the material
 material->SetMaterialEvaluationShader( evaluationShader );
}
csharp
void SetupMaterialEvaluationShaderForMaterial(Simplygon.spMaterial material, string assetPath)
{
    var materialName = material.GetName();
    
    // each material has material evaluation shader xml. Note this can be shared between material as long as the surface is evaluated in the same way.
    
    var evaluationShaderXml = assetPath + "\\" + materilaName + ".xml";

    // Create the serializer object
 var serializer = 
    sg.CreateMaterialEvaluationShaderSerializer();

    // deserialize xml to material evaluation shader object
 auto evaluationShader = serializer->LoadMaterialEvaluationShaderFromFile( evaluationShaderXml );

    //load GLSL file from disk . This is the user-defined shader block
    var evaluationShaderGlsl = assetPath + "\\" + materilaName + ".glsl";
    evaluationShader.LoadShaderFromFilePath(evaluationShaderGlsl);

    // set material evaluation shader on the material
 material.SetMaterialEvaluationShader( evaluationShader );
}
python
def SetupMaterialEvaluationShaderForMaterial(material:Simplygon.spMaterial, assetPath:str):
    materialName = material.GetName()
    # each material has material evaluation shader xml. Note this can be shared between material as long as the surface is evaluated in the same way.
    evaluationShaderXml = assetPath + "\\" + materilaName + ".xml"
    # Create the serializer object
    serializer =
    sg.CreateMaterialEvaluationShaderSerializer()
    # deserialize xml to material evaluation shader object
    evaluationShader = serializer.LoadMaterialEvaluationShaderFromFile( evaluationShaderXml )
    
    #load GLSL file from disk . This is the user-defined shader block
    evaluationShaderGlsl = assetPath + "\\" + materilaName + ".glsl"
    evaluationShader.LoadShaderFromFilePath(evaluationShaderGlsl)
    #set material evaluation shader on the material
    material.SetMaterialEvaluationShader( evaluationShader )

Generating shader source without casting

For generating shader source without baking texture you can call the GenerateShaderSources method on the compute caster. The method takes in three spStringArray arguments that return the shader source, the input binding digest and the shader source digest. See Compute Caster. User can use this to generate shader binaries and cache them. These digests can be used to validate when a cached precompiled shader binary is provided. See ShaderCodeInputMode on Compute Caster Setting.

Pre-built shader binaries

MaterialEvaluation allows user to load a precompiled shader binary. Either through XML (see snippet below) or via the API. ShaderBinaryBindingDigest and ShaderBinarySourceDiget can be provided for validation purpose. Providing a ShaderBinarySourceDiget will trigger shader source generation. However no shader would be compiled.

xml
<Material Name="clothSG1">
    <MaterialEvaluationShader Version="0.4.0" ShaderLanguage="HLSL" ShaderBinaryFilePath="shaderBinary.spv" ShaderBinaryBindingDigest="bafe6863335e7bde3f92fa77ed66a1326a12483eaa3fd66ed6e9251fae10799c" >
    </MaterialEvaluationShader>
</Material>
cpp
//read shader binary 
Simplygon::spUnsignedCharArray shaderBinary = ReadShaderBinary("shader.spv");
materialEvalutionShader->SetShaderBinary(shaderBinary);

//optional fields
materialEvalutionShader->SetShaderBinaryBindingDigest(bindingDigest);
materialEvalutionShader->SetShaderBinarySourceDigest(sourceDigest);

// switch compute caster input mode to use binary
computeCaster->GetComputeCasterSettings()->SetShaderCodeInputMode(Simplygon::EComputeCasterShaderCodeInputMode::Binary);

Debugging

To be able to debug compute caster's generated shader users can set a custom path on ComputeCaster object. See DebugOutputShaderFolder setting in Compute Caster.

Global override

Simplygon selects a physical device based on the device properties. If you have multiple devices and want to override which device is used, use the global string setting "VulkanDevice" (SetGlobalVulkanDevice) to set the name of the device, or a substring of the name, and Simplygon will only consider devices which match the name. E.g. "3080", "AMD" or "NVidia GeForce 3070". To see all available device names, please look in the log, using an ELogLevel verbosity setting of at least Info.

Shader compiler paths

Currently Simplygon depends on dxc and glslc. Users can use the global setting "DXCPath" (SetGlobalDXCPathSetting) for dxc and "DXCPath" (SetGlobalGLSLCPathSetting) for glslc. These are optional. If not provide the search order is to look through the "Bin" folder in path provided by "VULKAN_SDK" environment variable, if present. If not found in "VULKAN_SDK" it will fallback to searching for the executables under all paths in "PATH" environment variable.

Limitations

When using compute casters with pipeline you are limited to using RunScene method. RunSceneFromFile should be avoided as there is no clear way to define and read MaterialEvaluationShader or shader code when using third-party file formats. Therefore RunScene approach is recommended.

Example

Here is a compute casting example showing how to make a custom casting using a compute shader written by the user.