Skip to content
On this page

CGFX / DirectX material to Simplygon material

This section goes through how to set up a CGFX / DirectX (HLSL) material, how to export and import a material to and from Simplygon using Simplygon shading networks. We recommend reading Shading network concepts before proceeding.

First, make sure the plug-in (.mll) for the specific material type is loaded in the plug-in manager (Windows -> Settings / Preferences -> Plug-in Manager) as in figure 1.

Plug-in manager
Plug-in manager

Figure 1: CGFX / DirectX plug-in loaded in the plug-in manager.

Let’s create a cube as in figure 2. This cube will be the target for our soon to be created material.

Cube
Cube

Figure 2: A cube.

To create a new material, go to Hypershade (Windows -> Rendering Editors -> Hypershade) and click either Cgfx or DirectX shader (figure 3).
The following sections will focus more on the CGFX shader, and as most things are identical for DirectX shaders it would be redundant. See DirectX and CGFX examples for complete import / export scripts.

How to CGFX material
How to CGFX material

Figure 3: How to create a CGFX material in Hypershade.

In the panel (figure 3) there is a material name which we set to MyMaterial in this example. There is an empty field labeled CgFX File below the name - click Open and navigate to the HLSL file you wish to use. The Property Editor should now list various material properties depending on how the HLSL is written as well as the technique (figure 4).
In this example we use a HLSL shader with texture slots matching a simple PBR material, the rendering is somewhat simplified to make this example easier to follow.

CGFX material with properties
CGFX material with properties

Figure 4: CGFX material with properties.

It is now time to assign the material to our asset: Select the asset, go to Hypershade, click and hold the right mouse button on the recently created shader followed by releasing the button when hovering assign to selection.

Another way to do this is to simply drag the material from Hypershade (using the middle mouse button) and drop it onto the asset.

If we close Hypershade and bring forth the attribute editor (ctrl + A), then the asset should render with the new material. We have already prepared some textures for this specific material to make it somewhat more describing (figure 5).

Attribute editor
Attribute editor

Figure 5: Cube with CGFX material successfully applied.

That is it, we now have an asset with a HLSL shader attached to it!

Scripting

To translate a CGFX / DirectX material to a Simplygon material you might want to extract certain properties from your shader, for example a texture. Below is a snippet of a DirectX shader defining a texture.

HLSL
texture DiffuseTexture : Diffuse
<
    string ResourceType = "2D";
    string UIName =  "Diffuse Texture";
>;
sampler2D DiffuseSampler = sampler_state
{
    Texture = <DiffuseTexture>;
    MinFilter = LinearMipMapLinear;
    MagFilter = Linear;
};

For CGFX materials the sampler2D (DiffuseSampler) represent the texture slot (figure 6). For DirectX materials the texture (DiffuseTexture) represents the texture slot. This means that we'll use the sampler2D when mapping textures from CGFX to Simplygon, and texture when mapping textures from DirectX. Please see the complete scripts listed at the end of this tutorial for more information.

Diffuse texture slot
Diffuse texture slot

Figure 6: CGFX Diffuse texture slot.

Export

The first thing we need to do is to create a (shading) texture node using the SimplygonShadingNetwork-command along with the cn-flag (CreateNode), the name of the material, the type of the node we want to create as well as the name of the texture sampler.

MEL
SimplygonShadingNetwork
    -cn $materialName TextureNode DiffuseSampler;

To connect the shading network exit node to a material channel, in this case to a channel named Diffuse, we add another row to our script.

MEL
SimplygonShadingNetwork
    -cn $materialName TextureNode DiffuseSampler
    -sce $materialName Diffuse DiffuseSampler;

Commands in Maya are not state based and does not share any information, so to be able to pass the shading network templates from SimplygonShadingNetwork to Simplygon we will store the information to disk (using the exf-flag). Let’s add another flag to the SimplygonShadingNetwork-command.

MEL
SimplygonShadingNetwork
    -cn $materialName TextureNode DiffuseSampler
    -sce $materialName Diffuse DiffuseSampler
    -exf $materialName Diffuse ($xmlExportPath + $materialName + "_Diffuse.xml");

