tiramisu/material

Materials define how surfaces are rendered and interact with light.

Materials control the visual appearance of 3D objects - their color, shininess, texture, and how they respond to lighting. Different material types offer different trade-offs between visual quality and performance.

Material Types

Builder Pattern (Recommended)

let assert Ok(metal) = material.new()
  |> material.with_color(0xcccccc)
  |> material.with_metalness(1.0)
  |> material.with_roughness(0.3)
  |> material.build()

Textures

Load and apply textures for detailed surfaces:

let assert Ok(tex) = texture.load(...)

material.new()
  |> material.with_color(0xffffff)
  |> material.with_color_map(tex)
  |> material.with_normal_map(normal_tex)
  |> material.build()

Transparency

material.new()
  |> material.with_color(0x88ccff)
  |> material.with_transparent(True)
  |> material.with_opacity(0.5)
  |> material.build()

Emissive (Glow)

material.new()
  |> material.with_emissive(0xff0000)
  |> material.with_emissive_intensity(1.0)
  |> material.build()

Types

Material types for rendering objects.

Materials define how surfaces appear when rendered. Different materials have different performance characteristics and visual properties.

Performance

  • BasicMaterial: Fastest, no lighting calculations
  • LambertMaterial, ToonMaterial: Fast, simple lighting
  • PhongMaterial: Medium, specular highlights
  • StandardMaterial: Physically-based, most realistic but slower
pub opaque type Material
pub type MaterialError {
  OutOfBoundsColor(Int)
  OutOfBoundsOpacity(Float)
  OutOfBoundsRoughness(Float)
  OutOfBoundsMetalness(Float)
  NonPositiveLinewidth(Float)
  NonPositiveShininess(Float)
  OutOfBoundsEmissive(Int)
  OutOfBoundsEmissiveIntensity(Float)
}

Constructors

  • OutOfBoundsColor(Int)
  • OutOfBoundsOpacity(Float)
  • OutOfBoundsRoughness(Float)
  • OutOfBoundsMetalness(Float)
  • NonPositiveLinewidth(Float)
  • NonPositiveShininess(Float)
  • OutOfBoundsEmissive(Int)
  • OutOfBoundsEmissiveIntensity(Float)

Which sides of geometry to render.

pub type MaterialSide {
  FrontSide
  BackSide
  DoubleSide
}

Constructors

  • FrontSide
  • BackSide
  • DoubleSide

Builder for standard (PBR) materials with sensible defaults.

Use this opaque type with the builder functions to construct StandardMaterials using a fluent interface.

pub opaque type StandardMaterialBuilder

Values

pub fn basic(
  color color: Int,
  transparent transparent: Bool,
  opacity opacity: Float,
  map map: option.Option(savoiardi.Texture),
  side side: MaterialSide,
  alpha_test alpha_test: Float,
  depth_write depth_write: Bool,
) -> Result(Material, MaterialError)

Create a validated basic (unlit) material.

Basic materials don’t react to lights, making them very fast to render. Opacity must be between 0.0 (fully transparent) and 1.0 (fully opaque).

Example

let assert Ok(red) = material.basic(color: 0xff0000, transparent: False, opacity: 1.0, map: option.None)
let assert Ok(glass) = material.basic(color: 0x88ccff, transparent: True, opacity: 0.5, map: option.None)
pub fn build(
  builder: StandardMaterialBuilder,
) -> Result(Material, MaterialError)

Build the final StandardMaterial from the builder.

Validates all parameters and returns a Result. Will fail if any values are out of valid ranges.

Example

let result = material.new()
  |> material.with_color(0xff0000)
  |> material.with_metalness(0.8)
  |> material.with_roughness(0.3)
  |> material.build()

case result {
  Ok(material) -> // Use the material
  Error(material.OutOfBoundsColor(_)) -> // Handle error
}
pub fn lambert(
  color color: Int,
  map map: option.Option(savoiardi.Texture),
  normal_map normal_map: option.Option(savoiardi.Texture),
  ambient_oclusion_map ambient_oclusion_map: option.Option(
    savoiardi.Texture,
  ),
  transparent transparent: Bool,
  opacity opacity: Float,
  alpha_test alpha_test: Float,
) -> Result(Material, MaterialError)

Create a Lambert material for matte, non-shiny surfaces.

Lambert materials use diffuse-only lighting with no specular highlights, making them ideal for cloth, wood, concrete, or other matte surfaces. Cheaper than Phong or Standard.

