The Material Controller

Managing materials (see RED::IMaterial, RED::Shader, RED::RenderShader and RED::StateShader for instance) can be a complicated task, mainly when it comes to modifying shader parameter values. Some materials can have a big number of shaders, each one handling several parameters. Moreover, a user working with those materials needs to have a precise knowledge of how they were built. To overcome those difficulties in handling complex RED materials, HOOPS Luminate introduced the concept of material controller.

A material controller is an interface to an object who knows how a high-level, user-friendly parameter can be turned into underlying material shader parameter values. This way, anyone can build RED materials and give others access to them through comprehensive material controllers.

How Does the Material Controller Work?

Material controllers are additional data and do not modify new or existing RED materials. One can create a material controller using the RED::Factory::CreateMaterialController method. Each material controller is created for a given material and is automatically registered to the RED::IResourceManager.

It may be useful to fill some information about the controller at creation time:

  • Category

  • Sub-category

  • Name

  • Description

  • Author

  • Material’s thumbnail

  • Creation date

  • HOOPS Luminate version

That information will be later accessible through the RED::IMaterialController interface. For example, the Redmaterials catalog uses that information to display a complete description of each material.

Hints

Some additional information can be freely added by the user to a material controller using hints (RED::IMaterialController::AddHint and RED::IMaterialController::GetHint). Hints are custom strings that can be added to a controller to best describe it. Any number of hints can be added to a controller and they are automatically saved (or load) to .red files. For example, in Redmaterials, hints are added to textured materials to inform users about the needed mesh channel bindings (which channels are used and why).

../../../_images/material_library_011.png

The Redmaterial library displays material informations, hints and material properties

For a given material, we can retrieve its associated controller by calling RED::IResourceManager::GetMaterialController. We can also remove a registered controller by calling RED::IResourceManager::UnregisterMaterialController.

The Material Controller Property

The most interesting part of the controller is the set of methods letting you manage high-level material properties. As many properties as wanted can be added to a controller by calling the RED::IMaterialController::AddProperty method (and retrieved using the RED::IMaterialController::GetProperty method). The RED::IMaterialControllerProperty interface lets you set and get information about a property.

A property is a typed variable associated to a script. Its type can be any of the following:

  • float

  • integer

  • boolean

  • color (RED::Color)

  • 4d vector (RED::Vector4)

  • string (RED::String)

  • texture 2d (RED::IImage2D)

  • texture 3d (RED::IImage3D)

  • texture cube (RED::IImageCube)

Each time a property value is modified, the associated script is executed. The aim of the script is to translate property edition operations into RED material shader parameter values.

Properties are implicitly typed each time their values are set using one of the RED::IMaterialControllerProperty value assignment method. The language used to write material controller’s property script is called MCSL (for Material Controller Scripting Language) and is fully described later on (see The Material Controller Scripting Language).

Saving a material to a .red file will automatically save the associated controller as long as the streaming policy has its material-controller-auto-saving flag set to true (using RED::StreamingPolicy::SetMaterialControllerAutoSaving) which is the default value.

Enumerating a Material Controller’s Properties

Enumerating the properties of a controller is simple. First, one needs to get the controller from a given material:

// iresmgr is the resource manager.
// mat is a material.

// Get the material controller from the material.
RED::Object* matctrl = iresmgr->GetMaterialController( mat );
RED::IMaterialController* imatctrl = matctrl->As< RED::IMaterialController >();

Then, the controller property gives access to its number of properties via the RED::IMaterialController::GetPropertiesCount method and to its properties by index or by name with the RED::IMaterialController::GetProperty function:

// Get the number of properties.
unsigned int count = imatctrl->GetPropertiesCount();

// Loop through the properties.
for( unsigned int i = 0; i < count; ++i )
{
    // Get the property.
    RED::Object* prop = imatctrl->GetProperty( i );
    RED::IMaterialControllerProperty* iprop = prop->As< RED::IMaterialControllerProperty >();

    // Get the type of the property.
    RED::PROPERTY_TYPE type = iprop->GetType();

    // Do something according to the property type.
    switch( type )
    {
        case RED::PYT_FLOAT:
        {
            float value = iprop->GetFloatValue();
        // Do something...
        RC_TEST( iprop->SetFloatValue( value, iresmgr->GetState() ) );
        break;
        }
        case RED::PYT_COLOR:
        {
            RED::Color color = iprop->GetColor();
            // Do something...
            RC_TEST( iprop->SetColor( color, iresmgr->GetState() ) );
            break;
        }
        case RED::PYT_TEXTURE2D:
        {
            const RED::Object* texture = iprop->GetTexture();
            const RED::IImage2D* itexture = texture->As< RED::IImage2D >();
            // Do something...
            break;
        }
        // etc.
    }
}

Merging Material Controllers

With HOOPS Luminate, it is possible to merge two material controllers. Merging material controllers is very useful for instance when different similar materials have been created for different style of rendering (real-time and realistic). One will have the possibility to make a single material handling different layersets and merge their controllers.

The merge operation is done using the RED::IMaterialController::Merge method. It merges two controllers into a single one. The method adds the properties (RED::IMaterialControllerProperty) and hints of the input controller to the callee using the following rules:

  • any property of the input controller not found in the callee will be added to it

  • any property with the same name and type but different scripts will be merged. Scripts will be concatenated

  • any property with the same name, type and script will be discarded

  • any property with the same name but different types will make the function fail

  • any hint of the input controller not found in the callee will be added to it

  • any hint with the same name and types will be discarded

  • any hint of the input controller with the same name but different type will be added to the callee with a different name. A ‘_2’ string is added at the end of the name