Skip to main content
Material definitions are text files that describe all the information required by a material, including shader code, parameters, and rendering state.

Material Definition Format

Filament uses a JSON-like format called “JSONish” for material definitions. A material definition consists of three main blocks:
material {
    // material properties
}

vertex {
    // vertex shader code (optional)
}

fragment {
    // fragment shader code (required)
}

Differences from JSON

  • Quotes around strings are optional (unless the string contains spaces)
  • Single-line C++-style comments are allowed
  • Keys are case-sensitive, values are not
  • The vertex and fragment blocks contain unescaped GLSL code

Basic Material Example

Here’s a simple textured material:
material {
    name : "Textured material",
    shadingModel : lit,
    parameters : [
        {
            type : sampler2d,
            name : texture
        },
        {
            type : float,
            name : metallic
        },
        {
            type : float,
            name : roughness
        }
    ],
    requires : [
        uv0
    ]
}

fragment {
    void material(inout MaterialInputs material) {
        prepareMaterial(material);
        material.baseColor = texture(materialParams_texture, getUV0());
        material.metallic = materialParams.metallic;
        material.roughness = materialParams.roughness;
    }
}

Material Block Properties

General Properties

name

material {
    name : "My Material"  // or just: name : stone
}
Sets the name of the material for debugging purposes.

shadingModel

material {
    shadingModel : lit  // or subsurface, cloth, unlit, specularGlossiness
}
Selects the material model. Defaults to lit.

featureLevel

material {
    featureLevel : 2  // 1, 2, or 3 (default: 1)
}
Sets the feature level:
  • Level 1: 9 textures per material
  • Level 2: 9 textures, cubemap arrays, ESSL 3.10
  • Level 3: 12 textures, cubemap arrays, ESSL 3.10

Parameters

Define user-controllable parameters that can be set at runtime:
material {
    parameters : [
        {
            type : float3,
            name : baseColor
        },
        {
            type : sampler2d,
            name : albedoMap,
            precision : high
        },
        {
            type : float,
            name : roughness
        }
    ]
}

Parameter Types

Scalar and Vector Types:
  • bool, bool2, bool3, bool4
  • int, int2, int3, int4
  • uint, uint2, uint3, uint4
  • float, float2, float3, float4
Matrix Types:
  • float3x3, float4x4
Sampler Types:
  • sampler2d - 2D texture
  • sampler2dArray - Array of 2D textures
  • samplerExternal - External texture (platform-specific)
  • samplerCubemap - Cubemap texture
Arrays: Append [size] to create arrays:
{
    type : float[9],
    name : coefficients
}

Accessing Parameters

In shaders:
  • Samplers: Use materialParams_ prefix
  • Other types: Use materialParams. structure
fragment {
    void material(inout MaterialInputs material) {
        prepareMaterial(material);
        // Sampler access
        material.baseColor = texture(materialParams_albedoMap, getUV0());
        // Parameter access
        material.roughness = materialParams.roughness;
    }
}

Constants

Constants are specialized at material load time and cannot be changed:
material {
    constants : [
        {
            name : overrideAlpha,
            type : bool
        },
        {
            name : customAlpha,
            type : float,
            default : 0.5
        }
    ]
}

fragment {
    void material(inout MaterialInputs material) {
        prepareMaterial(material);
        if (materialConstants_overrideAlpha) {
            material.baseColor.a = materialConstants_customAlpha;
        }
    }
}
Access constants with materialConstants_ prefix.

Required Attributes

Specify which vertex attributes your material needs:
material {
    requires : [
        uv0,      // First UV set
        uv1,      // Second UV set
        color,    // Vertex colors
        tangents, // Tangents (auto-required for lit models)
        custom0,  // Custom attribute 0
        custom1   // Custom attributes 0-7
    ]
}
The position attribute is always required. The tangents attribute is automatically required for all shading models except unlit.

Variables (Interpolants)

Define custom data to pass from vertex to fragment shader:
material {
    variables : [
        eyeDirection,
        {
            name : eyeColor,
            precision : medium
        }
    ]
}

vertex {
    void materialVertex(inout MaterialVertexInputs material) {
        material.eyeDirection.xyz = /* calculate direction */;
    }
}

fragment {
    void material(inout MaterialInputs material) {
        prepareMaterial(material);
        // Access with variable_ prefix
        vec3 dir = variable_eyeDirection.xyz;
    }
}
Up to 5 variables (4 if color attribute is used). Each is a float4.