Color: Base color without lighting (0x000000 to 0xFFFFFF).

Example

import tiramisu/material
import gleam/option

// Matte red cloth
let assert Ok(cloth) = material.lambert(
  color: 0xcc0000,
  map: option.None,
  normal_map: option.None,
  ambient_oclusion_map: option.None,
)

// Wood with texture
let assert Ok(color_tex) = asset.get_texture(cache, "wood.jpg")
let assert Ok(wood) = material.lambert(
  color: 0xffffff,  // White base color (texture provides color)
  map: option.Some(color_tex),
  normal_map: option.None,
  ambient_oclusion_map: option.None,
)
pub fn line(
  color color: Int,
  linewidth linewidth: Float,
) -> Result(Material, MaterialError)

Create a validated line material for rendering lines.

Example

let assert Ok(line_mat) = scene.line_material(color: 0xff0000, linewidth: 2.0)
pub fn new() -> StandardMaterialBuilder

Create a new StandardMaterial builder with sensible defaults.

Default values:

  • Color: 0x808080 (medium gray)
  • Metalness: 0.5 (semi-metallic)
  • Roughness: 0.5 (semi-rough)
  • Transparent: False
  • Opacity: 1.0 (fully opaque)
  • All texture maps: None

Example

import tiramisu/material

// Start building a material
let assert Ok(metal) = material.new()
  |> material.with_color(0xcccccc)
  |> material.with_metalness(1.0)
  |> material.with_roughness(0.3)
  |> material.build()
pub fn phong(
  color color: Int,
  shininess shininess: Float,
  map map: option.Option(savoiardi.Texture),
  normal_map normal_map: option.Option(savoiardi.Texture),
  ambient_oclusion_map ambient_oclusion_map: option.Option(
    savoiardi.Texture,
  ),
  transparent transparent: Bool,
  opacity opacity: Float,
  alpha_test alpha_test: Float,
) -> Result(Material, MaterialError)

Create a Phong material for shiny surfaces with specular highlights.

Phong materials add specular highlights to simulate shiny surfaces like plastic, ceramic, or polished surfaces. More expensive than Lambert but cheaper than Standard.

Color: Base diffuse color (0x000000 to 0xFFFFFF). Shininess: Specular highlight size. Higher = smaller, sharper highlight (typical: 30-100).

Example

import tiramisu/material
import gleam/option

// Shiny red plastic
let assert Ok(plastic) = material.phong(
  color: 0xff0000,
  shininess: 80.0,
  map: option.None,
  normal_map: option.None,
  ambient_oclusion_map: option.None,
)

// Ceramic with low shininess (larger highlight)
let assert Ok(ceramic) = material.phong(
  color: 0xf5f5dc,
  shininess: 30.0,
  map: option.None,
  normal_map: option.None,
  ambient_oclusion_map: option.None,
)
pub fn sprite(
  color color: Int,
  transparent transparent: Bool,
  opacity opacity: Float,
  map map: option.Option(savoiardi.Texture),
) -> Result(Material, MaterialError)

Create a validated sprite material for 2D billboards.

Sprites always face the camera and are useful for particles, UI elements, etc.

Example

let assert Ok(sprite_mat) = material.sprite(color: 0xffffff, transparent: True, opacity: 0.8, map: option.None)
pub fn standard(
  color color: Int,
  metalness metalness: Float,
  roughness roughness: Float,
  transparent transparent: Bool,
  opacity opacity: Float,
  map map: option.Option(savoiardi.Texture),
  normal_map normal_map: option.Option(savoiardi.Texture),
  ambient_oclusion_map ambient_oclusion_map: option.Option(
    savoiardi.Texture,
  ),
  displacement_map displacement_map: option.Option(
    savoiardi.Texture,
  ),
  displacement_scale displacement_scale: Float,
  displacement_bias displacement_bias: Float,
  roughness_map roughness_map: option.Option(savoiardi.Texture),
  metalness_map metalness_map: option.Option(savoiardi.Texture),
  emissive emissive: Int,
  emissive_intensity emissive_intensity: Float,
) -> Result(Material, MaterialError)

Create a validated physically-based (PBR) standard material.

Standard materials use metalness/roughness workflow for realistic rendering.

  • Metalness: 0.0 = dielectric (plastic, wood), 1.0 = metal
  • Roughness: 0.0 = mirror-smooth, 1.0 = completely rough

