The Open Asset Importer Lib 6.0.2
The official Open-Asset-Importer-Library Repository. Loads 40+ 3D-file-formats into one unified and clean data structure.
Loading...
Searching...
No Matches
Material System

Overview

All materials are stored in an array of aiMaterial inside the aiScene.

Each aiMesh refers to one material by its index in the array. Due to the vastly diverging definitions and usages of material parameters there is no hard definition of a material structure. Instead a material is defined by a set of properties accessible by their names. Have a look at assimp/material.h to see what types of properties are defined. In this file there are also various functions defined to test for the presence of certain properties in a material and retrieve their values.

Textures

Textures are organized in stacks, each stack being evaluated independently. The final color value from a particular texture stack is used in the shading equation. For example, the computed color value of the diffuse texture stack (aiTextureType_DIFFUSE) is multiplied with the amount of incoming diffuse light to obtain the final diffuse color of a pixel.

Stack Resulting equation
------------------------
| Constant base color | color
------------------------
| Blend operation 0 | +
------------------------
| Strength factor 0 | 0.25*
------------------------
| Texture 0 | texture_0
------------------------
| Blend operation 1 | *
------------------------
| Strength factor 1 | 1.0*
------------------------
| Texture 1 | texture_1
------------------------
... ...

Constants

All material key constants start with 'AI_MATKEY' (it's an ugly macro for historical reasons, don't ask).

NameData TypeDefault ValueMeaningNotes
NAMEaiStringn/aThe name of the material, if available. Ignored by aiProcess_RemoveRedundantMaterials. Materials are considered equal even if their names are different.
COLOR_DIFFUSEaiColor3Dblack (0,0,0)Diffuse color of the material. This is typically scaled by the amount of incoming diffuse light (e.g. using gouraud shading)
COLOR_SPECULARaiColor3Dblack (0,0,0)Specular color of the material. This is typically scaled by the amount of incoming specular light (e.g. using phong shading)
COLOR_AMBIENTaiColor3Dblack (0,0,0)Ambient color of the material. This is typically scaled by the amount of ambient light
COLOR_EMISSIVEaiColor3Dblack (0,0,0)Emissive color of the material. This is the amount of light emitted by the object. In real time applications it will usually not affect surrounding objects, but raytracing applications may wish to treat emissive objects as light sources.
COLOR_TRANSPARENTaiColor3Dblack (0,0,0)Defines the transparent color of the material, this is the color to be multiplied with the color of translucent light to construct the final 'destination color' for a particular position in the screen buffer.
COLOR_REFLECTIVEaiColor3Dblack (0,0,0)Defines the reflective color of the material. This is typically scaled by the amount of incoming light from the direction of mirror reflection. Usually combined with an environment lightmap of some kind for real-time applications.
REFLECTIVITYfloat0.0Scales the reflective color of the material.
WIREFRAMEintfalseSpecifies whether wireframe rendering must be turned on for the material. 0 for false, !0 for true.
TWOSIDEDintfalseSpecifies whether meshes using this material must be rendered without backface culling. 0 for false, !0 for true. Some importers set this property if they don't know whether the output face order is right. As long as it is not set, you may safely enable backface culling.
SHADING_MODELintgouraudOne of the #aiShadingMode enumerated values. Defines the library shading model to use for (real time) rendering to approximate the original look of the material as closely as possible. The presence of this key might indicate a more complex material. If absent, assume phong shading only if a specular exponent is given.
BLEND_FUNCintfalseOne of the #aiBlendMode enumerated values. Defines how the final color value in the screen buffer is computed from the given color at that position and the newly computed color from the material. Simply said, alpha blending settings.-
OPACITYfloat1.0Defines the opacity of the material in a range between 0..1.Use this value to decide whether you have to activate alpha blending for rendering. OPACITY != 1 usually also implies TWOSIDED=1 to avoid cull artifacts.
SHININESSfloat0.fDefines the shininess of a phong-shaded material. This is actually the exponent of the phong specular equationSHININESS=0 is equivalent to SHADING_MODEL=aiShadingMode_Gouraud.
SHININESS_STRENGTHfloat1.0Scales the specular color of the material.This value is kept separate from the specular color by most modelers, and so do we.
REFRACTIfloat1.0Defines the Index Of Refraction for the material. That's not supported by most file formats.Might be of interest for raytracing.
TEXTURE(t,n)aiStringn/aDefines the path of the n'th texture on the stack 't', where 'n' is any value >= 0 and 't' is one of the #aiTextureType enumerated values. A file path to an external file or an embedded texture. Use aiScene::GetEmbeddedTexture to test if it is embedded for FBX files, in other cases embedded textures start with '*' followed by an index into aiScene::mTextures.See the Textures section above. Also see Textures for a more information about texture retrieval.
TEXBLEND(t,n)floatn/aDefines the strength the n'th texture on the stack 't'. All color components (rgb) are multiplied with this factor before any further processing is done.-
TEXOP(t,n)intn/aOne of the #aiTextureOp enumerated values. Defines the arithmetic operation to be used to combine the n'th texture on the stack 't' with the n-1'th. TEXOP(t,0) refers to the blend operation between the base color for this stack (e.g. COLOR_DIFFUSE for the diffuse stack) and the first texture.-
MAPPING(t,n)intn/aDefines how the input mapping coordinates for sampling the n'th texture on the stack 't' are computed. Usually explicit UV coordinates are provided, but some model file formats might also be using basic shapes, such as spheres or cylinders, to project textures onto meshes.See the 'Textures' section below. #aiProcess_GenUVCoords can be used to let Assimp compute proper UV coordinates from projective mappings.
UVWSRC(t,n)intn/aDefines the UV channel to be used as input mapping coordinates for sampling the n'th texture on the stack 't'. All meshes assigned to this material share the same UV channel setupPresence of this key implies MAPPING(t,n) to be #aiTextureMapping_UV. See How to map UV channels to textures (MATKEY_UVWSRC) for more details.
MAPPINGMODE_U(t,n)intn/aAny of the #aiTextureMapMode enumerated values. Defines the texture wrapping mode on the x axis for sampling the n'th texture on the stack 't'. 'Wrapping' occurs whenever UVs lie outside the 0..1 range. -
MAPPINGMODE_V(t,n)intn/aWrap mode on the v axis. See MAPPINGMODE_U. -
TEXMAP_AXIS(t,n)aiVector3Dn/aDefines the base axis to to compute the mapping coordinates for the n'th texture on the stack 't' from. This is not required for UV-mapped textures. For instance, if MAPPING(t,n) is #aiTextureMapping_SPHERE, U and V would map to longitude and latitude of a sphere around the given axis. The axis is given in local mesh space.-
TEXFLAGS(t,n)intn/aDefines miscellaneous flag for the n'th texture on the stack 't'. This is a bitwise combination of the #aiTextureFlags enumerated values.-

