# Mapping of CGFX (HLSL) materials
The following sections contains examples on how to setup, export and import Simplygon materials through MEL and Python. It is recommended to read Shading network concepts before proceeding.
# Simplygon PBR (CGFX)
This script loops through all Simplygon PBR materials (HLSL connected to CGFX) and sets up shading networks accordingly. Then it sends the selected assets to Simplygon for processing. When the processing is done the LODs are returned to Maya where the script takes over and maps the LOD materials back to a HLSL shader.
string $simplygonDocumentsPath[] = `SimplygonPreset -gsp`;
string $rootPath = $simplygonDocumentsPath[0] + "\\Samples\\Maya\\SimplygonMan";
// pipeline settings
string $pipelineFilePath = $rootPath + "\\Pipelines\\ReductionWithBaking.json";
// path to Simplygon PBR shader
string $pbgShaderFile = $rootPath + "\\Shader\\SimplygonPBRShader.fx";
// "" = default, "d:\\TextureOutputFolder\\" = custom
string $textureOutputDirectory = $rootPath + "\\OutputTextures\\";
// cube map path for all meshes with material baking
string $cubeMapFilePath = $rootPath + "\\CubeMap\\cube_map.dds";
// drive to store temporary xml files (c might be protected)
string $xmlExportPath = $rootPath + "\\XMLTempFolder\\";
// populate material list
string $cgfxMaterials[] = `ls -type cgfxShader`;
for( $cgfx_mat in $cgfxMaterials )
{
string $technique = `getAttr ($cgfx_mat + ".technique")`;
if($technique != "PBR")
{
$cgfx_mat = "";
}
}
// create shading networks for each cgfx material
// and export template to xml (for later use)
string $inputMaterialString = "";
for( $cgfx_mat in $cgfxMaterials )
{
if(size ($cgfx_mat) == 0)
continue;
print ("\nSimplygon PBR Shader:\n Name: " + $cgfx_mat + "\n");
string $normalMaps[] = `listConnections -type "file" ($cgfx_mat + ".NormalsSampler")`;
for ( $nMap in $normalMaps )
{
string $filename = `getAttr($nMap + ".fileTextureName")`;
print (" Normal map (" + $nMap + "): " + $filename + "\n");
// check color space for all textures connected to the normal map of this material
string $currentColorSpace = `getAttr ($nMap + ".colorSpace")`;
print (" Current color space: " + $currentColorSpace + "\n");
if($currentColorSpace != "Raw")
{
string $availableColorSpaces[] = `colorManagementPrefs -q -inputSpaceNames`;
if ( stringArrayContains("Raw", $availableColorSpaces) )
{
setAttr ($nMap+".ignoreColorSpaceFileRules") 1;
setAttr ($nMap+".colorSpace") -type "string" "Raw";
print (" New color space: Raw\n");
}
else
{
print ("Normal map with incorrect color space found but could not find a suitable color space, please check the color space setting for this texture!\n");
}
}
int $NameBasedSearchWarning = false;
string $result = `match "_n." $filename`;
if($result == "_n.")
{
$NameBasedSearchWarning = true;
}
$result = `match "normals" $filename`;
if($result == "normals")
{
$NameBasedSearchWarning = true;
}
if($NameBasedSearchWarning == true)
{
print (" Prediction (name based): most likely a normal map)\n");
}
}
SimplygonShadingNetwork
// create texture nodes
-cn $cgfx_mat TextureNode DiffuseSampler
-cn $cgfx_mat TextureNode SpecularSampler
-cn $cgfx_mat TextureNode RoughnessSampler
-cn $cgfx_mat TextureNode MetalnessSampler
-cn $cgfx_mat TextureNode NormalsSampler
// override uv channels
-uva DiffuseSampler map1
-uva SpecularSampler map1
-uva RoughnessSampler map1
-uva MetalnessSampler map1
-uva NormalsSampler map1
// override sRGB
-sa DiffuseSampler true
-sa SpecularSampler true
-sa RoughnessSampler true
-sa MetalnessSampler true
-sa NormalsSampler false
// connect textures to simplygon channels
-sce $cgfx_mat Diffuse DiffuseSampler
-sce $cgfx_mat Specular SpecularSampler
-sce $cgfx_mat Roughness RoughnessSampler
-sce $cgfx_mat Metalness MetalnessSampler
-sce $cgfx_mat Normals NormalsSampler
-tmc $cgfx_mat Diffuse DiffuseSampler 1.0 1.0
-omc $cgfx_mat Diffuse DiffuseSampler 0.0 0.0
// export material channel templates to xml for later use
-exf $cgfx_mat Diffuse ($xmlExportPath + $cgfx_mat + "_Diffuse.xml")
-exf $cgfx_mat Specular ($xmlExportPath + $cgfx_mat + "_Specular.xml")
-exf $cgfx_mat Roughness ($xmlExportPath + $cgfx_mat + "_Roughness.xml")
-exf $cgfx_mat Metalness ($xmlExportPath + $cgfx_mat + "_Metalness.xml")
-exf $cgfx_mat Normals ($xmlExportPath + $cgfx_mat + "_Normals.xml");
// append material name to string (for later use)
$inputMaterialString += $cgfx_mat + "|";
}
// parse arguments
string $arguments = "";
for( $cgfx_material in $cgfxMaterials )
{
if(size ($cgfx_material) == 0)
continue;
$arguments += " -ixf \"" + $cgfx_material + "\" Diffuse \"" + ($xmlExportPath + $cgfx_material + "_Diffuse.xml\"");
$arguments += " -ixf \"" + $cgfx_material + "\" Specular \"" + ($xmlExportPath + $cgfx_material + "_Specular.xml\"");
$arguments += " -ixf \"" + $cgfx_material + "\" Roughness \"" + ($xmlExportPath + $cgfx_material + "_Roughness.xml\"");
$arguments += " -ixf \"" + $cgfx_material + "\" Metalness \"" + ($xmlExportPath + $cgfx_material + "_Metalness.xml\"");
$arguments += " -ixf \"" + $cgfx_material + "\" Normals \"" + ($xmlExportPath + $cgfx_material + "_Normals.xml\"");
}
// correct double slashes
$arguments = substituteAllString($arguments, "\\", "\\\\");
// launch Simplygon and fetch the result
string $processedMeshes[];
$processedMeshes = eval("Simplygon -dgm -tod $textureOutputDirectory -sf $pipelineFilePath -asm $inputMaterialString" + $arguments);
// link cube map
string $cubeMapNode = `shadingNode -isColorManaged -asTexture file`;
setAttr -type "string" ( $cubeMapNode + ".fileTextureName" ) $cubeMapFilePath;
// fetch lod names
int $lodIndex = 0;
string $materialNameArray[];
string $SGNameArray[];
//$processedMeshes = `SimplygonQuery -gpm`;
for( $m in $processedMeshes )
{
// correct mesh names from Simplygon call
$m = substituteAllString($m, "|", "");
print ("\nMesh: " + $m + "\n");
// offset new mesh along x-axis
select -r $m;
$transAttr = $m+".translateX";
float $bbox[] = `exactWorldBoundingBox`;
float $moveOffset = ($lodIndex+1)*($bbox[3]-$bbox[0])*1.1;
setAttr -lock off $transAttr;
move -r $moveOffset 0 0;
string $material;
// fetch material name for mesh,
// start with checking for reused materials
$reuseMaterials = `SimplygonQuery -rms $m`;
if(size ($reuseMaterials) == 0)
{
print (" Not reusing material.\n");
$material = `SimplygonQuery -gmm $m`;
}
else
{
int $currentMaterialIndex = 0;
int $isReusingMaterial = false;
for( $reuseMaterial in $reuseMaterials )
{
print (" Checking material: " + $reuseMaterial + "\n");
int $i = stringArrayFind( $reuseMaterial, 0, $materialNameArray );
if($i < 0)
{
print (" Reusing original material!\n");
select -cl;
$materialIds = `SimplygonQuery -gmi $m`;
//print $materialIds;
int $tid = 0;
for( $mid in $materialIds )
{
if($mid == $currentMaterialIndex)
{
//print (" Selecting triangle " + $tid + " for material " + $mid + "\n");
select -tgl ($m + ".f[" + $tid + "]");
}
$tid++;
}
print (" Assigning material " + $reuseMaterial + " to selected triangles for mesh " + $m + "\n");
sets -e -forceElement $reuseMaterial;
select -cl;
$lodIndex++;
$currentMaterialIndex++;
$isReusingMaterial = true;
continue;
}
// material was found in lod chain, continuing
string $nameOfMaterialNode = $SGNameArray[$i];
// assign material to selected mesh
select -r $m;
if(size ($nameOfMaterialNode) != 0)
{
sets -e -forceElement $nameOfMaterialNode;
}
// offset new mesh along x-axis
$lodIndex++;
$currentMaterialIndex++;
$isReusingMaterial = true;
continue;
}
// if reuse, exit here
if($isReusingMaterial == true)
{
continue;
}
}
print (" Material: " + $material + "\n");
// create cgfx shader and matching SG node
string $shader = `shadingNode -asShader cgfxShader`;
string $shaderSG = `sets -renderable true -noSurfaceShader true -empty -name ($shader + "SG")`;
stringArrayInsertAtIndex($lodIndex, $SGNameArray, $shaderSG);
stringArrayInsertAtIndex($lodIndex, $materialNameArray, $material);
// connect shader to shaderSG
connectAttr -f ( $shader + ".outColor" ) ( $shaderSG + ".surfaceShader" );
// user Simplygon PBR shader with default PBR teqhnique
cgfxShader -e -fx $pbgShaderFile $shader;
setAttr -type "string" ($shader + ".technique") "PBR";
// connect cube map
connectAttr -force ($cubeMapNode + ".outColor") ($shader + ".CubemapSampler");
// fetch channel names for mesh material
$channels = `SimplygonQuery -gcm $material`;
for( $c in $channels )
{
// fetch texture path for channel
print (" Channel: " + $c + "\n");
$filepath = `SimplygonQuery -gtc $material $c`;
print (" Texture: " + $filepath + "\n");
// create texture nodes and link textures
string $fileNode = `shadingNode -isColorManaged -asTexture file`;
setAttr -type "string" ( $fileNode + ".fileTextureName" ) $filepath;
if($c == "Diffuse")
{
connectAttr -force ($fileNode + ".outColor") ($shader + ".DiffuseSampler");
}
else if($c == "Specular")
{
connectAttr -force ($fileNode + ".outColor") ($shader + ".SpecularSampler");
}
else if($c == "Roughness")
{
connectAttr -force ($fileNode + ".outColor") ($shader + ".RoughnessSampler");
}
else if($c == "Metalness")
{
connectAttr -force ($fileNode + ".outColor") ($shader + ".MetalnessSampler");
}
else if($c == "Normals")
{
connectAttr -force ($fileNode + ".outColor") ($shader + ".NormalsSampler");
// force colorspace, if possible
string $currentColorSpace = `getAttr ($fileNode + ".colorSpace")`;
if($currentColorSpace != "Raw")
{
string $availableColorSpaces[] = `colorManagementPrefs -q -inputSpaceNames`;
if ( stringArrayContains("Raw", $availableColorSpaces) )
{
setAttr ($fileNode+".ignoreColorSpaceFileRules") 1;
setAttr ($fileNode+".colorSpace") -type "string" "Raw";
}
}
}
}
// assign material to selected mesh
select -r $m;
sets -e -forceElement $shaderSG;
// offset new mesh along x-axis
$lodIndex++;
}