Example

let assert Ok(gold) = scene.standard_material(color: 0xffd700, metalness: 1.0, roughness: 0.3, transparent: False, opacity: 1.0, map: option.None, normal_map: option.None, ao_map: option.None, roughness_map: option.None, metalness_map: option.None)
let assert Ok(plastic) = scene.standard_material(color: 0xff0000, metalness: 0.0, roughness: 0.5, transparent: False, opacity: 1.0, map: option.None, normal_map: option.None, ao_map: option.None, roughness_map: option.None, metalness_map: option.None)
pub fn toon(
  color color: Int,
  map map: option.Option(savoiardi.Texture),
  normal_map normal_map: option.Option(savoiardi.Texture),
  ambient_oclusion_map ambient_oclusion_map: option.Option(
    savoiardi.Texture,
  ),
  transparent transparent: Bool,
  opacity opacity: Float,
  alpha_test alpha_test: Float,
) -> Result(Material, MaterialError)

Create a Toon material for cartoon-style cel-shaded rendering.

Toon materials create a cartoon/anime aesthetic by using banded shading instead of smooth gradients. Colors are quantized into distinct bands, creating a hand-drawn look.

Color: Base color (0x000000 to 0xFFFFFF).

Example

import tiramisu/material
import gleam/option

// Cartoon character
let assert Ok(toon_mat) = material.toon(
  color: 0xff6b35,
  map: option.None,
  normal_map: option.None,
  ambient_oclusion_map: option.None,
)

// Cel-shaded with texture
let assert Ok(color_tex) = asset.get_texture(cache, "character.png")
let assert Ok(toon_textured) = material.toon(
  color: 0xffffff,  // White base (texture provides color)
  map: option.Some(color_tex),
  normal_map: option.None,
  ambient_oclusion_map: option.None,
)
pub fn with_ambient_oclusion_map(
  builder: StandardMaterialBuilder,
  ambient_oclusion_map: savoiardi.Texture,
) -> StandardMaterialBuilder

Set the ambient occlusion map for contact shadows.

AO maps darken areas where ambient light would be occluded, adding depth and realism to crevices and corners.

Example

let assert Ok(ao) = asset.get_texture(cache, "brick_ao.jpg")

material.new()
  |> material.with_ambient_oclusion_map(ao)
pub fn with_color(
  builder: StandardMaterialBuilder,
  color: Int,
) -> StandardMaterialBuilder

Set the base color.

Color: Hex color from 0x000000 (black) to 0xFFFFFF (white).

Example

material.new()
  |> material.with_color(0xff0000)  // Red
pub fn with_color_map(
  builder: StandardMaterialBuilder,
  map: savoiardi.Texture,
) -> StandardMaterialBuilder

Set the color/albedo texture map.

The texture modulates the base color. Common practice is to set base color to white (0xFFFFFF) when using a color map.

Example

let assert Ok(texture) = asset.get_texture(cache, "brick_color.jpg")

material.new()
  |> material.with_color(0xffffff)  // White base
  |> material.with_color_map(texture)
pub fn with_displacement_bias(
  builder: StandardMaterialBuilder,
  displacement_bias: Float,
) -> StandardMaterialBuilder

Set the displacement bias for vertex deformation.

If a displacement map texture is set, this adjusts the base offset of the deformation. Since the displacement map texture is from 0.0 to 1.0 (black to white), negative displacement can be achieved by using a negative value for the bias.

The default value is 0.0.

Example

let assert Ok(dm) = asset.get_texture(cache, "water.jpg")

material.new()
  |> material.with_displacement_map(dm)
  |> material.with_displacement_bias(0.5)
pub fn with_displacement_map(
  builder: StandardMaterialBuilder,
  displacement_map: savoiardi.Texture,
) -> StandardMaterialBuilder

Set the displacement map for vertex deformation.

The displacement map affects the position of the mesh’s vertices. Unlike other maps which only affect the light and shade of the material the displaced vertices can cast shadows, block other objects, and otherwise act as real geometry. The displacement texture is an image where the value of each pixel (white being the highest) is mapped against, and repositions, the vertices of the mesh.

Example

let assert Ok(dm) = asset.get_texture(cache, "water.jpg")

material.new()
  |> material.with_displacement_map(dm)
pub fn with_displacement_scale(
  builder: StandardMaterialBuilder,
  displacement_scale: Float,
) -> StandardMaterialBuilder

