Material Library Overview

1.0 Material Library

The Material Library offers a way to rapidly load, maintain, manipulate and customized sophisticated materials in the HOOPS 3DF environment. The Material Library consists of two main components: HMaterialLibrary and Material Resources. To interact with the Material Library, use the HMaterialLibrary class. This class works in conjunction with the Material Library resources package that can be downloaded from the Developer Zone. The Material Resources package is a collection of materials and environments developed by a team of artists, shader experts, and engineering industry veterans. You can learn more about the collection of materials in our Material Resources section.

The HMaterialLibrary class works in concert with the resource package to give you the ability to enhance the visual appearance of your 3D models in a dynamic and highly interactive way. Complex and sophisticated materials can be loaded into the library rapidly. Once imported into the library, materials can be customized.

NOTE: In general, materials can only be applied to shells. Other geometry such as polygons and primitives can have some basic attributes (such as color) applied at the segment level but cannot use the more advanced materials such as textures and shaders.

2.0 HMaterialLibrary

The HMaterialLibrary class load and maintains materials in the Material Library. It exposes methods to manipulate and apply materials to models. To load materials into the Material Library and apply them to a model, follow these simple steps:

MaterialLibrary.png
The figure shows the Material Library workflow as detailed by the steps below.

  1. Register Materials: To begin using the Material Library, you must register your materials by calling HMaterialLibrary::RegisterMaterials and passing the directory where your materials reside.
  2. Get Material and Environment Lists: Once you have completed registration, you can find which materials and environments are currently in the Material Library with calls to HMaterialLibrary::GetMaterialList and HMaterialLibrary::GetEnvironmentList, respectively.
  3. Set the Environment: Any number of environments can exist in the Material library. However, there can be only one current environment. Use the HMaterialLibrary::SetEnvironment method to specify the environment to use for your materials.
  4. Apply Styles: Currently for a model to receive the lighting information found in an environment, the user must call HMaterialLibrary::ApplyStyles on the top level segment of the model segment tree.
  5. Applying Materials to a Model: To apply a specific material to a segment, open the segment and call HMaterialLibrary::ApplyMaterial passing the name of the material.
  6. Render Scene: Now we can call HC_Update_Display to see the changes to our model.

The following code sample show how these steps might be implemented:

    HMaterialLibrary hmat;
    
    const char *material_name = "car_panel_walnut";
    const char *environment_name = "environment_snow";

    /*************************/
    /* 1. Register Materials */
    /*************************/
    hmat.RegisterMaterials (H_FORMAT_TEXT ("%s%s", "C:/HOOPS-1800/datasets/", "materials"));
    
    /***************************************/
    /* 2. Get Material & Environment Lists */
    /***************************************/
    const char *list = hmat.GetMaterialList();
    if (list == NULL)
        return;

    const char *env_list = hmat.GetEnvironmentList();
    if (env_list == NULL)
        return;

    //checking if the environment_snow is in the materials library
    if (strstr(env_list, environment_name) == NULL)
        return;

    /**********************/
    /* 3. Set Environment */
    /**********************/
    hmat.SetEnvironment (environment_name);

    HC_Open_Segment_By_Key(m_pHView->GetModelKey()); {
        HC_Set_Color ("faces = green, text = red");
        HC_Set_Visibility ("faces, no edges, no vertices");
        
        //checking if the car_panel_walnut is in the materials library
        if (strstr(list, material_name) == NULL)
                return;
        HC_Open_Segment (""); {
            /*******************/
            /* 4. Apply Styles */
            /*******************/
            hmat.ApplyStyles();
            HC_POINT center = { 1, 1, 1 };
            HC_Insert_Sphere(center, 2, NULL, NULL );
            
            /*********************/
            /* 5. Apply Material */
            /*********************/
            hmat.ApplyMaterial (material_name);
            
        } 
        HC_Close_Segment ();

    } 
    HC_Close_Segment ();

    /*******************/
    /* 6. Render Scene */
    /*******************/
    HC_Update_Display();

2.1 Using Environments With Materials

In the Material Library, you can load any number of environments. However, only one environment takes effect in a scene. To set the current environment, call HMaterialLibrary::SetEnvironment passing the name of the environment. Recall that the name of an environment, like a material, is the name of the directory in which the environment_index.dat file and associated resources reside. Then open the top level segment of your model's segment tree and call HMaterialLibrary::ApplyStyles. This will ensure that any lighting information defined in the enviroment will be used in the scene. Once you set this information, subsequent calls to HMaterialLibrary::ApplyMaterial will use the environment currently set.

