Skip to main content

Materials

Atlas uses a Physically-Based Rendering (PBR) material system based on metallic-roughness workflow.

Material Structure

The Material struct defines surface properties:
struct Material {
    Color albedo = {1.0, 1.0, 1.0, 1.0};  // Base color
    float metallic = 0.0f;                 // Metallic factor
    float roughness = 0.5f;                // Roughness factor
    float ao = 1.0f;                       // Ambient occlusion
};
albedo
Color
default:"{1.0, 1.0, 1.0, 1.0}"
Base color contribution of the surface (RGB + Alpha)
metallic
float
default:"0.0f"
Metallic factor (0.0 = dielectric, 1.0 = metallic)
roughness
float
default:"0.5f"
Roughness factor influencing specular highlight spread (0.0 = smooth, 1.0 = rough)
ao
float
default:"1.0f"
Ambient occlusion term to darken creases and cavities

Setting Material Properties

// Create a box
CoreObject cube = createBox({1.0, 1.0, 1.0});

// Configure PBR material
cube.material.albedo = Color(0.8f, 0.1f, 0.1f, 1.0f);  // Red
cube.material.metallic = 0.0f;   // Non-metallic
cube.material.roughness = 0.6f;  // Slightly rough
cube.material.ao = 1.0f;         // Full ambient

window.addObject(&cube);

Common Material Presets

cube.material.albedo = Color::blue();
cube.material.metallic = 0.0f;
cube.material.roughness = 0.8f;
cube.material.ao = 1.0f;

Textures

Loading Textures from Resources

First, register resources with the workspace:
#include "atlas/texture.h"
#include "atlas/workspace.h"

// Set root path for resources
Workspace::get().setRootPath("assets/");

// Create resource
Resource brickResource = Workspace::get().createResource(
    "textures/brick.png",
    "BrickTexture",
    ResourceType::Image
);

// Create texture from resource
Texture brickTexture = Texture::fromResource(
    brickResource,
    TextureType::Color
);

// Or load by name directly
Texture diffuseMap = Texture::fromResourceName(
    "BrickTexture",
    TextureType::Color
);

Texture Types

Color
TextureType
Albedo/diffuse color map
Normal
TextureType
Normal map for surface detail
Metallic
TextureType
Metallic map (PBR)
Roughness
TextureType
Roughness map (PBR)
AO
TextureType
Ambient occlusion map
Specular
TextureType
Specular map (Phong/Blinn-Phong)
Parallax
TextureType
Height map for parallax mapping

Texture Parameters

Configure texture wrapping and filtering:
TextureParameters params;
params.wrappingModeS = TextureWrappingMode::Repeat;
params.wrappingModeT = TextureWrappingMode::Repeat;
params.minifyingFilter = TextureFilteringMode::Linear;
params.magnifyingFilter = TextureFilteringMode::Linear;

Texture texture = Texture::fromResource(
    resource,
    TextureType::Color,
    params
);

Wrapping Modes

  • Repeat - Repeats the texture infinitely
  • MirroredRepeat - Alternates direction on every repeat
  • ClampToEdge - Stretches edge pixels
  • ClampToBorder - Uses constant border color

Filtering Modes

  • Nearest - Picks closest texel (pixelated look)
  • Linear - Linearly interpolates texels (smoother)

Attaching Textures to Objects

CoreObject model = createBox({1.0, 1.0, 1.0});

// Attach albedo texture
Texture albedoMap = Texture::fromResourceName("WoodAlbedo", TextureType::Color);
model.attachTexture(albedoMap);

// Attach normal map
Texture normalMap = Texture::fromResourceName("WoodNormal", TextureType::Normal);
model.attachTexture(normalMap);

// Attach metallic map
Texture metallicMap = Texture::fromResourceName("WoodMetallic", TextureType::Metallic);
model.attachTexture(metallicMap);

// Attach roughness map
Texture roughnessMap = Texture::fromResourceName("WoodRoughness", TextureType::Roughness);
model.attachTexture(roughnessMap);

Procedural Textures

Checkerboard Texture

Texture checkerboard = Texture::createCheckerboard(
    512, 512,       // Width, height
    32,             // Check size
    Color::white(), // Color 1
    Color::black()  // Color 2
);

