reze-engine 0.65.0 → 0.66.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/engine.d.ts +156 -42
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +876 -186
- package/dist/graph/compile.d.ts.map +1 -1
- package/dist/graph/compile.js +5 -0
- package/dist/graph/presets/body.d.ts.map +1 -1
- package/dist/graph/presets/body.js +26 -24
- package/dist/graph/presets/cloth_rough.js +8 -8
- package/dist/graph/presets/cloth_smooth.js +8 -8
- package/dist/graph/presets/default.js +4 -4
- package/dist/graph/presets/eye.js +10 -10
- package/dist/graph/presets/face.d.ts.map +1 -1
- package/dist/graph/presets/face.js +28 -26
- package/dist/graph/presets/hair.js +6 -6
- package/dist/graph/presets/metal.js +8 -8
- package/dist/graph/presets/stockings.d.ts.map +1 -1
- package/dist/graph/presets/stockings.js +4 -11
- package/dist/graph/presets/unlit.d.ts.map +1 -1
- package/dist/graph/presets/unlit.js +9 -13
- package/dist/graph/registry.d.ts.map +1 -1
- package/dist/graph/registry.js +128 -157
- package/dist/graph/render-class.d.ts +5 -2
- package/dist/graph/render-class.d.ts.map +1 -1
- package/dist/graph/slots.d.ts.map +1 -1
- package/dist/graph/slots.js +5 -1
- package/dist/model.d.ts +14 -1
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +27 -1
- package/dist/pmx-loader.d.ts +4 -0
- package/dist/pmx-loader.d.ts.map +1 -1
- package/dist/pmx-loader.js +11 -2
- package/dist/shaders/anchor-table.d.ts +11 -0
- package/dist/shaders/anchor-table.d.ts.map +1 -1
- package/dist/shaders/anchor-table.js +9 -3
- package/dist/shaders/directives.d.ts +42 -5
- package/dist/shaders/directives.d.ts.map +1 -1
- package/dist/shaders/directives.js +51 -4
- package/dist/shaders/lights.d.ts +11 -7
- package/dist/shaders/lights.d.ts.map +1 -1
- package/dist/shaders/lights.js +315 -271
- package/dist/shaders/materials/common.d.ts.map +1 -1
- package/dist/shaders/materials/common.js +26 -3
- package/dist/shaders/materials/nodes.d.ts +1 -1
- package/dist/shaders/materials/nodes.d.ts.map +1 -1
- package/dist/shaders/materials/nodes.js +191 -271
- package/dist/shaders/passes/composite.d.ts +1 -1
- package/dist/shaders/passes/composite.d.ts.map +1 -1
- package/dist/shaders/passes/composite.js +3 -5
- package/dist/shaders/passes/ground.js +1 -1
- package/dist/shaders/passes/particles.d.ts.map +1 -1
- package/dist/shaders/passes/particles.js +9 -3
- package/dist/shaders/passes/probe.d.ts +45 -0
- package/dist/shaders/passes/probe.d.ts.map +1 -0
- package/dist/shaders/passes/probe.js +230 -0
- package/dist/shaders/passes/scene-contract.d.ts +13 -0
- package/dist/shaders/passes/scene-contract.d.ts.map +1 -1
- package/dist/shaders/passes/scene-contract.js +4 -0
- package/dist/shaders/scene-light-api.d.ts.map +1 -1
- package/dist/shaders/scene-light-api.js +1 -0
- package/dist/unity/globals.d.ts +7 -0
- package/dist/unity/globals.d.ts.map +1 -1
- package/dist/unity/globals.js +4 -3
- package/dist/unity/host.d.ts +3 -0
- package/dist/unity/host.d.ts.map +1 -1
- package/dist/unity/host.js +41 -7
- package/dist/unity/looks.d.ts +42 -0
- package/dist/unity/looks.d.ts.map +1 -1
- package/dist/unity/looks.js +131 -4
- package/dist/unity/stage.d.ts +17 -0
- package/dist/unity/stage.d.ts.map +1 -1
- package/dist/unity/stage.js +22 -5
- package/package.json +1 -1
- package/src/engine.ts +949 -215
- package/src/graph/compile.ts +4 -0
- package/src/graph/presets/body.ts +26 -24
- package/src/graph/presets/cloth_rough.ts +8 -8
- package/src/graph/presets/cloth_smooth.ts +8 -8
- package/src/graph/presets/default.ts +4 -4
- package/src/graph/presets/eye.ts +10 -10
- package/src/graph/presets/face.ts +28 -26
- package/src/graph/presets/hair.ts +6 -6
- package/src/graph/presets/metal.ts +8 -8
- package/src/graph/presets/stockings.ts +4 -11
- package/src/graph/presets/unlit.ts +9 -13
- package/src/graph/registry.ts +133 -158
- package/src/graph/render-class.ts +5 -2
- package/src/graph/slots.ts +5 -1
- package/src/model.ts +33 -1
- package/src/pmx-loader.ts +11 -2
- package/src/shaders/anchor-table.ts +15 -3
- package/src/shaders/directives.ts +88 -6
- package/src/shaders/lights.ts +464 -415
- package/src/shaders/materials/common.ts +26 -3
- package/src/shaders/materials/nodes.ts +191 -271
- package/src/shaders/passes/composite.ts +3 -5
- package/src/shaders/passes/ground.ts +1 -1
- package/src/shaders/passes/particles.ts +9 -3
- package/src/shaders/passes/probe.ts +240 -0
- package/src/shaders/passes/scene-contract.ts +17 -0
- package/src/shaders/scene-light-api.ts +1 -0
- package/src/unity/globals.ts +7 -3
- package/src/unity/host.ts +36 -6
- package/src/unity/looks.ts +161 -7
- package/src/unity/stage.ts +28 -5
- package/dist/physics-debug.d.ts +0 -30
- package/dist/physics-debug.d.ts.map +0 -1
- package/dist/physics-debug.js +0 -526
- package/dist/shaders/agx-lut.d.ts +0 -11
- package/dist/shaders/agx-lut.d.ts.map +0 -1
- package/dist/shaders/agx-lut.js +0 -29
- package/dist/shaders/dfg_lut.d.ts +0 -3
- package/dist/shaders/dfg_lut.d.ts.map +0 -1
- package/dist/shaders/dfg_lut.js +0 -129
- package/dist/shaders/ltc_mag_lut.d.ts +0 -3
- package/dist/shaders/ltc_mag_lut.d.ts.map +0 -1
- package/dist/shaders/ltc_mag_lut.js +0 -1033
- package/dist/shaders/materials/body.d.ts +0 -2
- package/dist/shaders/materials/body.d.ts.map +0 -1
- package/dist/shaders/materials/body.js +0 -95
- package/dist/shaders/materials/cloth_rough.d.ts +0 -2
- package/dist/shaders/materials/cloth_rough.d.ts.map +0 -1
- package/dist/shaders/materials/cloth_rough.js +0 -69
- package/dist/shaders/materials/cloth_smooth.d.ts +0 -2
- package/dist/shaders/materials/cloth_smooth.d.ts.map +0 -1
- package/dist/shaders/materials/cloth_smooth.js +0 -61
- package/dist/shaders/materials/default.d.ts +0 -2
- package/dist/shaders/materials/default.d.ts.map +0 -1
- package/dist/shaders/materials/default.js +0 -43
- package/dist/shaders/materials/eye.d.ts +0 -2
- package/dist/shaders/materials/eye.d.ts.map +0 -1
- package/dist/shaders/materials/eye.js +0 -60
- package/dist/shaders/materials/face.d.ts +0 -2
- package/dist/shaders/materials/face.d.ts.map +0 -1
- package/dist/shaders/materials/face.js +0 -95
- package/dist/shaders/materials/hair.d.ts +0 -2
- package/dist/shaders/materials/hair.d.ts.map +0 -1
- package/dist/shaders/materials/hair.js +0 -90
- package/dist/shaders/materials/metal.d.ts +0 -2
- package/dist/shaders/materials/metal.d.ts.map +0 -1
- package/dist/shaders/materials/metal.js +0 -77
- package/dist/shaders/materials/mmd_classic.d.ts +0 -2
- package/dist/shaders/materials/mmd_classic.d.ts.map +0 -1
- package/dist/shaders/materials/mmd_classic.js +0 -66
- package/dist/shaders/materials/stockings.d.ts +0 -2
- package/dist/shaders/materials/stockings.d.ts.map +0 -1
- package/dist/shaders/materials/stockings.js +0 -122
- package/dist/shaders/passes/physics-debug.d.ts +0 -2
- package/dist/shaders/passes/physics-debug.d.ts.map +0 -1
- package/dist/shaders/passes/physics-debug.js +0 -69
- package/src/shaders/dfg_lut.ts +0 -131
- package/src/shaders/ltc_mag_lut.ts +0 -1035
|
@@ -1,16 +1,9 @@
|
|
|
1
|
-
// Shared WGSL primitives for
|
|
2
|
-
//
|
|
1
|
+
// Shared WGSL primitives for the material graph's nodes: Unity's lighting
|
|
2
|
+
// (Lit, Lambert, the reflection probe) and the colour and vector maths a
|
|
3
|
+
// Shader Graph builds from.
|
|
3
4
|
// Hand-ported material shaders concatenate this block before their own code.
|
|
4
5
|
export const NODES_WGSL = /* wgsl */ `
|
|
5
6
|
|
|
6
|
-
// Baked 64×64 rgba8unorm combined BRDF LUT — created once at engine init by dfg_lut.ts.
|
|
7
|
-
// .rg = split-sum DFG (Karis: tint = f0·x + f90·y) → F_brdf_*_scatter
|
|
8
|
-
// .ba = Heitz 2016 LTC magnitude (ltc_mag_ggx) → ltc_brdf_scale_from_lut
|
|
9
|
-
// Paired with group(0) binding(2) diffuseSampler (linear filter). Sample once per
|
|
10
|
-
// fragment via brdf_lut_sample() — callers feed .rg and the whole vec4 into the
|
|
11
|
-
// helpers below, halving LUT taps on the default Principled path.
|
|
12
|
-
@group(0) @binding(9) var brdfLut: texture_2d<f32>;
|
|
13
|
-
|
|
14
7
|
// ─── RGB ↔ HSV ──────────────────────────────────────────────────────
|
|
15
8
|
|
|
16
9
|
fn rgb_to_hsv(rgb: vec3f) -> vec3f {
|
|
@@ -274,8 +267,23 @@ fn node_normal_map(color: vec3f, strength: f32, N: vec3f, worldPos: vec3f, uv: v
|
|
|
274
267
|
let B = safe_normal(cross(N, T));
|
|
275
268
|
// Tangent-space [0,1] → [-1,1], then into world.
|
|
276
269
|
let t = color * 2.0 - vec3f(1.0);
|
|
277
|
-
|
|
278
|
-
|
|
270
|
+
// Strength scales the tangent tilt (x, y), as Unity's _NormalScale and
|
|
271
|
+
// Blender's Normal Map strength both do — so it may exceed 1 and steepen a
|
|
272
|
+
// shallow map, which a lerp toward the map could never do.
|
|
273
|
+
let s = max(strength, 0.0);
|
|
274
|
+
return safe_normal(T * (t.x * s) + B * (t.y * s) + N * t.z);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* The same, for a map packed the way game engines store normals (DXT5nm /
|
|
279
|
+
* BC5): X in alpha, Y in green, Z rebuilt from the two. Aether Gazer's stage
|
|
280
|
+
* normals are packed so (and its red channel is a constant 1). A converter
|
|
281
|
+
* normally swizzles these to a plain RGB map; this reads one that was not.
|
|
282
|
+
*/
|
|
283
|
+
fn node_normal_map_packed(color: vec4f, strength: f32, N: vec3f, worldPos: vec3f, uv: vec2f) -> vec3f {
|
|
284
|
+
let xy = vec2f(color.a * color.r, color.g) * 2.0 - vec2f(1.0);
|
|
285
|
+
let z = sqrt(max(1.0 - dot(xy, xy), 0.0));
|
|
286
|
+
return node_normal_map(vec3f(xy, z) * 0.5 + vec3f(0.5), strength, N, worldPos, uv);
|
|
279
287
|
}
|
|
280
288
|
|
|
281
289
|
/** Vector Transform, world ↔ camera. Object space IS world here: a PMX model is
|
|
@@ -792,6 +800,15 @@ fn luminance_rec709_linear(c: vec3f) -> f32 {
|
|
|
792
800
|
return dot(max(c, vec3f(0.0)), vec3f(0.2126, 0.7152, 0.0722));
|
|
793
801
|
}
|
|
794
802
|
|
|
803
|
+
/** URP's LightingLambert for the main light, plus the ambient: the light a
|
|
804
|
+
* white surface facing n receives — light·max(N·L, 0)·shadow + ambient, in
|
|
805
|
+
* Unity's units. What a toon shader in Shader Graph ramps. .rgb is the light,
|
|
806
|
+
* .a its luminance (Unity's Luminance, Rec. 709). */
|
|
807
|
+
fn urp_lambert(n: vec3f, l: vec3f, sun_rgb: vec3f, ambient_rgb: vec3f, shadow: f32) -> vec4f {
|
|
808
|
+
let c = sun_rgb * (max(dot(n, l), 0.0) * shadow) + ambient_rgb;
|
|
809
|
+
return vec4f(c, luminance_rec709_linear(c));
|
|
810
|
+
}
|
|
811
|
+
|
|
795
812
|
// ─── FRESNEL node ───────────────────────────────────────────────────
|
|
796
813
|
// Schlick approximation matching Blender's Fresnel node
|
|
797
814
|
|
|
@@ -832,36 +849,6 @@ fn layer_weight_facing(blend: f32, n: vec3f, v: vec3f) -> f32 {
|
|
|
832
849
|
// Eevee captures lit diffuse: (albedo/π)*sun*N·L*shadow + ambient (linear). Albedo=1.
|
|
833
850
|
// Matches default.ts direct term scale so VALTORGB thresholds from Blender JSON stay valid.
|
|
834
851
|
|
|
835
|
-
/**
|
|
836
|
-
* Shader → RGB on a white diffuse closure, as a COLOUR.
|
|
837
|
-
*
|
|
838
|
-
* Blender's ShaderToRGB hands back what the closure actually radiates, and that
|
|
839
|
-
* is coloured: a warm sun against a cool ambient gives warm light and cool
|
|
840
|
-
* shadow, which is most of what an NPR ramp is reading. Collapsing it to
|
|
841
|
-
* luminance first — which this used to do — throws that away and leaves every
|
|
842
|
-
* ramp working on grey.
|
|
843
|
-
*
|
|
844
|
-
* Feeding this into a scalar socket still yields a float, because Blender's own
|
|
845
|
-
* implicit Color → Value conversion (BT.601, see color_to_value) does it at the
|
|
846
|
-
* link. So a graph that wants the scalar gets Blender's scalar, and one that
|
|
847
|
-
* wants the colour now gets that too.
|
|
848
|
-
*
|
|
849
|
-
* The maths matches 5.2's bxdf_diffuse_eval, which is saturate(dot(N,L))
|
|
850
|
-
* integrated against a cosine distribution: radiance = E·N·L/π for the sun, plus
|
|
851
|
-
* the world's own irradiance. EEVEE Next's extra transport — probe GI, virtual
|
|
852
|
-
* shadow maps, ray-traced bounce — is machinery rather than a term, and is not
|
|
853
|
-
* here.
|
|
854
|
-
*/
|
|
855
|
-
fn shader_to_rgb_lit(n: vec3f, l: vec3f, sun_rgb: vec3f, ambient_rgb: vec3f, shadow: f32) -> vec3f {
|
|
856
|
-
const PI_S: f32 = 3.141592653589793;
|
|
857
|
-
let ndotl = max(dot(n, l), 0.0);
|
|
858
|
-
return sun_rgb * (ndotl * shadow / PI_S) + ambient_rgb;
|
|
859
|
-
}
|
|
860
|
-
|
|
861
|
-
fn shader_to_rgb_diffuse(n: vec3f, l: vec3f, sun_rgb: vec3f, ambient_rgb: vec3f, shadow: f32) -> f32 {
|
|
862
|
-
return luminance_rec709_linear(shader_to_rgb_lit(n, l, sun_rgb, ambient_rgb, shadow));
|
|
863
|
-
}
|
|
864
|
-
|
|
865
852
|
// ─── SUBSURFACE node ────────────────────────────────────────────────
|
|
866
853
|
// Marks this fragment for the screen-space scattering pass (passes/subsurface.ts)
|
|
867
854
|
// and passes its colour through. The strength lands in the aux target's .b via
|
|
@@ -1073,41 +1060,12 @@ fn normal_map(strength: f32, map_color: vec3f, normal: vec3f, tangent: vec3f, bi
|
|
|
1073
1060
|
return normalize(mix(normal, perturbed, strength));
|
|
1074
1061
|
}
|
|
1075
1062
|
|
|
1076
|
-
// ───
|
|
1077
|
-
// Ports from Blender 3.6 source/blender/draw/engines/eevee/shaders/
|
|
1078
|
-
// bsdf_common_lib.glsl + gpu_shader_material_principled.glsl.
|
|
1079
|
-
// Usage pattern (see material shaders): direct spec = bsdf_ggx × sun × shadow
|
|
1080
|
-
// (NL baked in, no F yet); ambient spec = probe_radiance; tint both with
|
|
1081
|
-
// reflection_color = F_brdf_multi_scatter(f0, f90, split_sum) AFTER summing.
|
|
1082
|
-
|
|
1083
|
-
const EEVEE_PI: f32 = 3.141592653589793;
|
|
1084
|
-
|
|
1085
|
-
// Fused analytic GGX specular (direct lights). Returns BRDF × NL.
|
|
1086
|
-
// 4·NL·NV is cancelled via G1_Smith reciprocal form — see bsdf_common_lib.glsl:115.
|
|
1087
|
-
// Caller passes NL, NV (already computed for diffuse + brdf_lut_sample) so WebKit
|
|
1088
|
-
// can reuse them instead of recomputing dot products across the function boundary.
|
|
1089
|
-
fn bsdf_ggx(N: vec3f, L: vec3f, V: vec3f, NL_in: f32, NV_in: f32, roughness: f32) -> f32 {
|
|
1090
|
-
let a = max(roughness, 1e-4);
|
|
1091
|
-
let a2 = a * a;
|
|
1092
|
-
let H = normalize(L + V);
|
|
1093
|
-
let NH = max(dot(N, H), 1e-8);
|
|
1094
|
-
let NL = max(NL_in, 1e-8);
|
|
1095
|
-
let NV = max(NV_in, 1e-8);
|
|
1096
|
-
// G1_Smith_GGX_opti reciprocal form — denominator piece only.
|
|
1097
|
-
let G1L = NL + sqrt(NL * (NL - NL * a2) + a2);
|
|
1098
|
-
let G1V = NV + sqrt(NV * (NV - NV * a2) + a2);
|
|
1099
|
-
let G = G1L * G1V;
|
|
1100
|
-
// D_ggx_opti = pi * denom² — reciprocal D × a².
|
|
1101
|
-
let tmp = (NH * a2 - NH) * NH + 1.0;
|
|
1102
|
-
let D_opti = EEVEE_PI * tmp * tmp;
|
|
1103
|
-
return NL * a2 / (D_opti * G);
|
|
1104
|
-
}
|
|
1063
|
+
// ─── URP's direct specular ──────────────────────────────────────────
|
|
1105
1064
|
|
|
1106
1065
|
// URP's direct-light specular, as a game on URP (or a fork of it) shades its
|
|
1107
1066
|
// lamps and sun: D·V·F folded into a2 / (d²·max(0.1, LoH²)·(4a + 2)), a the
|
|
1108
|
-
// SQUARED roughness
|
|
1109
|
-
//
|
|
1110
|
-
// loader), so it comes back out here. Returns BRDF × NL, like bsdf_ggx.
|
|
1067
|
+
// SQUARED roughness, exactly as URP writes it — this engine's lights are in
|
|
1068
|
+
// Unity's units (LIGHT UNITS). Returns BRDF × NL.
|
|
1111
1069
|
fn bsdf_urp(N: vec3f, L: vec3f, V: vec3f, NL: f32, roughness: f32) -> f32 {
|
|
1112
1070
|
let a = max(roughness * roughness, 6.1035156e-5);
|
|
1113
1071
|
let a2 = a * a;
|
|
@@ -1115,94 +1073,10 @@ fn bsdf_urp(N: vec3f, L: vec3f, V: vec3f, NL: f32, roughness: f32) -> f32 {
|
|
|
1115
1073
|
let NH = max(dot(N, H), 0.0);
|
|
1116
1074
|
let LH = max(dot(L, H), 0.0);
|
|
1117
1075
|
let d = NH * NH * (a2 - 1.0) + 1.00001;
|
|
1118
|
-
return a2 / (d * d * max(0.1, LH * LH) * (a * 4.0 + 2.0)) * NL
|
|
1119
|
-
}
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
* 1 URP's (principled's unity_direct). */
|
|
1123
|
-
fn _rzDirectLobe(N: vec3f, L: vec3f, V: vec3f, NL: f32, NV: f32, roughness: f32, unity: f32) -> f32 {
|
|
1124
|
-
if (unity > 0.5) { return bsdf_urp(N, L, V, NL, roughness); }
|
|
1125
|
-
return bsdf_ggx(N, L, V, NL, NV, roughness);
|
|
1126
|
-
}
|
|
1127
|
-
|
|
1128
|
-
// Split-sum DFG LUT — Karis 2013 curve fit stand-in for the 64×64 baked LUT.
|
|
1129
|
-
// Returns (lut.x, lut.y) in Blender convention: tint = f0·lut.x + f90·lut.y.
|
|
1130
|
-
fn brdf_lut_approx(NV: f32, roughness: f32) -> vec2f {
|
|
1131
|
-
let c0 = vec4f(-1.0, -0.0275, -0.572, 0.022);
|
|
1132
|
-
let c1 = vec4f(1.0, 0.0425, 1.04, -0.04);
|
|
1133
|
-
let r = roughness * c0 + c1;
|
|
1134
|
-
let a004 = min(r.x * r.x, exp2(-9.28 * NV)) * r.x + r.y;
|
|
1135
|
-
return vec2f(-1.04, 1.04) * a004 + r.zw;
|
|
1136
|
-
}
|
|
1137
|
-
|
|
1138
|
-
// Baked combined BRDF LUT — exact port of Blender bsdf_lut_frag.glsl packed with
|
|
1139
|
-
// ltc_mag_ggx from eevee_lut.c. Single sample returns DFG (.rg) and LTC mag (.ba).
|
|
1140
|
-
// Addressed as Blender's common_utiltex_lib.glsl:lut_coords:
|
|
1141
|
-
// coords = (roughness, sqrt(1 - NV)), then half-texel bias for filtering.
|
|
1142
|
-
// Requires group(0) binding(9) brdfLut + binding(2) diffuseSampler in the host shader.
|
|
1143
|
-
fn brdf_lut_sample(NV: f32, roughness: f32) -> vec4f {
|
|
1144
|
-
let LUT_SIZE: f32 = 64.0;
|
|
1145
|
-
var uv = vec2f(saturate(roughness), sqrt(saturate(1.0 - NV)));
|
|
1146
|
-
uv = uv * ((LUT_SIZE - 1.0) / LUT_SIZE) + 0.5 / LUT_SIZE;
|
|
1147
|
-
return textureSampleLevel(brdfLut, diffuseSampler, uv, 0.0);
|
|
1148
|
-
}
|
|
1149
|
-
|
|
1150
|
-
fn F_brdf_single_scatter(f0: vec3f, f90: vec3f, lut: vec2f) -> vec3f {
|
|
1151
|
-
return lut.y * f90 + lut.x * f0;
|
|
1152
|
-
}
|
|
1153
|
-
|
|
1154
|
-
// Fdez-Agüera 2019 multi-scatter compensation (EEVEE do_multiscatter=1).
|
|
1155
|
-
fn F_brdf_multi_scatter(f0: vec3f, f90: vec3f, lut: vec2f) -> vec3f {
|
|
1156
|
-
let FssEss = lut.y * f90 + lut.x * f0;
|
|
1157
|
-
let Ess = lut.x + lut.y;
|
|
1158
|
-
let Ems = 1.0 - Ess;
|
|
1159
|
-
let Favg = f0 + (1.0 - f0) / 21.0;
|
|
1160
|
-
let Fms = FssEss * Favg / (1.0 - (1.0 - Ess) * Favg);
|
|
1161
|
-
return FssEss + Fms * Ems;
|
|
1162
|
-
}
|
|
1163
|
-
|
|
1164
|
-
// EEVEE direct-specular energy compensation factor — closure_eval_glossy_lib.glsl:79-81:
|
|
1165
|
-
// ltc_brdf_scale = (ltc.x + ltc.y) / (split_sum.x + split_sum.y)
|
|
1166
|
-
// Blender evaluates direct lights via LTC (Heitz 2016) but indirect via split-sum;
|
|
1167
|
-
// direct radiance is rescaled so total-energy matches the split-sum LUT.
|
|
1168
|
-
// Takes a pre-sampled vec4f from brdf_lut_sample() to share the fetch with
|
|
1169
|
-
// F_brdf_multi_scatter on the same fragment.
|
|
1170
|
-
fn ltc_brdf_scale_from_lut(lut: vec4f) -> f32 {
|
|
1171
|
-
return (lut.z + lut.w) / max(lut.x + lut.y, 1e-6);
|
|
1172
|
-
}
|
|
1173
|
-
|
|
1174
|
-
// Luminance-normalized hue extraction — Blender tint_from_color (isolates hue+sat).
|
|
1175
|
-
fn tint_from_color(color: vec3f) -> vec3f {
|
|
1176
|
-
let lum = dot(color, vec3f(0.3, 0.6, 0.1));
|
|
1177
|
-
return select(vec3f(1.0), color / lum, lum > 0.0);
|
|
1178
|
-
}
|
|
1179
|
-
|
|
1180
|
-
// ─── Principled sheen (gpu_shader_material_principled.glsl:8-14) ────
|
|
1181
|
-
// Empirical NV-only curve that approximates grazing retroreflection on cloth/velvet.
|
|
1182
|
-
// Scales the sheen layer's diffuse contribution; no sheen call site has sheen=0
|
|
1183
|
-
// shortcut because the multiplier is tiny at normal view angles anyway.
|
|
1184
|
-
fn principled_sheen(NV: f32) -> f32 {
|
|
1185
|
-
let f = 1.0 - NV;
|
|
1186
|
-
return f * f * f * 0.077 + f * 0.01 + 0.00026;
|
|
1187
|
-
}
|
|
1188
|
-
|
|
1189
|
-
// ─── Principled BSDF eval ───────────────────────────────────────────
|
|
1190
|
-
// Shared EEVEE Principled path used by every material in the engine — metallic,
|
|
1191
|
-
// dielectric, and sheen variants all fold into these ~15 lines via the struct
|
|
1192
|
-
// fields. NPR materials still compute a separate toon/rim/warm stack on top and
|
|
1193
|
-
// mix(npr_stack, eval_principled(...), fac); see body.ts / face.ts / etc.
|
|
1194
|
-
//
|
|
1195
|
-
// Field conventions:
|
|
1196
|
-
// base — diffuse albedo. Mixed into f0 only when metallic > 0.
|
|
1197
|
-
// metallic — 0 = dielectric (f0 from specular), 1 = pure metal (f0 = base).
|
|
1198
|
-
// specular — Principled Specular input (0.5 default → f0 = 0.04). sqrt for f90.
|
|
1199
|
-
// roughness — GGX roughness; drives BRDF LUT coord + bsdf_ggx.
|
|
1200
|
-
// spec_clamp — EEVEE Light Clamp equivalent. Caps firefly spec from noise-bumped
|
|
1201
|
-
// NDF aliasing (Blender hides this via TAA which we don't have).
|
|
1202
|
-
// Pass 1e30 (effectively disabled) for materials that don't bump.
|
|
1203
|
-
// sheen — 0 disables. Scales the sheen diffuse add; cloth/stockings use ~0.7.
|
|
1204
|
-
// sheen_tint — 0 = white sheen, 1 = fully tinted by base. Multiplied by sheen,
|
|
1205
|
-
// so value is don't-care when sheen=0.
|
|
1076
|
+
return a2 / (d * d * max(0.1, LH * LH) * (a * 4.0 + 2.0)) * NL;
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
|
|
1206
1080
|
// The PMX sphere map, applied the way MMD applies it: the texture is a
|
|
1207
1081
|
// VIEW-SPACE lighting mask, sampled by the camera-space normal rather than by
|
|
1208
1082
|
// any UV the mesh carries, which is why it tracks the viewer and reads as a
|
|
@@ -1224,20 +1098,6 @@ fn pmx_sphere_map(base: vec3f, strength: f32, N: vec3f) -> vec3f {
|
|
|
1224
1098
|
return base + sphere_rgb * amount;
|
|
1225
1099
|
}
|
|
1226
1100
|
|
|
1227
|
-
/**
|
|
1228
|
-
* Principled v2 reflectance: IOR sets it, the level scales it.
|
|
1229
|
-
*
|
|
1230
|
-
* Blender 3.6 took Specular directly, where 0.5 meant f0 = 0.04. v2 computes
|
|
1231
|
-
* f0 from IOR — ((ior-1)/(ior+1))² — and Specular IOR Level scales that, with
|
|
1232
|
-
* 0.5 meaning "the IOR's own value". Returned in the 3.6 convention the BSDF
|
|
1233
|
-
* below still speaks (f0 = 0.08 · specular), so the two agree at their defaults
|
|
1234
|
-
* and v2 wins whenever a preset moves either socket.
|
|
1235
|
-
*/
|
|
1236
|
-
fn principled_specular(ior: f32, level: f32) -> f32 {
|
|
1237
|
-
let r = (ior - 1.0) / max(ior + 1.0, 1e-6);
|
|
1238
|
-
return (r * r * 2.0 * max(level, 0.0)) / 0.08;
|
|
1239
|
-
}
|
|
1240
|
-
|
|
1241
1101
|
// ─── The scene's lamps, on a PBR closure ───────────────────────────
|
|
1242
1102
|
//
|
|
1243
1103
|
// A lamp reaches a material as rzLightsDiffuse, added outside the graph and
|
|
@@ -1247,7 +1107,7 @@ fn principled_specular(ior: f32, level: f32) -> f32 {
|
|
|
1247
1107
|
// REFLECTS a lamp instead of having it painted on — without this a ported
|
|
1248
1108
|
// stage is a photograph of itself, lit but never shining.
|
|
1249
1109
|
//
|
|
1250
|
-
// Same reach as _rzLightOne: the inverse square past
|
|
1110
|
+
// Same reach as _rzLightOne: the inverse square past the lamp's bulb, the
|
|
1251
1111
|
// (1 − (d/R)⁴)² window that makes the radius real, the squared cone. N·L is
|
|
1252
1112
|
// inside bsdf_ggx. Declared here for bsdf_ggx and resolved against the lights
|
|
1253
1113
|
// API the material prelude brings; the ground pass takes that API without
|
|
@@ -1262,7 +1122,7 @@ fn principled_specular(ior: f32, level: f32) -> f32 {
|
|
|
1262
1122
|
// second pass over the grid. See lights.ts.
|
|
1263
1123
|
struct _RzLampPair { d: vec3f, s: vec3f };
|
|
1264
1124
|
|
|
1265
|
-
fn _rzLampOne(i: u32, p: vec3f, n: vec3f, v: vec3f,
|
|
1125
|
+
fn _rzLampOne(i: u32, p: vec3f, n: vec3f, v: vec3f, roughness: f32) -> _RzLampPair {
|
|
1266
1126
|
var out = _RzLampPair(vec3f(0.0), vec3f(0.0));
|
|
1267
1127
|
if (!_rzLightReaches(i)) { return out; }
|
|
1268
1128
|
let pr = _rzLightVec(i, 0u);
|
|
@@ -1276,140 +1136,200 @@ fn _rzLampOne(i: u32, p: vec3f, n: vec3f, v: vec3f, ndv: f32, roughness: f32, un
|
|
|
1276
1136
|
let t = clamp(dist / max(pr.w, 1e-4), 0.0, 1.0);
|
|
1277
1137
|
let t2 = t * t;
|
|
1278
1138
|
let window = 1.0 - t2 * t2;
|
|
1279
|
-
let
|
|
1139
|
+
let bulb = rzLightNear(i);
|
|
1140
|
+
let falloff = window * window / max(dist * dist, bulb * bulb);
|
|
1280
1141
|
let cone = rzLightCone(i);
|
|
1281
1142
|
let aim = clamp((dot(-toLight, rzLightAim(i)) - cone.x) / max(cone.y - cone.x, 1e-4), 0.0, 1.0);
|
|
1282
|
-
let c = rzLightColor(i);
|
|
1143
|
+
let c = rzLightColor(i) * rzLightCookie(i, toLight);
|
|
1283
1144
|
if (ndlD > 0.0) { out.d = c * (ndlD * falloff * aim * aim); }
|
|
1284
|
-
if (ndl > 0.0) { out.s = c * (
|
|
1145
|
+
if (ndl > 0.0) { out.s = c * (bsdf_urp(n, toLight, v, ndl, roughness) * falloff * aim * aim); }
|
|
1285
1146
|
return out;
|
|
1286
1147
|
}
|
|
1287
1148
|
|
|
1288
|
-
fn _rzLampWord(bits0: u32, base: u32, p: vec3f, n: vec3f, v: vec3f,
|
|
1149
|
+
fn _rzLampWord(bits0: u32, base: u32, p: vec3f, n: vec3f, v: vec3f, roughness: f32) -> _RzLampPair {
|
|
1289
1150
|
var acc = _RzLampPair(vec3f(0.0), vec3f(0.0));
|
|
1290
1151
|
var bits = bits0;
|
|
1291
1152
|
loop {
|
|
1292
1153
|
if (bits == 0u) { break; }
|
|
1293
1154
|
let i = base + firstTrailingBit(bits);
|
|
1294
1155
|
bits = bits & (bits - 1u);
|
|
1295
|
-
let one = _rzLampOne(i, p, n, v,
|
|
1156
|
+
let one = _rzLampOne(i, p, n, v, roughness);
|
|
1296
1157
|
acc.d = acc.d + one.d;
|
|
1297
1158
|
acc.s = acc.s + one.s;
|
|
1298
1159
|
}
|
|
1299
1160
|
return acc;
|
|
1300
1161
|
}
|
|
1301
1162
|
|
|
1302
|
-
fn rzLampsSpecular(p: vec3f, n: vec3f, v: vec3f,
|
|
1163
|
+
fn rzLampsSpecular(p: vec3f, n: vec3f, v: vec3f, roughness: f32) -> vec3f {
|
|
1303
1164
|
var d = vec3f(0.0);
|
|
1304
1165
|
var s = vec3f(0.0);
|
|
1305
1166
|
let count = rzLightCount();
|
|
1306
1167
|
let docs = _rzLightDocCount();
|
|
1307
1168
|
if (docs > 0u) {
|
|
1308
1169
|
let m = _rzLightCellMask(p);
|
|
1309
|
-
let
|
|
1310
|
-
let
|
|
1311
|
-
let
|
|
1312
|
-
let
|
|
1313
|
-
|
|
1314
|
-
|
|
1170
|
+
let w0 = _rzLampWord(m.lo.x, 0u, p, n, v, roughness);
|
|
1171
|
+
let w1 = _rzLampWord(m.lo.y, 32u, p, n, v, roughness);
|
|
1172
|
+
let w2 = _rzLampWord(m.lo.z, 64u, p, n, v, roughness);
|
|
1173
|
+
let w3 = _rzLampWord(m.lo.w, 96u, p, n, v, roughness);
|
|
1174
|
+
let w4 = _rzLampWord(m.hi.x, 128u, p, n, v, roughness);
|
|
1175
|
+
let w5 = _rzLampWord(m.hi.y, 160u, p, n, v, roughness);
|
|
1176
|
+
let w6 = _rzLampWord(m.hi.z, 192u, p, n, v, roughness);
|
|
1177
|
+
let w7 = _rzLampWord(m.hi.w, 224u, p, n, v, roughness);
|
|
1178
|
+
d = d + w0.d + w1.d + w2.d + w3.d + w4.d + w5.d + w6.d + w7.d;
|
|
1179
|
+
s = s + w0.s + w1.s + w2.s + w3.s + w4.s + w5.s + w6.s + w7.s;
|
|
1315
1180
|
}
|
|
1316
1181
|
for (var i = docs; i < count; i = i + 1u) {
|
|
1317
|
-
let one = _rzLampOne(i, p, n, v,
|
|
1182
|
+
let one = _rzLampOne(i, p, n, v, roughness);
|
|
1318
1183
|
d = d + one.d;
|
|
1319
1184
|
s = s + one.s;
|
|
1320
1185
|
}
|
|
1321
1186
|
// The first closure's walk speaks for the fragment; a second principled in
|
|
1322
1187
|
// the same graph shares p and the prelude normal, so its answer is the same.
|
|
1323
1188
|
if (!_rzLampDiffuseSet) {
|
|
1324
|
-
_rzLampDiffuse = d
|
|
1189
|
+
_rzLampDiffuse = d;
|
|
1325
1190
|
_rzLampDiffuseSet = true;
|
|
1326
1191
|
}
|
|
1327
1192
|
return s;
|
|
1328
1193
|
}
|
|
1329
1194
|
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1195
|
+
// ─── Lit: URP's PBR, term for term ─────────────
|
|
1196
|
+
//
|
|
1197
|
+
// What Unity's Lit shader (URP's UniversalFragmentPBR) computes, so a
|
|
1198
|
+
// surface authored with its inputs looks the way it does in Unity: stage,
|
|
1199
|
+
// props, scenery and weather. Light units are Unity's (see LIGHT UNITS in
|
|
1200
|
+
// lights.ts) — no 1/π anywhere.
|
|
1201
|
+
|
|
1202
|
+
/** URP's EnvironmentBRDFSpecular: the reflection's reflectance —
|
|
1203
|
+
* 1/(α² + 1)·mix(f0, grazing, (1 − N·V)⁴), grazing = saturate(s + reflectivity). */
|
|
1204
|
+
fn urp_env_brdf(f0: vec3f, roughness: f32, smoothness: f32, reflectivity: f32, NV: f32) -> vec3f {
|
|
1205
|
+
let a = max(roughness * roughness, 0.0078125);
|
|
1206
|
+
let grazing = saturate(smoothness + reflectivity);
|
|
1207
|
+
let f = pow(1.0 - NV, 4.0);
|
|
1208
|
+
return (1.0 / (a * a + 1.0)) * mix(f0, vec3f(grazing), f);
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
/**
|
|
1212
|
+
* A box projection: where a ray from p along d leaves the box, seen from the
|
|
1213
|
+
* probe's capture point. What turns one cube captured at the middle of a room
|
|
1214
|
+
* into a reflection that lines up with that room from anywhere inside it —
|
|
1215
|
+
* the floor near the bar reflects the bar, not whatever was opposite the
|
|
1216
|
+
* capture point. A point outside the box (or a box of zero size) keeps the
|
|
1217
|
+
* plain direction.
|
|
1218
|
+
*/
|
|
1219
|
+
fn rz_box_project(d: vec3f, p: vec3f, bmin: vec3f, bmax: vec3f, c: vec3f) -> vec3f {
|
|
1220
|
+
let dd = select(d, vec3f(1e-5), abs(d) < vec3f(1e-5));
|
|
1221
|
+
let far = max((bmax - p) / dd, (bmin - p) / dd);
|
|
1222
|
+
let t = min(min(far.x, far.y), far.z);
|
|
1223
|
+
let inside = all(p > bmin) && all(p < bmax);
|
|
1224
|
+
return select(d, normalize(p + d * t - c), inside && t > 0.0);
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
/**
|
|
1228
|
+
* The scene's reflection: the stage's own reflection probe where the engine
|
|
1229
|
+
* captured one (Engine reflection probe — rendered from the stage's middle,
|
|
1230
|
+
* GGX-prefiltered, box-projected to the stage's bounds), else the world's sky.
|
|
1231
|
+
*
|
|
1232
|
+
* ROUGHNESS PICKS THE MIP ON UNITY'S CURVE, r·(1.7 − 0.7r)·6 on a cube of
|
|
1233
|
+
* seven levels (64² down to 1²) — URP's PerceptualRoughnessToMipmapLevel with
|
|
1234
|
+
* UNITY_SPECCUBE_LOD_STEPS 6, which the prefilter that built the levels assumed.
|
|
1235
|
+
*/
|
|
1236
|
+
fn rzProbeSpecular(dir: vec3f, wp: vec3f, roughness: f32) -> vec3f {
|
|
1237
|
+
let r = clamp(roughness, 0.0, 1.0);
|
|
1238
|
+
if (probe.boxMin.w < 0.5) { return rzWorldSpecularLod(dir, r, 1.0); }
|
|
1239
|
+
let levels = f32(textureNumLevels(probeCube) - 1u);
|
|
1240
|
+
let lod = min(r * (1.7 - 0.7 * r) * 6.0, levels);
|
|
1241
|
+
let d = rz_box_project(normalize(dir), wp, probe.boxMin.xyz, probe.boxMax.xyz, probe.center.xyz);
|
|
1242
|
+
return textureSampleLevel(probeCube, diffuseSampler, d, lod).rgb * probe.center.w;
|
|
1243
|
+
}
|
|
1349
1244
|
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
let
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
let
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
let sheen_color = mix(vec3f(1.0), base_tint, p.sheen_tint);
|
|
1391
|
-
let diffuse_color = p.base + p.sheen * sheen_color * principled_sheen(NV);
|
|
1392
|
-
|
|
1393
|
-
// diffuse_weight = (1-metallic). Indirect diffuse uses amb (L_w) with no π factor
|
|
1394
|
-
// (probe_evaluate_world_diff returns SH-projected radiance, not cosine-convolved).
|
|
1395
|
-
let diffuse_weight = 1.0 - p.metallic;
|
|
1396
|
-
var diffuse_radiance = diffuse_color * (sun_rgb * NL * shadow / EEVEE_PI + amb_rgb) * diffuse_weight;
|
|
1397
|
-
// The lamps' diffuse, in Unity mode, as URP shades it: THIS surface's albedo
|
|
1398
|
-
// — its tint and its maps, not the raw texture the epilogue would use —
|
|
1399
|
-
// times 0.96·(1 − metal). X340's floor wears a 0.588 tint the epilogue never
|
|
1400
|
-
// saw, and every lamp on it landed 1.7× too bright.
|
|
1401
|
-
if (p.unity_direct > 0.5 && !_rzLampDiffuseTaken) {
|
|
1402
|
-
diffuse_radiance += p.base * (0.96 * (1.0 - p.metallic)) * rzLightsDiffuseOnce(wp, N);
|
|
1245
|
+
/**
|
|
1246
|
+
* URP's Lit, whole: the sun and every lamp, the ambient, the reflection and
|
|
1247
|
+
* the emission, as UniversalFragmentPBR adds them.
|
|
1248
|
+
*
|
|
1249
|
+
* diffuse = base·(1 − f)·(1 − m) specular = mix(f, base, m), f = 0.08·spec
|
|
1250
|
+
* (spec 0.5 is URP's own dielectric 0.04 — Unreal's and HDRP's Specular)
|
|
1251
|
+
* direct = (diffuse + specular·DirectBRDFSpecular)·light·N·L·shadow
|
|
1252
|
+
* indirect = (diffuse·SH(n) + probe(R, mip(1 − s))·EnvironmentBRDF)·occlusion
|
|
1253
|
+
* out = direct + indirect + emission
|
|
1254
|
+
*
|
|
1255
|
+
* Alpha below 1 is Transparent with Preserve Specular Lighting (URP's
|
|
1256
|
+
* _ALPHAPREMULTIPLY_ON): the diffuse is weighted by alpha, reflection and
|
|
1257
|
+
* highlights are not, and the coverage is alpha·0.96(1 − m) + reflectivity —
|
|
1258
|
+
* a window keeps its reflections at any transparency. Pair it with a group
|
|
1259
|
+
* blending "premultiplied". The result is .rgb and that coverage is .a.
|
|
1260
|
+
*
|
|
1261
|
+
* As the surface (the graph's output), the lamps' diffuse is
|
|
1262
|
+
* shaded here by THIS surface's albedo and the epilogue adds none; as a layer
|
|
1263
|
+
* of a larger look it leaves them to the epilogue. The cast's shadow on a
|
|
1264
|
+
* stage multiplies the lit part.
|
|
1265
|
+
*/
|
|
1266
|
+
fn urp_lit(base: vec3f, metallic: f32, smoothness: f32, spec: f32, occlusion: f32, emission: vec3f, alpha: f32,
|
|
1267
|
+
N: vec3f, L: vec3f, V: vec3f, sun_rgb: vec3f, amb_rgb: vec3f, shadow: f32, wp: vec3f,
|
|
1268
|
+
surface: bool) -> vec4f {
|
|
1269
|
+
let m = clamp(metallic, 0.0, 1.0);
|
|
1270
|
+
let sm = clamp(smoothness, 0.0, 1.0);
|
|
1271
|
+
let r = 1.0 - sm;
|
|
1272
|
+
let a = clamp(alpha, 0.0, 1.0);
|
|
1273
|
+
let NL = saturate(dot(N, L));
|
|
1274
|
+
let NV = max(dot(N, V), 1e-4);
|
|
1275
|
+
let f = 0.08 * clamp(spec, 0.0, 1.0);
|
|
1276
|
+
let oneMinusReflectivity = (1.0 - f) * (1.0 - m);
|
|
1277
|
+
let reflectivity = 1.0 - oneMinusReflectivity;
|
|
1278
|
+
let diffuse = base * oneMinusReflectivity * a;
|
|
1279
|
+
let specular = mix(vec3f(f), base, m);
|
|
1280
|
+
// The lamps first: their walk caches the diffuse layer it passes over.
|
|
1281
|
+
let lampSpec = rzLampsSpecular(wp, N, V, r);
|
|
1282
|
+
var lampDiff = vec3f(0.0);
|
|
1283
|
+
if (surface) {
|
|
1284
|
+
lampDiff = rzLightsDiffuseOnce(wp, N);
|
|
1403
1285
|
_rzLampDiffuseTaken = true;
|
|
1404
1286
|
}
|
|
1287
|
+
let ao = clamp(occlusion, 0.0, 1.0);
|
|
1288
|
+
let direct = diffuse * (sun_rgb * (NL * shadow) + lampDiff)
|
|
1289
|
+
+ specular * (bsdf_urp(N, L, V, NL, r) * sun_rgb * shadow + lampSpec);
|
|
1290
|
+
let indirect = diffuse * amb_rgb * ao
|
|
1291
|
+
+ rzProbeSpecular(reflect(-V, N), wp, r) * ao * urp_env_brdf(specular, r, sm, reflectivity, NV);
|
|
1292
|
+
var lit = direct + indirect;
|
|
1293
|
+
lit = lit * mix(vec3f(1.0), light.castShadow.rgb, _rzCastShadow(wp) * light.castShadow.w);
|
|
1294
|
+
return vec4f(lit + max(emission, vec3f(0.0)), a * oneMinusReflectivity + reflectivity);
|
|
1295
|
+
}
|
|
1405
1296
|
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1297
|
+
/**
|
|
1298
|
+
* A packed property map, read the game's way: R metal, G perceptual
|
|
1299
|
+
* roughness (answered as Unity's smoothness, 1 − r), B occlusion, A emission
|
|
1300
|
+
* mask, each remapped through the material's own range — v = min +
|
|
1301
|
+
* (max − min)·tex for the first three, and
|
|
1302
|
+
* e = max((A − min)/(max − min), 0) for the glow, so max is the alpha that
|
|
1303
|
+
* means "full glow" and anything brighter overdrives. A min equal to its max
|
|
1304
|
+
* turns the glow off (the game's default, 1 and 1).
|
|
1305
|
+
*
|
|
1306
|
+
* A slot with no map in it (the 1×1 stand-in) answers with the constants
|
|
1307
|
+
* instead, which is how one look serves a set that brought maps and a model
|
|
1308
|
+
* that did not. Returns (metal, smoothness, occlusion, emission).
|
|
1309
|
+
*/
|
|
1310
|
+
fn rz_property_map(t: vec4f, bound: bool, consts: vec4f, mn: vec4f, mx: vec4f) -> vec4f {
|
|
1311
|
+
if (!bound) { return consts; }
|
|
1312
|
+
let mro = mn.xyz + (mx.xyz - mn.xyz) * t.xyz;
|
|
1313
|
+
let span = mx.w - mn.w;
|
|
1314
|
+
let e = select(0.0, max((t.w - mn.w) / span, 0.0), abs(span) > 1e-6);
|
|
1315
|
+
return vec4f(mro.x, 1.0 - mro.y, mro.z, e);
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
/** The highlights alone: the sun's and every lamp's specular on a GGX lobe
|
|
1319
|
+
* (URP's, α = r²), untinted — light, to be multiplied by whatever the
|
|
1320
|
+
* surface's reflectance is. What a water or a glass shader adds as its glint
|
|
1321
|
+
* on top of a reflection it computes itself. */
|
|
1322
|
+
fn rz_glossy_direct(N: vec3f, L: vec3f, V: vec3f, sun_rgb: vec3f, shadow: f32, wp: vec3f, roughness: f32) -> vec3f {
|
|
1323
|
+
let r = clamp(roughness, 0.0, 1.0);
|
|
1324
|
+
let NL = saturate(dot(N, L));
|
|
1325
|
+
return bsdf_urp(N, L, V, NL, r) * sun_rgb * shadow + rzLampsSpecular(wp, N, V, r);
|
|
1413
1326
|
}
|
|
1414
1327
|
|
|
1328
|
+
/** Does group slot k hold a real image, rather than the 1×1 stand-in a
|
|
1329
|
+
* missing map is bound as? */
|
|
1330
|
+
fn rz_group_bound0() -> bool { return textureDimensions(groupTexture0).x > 1u; }
|
|
1331
|
+
fn rz_group_bound1() -> bool { return textureDimensions(groupTexture1).x > 1u; }
|
|
1332
|
+
fn rz_group_bound2() -> bool { return textureDimensions(groupTexture2).x > 1u; }
|
|
1333
|
+
fn rz_group_bound3() -> bool { return textureDimensions(groupTexture3).x > 1u; }
|
|
1334
|
+
|
|
1415
1335
|
`;
|