Now, after running this script there should be a xml file in the specified output folder containing the shading network template for the specific material channel. We will now use the generated template as input when calling the Simplygon-command.

First we need the material input arguments for the Simplygon-command, which in this case is the path to the xml we exported earlier. We import it using Import Xml File (ixf).

MEL
string $arguments = " -ixf \"" + $materialName + "\" Diffuse \"" + ($xmlExportPath + $materialName + "_Diffuse.xml\"");

When calling the Simplygon-command we can specify some optional parameters which in this case are:
dgm to not generate standard Phong material when importing LOD) and tod to specify a texture output directory where the resulting textures shall end up after LOD import. Finally we add the required flag, add shader material (asm) followed by material name and the previous xml import path. Remember to select the asset before running the Simplygon-command , otherwise the command will be ignored.

MEL
string $processedMeshes[] = eval("Simplygon -sf $pipelineFilePath -dgm -tod $textureOutputDirectory -asm $materialName " + $arguments);

Let us add the NormalsSampler texture to the Normals channel, this should be fairly easy from what we have learned. Let us take a look at the definition in the HLSL shader.

HLSL
texture NormalTexture : Normal
<
    string ResourceType = "2D";
    string UIName =  "Normal Texture";
>;
sampler2D NormalsSampler = sampler_state
{
    Texture = <NormalTexture>;
    MinFilter = LinearMipMapLinear;
    MagFilter = Linear;
};

We add similar rows for normals as for the diffuse texture.

MEL
SimplygonShadingNetwork
    -cn $materialName TextureNode DiffuseSampler
    -cn $materialName TextureNode NormalsSampler
    -sce $materialName Diffuse DiffuseSampler
    -sce $materialName Normals NormalsSampler
    -exf $materialName Diffuse ($xmlExportPath + $materialName + "_Diffuse.xml")
    -exf $materialName Normals ($xmlExportPath + $materialName + "_Normals.xml");
string $arguments =
" -ixf \"" + $materialName + "\" Diffuse \"" + ($xmlExportPath + $materialName + "_Diffuse.xml\"") +
" -ixf \"" + $materialName + "\" Normals \"" + ($xmlExportPath + $materialName + "_Normals.xml\"");
string $processedMeshes[] = eval("Simplygon -sf $pipelineFilePath -dgm -tod $textureOutputDirectory -asm $materialName " + $arguments);

This is a short example of how to use shading networks to translate a custom HLSL shader. Please take a look at the tables above including shading nodes, commands and flags to see what is available. There are also a couple of examples at the end of this document which focusing more on shading nodes and hierarchy.

This is the end of the export part and how to get the asset to Simplygon. What happens next is more dependent on the settings that is used for processing and what kind of LODs that come back.

Import

If we continue where we left off at the export step the return value of the Simplygon-command will contain the names of the processed meshes.

MEL
string $processedMeshes[] = eval("Simplygon -sf $pipelineFilePath -dgm -tod $textureOutputDirectory -asm $materialName " + $arguments);

The Simplygon Maya plug-in stores some material information from the last run to give the user a chance to manually setup materials via script. To access such information we will use the SimplygonQuery-command with the appropriate flags. We will start by asking the plug-in for the material name of a mesh, material channels as well as textures.

MEL
for($m in $processedMeshes)
{
    $m = substituteAllString($m, "|", "");
    print ("\nMesh: " + $m + "\n");
    string $material;
    $material = `SimplygonQuery -gmm $m`;
    print ("  Material: " + $material + "\n");
    $channels = `SimplygonQuery -gcm $material`;
    for($c in $channels)
    {
        print ("    Channel: " + $c + "\n");
        $filepath = `SimplygonQuery -gtc $material $c`;
        print ("      Texture: " + $filepath + "\n");
    }
}

What remains is to create a target CGFX / DirectX material (or any other material) and map back the information that was fetched from the SimplygonQuery-command. We've excluded the material creation part from this tutorial as there usually are many lines of code and special conditions that does not really contribute that much, see CGFX and DirectX examples for complete import / export scripts.