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 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 Pixel | Color space | Vulkan Format | Range |
---|---|---|---|---|
U8vec4 | 8 | Linear | VK_FORMAT_R8G8B8A8_UINT | |
S8vec4 | 8 | Linear | VK_FORMAT_R8G8B8A8_SINT | |
U8vec4 | 8 | Linear | VK_FORMAT_R8G8B8A8_UNORM | |
U8vec4 | 8 | sRGB | VK_FORMAT_R8G8B8A8_SRGB | |
U16vec4 | 16 | Linear | VK_FORMAT_R16G16B16A16_SINT | |
S16vec4 | 16 | Linear | VK_FORMAT_R16G16B16A16_UINT | |
F32vec2 | 16 | Linear | VK_FORMAT_R16G16B16A16_UNORM | Two Half-precision floating point numbers |
F32vec4 | 32 | Linear | VK_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
Property | Default |
---|---|
MagFilter | Linear |
MinFilter | Linear |
AddressModeU | Repeat |
AddressModeV | Repeat |
AddressModeW | Repeat |
UnnormalizedCoordinates | false |
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:
struct TintAndMultiplyField
{
float4 color;
float multiplier;
};
<?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.
Value | Type | Description |
---|---|---|
sg_MaterialIdFilter | #define (unsigned value) | The Id of the current material being compiled |
sg_TriangleId | int | The triangle Id of the current triangle |
sg_BCoord0 | float | The barycentric coordinate of the current sample in the current triangle, value 0 |
sg_BCoord1 | float | The barycentric coordinate of the current sample in the current triangle, value 1 |
sg_BCoord2 | float | The barycentric coordinate of the current sample in the current triangle, value 2 |
sg_WorldCoord | 3d vector | The projected world coordinate of the current sample |
sg_HasPreviousValue | bool | When 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_PreviousValue | 4d vector | If there is a previous layer data (sg_HasPreviousValue == true), this is the accumulated value |
sg_DiscardValue | bool | Set 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_DestinationWorldCoord | 3d vector | The projected world coordinate of the destination sample, on the destination mesh |
sg_DestinationTangent | 3d vector | The tangent basis tangent vector of the destination sample, on the destination mesh |
sg_DestinationBitangent | 3d vector | The tangent basis bitangent vector of the destination sample, on the destination mesh |
sg_DestinationNormal | 3d vector | The 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.
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 );
}
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 );
}
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 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 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 Element | API Object | *Additional Info |
---|---|---|
MaterialEvaluationShader | MaterialEvaluationShader | Root |
EvaluationFunction | ShaderEvaluationFunction | Required |
Attribute | MaterialEvaluationShaderAttribute | Optional |
ShaderParameterBuffer | ShaderParameterBuffer | Optional. (Is a ShaderParameter) |
ShaderParameterSamplerState | ShaderParameterSamplerState | Optional. (Is a ShaderParameter) |
ShaderParameterSampler | ShaderParameterSampler | Optional. (Is a ShaderParameter) |
ShaderParameterTexture | ShaderParameterTexture | Optional. (Is a ShaderParameter) |
ShaderParameterTextureArray | ShaderParameterTextureArray | Optional. (Is a ShaderParameter) |
Define | MaterialEvaluationShaderDefine | Optional |
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.
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.
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 );
}
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 );
}
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.
<Material Name="clothSG1">
<MaterialEvaluationShader Version="0.4.0" ShaderLanguage="HLSL" ShaderBinaryFilePath="shaderBinary.spv" ShaderBinaryBindingDigest="bafe6863335e7bde3f92fa77ed66a1326a12483eaa3fd66ed6e9251fae10799c" >
</MaterialEvaluationShader>
</Material>
//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.