Need Help with Textured MDL Materials through Omniverse Connector

Hi,

I’m getting a little hung up on textures and materials in Omniverse Connectors.

We have a database of materials and textures that we’re pulling from. The source file going into the connector eventually returns a material name and subidentifier for an mdl that are then used to look up that material in the database and append it to the relevant mesh. This has generally worked very well, but textures have to be reapplied manually to the resulting USD file.

Right now I have this function that I made based off of the CreateMaterial function in the connect sample:

static void appendMaterialtoMesh(UsdGeomMesh meshIn, std::string& materialName, std::string& materialPath, UsdStageRefPtr stagePointer)
{
	// Create a material instance for this in USD
	TfToken materialNameToken(materialName);
	// Make path in the tree structure of the USD file;
	SdfPath matPath = SdfPath::AbsoluteRootPath()
		.AppendChild(_tokens->Root)
		.AppendChild(_tokens->Looks)
		.AppendChild(materialNameToken);
	UsdShadeMaterial newMat = UsdShadeMaterial::Define(stagePointer, matPath);

	// MDL Shader
	{
		// Create the MDL shader to bind to the material
		SdfAssetPath mdlShaderModule = SdfAssetPath(materialPath);
		SdfPath shaderPath = matPath.AppendChild(materialNameToken);
		UsdShadeShader mdlShader = UsdShadeShader::Define(stagePointer, shaderPath);
		
		mdlShader.CreateIdAttr(VtValue(_tokens->shaderId)); //this line will break if we don't associate our stage properly - check stagePointer if this breaks
		// These attributes will be reworked or replaced in the official MDL schema for USD.
		// https://developer.nvidia.com/usd/MDLschema
		mdlShader.SetSourceAsset(mdlShaderModule, _tokens->mdl);
		mdlShader.GetPrim().CreateAttribute(TfToken("info:mdl:sourceAsset:subIdentifier"), SdfValueTypeNames->Token, false, SdfVariabilityUniform).Set(materialNameToken);

		// Set the linkage between material and MDL shader
		UsdShadeOutput mdlOutput = newMat.CreateSurfaceOutput(_tokens->mdl);
		mdlOutput.ConnectToSource(mdlShader, _tokens->out);
	}

	// Final step, associate the material with the face
	UsdShadeMaterialBindingAPI usdMaterialBinding(meshIn);
	usdMaterialBinding.Bind(newMat);

	// Commit the changes to the USD
	stagePointer->Save();
	omniUsdLiveProcess();
}

which gives me this in the property window upon conversion (no texture selection):

I can then go into Create and edit the parent material inside the material graph - adding a bitmap texture giving me the file selection box I’m looking for. (as well as bump/normal maps)

My main question is: How do I automate the addition of textures (albedo/color map most importantly) like this via c++? I assume it’s going to be similar to the way the ‘subIdentifier’ was defined as a parameter but I can’t seem to find any example.

It doesn’t have to be defined as a NodeGraph either, that’s just the way I know how to do it in Create. I have conversions of materials out of IRay that don’t rely on Create’s Node Graph at all. Here’s what they look like:


I can’t use these in my material library though because they’re generated at runtime as part of the USD in this IRay->USD conversion, and it appears Create doesn’t support exporting mdls.

Two other important considerations are:

-How do materials and textures combine for rendering in Create? Do textures replace or multiply/modulate? Can I control which?

-I will likely need the same material multiple times with different textures, meaning I’ll need multiple instances of the same material unless there’s some way to designate a texture subidentifier on the mesh itself.

I appreciate any insight, thank you!

-Matthew

Hello @LMTraina99! I reached out to the development team for some help! Will post back when I have more information for you!

1 Like

The development team suggest to try looking at the USDA that was generated by Kit for guidance in what you need to use in your code.

1 Like

Hi @LMTraina99

I’ll try and help but take my answer with a grain of salt. I’m not a Dev so C++ is not in my skillset.

UsdShade nodes are created just like you did in your C++ example. You specify a sourceAsset and subIdentifier for the shade node. And then you connect it’s inputs and outputs together.

This page has a small example how to create shaders in Python which looks similar to your C++ calls. I suspect they’re the same.

https://graphics.pixar.com/usd/release/api/usd_shade_page_front.html

materialPath = Sdf.Path('/Model/Materials/MyMaterial')
material = UsdShade.Material.Define(stage, materialPath)
# create shaders
downstreamShader = UsdShade.Shader.Define(
    stage, materialPath.AppendChild('Downstream'))
upstreamShader = UsdShade.Shader.Define(
    stage, materialPath.AppendChild('Upstream'))
# Connect
inputPort = downstreamShader.CreateInput(
    'DownstreamInput', Sdf.ValueTypeNames.Float)
inputPort.ConnectToSource(upstreamShader, 'UpstreamOutput')

The example you posted uses a USD Compound Node for file_texture. If you double click it, you’ll see that it has several nodes inside of it. It’s a bit more than what you need so I’m attaching a simpler yet similar texture graph.
SimpleMat.material.material.usda (7.8 KB)

But it essentially tells you all the source and connection info you need in your C++.

the tl;dr

define a shader “file_texture_01” with

sourceAsset “nvidia/core_definitions.mdl”
sourceAsset:subIdentifier "file_texture

define a shader “construct_color” with

sourceAsset “nvidia/aux_definitions.mdl”
sourceAsset:subIdentifier “construct_color(::base::texture_return)”

connect the construct_color inputs:a to the output of the file_texture_01

inputPort = constructColorShader.CreateInput(
    'a', Sdf.ValueTypeNames.token)
inputPort.ConnectToSource(fileTextureShader, 'out')

connect the Paint_Flat inputs:Color to the output of construct_color

inputPort = flatPaintShader.CreateInput(
    'Color', Sdf.ValueTypeNames.Color)
inputPort.ConnectToSource(constructColorShader, 'out')

Another thing is that in the near future we’ll support exporting UsdShade to MDL files. So that may be a future option for you.

Lastly, textures are just evaluated for the input. So you’ll need to create each instance of the material.

1 Like

Thanks for Frankie’s reply.
Hi @LMTraina99
Another way to do that is to change your Flat.mdl.
I saw you’ve already defined the parameter Color, you can define another parameter Texture like this:
color Color = color(0.0f),
uniform texture_2d Texture = texture_2d()

Then you can replace the code to use Color like this:
tex::texture_isvalid(Texture)? tex::lookup_color(Texture, state::texture_coordinate(0)) : Color;

You’ll find the Texture is listed at mdl schema and set value to this input

Thanks

1 Like