CHANNEL: ENVIRONMENT
SOURCE: environment2

The record above does not name a specific environment name. Instead it specificies which cubemap to use for a given environment. Naming the cube map allows you the flexibilty to change environments on demand.

Let's take a look at an example of how this flexiblity in specifying an environment can be useful. Let's say you have a car model. If you have defined a material like car paint, you might want to apply the paint to a car that is in the mountains or a canyon. Both the mountains and canyon environments have cubemaps for a sunny day and stormy weather identified as CUBEMAP0 and CUBEMAP1, respectively. The following is how the enviroment_index.dat might look for the mountains environment:

CHANNEL: CUBEMAP0
SOURCE: sunny

CHANNEL: CUBEMAP1
SOURCE: stormy

If your goal is to show off the car paint, then you will want to use the cube map that depicts sunny weather (you might use the stormy weather environment in an animation that shows how your car model has excellent handling with its all-weather tires). Thus your material specification would include this record for the environment specification:

CHANNEL: ENVIRONMENT
SOURCE: environment0

During application usage, whether the environment is mountains or canyon, the cube map that reflects off the car paint is the sunny weather cube map.

2.2 Dynamic Loading and Interaction

One of the most useful features of the Materail Library is its dynamic loading capability. In the Material Library, you can load a material and use it in your scene. If the material's resources and/or the shader code changes, you can update the directory with the new files and call HMaterialLibrary::ReloadMaterial passing the material name. At render time, the changes will be reflected in the scene with no need for recompiling.

2.3 Tweakables

Another capability of the HMaterialLibrary is to change the default values of specific variables in customer shader code dynamically. These variables are called tweakables. For example, let's say we have a material called brass. Once we load the brass material, we can access whether brass has a tweakable variable and then change its default value. The example below shows how a variable can be tweaked via methods in the HMaterialLibrary:

    HMaterialLibrary hmat;
    
    const char *material_name = "brass";
    const char *environment_name = "environment_snow";
    char tweakable_name[512], tweakable_type[64];
    int tweakable_count = 0;


    //register materials
    hmat.RegisterMaterials (H_FORMAT_TEXT ("%s%s", "C:/HOOPS-1900/datasets/", "materials"));
    const char *list = hmat.GetMaterialList();
    if (list == NULL)
        return;

    //checking if the environment_snow is in the materials library
    const char *env_list = hmat.GetEnvironmentList();
    if (env_list == NULL)
        return;
    if (strstr(env_list, environment_name) == NULL)
        return;

    //setting the current environment to environment_snow
    hmat.SetEnvironment (environment_name);

    HC_Open_Segment_By_Key(m_pHView->GetModelKey()); {
        HC_Set_Color ("faces = green, text = red");
        HC_Set_Visibility ("faces, no edges, no vertices");
        
        //checking if brass is in the material library
        if (strstr(list, material_name) == NULL)
                return;
        HC_Open_Segment (""); {
            hmat.ApplyStyles();
            HPoint center(0,0,0);
            HPoint axis(0,1,0);
            HPoint ref(0,0,1);
            HUtilityGeometryCreation::CreateSphere(center, 1.0,20,axis,ref);
            hmat.ApplyMaterial (material_names[0]);
            
            //Seeing if there are any tweakable values in the brass material
            if (!hmat.GetTweakablesCount (material_name, &tweakables_count))
                return;
    
            for (i = 0 ; i < tweakables_count ; i++) {
                if (hmat.GetTweakableByIndex (material_name, i, tweakable_name, tweakable_type)) {
                    //looking for the my_tweak variable
                    if (streq (tweakable_name, "my_tweak")) {
                                //Changing the default value of the my_tweak variable
                                if (!hmat.Tweak (material_name, i, 1.0, 1.0, 1.0))
                                    return;
                    }
                }
            }

        } HC_Close_Segment ();

    } HC_Close_Segment ();

    HC_Update_Display();

In the code above, we use several key methods in HMaterialLibrary to change the my_tweak variable. To begin, we first find out if there are any tweakable variables for a given material using the HMaterialLibrary::GetTweakablesCount. If it returns a number greater than zero, then we can iterate through the tweakable variable list using HMaterialLibrary::GetTweakableByIndex to find our my_tweak variable and the tweakable_type of variable it is. The tweakable_type tells us how many values we can change. For my_tweak, it is float3. So when we called HMaterialLibrary::Tweak, we know change three float values for the my_tweak variable.