@@ -106,17 +106,17 @@ struct XiexeToon2Material {
106106 _Glossiness : f32 ,
107107 /// Reflectivity weight applied to indirect specular.
108108 _Reflectivity : f32 ,
109- /// Clear-coat layer strength (reserved; passed through for future use) .
109+ /// Clear-coat layer strength multiplier .
110110 _ClearcoatStrength : f32 ,
111111 /// Clear-coat smoothness.
112112 _ClearcoatSmoothness : f32 ,
113- /// Reflection mode: 0 = PBR, 2 = matcap (the only branches currently implemented) .
113+ /// Reflection mode: 0 = PBR, 1 = baked cubemap, 2 = matcap, 3 = off .
114114 _ReflectionMode : f32 ,
115- /// Reflection blend mode: 0 = additive, 1 = subtractive , 2 = multiplicative .
115+ /// Reflection blend mode: 0 = additive, 1 = multiplicative , 2 = subtractive .
116116 _ReflectionBlendMode : f32 ,
117117 /// Clear-coat enable flag.
118118 _ClearCoat : f32 ,
119- /// Light -scaling flag for indirect lighting normalisation (passthrough ).
119+ /// Emission light -scaling flag (`0 = scale with light`, `1 = keep emission unscaled` ).
120120 _ScaleWithLight : f32 ,
121121 /// Lerp factor that blends emission toward `emission * albedo`.
122122 _EmissionToDiffuse : f32 ,
@@ -346,6 +346,8 @@ struct SurfaceData {
346346 clip_alpha : f32 ,
347347 /// Saturation-adjusted diffuse color (RGB only).
348348 diffuse_color : vec3 <f32 >,
349+ /// Geometry normal after dual-sided back-face correction but before normal-map perturbation.
350+ raw_normal : vec3 <f32 >,
349351 /// Final perturbed world-space normal (post-detail blend, post-back-face flip).
350352 normal : vec3 <f32 >,
351353 /// World-space tangent matching `normal` after re-orthonormalisation.
@@ -358,11 +360,17 @@ struct SurfaceData {
358360 roughness : f32 ,
359361 /// Raw smoothness (for matcap LOD selection).
360362 smoothness : f32 ,
361- /// Reflectivity weight × `_ReflectivityMask.r`.
363+ /// Effective clear-coat strength after `_ClearcoatStrength * metallicGlossMap.b`.
364+ clearcoat_strength : f32 ,
365+ /// Effective clear-coat smoothness after `_ClearcoatSmoothness * metallicGlossMap.g`.
366+ clearcoat_smoothness : f32 ,
367+ /// Scalar reflectivity control used for the dielectric Fresnel floor.
362368 reflectivity : f32 ,
369+ /// `_ReflectivityMask.r`, used when blending indirect specular into the surface.
370+ reflectivity_mask : f32 ,
363371 /// AO color tint, lerped from `_OcclusionColor` to white by AO sample.
364372 occlusion : vec3 <f32 >,
365- /// Emission color (post- `_EmissionToDiffuse` blend) .
373+ /// Base emission sample before `_EmissionToDiffuse` / `_ScaleWithLight` are applied .
366374 emission : vec3 <f32 >,
367375 /// Ramp-mask row used as the V coordinate when sampling `_Ramp`.
368376 ramp_mask : f32 ,
@@ -400,6 +408,12 @@ fn saturate_vec(v: vec3<f32>) -> vec3<f32> {
400408 return clamp (v , vec3 <f32 >(0 .0 ), vec3 <f32 >(1 .0 ));
401409}
402410
411+ /// `(1 − x)^5` — shared by Fresnel helpers in the stylised specular and reflection paths.
412+ fn pow5 (x : f32 ) -> f32 {
413+ let x2 = x * x ;
414+ return x2 * x2 * x ;
415+ }
416+
403417/// Normalises `v`, falling back to `fallback` if the squared length is at-or-below epsilon.
404418/// Used everywhere the input is potentially the result of a host-supplied transform that
405419/// might be near-zero (e.g. a degenerate skinning frame).
@@ -456,10 +470,40 @@ fn thickness_enabled() -> bool {
456470}
457471
458472/// True when matcap mode is selected via the `MATCAP` keyword or `_ReflectionMode == 2`.
473+ ///
474+ /// The keyword path is kept because Resonite's `XiexeToonMaterial` drives matcap through a
475+ /// texture-presence keyword even when it does not populate `_ReflectionMode` explicitly.
459476fn matcap_enabled () -> bool {
460477 return kw (mat . MATCAP ) || abs (mat . _ReflectionMode - 2 .0 ) < 0 .5 ;
461478}
462479
480+ /// True when the reflection mode explicitly disables indirect specular and no matcap keyword is set.
481+ fn reflection_disabled () -> bool {
482+ return ! kw (mat . MATCAP ) && abs (mat . _ReflectionMode - 3 .0 ) < 0 .5 ;
483+ }
484+
485+ /// True when the shader should use the skybox/PBR reflection branch.
486+ ///
487+ /// The legacy "baked cubemap" mode has no dedicated cubemap binding in the XSToon2 contract, so
488+ /// both mode `0` and mode `1` fall back to the renderer's frame-global skybox specular source.
489+ fn reflection_uses_pbr () -> bool {
490+ return ! reflection_disabled () && ! matcap_enabled ();
491+ }
492+
493+ /// True when the legacy clear-coat controls should add the secondary lobe.
494+ fn clearcoat_enabled () -> bool {
495+ return kw (mat . _ClearCoat ) && mat . _ClearcoatStrength > 1e-4 && mat . _ClearcoatSmoothness > 1e-4 ;
496+ }
497+
498+ /// True when emission should be dimmed by scene brightness.
499+ ///
500+ /// Legacy Resonite-authored XSToon2 materials never populated `_ScaleWithLight`; keeping the
501+ /// sensitivity check avoids unexpectedly changing those materials while still honoring imported
502+ /// content that explicitly enables the feature.
503+ fn scale_with_light_enabled () -> bool {
504+ return mat . _ScaleWithLight < 0 .5 && mat . _ScaleWithLightSensitivity > 1e-4 ;
505+ }
506+
463507/// True when vertex-color albedo tinting is enabled via either keyword spelling.
464508fn vertex_color_albedo_enabled () -> bool {
465509 return kw (mat . _VertexColorAlbedo ) || kw (mat . VERTEX_COLOR_ALBEDO );
0 commit comments