Record Class SurfaceOutputs

java.lang.Object
java.lang.Record
limn.render3d.shader.SurfaceOutputs

public record SurfaceOutputs(Expr baseColor, Expr metallic, Expr roughness, Expr emissive, Expr normal, Expr diffuseResponse) extends Record
What a material's surface function contributes to the engine's lighting core: the metallic-roughness inputs. The backend owns the BRDF and consumes these: baseColor (vec4, linear rgb + alpha), metallic and roughness (floats), emissive (vec3, linear) and normal, the shading normal in world space. AO joins in a later phase.

normal may be null, meaning "shade with the interpolated geometric normal". A tangent-space map becomes a world normal through the framework helper normalMapToWorld(tangentNormal, scale), which builds a per-pixel frame from the screen-space derivatives of the world position and the UVs, so no mesh tangent attribute is required and the vertex stage is untouched. That is not only convenient: nothing in this toolkit produces tangents (neither the primitives nor the glTF loader), so a surface that demanded them would shade most meshes from a zero-length frame.

The diffuse response

diffuseResponse is the one output evaluated inside the light loop, once per light rather than once per fragment. It replaces the max(dot(N, L), 0) that scales the diffuse lobe, and it may read two framework locals the other expressions cannot see:
  • L: a vec3, the unit vector from the surface toward the light, in world space, with the light's type and attenuation already resolved;
  • NdotL: a float, the value this expression is replacing, so a surface that wants to blend with the standard term does not have to rebuild it.

Null means the standard term, and null is not merely the default: it is a different generated line. With no response the backend emits the factored form it always emitted, (kd * albedo / PI + specular) * radiance * NdotL; with one it has to distribute the NdotL across the two lobes so the diffuse half can escape it. Those two are equal in real arithmetic and not in IEEE, so a surface that supplied NdotL back verbatim would still shift the last bits of every lit pixel. Keeping the null path byte-identical is what lets a material adopt this without re-pinning a single existing image.

Why the diffuse lobe only. Specular is a mirror about the normal and stays on NdotL: a response is a statement about how light is scattered by the surface, not about where it reflects. Wrap lighting, toon ramps, a cloth or hair term, and the six-way directional response a volumetric billboard wants are all the diffuse half; none of them wants the highlight moved.

To turn L into the same tangent frame normalMapToWorld shades in, use the framework helper worldToTangent(v).

  • Constructor Details

    • SurfaceOutputs

      public SurfaceOutputs(Expr baseColor, Expr metallic, Expr roughness, Expr emissive, Expr normal)
      A surface shaded by the standard N·L diffuse response.
    • SurfaceOutputs

      public SurfaceOutputs(Expr baseColor, Expr metallic, Expr roughness, Expr emissive, Expr normal, Expr diffuseResponse)
      Creates an instance of a SurfaceOutputs record class.
      Parameters:
      baseColor - the value for the baseColor record component
      metallic - the value for the metallic record component
      roughness - the value for the roughness record component
      emissive - the value for the emissive record component
      normal - the value for the normal record component
      diffuseResponse - the value for the diffuseResponse record component
  • Method Details

    • of

      public static SurfaceOutputs of(Expr baseColor, Expr metallic, Expr roughness, Expr emissive)
      A surface shaded by its geometric normal.
    • withNormal

      public SurfaceOutputs withNormal(Expr normal)
      A copy whose surface normal comes from normal, in tangent space.
    • withDiffuseResponse

      public SurfaceOutputs withDiffuseResponse(Expr diffuseResponse)
      A copy whose diffuse lobe is scaled by diffuseResponse instead of by max(dot(N, L), 0). The expression is evaluated once per light and may reference the framework locals L and NdotL.
    • toString

      public final String toString()
      Returns a string representation of this record class. The representation contains the name of the class, followed by the name and value of each of the record components.
      Specified by:
      toString in class Record
      Returns:
      a string representation of this object
    • hashCode

      public final int hashCode()
      Returns a hash code value for this object. The value is derived from the hash code of each of the record components.
      Specified by:
      hashCode in class Record
      Returns:
      a hash code value for this object
    • equals

      public final boolean equals(Object o)
      Indicates whether some other object is "equal to" this one. The objects are equal if the other object is of the same class and if all the record components are equal. All components in this record class are compared with Objects::equals(Object,Object).
      Specified by:
      equals in class Record
      Parameters:
      o - the object with which to compare
      Returns:
      true if this object is the same as the o argument; false otherwise.
    • baseColor

      public Expr baseColor()
      Returns the value of the baseColor record component.
      Returns:
      the value of the baseColor record component
    • metallic

      public Expr metallic()
      Returns the value of the metallic record component.
      Returns:
      the value of the metallic record component
    • roughness

      public Expr roughness()
      Returns the value of the roughness record component.
      Returns:
      the value of the roughness record component
    • emissive

      public Expr emissive()
      Returns the value of the emissive record component.
      Returns:
      the value of the emissive record component
    • normal

      public Expr normal()
      Returns the value of the normal record component.
      Returns:
      the value of the normal record component
    • diffuseResponse

      public Expr diffuseResponse()
      Returns the value of the diffuseResponse record component.
      Returns:
      the value of the diffuseResponse record component