← Back to work

Real-time rendering / Rendering system

Layered Material Renderer

I owned an artist-facing layered material system that turned curvature and thickness into stable controls, reducing look-dev diagnosis from repeated shader edits to explicit inputs and debug channels.

Move pointer to disturb the field
Interactive previewChannels available below
Role
Technical Artist / Rendering Owner
Contribution
Owned the material model, artist controls, debug channels, and performance validation; handed a repeatable review contract to look-dev.
Engine / environment
Unity URP / HLSL
Platform
PC / Current-generation console target
Status
Personal reconstruction of a production workflow
Team context
Designed as a single-owner system that could be handed to environment artists without requiring shader knowledge.
Year
2026
Technologies

HLSL · Shader Graph · Custom Inspector · RenderDoc · GPU instancing

At a glance

I built the shared material model, artist-facing controls, debug views, and validation plan. The result is a material path that lets look-dev artists diagnose a missing layer through inputs and channels instead of repeated shader edits.

Validation materials48Across the representative look-dev sample
Lighting conditions3Same contract, different scene response
Quality tiers2Integrated and desktop GPU paths
Detail-layer cost+1 sampleBounded cost accepted for authoring clarity
Evidence at a glance; the later Scale and Results sections explain how these measurements informed the decision.
Before: noisy material iteration with unstable layer responseBefore / repeated shader edits
After: stable material iteration with a shared layer contractAfter / shared debug contract
Synthetic evidence for the presentation test: the stable result should be legible before the technical breakdown begins.

How to read the breakdown

The sections below move from the production problem to ownership, implementation, and trade-offs. The visual comparison shows the claim; the narrative explains the decision behind it.

Case study

Context

The art team needed layered surfaces that could be iterated by look-development artists rather than hard-coded per asset. The old approach duplicated masks and material functions across scenes, which made small visual changes expensive to validate.

Audience

Environment artists author the look; rendering engineers review the budget; production needs a stable surface that can survive asset scale-up.

Case study

Problem

The system had to expose enough control to make the material useful without turning the inspector into a list of implementation details. The original prototype could look correct on one hero asset but gave artists no way to diagnose why a layer disappeared on another asset.

Case study

Constraints

  • One material variant for the common path; no per-asset shader forks.
  • A predictable mobile and console fallback path.
  • Debug output must explain inputs without requiring a capture session.
  • The visual language must remain coherent across hard-surface and organic test assets.

Case study

Ownership

I owned the material function graph, the HLSL include that held shared evaluation logic, the debug channel design, the inspector naming pass, and the capture checklist used for review.

Case study

Solution

The solution separates authoring inputs from shading evaluation. Artists see layer intent, breakup, and preview channels; the shader receives packed parameters with a single normalization step before lighting.

MaterialDebug.hlsl
struct MaterialDebug { float3 normal; float depth; float mask; float2 uv; };
MaterialDebug BuildDebug(float3 n, float d, float m, float2 uv)
{
  return (MaterialDebug) { n, d, m, uv };
}

Case study

Scale

The intended content range is hundreds of authored materials across multiple environment sets. The target budget was one additional texture sample for the detail layer and a bounded branch count in the forward path.

Validation sample

The test corpus includes 48 materials, three lighting conditions, two quality tiers, and a capture on both an integrated GPU and a desktop GPU.

Case study

Technical breakdown

Decision: shared material evaluation

I separated authoring inputs from shading evaluation so one material variant could serve the common path without hiding layer intent from artists.

LayeredMaterial.hlsl
float layerWeight = saturate(curvature * _WearBreakup + thickness * _LayerBlend);
float3 blendedNormal = normalize(lerp(baseNormal, detailNormal, layerWeight));
return EvaluateMaterial(albedo, blendedNormal, roughness);

Debug contract

Final, normal, depth, mask, UV, roughness, and metallic each answer a review question; they are not decorative display modes.

Case study

Results / impact

The final model made the material readable to artists and reviewable by rendering. The strongest result is not a single image: it is the shorter feedback loop from ?the layer is wrong? to ?this input or stage is wrong.?

Observed impact

A representative look-dev pass moved from repeated shader edits to parameter iteration, while the debug channels made the remaining implementation issues visible in captures.

Case study

Trade-offs

What I did not optimize

I did not pursue bespoke per-asset shader forks or a richer hero effect. Both could produce a more expressive single image, but they would weaken consistency and make the review contract harder to maintain.

Why this trade-off is acceptable

The shared path is easier to hand off, profile, and debug. I accepted the lower ceiling on bespoke visual expression because predictable performance and artist comprehension were the stronger production constraints.