Materials define the way the surfaces of your meshes react to light.
You define materials within a scene. When you create a mesh, you give each of its triangles a material by name. Then, when you create an instance of a mesh within a scene, each of its triangles uses the material in that scene whose name matches the name of the material assigned to it when the mesh was created. See Creating Meshes. You can also override the materials used in each instance of a mesh. See Creating Mesh Instances.
Beast uses a physical rendering system based on shaders expressed in the Open Shading Language (OSL). To customize the way each material interacts with light, you assign it a shader. Depending on the shader you use, you may also be able to set various input parameters (colors, textures, numeric values, etc.) for the material, which are passed to the shader as input values.
Open Shading Language is an open-source shading system developed by Sony Pictures Imageworks for use in major feature films.
For more information, including source code, and a complete language specification that also outlines the library of functions you can use in your shaders, see: https://github.com/imageworks/OpenShadingLanguage
Since OSL was designed for VFX film production, some aspects of it are not relevant for use when baking textures for games. In particular, Beast does not support:
If you find that you need support for these or any other unsupported aspects of OSL, please contact Autodesk Support. See Support.
In order to set up a material, you need to provide a file that contains an OSL shader. A shader can be as simple or as complex as you need in order to express the way your material surface interacts with light to produce its final shading. You can use the sample shader files provided in the shaders sub-directory of the Beast SDK package, or write your own from scratch.
For example, the following code shows a simple shader that multiplies the diffuse closure in OSL with a texture file that is passed as an input parameter:
Surface //< All Beast shaders use the Surface type. diffuseTexture //< A name for this shader. ( string diffuseFile = "" //< An input parameter. [[ string description = "Diffuse texture file" ]] ) //< Anything inside [[ ]] is optional metadata. { Ci = (color)texture (filename, u, v) * diffuse(N); //< Beast expects the shader to set the output //< closure in the Ci variable. }
For a more complex and interesting example, see the beastphong.osl file, which models a Phong-type shading similar to the one used by Beast to render "classic" non-physical materials (see also Creating Classic Materials).
Once you have your shader file ready, you need to:
// Create and initialize the material. ILBMaterialHandle material; ILBCreateMaterial(scene, _T("materialWithShader"), &material); // Create and initialize the shader. ILBShaderHandle diffuseShader; ILBCreateShader(scene, _T("diffuse"), _T("diffuseTexture.osl"), &diffuseShader); // Assign the shader to the material. ILBSetShader(material, diffuseShader); // Create a new texture, and bind it to the material as an input parameter for the shader. // Note that the call to ILBSetShaderParamTexture() specifies the name "diffuseFile", which is the // name of the input parameter in the simple shader file shown above. ILBTextureHandle tex; ILBReferenceTexture(manager, _T("AUniqueName"), _T("C:\textures\wood.exr"), &tex); ILBSetShaderParamTexture(material, _T("diffuseFile"), tex);
Note that this is a very simple example. A more in-depth usage might involve iterating over the attributes accepted by the shader, querying the type of each attribute (float, color, texture, etc.), and binding the necessary values to the material.
For a more complex example, look at the source for the Maya plugin. A Python script is used to extract the attributes accepted by the shader. These attributes are used to set up the BeastOSL node in Maya. The user can set values in the Maya UI. The settings in the Maya node are then queried, parsed, and bound to the material using that shader. See the createMaterial() method in scenemanager.cpp.
You can use the Beast API to set the following types of input parameters for your shaders:
Each of these functions requires a material handle, a string that matches the name of the corresponding input parameter declared in the shader file, and the value that you want to pass to the shader.
Note that the input parameters are bound to a material handle, rather than to the shader handle. This allows you to use the same shader for multiple different kinds of materials, but to specify different input parameters for each of the different materials.
For example, in the examples-physical project, two different materials are created using the same shader, and set up with different parameters:
ILBShaderHandle phongishShader; bex::apiCall(ILBCreateShader(bmh, _T("PhongishShader"), "../../data/phongish.osl", &phongishShader)); ... // Sphere 1 - Textured lambert ILBMaterialHandle sm1; bex::apiCall(ILBCreateMaterial(scene, _T("TexturedLambert"), &sm1)); bex::apiCall(ILBSetShader(sm1, phongishShader)); bex::apiCall(ILBSetShaderParamTexture(sm1, _T("DiffuseTexture"), xorTexture)); bex::apiCall(ILBSetShaderParamColor(sm1, _T("DiffuseColor"), &ILBLinearRGB(0.5f, 0.5f, 1.0f))); bex::apiCall(ILBSetMaterialOverrides(sphereInstances[1], &sm1, 1)); // Sphere 2 - Phongish ILBMaterialHandle sm2; bex::apiCall(ILBCreateMaterial(scene, _T("Phongish"), &sm2)); bex::apiCall(ILBSetShader(sm2, phongishShader)); bex::apiCall(ILBSetShaderParamColor(sm2, _T("DiffuseColor"), &ILBLinearRGB(0.0f, 0.0f, 0.0f))); bex::apiCall(ILBSetShaderParamColor(sm2, _T("SpecularColor"), &ILBLinearRGB(1.0f, 0.0f, 0.0f))); bex::apiCall(ILBSetShaderParamColor(sm2, _T("Shininess"), &ILBLinearRGB(400.0f,400.0f,400.0f))); bex::apiCall(ILBSetMaterialOverrides(sphereInstances[2], &sm2, 1));
Despite using the same shader, the result of rendering the two spheres is very different.
You can create multiple different materials simultaneously in multiple threads. In addition, multiple threads can find materials in the cache and use them simultaneously. You can also modify a single material from multiple different threads at the same time.
API functions related to the creation and setup of materials are declared in the beastmaterial.h file.