C++-API

Retrieving a property from a material is done using various utility functions. For C++ it's simply calling aiMaterial::Get()

aiMaterial* mat = .....
// The generic way
if(AI_SUCCESS != mat->Get(<material-key>,<where-to-store>)) {
// handle epic failure here
}

Simple, isn't it? To get the name of a material you would use

aiString name;
mat->Get(AI_MATKEY_NAME,name);

Or for the diffuse color ('color' won't be modified if the property is not set)

aiColor3D color (0.f,0.f,0.f);
mat->Get(AI_MATKEY_COLOR_DIFFUSE,color);

Note: Get() is actually a template with explicit specializations for aiColor3D, aiColor4D, aiString, float, int and some others. Make sure that the type of the second parameter matches the expected data type of the material property (no compile-time check yet!). Don't follow this advice if you wish to encounter very strange results.

C-API

For good old C it's slightly different. Take a look at the aiGetMaterialGet<data-type> functions.

aiMaterial* mat = .....
if(AI_SUCCESS != aiGetMaterialFloat(mat,<material-key>,<where-to-store>)) {
// handle epic failure here
}

To get the name of a material you would use

aiString name;
aiGetMaterialString(mat,AI_MATKEY_NAME,&name);

Or for the diffuse color ('color' won't be modified if the property is not set)

aiColor3D color (0.f,0.f,0.f);
aiGetMaterialColor(mat,AI_MATKEY_COLOR_DIFFUSE,&color);

How to map UV channels to textures (MATKEY_UVWSRC)

The MATKEY_UVWSRC property is only present if the source format doesn't specify an explicit mapping from textures to UV channels. Many formats don't do this and assimp is not aware of a perfect rule either.

Your handling of UV channels needs to be flexible therefore. Our recommendation is to use logic like this to handle most cases properly:

have only one uv channel?
   assign channel 0 to all textures and break

for all textures
   have uvwsrc for this texture?
      assign channel specified in uvwsrc
   else
      assign channels in ascending order for all texture stacks,
      i.e. diffuse1 gets channel 1, opacity0 gets channel 0.

Pseudo Code Listing

For completeness, the following is a very rough pseudo-code sample showing how to evaluate Assimp materials in your shading pipeline. You'll probably want to limit your handling of all those material keys to a reasonable subset suitable for your purposes (for example most 3d engines won't support highly complex multi-layer materials, but many 3d modellers do).

Also note that this sample is targeted at a (shader-based) rendering pipeline for real time graphics.

// ---------------------------------------------------------------------------------------
// Evaluate multiple textures stacked on top of each other
float3 EvaluateStack(stack)
{
// For the 'diffuse' stack stack.base_color would be COLOR_DIFFUSE
// and TEXTURE(aiTextureType_DIFFUSE,n) the n'th texture.
float3 base = stack.base_color;
for (every texture in stack)
{
// assuming we have explicit & pretransformed UVs for this texture
float3 color = SampleTexture(texture,uv);
// scale by texture blend factor
color *= texture.blend;
if (texture.op == add)
base += color;
else if (texture.op == multiply)
base *= color;
else // other blend ops go here
}
return base;
}
// ---------------------------------------------------------------------------------------
// Compute the diffuse contribution for a pixel
float3 ComputeDiffuseContribution()
{
if (shading == none)
return float3(1,1,1);
float3 intensity (0,0,0);
for (all lights in range)
{
float fac = 1.f;
if (shading == gouraud)
fac = lambert-term ..
else // other shading modes go here
// handling of different types of lights, such as point or spot lights
// ...
// and finally sum the contribution of this single light ...
intensity += light.diffuse_color * fac;
}
// ... and combine the final incoming light with the diffuse color
return EvaluateStack(diffuse) * intensity;
}
// ---------------------------------------------------------------------------------------
// Compute the specular contribution for a pixel
float3 ComputeSpecularContribution()
{
if (shading == gouraud || specular_strength == 0 || specular_exponent == 0)
return float3(0,0,0);
float3 intensity (0,0,0);
for (all lights in range)
{
float fac = 1.f;
if (shading == phong)
fac = phong-term ..
else // other specular shading modes go here
// handling of different types of lights, such as point or spot lights
// ...
// and finally sum the specular contribution of this single light ...
intensity += light.specular_color * fac;
}
// ... and combine the final specular light with the specular color
return EvaluateStack(specular) * intensity * specular_strength;
}
// ---------------------------------------------------------------------------------------
// Compute the ambient contribution for a pixel
float3 ComputeAmbientContribution()
{
if (shading == none)
return float3(0,0,0);
float3 intensity (0,0,0);
for (all lights in range)
{
float fac = 1.f;
// handling of different types of lights, such as point or spot lights
// ...
// and finally sum the ambient contribution of this single light ...
intensity += light.ambient_color * fac;
}
// ... and combine the final ambient light with the ambient color
return EvaluateStack(ambient) * intensity;
}
// ---------------------------------------------------------------------------------------
// Compute the final color value for a pixel
// @param prev Previous color at that position in the framebuffer
float4 PimpMyPixel (float4 prev)
{
// .. handle displacement mapping per vertex
// .. handle bump/normal mapping
// Get all single light contribution terms
float3 diff = ComputeDiffuseContribution();
float3 spec = ComputeSpecularContribution();
float3 ambi = ComputeAmbientContribution();
// .. and compute the final color value for this pixel
float3 color = diff + spec + ambi;
float3 opac = EvaluateStack(opacity);
// note the *slightly* strange meaning of additive and multiplicative blending here ...
// those names will most likely be changed in future versions
if (blend_func == add)
return prev+color*opac;
else if (blend_func == multiply)
return prev*(1.0-opac)+prev*opac;
return color;
}

How to access shader-code from a texture (AI_MATKEY_GLOBAL_SHADERLANG and AI_MATKEY_SHADER_VERTEX, ...)

You can get assigned shader sources by using the following material keys:

AI_MATKEY_GLOBAL_SHADERLANGTo get the used shader language. AI_MATKEY_SHADER_VERTEX Assigned vertex shader code stored as a string. AI_MATKEY_SHADER_FRAGMENT Assigned fragment shader code stored as a string. AI_MATKEY_SHADER_GEO Assigned geometry shader code stored as a string. AI_MATKEY_SHADER_TESSELATION Assigned tessellation shader code stored as a string. AI_MATKEY_SHADER_PRIMITIVE Assigned primitive shader code stored as a string. AI_MATKEY_SHADER_COMPUTE Assigned compute shader code stored as a string.