agentskills.codes
FO

forge-pbr-textures

Add PBR texture loading with separate roughness/metallic support to an SDL GPU project using forge_scene.h

Install

mkdir -p .claude/skills/forge-pbr-textures && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/14606" && unzip -o skill.zip -d .claude/skills/forge-pbr-textures && rm skill.zip

Installs to .claude/skills/forge-pbr-textures

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Add PBR texture loading with separate roughness/metallic support to an SDL GPU project using forge_scene.h
106 charsno explicit “when” trigger

About this skill

Load PBR material texture sets (albedo, normal, roughness, metallic, AO, emissive) from the asset pipeline and render them with a Cook-Torrance BRDF shader. Supports both packed metallic-roughness (glTF convention) and separate single-channel textures (ambientCG convention).

When to use

  • Loading PBR materials from .fmat sidecar files
  • Rendering textured PBR materials on scene models
  • Supporting both packed and separate metallic-roughness workflows
  • Adding multiple material support to a scene

Material loading pattern

/* Parse .fmat sidecar */
ForgePipelineMaterialSet mat_set;
if (!forge_pipeline_load_materials("assets/materials/Rock026/Rock026.fmat", &mat_set)
    || mat_set.material_count == 0) {
    SDL_Log("Failed to load Rock026 material");
    return false;
}
const ForgePipelineMaterial *mat = &mat_set.materials[0];

/* Load textures from processed assets.
 * vram tracks GPU memory usage — must be non-NULL. */
ForgeSceneVramStats vram = {0};
ForgeSceneModelTextures tex = {0};

/* Base color — sRGB (authored color) */
tex.base_color = forge_scene_load_pipeline_texture(
    scene, &vram, "assets/materials/Rock026/Rock026_Color.png", true, false);

/* Normal map — linear, is_normal_map=true for BC5 */
tex.normal = forge_scene_load_pipeline_texture(
    scene, &vram, "assets/materials/Rock026/Rock026_NormalGL.png", false, true);

/* Separate roughness — linear */
tex.roughness = forge_scene_load_pipeline_texture(
    scene, &vram, "assets/materials/Rock026/Rock026_Roughness.png", false, false);

/* AO — linear, R channel */
tex.occlusion = forge_scene_load_pipeline_texture(
    scene, &vram, "assets/materials/Rock026/Rock026_AmbientOcclusion.png", false, false);

8-sampler PBR pipeline

The shader uses 8 texture slots to support both packed and separate workflows:

SlotTextureColor spaceFallback
0Base colorsRGBWhite
1Normal mapLinearFlat (+Z)
2Packed metallic-roughnessLinearWhite
3Occlusion (AO)LinearWhite
4EmissivesRGBBlack
5Shadow mapDepthScene shadow
6Separate roughnessLinearWhite
7Separate metallicLinearWhite

Separate MR flag

The shininess field in ForgeSceneModelFragUniforms (offset 80, unused by PBR) is repurposed as use_separate_mr:

ForgeSceneModelFragUniforms fu;
forge_scene__fill_model_frag_uniforms(scene, mat, &fu);
fu.shininess = (tex.roughness || tex.metallic) ? 1.0f : 0.0f;

In the shader:

if (use_separate_mr > 0.5) {
    roughness = roughness_tex.Sample(roughness_smp, input.uv).r * roughness_factor;
    metallic  = metallic_tex.Sample(metallic_smp, input.uv).r * metallic_factor;
} else {
    float2 mr = mr_tex.Sample(mr_smp, input.uv).bg;
    metallic  = mr.x * metallic_factor;
    roughness = mr.y * roughness_factor;
}

sRGB vs linear

Data typeColor spaceWhy
Base color, emissivesRGBAuthored as visible color — GPU linearizes on sample
Normal, roughness, metallic, AOLinearPhysical parameters — gamma would distort values

Common mistakes

  • Loading roughness as sRGB — makes 0.5 appear as ~0.22, materials look too shiny
  • Loading normal maps with sRGB — corrupts direction vectors, surface detail is lost
  • Forgetting the use_separate_mr flag — shader reads packed MR texture (white fallback = all 1.0), making everything fully metallic and rough
  • Not checking metallic_roughness_texture before loading separate — if both packed and separate exist, prefer packed

Reference

See Lesson 52 — PBR Textures for the full implementation.

Search skills

Search the agent skills registry