Skip to content

Commit cd432f2

Browse files
committed
Modernize XSToon2 Xiexe lighting math
1 parent 68be9ef commit cd432f2

4 files changed

Lines changed: 406 additions & 218 deletions

File tree

crates/renderide/shaders/source/modules/xiexe_toon2_base.wgsl

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
459476
fn 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.
464508
fn vertex_color_albedo_enabled() -> bool {
465509
return kw(mat._VertexColorAlbedo) || kw(mat.VERTEX_COLOR_ALBEDO);

0 commit comments

Comments
 (0)