Set the displacement scale for vertex deformation.

If a displacement map texture is set, this affects how much the texture affects the deformation of vertices. Greater values cause greater deformation, lesser values create less deformation. Negative values invert the effect.

The default value is 1.0.

Example

let assert Ok(dm) = asset.get_texture(cache, "water.jpg")

material.new()
  |> material.with_displacement_map(dm)
  |> material.with_displacement_scale(2.5)
pub fn with_emissive(
  builder: StandardMaterialBuilder,
  emissive: Int,
) -> StandardMaterialBuilder

Set the emissive color (glow).

Emissive: Hex color from 0x000000 (no glow) to 0xFFFFFF (white glow). Objects with emissive colors appear to emit light and are perfect for bloom effects.

Example

// Glowing red cube
material.new()
  |> material.with_color(0xff0000)
  |> material.with_emissive(0xff0000)
  |> material.with_emissive_intensity(0.5)
pub fn with_emissive_intensity(
  builder: StandardMaterialBuilder,
  intensity: Float,
) -> StandardMaterialBuilder

Set the emissive intensity.

Emissive Intensity: Multiplier for the emissive color brightness. 0.0 = no emission, higher values = brighter glow. Especially visible with bloom.

Example

// Bright glowing sphere
material.new()
  |> material.with_color(0x00ff00)
  |> material.with_emissive(0x00ff00)
  |> material.with_emissive_intensity(1.0)
pub fn with_metalness(
  builder: StandardMaterialBuilder,
  metalness: Float,
) -> StandardMaterialBuilder

Set the metalness value.

Metalness: 0.0 = non-metal (plastic, wood, fabric), 1.0 = pure metal (gold, steel).

Example

// Metallic surface
material.new()
  |> material.with_metalness(1.0)

// Non-metallic surface
material.new()
  |> material.with_metalness(0.0)
pub fn with_metalness_map(
  builder: StandardMaterialBuilder,
  metalness_map: savoiardi.Texture,
) -> StandardMaterialBuilder

Set the metalness map for per-pixel metalness variation.

Useful for surfaces that are partially metallic, like painted metal with scratches revealing bare metal underneath.

Example

let assert Ok(metalness) = asset.get_texture(cache, "metal_metalness.jpg")

material.new()
  |> material.with_metalness_map(metalness)
pub fn with_normal_map(
  builder: StandardMaterialBuilder,
  normal_map: savoiardi.Texture,
) -> StandardMaterialBuilder

Set the normal map for surface detail.

Normal maps add surface details like bumps and grooves without adding geometry. They affect how light interacts with the surface.

Example

let assert Ok(normal) = asset.get_texture(cache, "brick_normal.jpg")

material.new()
  |> material.with_normal_map(normal)
pub fn with_opacity(
  builder: StandardMaterialBuilder,
  opacity: Float,
) -> StandardMaterialBuilder

Set the opacity value.

Opacity: 0.0 = fully transparent, 1.0 = fully opaque. Only takes effect when with_transparent(True) is set.

Example

// Semi-transparent glass
material.new()
  |> material.with_color(0x88ccff)
  |> material.with_transparent(True)
  |> material.with_opacity(0.3)
pub fn with_roughness(
  builder: StandardMaterialBuilder,
  roughness: Float,
) -> StandardMaterialBuilder

Set the roughness value.

Roughness: 0.0 = mirror-smooth (polished), 1.0 = completely rough (matte).

Example

// Polished chrome
material.new()
  |> material.with_roughness(0.1)

// Rough concrete
material.new()
  |> material.with_roughness(0.9)
pub fn with_roughness_map(
  builder: StandardMaterialBuilder,
  roughness_map: savoiardi.Texture,
) -> StandardMaterialBuilder

Set the roughness map for per-pixel roughness variation.

Allows different parts of the surface to have different roughness values, like scratches on polished metal or worn areas on wood.

Example

let assert Ok(roughness) = asset.get_texture(cache, "metal_roughness.jpg")

material.new()
  |> material.with_roughness_map(roughness)
pub fn with_transparent(
  builder: StandardMaterialBuilder,
  transparent: Bool,
) -> StandardMaterialBuilder

Enable or disable transparency.

When True, the material’s opacity value will be used for alpha blending. Set to True when creating glass, water, or semi-transparent effects.

Example

// Glass material
material.new()
  |> material.with_transparent(True)
  |> material.with_opacity(0.3)
Search Document