Double Checkerboard

Texture doubleChecker = Texture::createDoubleCheckerboard(
    512, 512,       // Width, height
    64,             // Big check size
    16,             // Small check size
    Color::red(),   // Color 1
    Color::green(), // Color 2
    Color::blue()   // Color 3
);

Tiled Checkerboard

std::vector<CheckerTile> tiles = {
    {Color::red(), Color::black(), 64},
    {Color::green(), Color::black(), 32},
    {Color::blue(), Color::black(), 16}
};

Texture tiledTexture = Texture::createTiledCheckerboard(
    512, 512,
    tiles
);

Rain Streak Texture

For particle effects:
Texture rainStreak = Texture::createRainStreak(64, 256);

Cubemaps

Cubemaps are used for skyboxes and environment mapping:
// Create resources for each face
Resource right = Workspace::get().createResource(
    "skybox/px.png", "RightSkybox", ResourceType::Image
);
Resource left = Workspace::get().createResource(
    "skybox/nx.png", "LeftSkybox", ResourceType::Image
);
Resource top = Workspace::get().createResource(
    "skybox/py.png", "TopSkybox", ResourceType::Image
);
Resource bottom = Workspace::get().createResource(
    "skybox/ny.png", "BottomSkybox", ResourceType::Image
);
Resource front = Workspace::get().createResource(
    "skybox/pz.png", "FrontSkybox", ResourceType::Image
);
Resource back = Workspace::get().createResource(
    "skybox/nz.png", "BackSkybox", ResourceType::Image
);

// Create resource group
ResourceGroup group = Workspace::get().createResourceGroup(
    "Skybox",
    {right, left, top, bottom, front, back}
);

// Create cubemap
Cubemap skyboxCubemap = Cubemap::fromResourceGroup(group);

Solid Color Cubemap

std::array<Color, 6> colors = {
    Color::red(),    // +X
    Color::green(),  // -X
    Color::blue(),   // +Y
    Color::yellow(), // -Y
    Color::cyan(),   // +Z
    Color::magenta() // -Z
};

Cubemap colorCubemap = Cubemap::fromColors(colors, 512);

Advanced Texture Usage

Water with DUDV and Normal Maps

From the test suite:
Texture waterDUDV = Texture::fromResource(
    Workspace::get().createResource(
        "water_dudv.png", "WaterDUDV", ResourceType::Image
    )
);

Texture waterNormal = Texture::fromResource(
    Workspace::get().createResource(
        "water_normal.png", "WaterNormal", ResourceType::Image
    )
);

Fluid water = Fluid();
water.create({0.9, 0.9}, Color::blue());
water.setPosition({0.0f, 0.10f, 0.5f});
water.movementTexture = waterDUDV;
water.normalTexture = waterNormal;
water.initialize();

Border Color for Clamped Textures

Texture texture = Texture::fromResource(
    resource,
    TextureType::Color,
    params,
    Color(0.0f, 0.0f, 0.0f, 1.0f)  // Black border
);

Texture Coordinates

Vertex texture coordinates are defined in the CoreVertex struct:
struct CoreVertex {
    Position3d position;
    Color color;
    TextureCoordinate textureCoordinate;  // {u, v}
    Normal3d normal;
    Normal3d tangent;
    Normal3d bitangent;
};
Texture coordinates typically range from [0, 0] to [1, 1]:
CoreVertex vertex(
    {1.0f, 1.0f, 0.0f},  // Position
    Color::white(),      // Color
    {1.0f, 1.0f},        // Top-right UV
    {0.0f, 0.0f, 1.0f}   // Normal (Z+)
);

Best Practices

Use power-of-two resolutions (256, 512, 1024, 2048) for better GPU compatibility and mipmap generation.
Enable mipmaps for textures viewed at varying distances to improve performance and reduce aliasing.
Combine multiple small textures into a single atlas to reduce draw calls.
Use compressed texture formats (DXT, ASTC) for production builds to save memory.
Keep metallic at 0.0 or 1.0 for physically accurate materials. Use roughness to control specular highlights.

See Also

Build docs developers (and LLMs) love