Material Scripting

Material Asset Request

The simplest way to get a material from code:

let material = request_material("my_material.material")

Material Creation

See MaterialImport for additional info.

Create a material with the standard shader and red color:

let material = create_material(MaterialImport(
    shaderName = "standard_diffuse_shader",
    properties = MaterialProperties("color", RED_COLOR)
))

The standard shader can be omitted:

let material = create_material(MaterialImport(
    properties = MaterialProperties("color", RED_COLOR)
))

Create a material with a specified diffuse texture and green color:

let noiseTexture = request_texture("%builtin_package/logo.png")
let material = create_material(MaterialImport(
    shaderName = "standard_diffuse_shader",
    diffuse = noiseTexture,
    properties = MaterialProperties("color", GREEN_COLOR)
))

shaderName is the name of a built-in shader, see Shaders. A shader written in the project is a separate resource, pass it as shaderId:

let material = create_material(MaterialImport(
    shaderId = request_shader("shaders/my_shader.shader"),
    properties = MaterialProperties("strength", 0.5)
))

Material Update

update_material changes properties and keeps the rest of the material as is - its shader, its textures and the properties that are not listed:

let material = request_material("my_material.material")

update_material(material, MaterialProperties("color", GREEN_COLOR))

Properties are matched by name, so the same call also rebinds a texture slot or changes the render state:

update_material(material, MaterialProperties("diffuse", request_texture("assets/wood.jpg")))
update_material(material, MaterialProperties("transparencyMode", TransparencyMode.AlphaBlend))

Names of the properties come from the shader: for a built-in shader they are listed on the Shaders page, for a shader written in the project they are the names of its var block. A name the shader does not have is ignored.

A material asset is shared by everything that uses it, so an update is visible on every mesh with that material. It also survives a reload of the asset, and can be called right after request_material, before the asset has finished loading.

To rebuild a material from scratch - to change its shader, for example - use replace_material. It drops everything that is not listed in MaterialImport, including properties set by update_material:

replace_material(material, MaterialImport(
    shaderName = "standard_unlit_shader",
    properties = MaterialProperties("color", GREEN_COLOR)
))

Material Copy

To change a single instance instead of every user of the asset, copy the material first:

let material = request_material("my_material.material")
let team1Material = copy_material(material)
let team2Material = copy_material(material)

update_material(team1Material, MaterialProperties("color", GREEN_COLOR))
update_material(team2Material, MaterialProperties("color", RED_COLOR))

Material Request

There is a way to reduce the number of materials in the scene. You can call request to avoid creating a new material every time. This function will return an already created material if a request with the same settings was called before.

Example:

let materialSettings = MaterialImport(
    properties = MaterialProperties("color", RED_COLOR)
)

let requestedMaterial1 = create_material(materialSettings)
let requestedMaterial2 = create_material(materialSettings)
assert(requestedMaterial1 == requestedMaterial2)

let createdMaterial1 = create_material(materialSettings, MaterialReusePolicy.AlwaysCreateNew)
let createdMaterial2 = create_material(materialSettings, MaterialReusePolicy.AlwaysCreateNew)
assert(createdMaterial1 != createdMaterial2)

Note

Instead of creating multiple materials with different colors, it is better (for render performance) to create one material and use Mesh.setPerInstanceData.