Blending Modes

material {
    blending : opaque  // or transparent, fade, add, masked, multiply, screen
}
ModeDescription
opaqueNo blending, alpha ignored
transparentAlpha compositing with pre-multiplied alpha
fadeTransparency applied to both diffuse and specular
addAdditive blending
maskedAlpha masking with threshold
multiplyMultiply blending (darkening)
screenScreen blending (brightening)

Rasterization State

material {
    culling : back,        // none, front, back, frontAndBack
    colorWrite : true,     // Enable/disable color writes
    depthWrite : true,     // Enable/disable depth writes
    depthCulling : true,   // Enable/disable depth testing
    doubleSided : false    // Two-sided rendering
}

Transparency Options

material {
    transparency : default,  // default, twoPassesOneSide, twoPassesTwoSides
    maskThreshold : 0.4,     // Alpha threshold for masked mode
    refractionMode : none,   // none, cubemap, screenspace
    refractionType : solid   // solid, thin
}

Fragment Block

The fragment block is required and must implement the material() function:
fragment {
    void material(inout MaterialInputs material) {
        prepareMaterial(material);
        
        // Set material properties
        material.baseColor.rgb = vec3(1.0, 0.0, 0.0);
        material.metallic = 1.0;
        material.roughness = 0.3;
    }
}

Important Rules

  1. Always call prepareMaterial() before returning
  2. Set normal before calling prepareMaterial() if using normal mapping
  3. Set other properties after prepareMaterial()

Normal Mapping Example

fragment {
    void material(inout MaterialInputs material) {
        // Fetch and set normal BEFORE prepareMaterial
        vec3 normal = texture(materialParams_normalMap, getUV0()).xyz;
        material.normal = normal * 2.0 - 1.0;
        
        // NOW call prepareMaterial
        prepareMaterial(material);
        
        // Set other properties
        material.baseColor.rgb = vec3(1.0, 0.0, 0.0);
        material.roughness = 0.5;
    }
}

Vertex Block (Optional)

The vertex block allows custom vertex transformations:
material {
    requires : [uv0, color],
    variables : [customData]
}

vertex {
    void materialVertex(inout MaterialVertexInputs material) {
        // Modify attributes
        material.color *= sin(getUserTime().x);
        material.uv0 *= 2.0;
        
        // Set custom variables
        material.customData = vec4(material.worldPosition.xyz, 1.0);
    }
}

Complete Examples

Lit Material with Textures

material {
    name : "PBR Textured",
    shadingModel : lit,
    requires : [uv0],
    parameters : [
        { type : sampler2d, name : albedo },
        { type : sampler2d, name : roughness },
        { type : sampler2d, name : metallic },
        { type : sampler2d, name : normal },
        { type : sampler2d, name : ao }
    ]
}

fragment {
    void material(inout MaterialInputs material) {
        vec2 uv = getUV0();
        
        // Normal mapping before prepareMaterial
        material.normal = texture(materialParams_normal, uv).xyz * 2.0 - 1.0;
        
        prepareMaterial(material);
        
        material.baseColor = texture(materialParams_albedo, uv);
        material.roughness = texture(materialParams_roughness, uv).r;
        material.metallic = texture(materialParams_metallic, uv).r;
        material.ambientOcclusion = texture(materialParams_ao, uv).r;
    }
}

Cloth Material

material {
    name : "Fabric",
    shadingModel : cloth,
    parameters : [
        { type : float3, name : baseColor },
        { type : float, name : roughness },
        { type : float3, name : sheenColor },
        { type : float3, name : subsurfaceColor }
    ],
    specularAntiAliasing : true
}

fragment {
    void material(inout MaterialInputs material) {
        prepareMaterial(material);
        material.baseColor.rgb = materialParams.baseColor;
        material.roughness = materialParams.roughness;
        material.sheenColor = materialParams.sheenColor;
        material.subsurfaceColor = materialParams.subsurfaceColor;
    }
}

Unlit Material

material {
    name : "UI Element",
    shadingModel : unlit,
    blending : transparent,
    depthWrite : false,
    parameters : [
        { type : sampler2d, name : texture },
        { type : float4, name : color }
    ],
    requires : [uv0]
}

fragment {
    void material(inout MaterialInputs material) {
        prepareMaterial(material);
        material.baseColor = texture(materialParams_texture, getUV0());
        material.baseColor *= materialParams.color;
    }
}

Next Steps

Build docs developers (and LLMs) love