Class StandardSurface

java.lang.Object
limn.render3d.shader.StandardSurface

public final class StandardSurface extends Object
Builds the SurfaceOutputs for the built-in metallic-roughness material, the same surface the hand-written reference shader computes, expressed as neutral IR so one code generator can target multiple shading languages. The expressions reference the engine's provided inputs by name (the framework declares u_baseColor, u_mr, u_emissiveHasTex, u_baseColorTex, u_normalTex, v_uv, v_color).

Every optional input has a neutral default bound for it (a 1×1 white texture, a 1×1 flat normal map, a per-vertex colour of opaque white, a normal scale of zero), so this one surface covers every material without variants. One surface means one compiled program, and that is worth more than the few multiplies it costs: the pass's uniforms are program state, so a second program would have to re-issue all of them or silently sample the wrong texture unit.

  • Method Details

    • metallicRoughness

      public static SurfaceOutputs metallicRoughness()
      Base color = sRGB-decoded factor × sRGB-decoded base-color texture × per-vertex colour, with alpha the product of all three.

      Three things about that sentence are load-bearing.

      The texture's alpha is honoured. It used to be dropped in favour of the factor's, which makes a soft-edged sprite unreachable: the falloff that turns a quad into a puff of smoke lives in exactly that channel.

      The per-vertex colour is neither decoded nor clamped. It is already linear (glTF COLOR_0 semantics), so passing it through srgbToLinear would darken it; and a component above 1 is a legitimate over-range tint, so clamping it would flatten the brightest thing in the frame. A mesh without the attribute reads opaque white and nothing changes.

      The per-vertex colour also modulates emissive, which is what makes an over-range tint mean anything. Base colour is reflectance: 1.6 there is not "bright", it is unphysical, and with no light it is black. Emissive is added after the BRDF, so it reaches the tonemap as light. This is a deliberate step past glTF, where COLOR_0 touches base colour only. It is also the only way a per-vertex value can drive emission at all, since the emissive factor is per material.