reze-engine 0.12.1 → 0.12.3
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/README.md +102 -61
- package/dist/engine.d.ts +9 -4
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +62 -18
- package/dist/shaders/body.d.ts +1 -1
- package/dist/shaders/body.d.ts.map +1 -1
- package/dist/shaders/body.js +7 -28
- package/dist/shaders/cloth_rough.d.ts +1 -1
- package/dist/shaders/cloth_rough.d.ts.map +1 -1
- package/dist/shaders/cloth_rough.js +4 -16
- package/dist/shaders/cloth_smooth.d.ts +1 -1
- package/dist/shaders/cloth_smooth.d.ts.map +1 -1
- package/dist/shaders/cloth_smooth.js +5 -17
- package/dist/shaders/default.d.ts +1 -1
- package/dist/shaders/default.d.ts.map +1 -1
- package/dist/shaders/eye.d.ts +1 -1
- package/dist/shaders/eye.d.ts.map +1 -1
- package/dist/shaders/face.d.ts +1 -1
- package/dist/shaders/face.d.ts.map +1 -1
- package/dist/shaders/face.js +21 -57
- package/dist/shaders/hair.d.ts +1 -1
- package/dist/shaders/hair.d.ts.map +1 -1
- package/dist/shaders/hair.js +7 -27
- package/dist/shaders/materials/body.d.ts +1 -1
- package/dist/shaders/materials/body.d.ts.map +1 -1
- package/dist/shaders/materials/body.js +86 -197
- package/dist/shaders/materials/cloth_rough.d.ts +1 -1
- package/dist/shaders/materials/cloth_rough.d.ts.map +1 -1
- package/dist/shaders/materials/cloth_rough.js +11 -122
- package/dist/shaders/materials/cloth_smooth.d.ts +1 -1
- package/dist/shaders/materials/cloth_smooth.d.ts.map +1 -1
- package/dist/shaders/materials/cloth_smooth.js +59 -172
- package/dist/shaders/materials/common.d.ts +6 -0
- package/dist/shaders/materials/common.d.ts.map +1 -0
- package/dist/shaders/materials/common.js +160 -0
- package/dist/shaders/materials/default.d.ts +1 -1
- package/dist/shaders/materials/default.d.ts.map +1 -1
- package/dist/shaders/materials/default.js +13 -146
- package/dist/shaders/materials/eye.d.ts +1 -1
- package/dist/shaders/materials/eye.d.ts.map +1 -1
- package/dist/shaders/materials/eye.js +13 -118
- package/dist/shaders/materials/face.d.ts +1 -1
- package/dist/shaders/materials/face.d.ts.map +1 -1
- package/dist/shaders/materials/face.js +85 -197
- package/dist/shaders/materials/hair.d.ts +1 -1
- package/dist/shaders/materials/hair.d.ts.map +1 -1
- package/dist/shaders/materials/hair.js +78 -183
- package/dist/shaders/materials/metal.d.ts +1 -1
- package/dist/shaders/materials/metal.d.ts.map +1 -1
- package/dist/shaders/materials/metal.js +16 -122
- 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 +77 -0
- package/dist/shaders/materials/stockings.d.ts +1 -1
- package/dist/shaders/materials/stockings.d.ts.map +1 -1
- package/dist/shaders/materials/stockings.js +26 -152
- package/dist/shaders/metal.d.ts +1 -1
- package/dist/shaders/metal.d.ts.map +1 -1
- package/dist/shaders/metal.js +4 -17
- package/dist/shaders/nodes.d.ts +1 -1
- package/dist/shaders/nodes.d.ts.map +1 -1
- package/dist/shaders/nodes.js +0 -9
- package/dist/shaders/passes/bloom.d.ts +1 -1
- package/dist/shaders/passes/bloom.d.ts.map +1 -1
- package/dist/shaders/passes/bloom.js +7 -4
- 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 +11 -4
- package/dist/shaders/passes/ground.d.ts +1 -1
- package/dist/shaders/passes/ground.d.ts.map +1 -1
- package/dist/shaders/passes/ground.js +6 -2
- package/dist/shaders/passes/outline.d.ts +1 -1
- package/dist/shaders/passes/outline.d.ts.map +1 -1
- package/dist/shaders/passes/outline.js +2 -2
- package/dist/shaders/stockings.d.ts +1 -1
- package/dist/shaders/stockings.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/engine.ts +60 -18
- package/src/shaders/materials/body.ts +90 -201
- package/src/shaders/materials/cloth_rough.ts +11 -122
- package/src/shaders/materials/cloth_smooth.ts +63 -176
- package/src/shaders/materials/common.ts +171 -0
- package/src/shaders/materials/default.ts +13 -146
- package/src/shaders/materials/eye.ts +13 -118
- package/src/shaders/materials/face.ts +89 -201
- package/src/shaders/materials/hair.ts +82 -187
- package/src/shaders/materials/metal.ts +16 -122
- package/src/shaders/materials/nodes.ts +77 -0
- package/src/shaders/materials/stockings.ts +27 -153
- package/src/shaders/passes/bloom.ts +7 -4
- package/src/shaders/passes/composite.ts +11 -4
- package/src/shaders/passes/ground.ts +6 -2
- package/src/shaders/passes/outline.ts +2 -2
- package/dist/bezier-interpolate.d.ts +0 -15
- package/dist/bezier-interpolate.d.ts.map +0 -1
- package/dist/bezier-interpolate.js +0 -40
- package/dist/engine_ts.d.ts +0 -143
- package/dist/engine_ts.d.ts.map +0 -1
- package/dist/engine_ts.js +0 -1575
- package/dist/ik.d.ts +0 -32
- package/dist/ik.d.ts.map +0 -1
- package/dist/ik.js +0 -337
- package/dist/player.d.ts +0 -64
- package/dist/player.d.ts.map +0 -1
- package/dist/player.js +0 -220
- package/dist/pool-scene.d.ts +0 -52
- package/dist/pool-scene.d.ts.map +0 -1
- package/dist/pool-scene.js +0 -1122
- package/dist/pool.d.ts +0 -38
- package/dist/pool.d.ts.map +0 -1
- package/dist/pool.js +0 -422
- package/dist/rzm-converter.d.ts +0 -12
- package/dist/rzm-converter.d.ts.map +0 -1
- package/dist/rzm-converter.js +0 -40
- package/dist/rzm-loader.d.ts +0 -24
- package/dist/rzm-loader.d.ts.map +0 -1
- package/dist/rzm-loader.js +0 -488
- package/dist/rzm-writer.d.ts +0 -27
- package/dist/rzm-writer.d.ts.map +0 -1
- package/dist/rzm-writer.js +0 -701
|
@@ -1,201 +1,90 @@
|
|
|
1
|
-
// M_Body — 仿深空之眼渲染预设v1.0_by_小绿毛猫
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
let
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
let
|
|
57
|
-
|
|
58
|
-
let
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
let
|
|
62
|
-
let
|
|
63
|
-
let
|
|
64
|
-
let
|
|
65
|
-
|
|
66
|
-
let
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
return
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
@location(0) position: vec3f,
|
|
92
|
-
@location(1) normal: vec3f,
|
|
93
|
-
@location(2) uv: vec2f,
|
|
94
|
-
@location(3) joints0: vec4<u32>,
|
|
95
|
-
@location(4) weights0: vec4<f32>
|
|
96
|
-
) -> VertexOutput {
|
|
97
|
-
var output: VertexOutput;
|
|
98
|
-
let pos4 = vec4f(position, 1.0);
|
|
99
|
-
let weightSum = weights0.x + weights0.y + weights0.z + weights0.w;
|
|
100
|
-
let invWeightSum = select(1.0, 1.0 / weightSum, weightSum > 0.0001);
|
|
101
|
-
let nw = select(vec4f(1.0, 0.0, 0.0, 0.0), weights0 * invWeightSum, weightSum > 0.0001);
|
|
102
|
-
var skinnedPos = vec4f(0.0);
|
|
103
|
-
var skinnedNrm = vec3f(0.0);
|
|
104
|
-
for (var i = 0u; i < 4u; i++) {
|
|
105
|
-
let m = skinMats[joints0[i]];
|
|
106
|
-
let w = nw[i];
|
|
107
|
-
skinnedPos += (m * pos4) * w;
|
|
108
|
-
skinnedNrm += (mat3x3f(m[0].xyz, m[1].xyz, m[2].xyz) * normal) * w;
|
|
109
|
-
}
|
|
110
|
-
output.position = camera.projection * camera.view * vec4f(skinnedPos.xyz, 1.0);
|
|
111
|
-
// Skip VS normalize — interpolation denormalizes anyway, and FS always does normalize(input.normal).
|
|
112
|
-
output.normal = skinnedNrm;
|
|
113
|
-
output.uv = uv;
|
|
114
|
-
output.worldPos = skinnedPos.xyz;
|
|
115
|
-
return output;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
struct FSOut {
|
|
119
|
-
@location(0) color: vec4f,
|
|
120
|
-
@location(1) mask: f32,
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
@fragment fn fs(input: VertexOutput) -> FSOut {
|
|
124
|
-
let alpha = material.alpha;
|
|
125
|
-
if (alpha < 0.001) { discard; }
|
|
126
|
-
|
|
127
|
-
let n = normalize(input.normal);
|
|
128
|
-
let v = normalize(camera.viewPos - input.worldPos);
|
|
129
|
-
let l = -light.lights[0].direction.xyz;
|
|
130
|
-
let sun = light.lights[0].color.xyz * light.lights[0].color.w;
|
|
131
|
-
|
|
132
|
-
let tex_color = textureSample(diffuseTexture, diffuseSampler, input.uv).rgb;
|
|
133
|
-
let shadow = sampleShadow(input.worldPos, n);
|
|
134
|
-
|
|
135
|
-
let ndotl_raw = shader_to_rgb_diffuse(n, l, sun, light.ambientColor.xyz, shadow);
|
|
136
|
-
let toon = ramp_constant(ndotl_raw, 0.0, vec4f(0,0,0,1), 0.2966, vec4f(1,1,1,1)).r;
|
|
137
|
-
|
|
138
|
-
let shadow_tint = hue_sat_id(2.0, 0.3499999940395355, 1.0, tex_color);
|
|
139
|
-
let lit_tint = hue_sat_id(1.5, 1.0, 1.0, tex_color);
|
|
140
|
-
let toon_color = mix_blend(toon, shadow_tint, lit_tint);
|
|
141
|
-
let bc = bright_contrast(toon_color, 0.1, 0.2);
|
|
142
|
-
|
|
143
|
-
let emission3 = bc * 4.0;
|
|
144
|
-
|
|
145
|
-
let warm_input = clamp(toon + 0.5, 0.0, 1.0);
|
|
146
|
-
let warm_color = ramp_cardinal(warm_input, 0.2409,
|
|
147
|
-
vec4f(0.2426, 0.068, 0.0588, 1.0), 0.4663,
|
|
148
|
-
vec4f(0.6677, 0.5024, 0.5126, 1.0)).rgb;
|
|
149
|
-
let warm_emission = warm_color * BODY_WARM_STR;
|
|
150
|
-
|
|
151
|
-
let rim1_str = fresnel(2.0, n, v) * layer_weight_facing(0.24000005424022675, n, v);
|
|
152
|
-
let rim1 = vec3f(0.984157919883728, 0.6110184788703918, 0.5736401677131653) * rim1_str;
|
|
153
|
-
|
|
154
|
-
let facing_raw = layer_weight_facing(BODY_RIM2_LAYER_BLEND, n, v);
|
|
155
|
-
let facing_pow = math_power(facing_raw, BODY_RIM2_POW);
|
|
156
|
-
let rim2_fac = ramp_ease(facing_pow, 0.0, vec4f(0,0,0,1), 0.5052, vec4f(1,1,1,1)).r;
|
|
157
|
-
let rim2_mixed = mix(emission3, BODY_RIM2_BG, rim2_fac);
|
|
158
|
-
|
|
159
|
-
let npr_stack = rim1 + rim2_mixed + warm_emission;
|
|
160
|
-
|
|
161
|
-
// Noise bump — Mapping loc=rot=0 folds to a plain scale multiply.
|
|
162
|
-
let noise_val = tex_noise_d2(input.worldPos * vec3f(1.0, 1.0, 1.5), 1.0);
|
|
163
|
-
let noise_ramp = ramp_linear(noise_val, 0.0, vec4f(0,0,0,1), 1.0, vec4f(1,1,1,1)).r;
|
|
164
|
-
let bumped_n = bump_lh(0.324644535779953, noise_ramp, n, input.worldPos);
|
|
165
|
-
|
|
166
|
-
let principled_base = mix_blend(noise_ramp, bc, vec3f(0.6831911206245422, 0.19474034011363983, 0.13732507824897766));
|
|
167
|
-
let p_emission = bc * 0.2;
|
|
168
|
-
|
|
169
|
-
// Principled BSDF (EEVEE port): metallic=0, specular=0.5, roughness=0.3, specular_tint=0.
|
|
170
|
-
let NL = max(dot(bumped_n, l), 0.0);
|
|
171
|
-
let NV = max(dot(bumped_n, v), 1e-4);
|
|
172
|
-
|
|
173
|
-
// f0/f90 per gpu_shader_material_principled.glsl — specular_tint=0 → dielectric_f0_color=white.
|
|
174
|
-
let f0 = vec3f(0.08 * BODY_SPECULAR);
|
|
175
|
-
let f90 = mix(f0, vec3f(1.0), sqrt(BODY_SPECULAR));
|
|
176
|
-
let brdf_lut = brdf_lut_sample(NV, BODY_ROUGHNESS);
|
|
177
|
-
let reflection_color = F_brdf_multi_scatter(f0, f90, brdf_lut.xy);
|
|
178
|
-
|
|
179
|
-
// Direct glossy — bsdf_ggx already includes NL; no F applied here (tinted after accum).
|
|
180
|
-
// ltc_brdf_scale: EEVEE direct path uses LTC; split-sum LUT path is rescaled to match.
|
|
181
|
-
let spec_direct_raw = bsdf_ggx(bumped_n, l, v, NL, NV, BODY_ROUGHNESS) * sun * shadow * ltc_brdf_scale_from_lut(brdf_lut);
|
|
182
|
-
let spec_direct = min(spec_direct_raw, vec3f(BODY_SPEC_CLAMP));
|
|
183
|
-
// Indirect glossy — flat world probe (solid color). Phase 2 adds cubemap.
|
|
184
|
-
let spec_indirect = light.ambientColor.xyz;
|
|
185
|
-
let spec_radiance = (spec_direct + spec_indirect) * reflection_color;
|
|
186
|
-
|
|
187
|
-
// Indirect diffuse = base_color × L_w per Blender closure_eval_surface_lib.glsl line 302;
|
|
188
|
-
// probe_evaluate_world_diff returns radiance (SH-projected, not cosine-convolved).
|
|
189
|
-
// No (1-F) factor per EEVEE — it doesn't energy-conserve spec<->diffuse.
|
|
190
|
-
let diffuse_radiance = principled_base * (sun * NL * shadow / PI_B + light.ambientColor.xyz);
|
|
191
|
-
let principled = diffuse_radiance + spec_radiance + p_emission;
|
|
192
|
-
|
|
193
|
-
let final_color = mix(npr_stack, principled, BODY_MIX_NPR);
|
|
194
|
-
|
|
195
|
-
var out: FSOut;
|
|
196
|
-
out.color = vec4f(final_color, alpha);
|
|
197
|
-
out.mask = 1.0;
|
|
198
|
-
return out;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
`
|
|
1
|
+
// M_Body — 仿深空之眼渲染预设v1.0_by_小绿毛猫 "M_Body". Toon + warm rim + rim1/rim2
|
|
2
|
+
// stack mixed 50/50 against a Principled BSDF with noise-bumped normal.
|
|
3
|
+
|
|
4
|
+
import { NODES_WGSL } from "./nodes"
|
|
5
|
+
import { COMMON_MATERIAL_PRELUDE_WGSL } from "./common"
|
|
6
|
+
|
|
7
|
+
export const BODY_SHADER_WGSL = /* wgsl */ `
|
|
8
|
+
|
|
9
|
+
${NODES_WGSL}
|
|
10
|
+
${COMMON_MATERIAL_PRELUDE_WGSL}
|
|
11
|
+
|
|
12
|
+
const BODY_ROUGHNESS: f32 = 0.3;
|
|
13
|
+
const BODY_SPECULAR: f32 = 0.5;
|
|
14
|
+
const BODY_MIX_NPR: f32 = 0.5;
|
|
15
|
+
const BODY_SPEC_CLAMP: f32 = 10.0;
|
|
16
|
+
const BODY_RIM2_LAYER_BLEND: f32 = 0.20000000298023224;
|
|
17
|
+
const BODY_RIM2_POW: f32 = 1.4300000667572021;
|
|
18
|
+
const BODY_RIM2_BG: vec3f = vec3f(1.0, 0.4303792119026184, 0.3315804898738861);
|
|
19
|
+
const BODY_WARM_STR: f32 = 0.30000001192092896;
|
|
20
|
+
|
|
21
|
+
// smoothstep-based ramp: t*t*(3-2*t) between two color stops
|
|
22
|
+
fn ramp_ease(f: f32, p0: f32, c0: vec4f, p1: f32, c1: vec4f) -> vec4f {
|
|
23
|
+
let t = saturate((f - p0) / max(p1 - p0, 1e-6));
|
|
24
|
+
let ss = t * t * (3.0 - 2.0 * t);
|
|
25
|
+
return mix(c0, c1, ss);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@fragment fn fs(input: VertexOutput) -> FSOut {
|
|
29
|
+
let alpha = material.alpha;
|
|
30
|
+
if (alpha < 0.001) { discard; }
|
|
31
|
+
|
|
32
|
+
let n = normalize(input.normal);
|
|
33
|
+
let v = normalize(camera.viewPos - input.worldPos);
|
|
34
|
+
let l = -light.lights[0].direction.xyz;
|
|
35
|
+
let sun = light.lights[0].color.xyz * light.lights[0].color.w;
|
|
36
|
+
let amb = light.ambientColor.xyz;
|
|
37
|
+
let shadow = sampleShadow(input.worldPos, n);
|
|
38
|
+
|
|
39
|
+
let tex_color = textureSample(diffuseTexture, diffuseSampler, input.uv).rgb;
|
|
40
|
+
|
|
41
|
+
// ═══ NPR STACK ═══
|
|
42
|
+
let ndotl_raw = shader_to_rgb_diffuse(n, l, sun, amb, shadow);
|
|
43
|
+
let toon = ramp_constant(ndotl_raw, 0.0, vec4f(0,0,0,1), 0.2966, vec4f(1,1,1,1)).r;
|
|
44
|
+
|
|
45
|
+
let shadow_tint = hue_sat_id(2.0, 0.3499999940395355, 1.0, tex_color);
|
|
46
|
+
let lit_tint = hue_sat_id(1.5, 1.0, 1.0, tex_color);
|
|
47
|
+
let toon_color = mix_blend(toon, shadow_tint, lit_tint);
|
|
48
|
+
let bc = bright_contrast(toon_color, 0.1, 0.2);
|
|
49
|
+
|
|
50
|
+
let emission3 = bc * 4.0;
|
|
51
|
+
|
|
52
|
+
let warm_input = clamp(toon + 0.5, 0.0, 1.0);
|
|
53
|
+
let warm_color = ramp_cardinal(warm_input, 0.2409,
|
|
54
|
+
vec4f(0.2426, 0.068, 0.0588, 1.0), 0.4663,
|
|
55
|
+
vec4f(0.6677, 0.5024, 0.5126, 1.0)).rgb;
|
|
56
|
+
let warm_emission = warm_color * BODY_WARM_STR;
|
|
57
|
+
|
|
58
|
+
let rim1_str = fresnel(2.0, n, v) * layer_weight_facing(0.24000005424022675, n, v);
|
|
59
|
+
let rim1 = vec3f(0.984157919883728, 0.6110184788703918, 0.5736401677131653) * rim1_str;
|
|
60
|
+
|
|
61
|
+
let facing_raw = layer_weight_facing(BODY_RIM2_LAYER_BLEND, n, v);
|
|
62
|
+
let facing_pow = math_power(facing_raw, BODY_RIM2_POW);
|
|
63
|
+
let rim2_fac = ramp_ease(facing_pow, 0.0, vec4f(0,0,0,1), 0.5052, vec4f(1,1,1,1)).r;
|
|
64
|
+
let rim2_mixed = mix(emission3, BODY_RIM2_BG, rim2_fac);
|
|
65
|
+
|
|
66
|
+
let npr_stack = rim1 + rim2_mixed + warm_emission;
|
|
67
|
+
|
|
68
|
+
// ═══ PRINCIPLED BSDF with noise bump ═══
|
|
69
|
+
// Mapping loc=rot=0 in the Blender graph folds to a plain scale multiply.
|
|
70
|
+
let noise_val = tex_noise_d2(input.worldPos * vec3f(1.0, 1.0, 1.5), 1.0);
|
|
71
|
+
let noise_ramp = ramp_linear(noise_val, 0.0, vec4f(0,0,0,1), 1.0, vec4f(1,1,1,1)).r;
|
|
72
|
+
let bumped_n = bump_lh(0.324644535779953, noise_ramp, n, input.worldPos);
|
|
73
|
+
|
|
74
|
+
let principled_base = mix_blend(noise_ramp, bc, vec3f(0.6831911206245422, 0.19474034011363983, 0.13732507824897766));
|
|
75
|
+
let p_emission = bc * 0.2;
|
|
76
|
+
|
|
77
|
+
let principled = eval_principled(
|
|
78
|
+
PrincipledIn(principled_base, 0.0, BODY_SPECULAR, BODY_ROUGHNESS, BODY_SPEC_CLAMP, 0.0, 0.0),
|
|
79
|
+
bumped_n, l, v, sun, amb, shadow
|
|
80
|
+
) + p_emission;
|
|
81
|
+
|
|
82
|
+
let final_color = mix(npr_stack, principled, BODY_MIX_NPR);
|
|
83
|
+
|
|
84
|
+
var out: FSOut;
|
|
85
|
+
out.color = vec4f(final_color, alpha);
|
|
86
|
+
out.mask = vec4f(1.0, 1.0, 0.0, out.color.a);
|
|
87
|
+
return out;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
`
|
|
@@ -1,76 +1,14 @@
|
|
|
1
|
-
// M_Rough_Cloth — NPR graph identical to M_Smooth_Cloth but
|
|
2
|
-
//
|
|
1
|
+
// M_Rough_Cloth — NPR graph identical to M_Smooth_Cloth, but the noise bump subtree
|
|
2
|
+
// IS live on Principled.Normal and Roughness is raised to 0.8187.
|
|
3
3
|
|
|
4
4
|
import { NODES_WGSL } from "./nodes"
|
|
5
|
+
import { COMMON_MATERIAL_PRELUDE_WGSL } from "./common"
|
|
5
6
|
|
|
6
7
|
export const CLOTH_ROUGH_SHADER_WGSL = /* wgsl */ `
|
|
7
8
|
|
|
8
9
|
${NODES_WGSL}
|
|
10
|
+
${COMMON_MATERIAL_PRELUDE_WGSL}
|
|
9
11
|
|
|
10
|
-
struct CameraUniforms {
|
|
11
|
-
view: mat4x4f,
|
|
12
|
-
projection: mat4x4f,
|
|
13
|
-
viewPos: vec3f,
|
|
14
|
-
_padding: f32,
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
struct Light {
|
|
18
|
-
direction: vec4f,
|
|
19
|
-
color: vec4f,
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
struct LightUniforms {
|
|
23
|
-
ambientColor: vec4f,
|
|
24
|
-
lights: array<Light, 4>,
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
struct MaterialUniforms {
|
|
28
|
-
diffuseColor: vec3f,
|
|
29
|
-
alpha: f32,
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
struct VertexOutput {
|
|
33
|
-
@builtin(position) position: vec4f,
|
|
34
|
-
@location(0) normal: vec3f,
|
|
35
|
-
@location(1) uv: vec2f,
|
|
36
|
-
@location(2) worldPos: vec3f,
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
struct LightVP { viewProj: mat4x4f, };
|
|
40
|
-
|
|
41
|
-
@group(0) @binding(0) var<uniform> camera: CameraUniforms;
|
|
42
|
-
@group(0) @binding(1) var<uniform> light: LightUniforms;
|
|
43
|
-
@group(0) @binding(2) var diffuseSampler: sampler;
|
|
44
|
-
@group(0) @binding(3) var shadowMap: texture_depth_2d;
|
|
45
|
-
@group(0) @binding(4) var shadowSampler: sampler_comparison;
|
|
46
|
-
@group(0) @binding(5) var<uniform> lightVP: LightVP;
|
|
47
|
-
@group(1) @binding(0) var<storage, read> skinMats: array<mat4x4f>;
|
|
48
|
-
@group(2) @binding(0) var diffuseTexture: texture_2d<f32>;
|
|
49
|
-
@group(2) @binding(1) var<uniform> material: MaterialUniforms;
|
|
50
|
-
|
|
51
|
-
fn sampleShadow(worldPos: vec3f, n: vec3f) -> f32 {
|
|
52
|
-
// Back-facing to key light: direct contribution is zero anyway, skip 9 texture samples.
|
|
53
|
-
if (dot(n, -light.lights[0].direction.xyz) <= 0.0) { return 0.0; }
|
|
54
|
-
let biasedPos = worldPos + n * 0.08;
|
|
55
|
-
let lclip = lightVP.viewProj * vec4f(biasedPos, 1.0);
|
|
56
|
-
let ndc = lclip.xyz / max(lclip.w, 1e-6);
|
|
57
|
-
let suv = vec2f(ndc.x * 0.5 + 0.5, 0.5 - ndc.y * 0.5);
|
|
58
|
-
let cmpZ = ndc.z - 0.001;
|
|
59
|
-
let ts = 1.0 / 2048.0;
|
|
60
|
-
// 3x3 PCF unrolled — Safari's Metal backend doesn't unroll nested shadow loops reliably.
|
|
61
|
-
let s00 = textureSampleCompareLevel(shadowMap, shadowSampler, suv + vec2f(-ts, -ts), cmpZ);
|
|
62
|
-
let s10 = textureSampleCompareLevel(shadowMap, shadowSampler, suv + vec2f(0.0, -ts), cmpZ);
|
|
63
|
-
let s20 = textureSampleCompareLevel(shadowMap, shadowSampler, suv + vec2f( ts, -ts), cmpZ);
|
|
64
|
-
let s01 = textureSampleCompareLevel(shadowMap, shadowSampler, suv + vec2f(-ts, 0.0), cmpZ);
|
|
65
|
-
let s11 = textureSampleCompareLevel(shadowMap, shadowSampler, suv, cmpZ);
|
|
66
|
-
let s21 = textureSampleCompareLevel(shadowMap, shadowSampler, suv + vec2f( ts, 0.0), cmpZ);
|
|
67
|
-
let s02 = textureSampleCompareLevel(shadowMap, shadowSampler, suv + vec2f(-ts, ts), cmpZ);
|
|
68
|
-
let s12 = textureSampleCompareLevel(shadowMap, shadowSampler, suv + vec2f(0.0, ts), cmpZ);
|
|
69
|
-
let s22 = textureSampleCompareLevel(shadowMap, shadowSampler, suv + vec2f( ts, ts), cmpZ);
|
|
70
|
-
return (s00 + s10 + s20 + s01 + s11 + s21 + s02 + s12 + s22) * (1.0 / 9.0);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const PI_CR: f32 = 3.141592653589793;
|
|
74
12
|
const CLOTH_R_SPECULAR: f32 = 0.8;
|
|
75
13
|
const CLOTH_R_ROUGHNESS: f32 = 0.8187;
|
|
76
14
|
const CLOTH_R_TOON_EDGE: f32 = 0.2966;
|
|
@@ -79,42 +17,8 @@ const CLOTH_R_EMIT_STR: f32 = 18.200000762939453;
|
|
|
79
17
|
const CLOTH_R_MIX_SHADER_FAC: f32 = 0.8999999761581421;
|
|
80
18
|
const CLOTH_R_NOISE_SCALE: f32 = 17.7;
|
|
81
19
|
const CLOTH_R_BUMP_STR: f32 = 1.0;
|
|
82
|
-
// EEVEE Light Clamp equivalent — caps firefly specular from noise-bumped NDF aliasing.
|
|
83
20
|
const CLOTH_R_SPEC_CLAMP: f32 = 10.0;
|
|
84
21
|
|
|
85
|
-
@vertex fn vs(
|
|
86
|
-
@location(0) position: vec3f,
|
|
87
|
-
@location(1) normal: vec3f,
|
|
88
|
-
@location(2) uv: vec2f,
|
|
89
|
-
@location(3) joints0: vec4<u32>,
|
|
90
|
-
@location(4) weights0: vec4<f32>
|
|
91
|
-
) -> VertexOutput {
|
|
92
|
-
var output: VertexOutput;
|
|
93
|
-
let pos4 = vec4f(position, 1.0);
|
|
94
|
-
let weightSum = weights0.x + weights0.y + weights0.z + weights0.w;
|
|
95
|
-
let invWeightSum = select(1.0, 1.0 / weightSum, weightSum > 0.0001);
|
|
96
|
-
let nw = select(vec4f(1.0, 0.0, 0.0, 0.0), weights0 * invWeightSum, weightSum > 0.0001);
|
|
97
|
-
var skinnedPos = vec4f(0.0);
|
|
98
|
-
var skinnedNrm = vec3f(0.0);
|
|
99
|
-
for (var i = 0u; i < 4u; i++) {
|
|
100
|
-
let m = skinMats[joints0[i]];
|
|
101
|
-
let w = nw[i];
|
|
102
|
-
skinnedPos += (m * pos4) * w;
|
|
103
|
-
skinnedNrm += (mat3x3f(m[0].xyz, m[1].xyz, m[2].xyz) * normal) * w;
|
|
104
|
-
}
|
|
105
|
-
output.position = camera.projection * camera.view * vec4f(skinnedPos.xyz, 1.0);
|
|
106
|
-
// Skip VS normalize — interpolation denormalizes anyway, and FS always does normalize(input.normal).
|
|
107
|
-
output.normal = skinnedNrm;
|
|
108
|
-
output.uv = uv;
|
|
109
|
-
output.worldPos = skinnedPos.xyz;
|
|
110
|
-
return output;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
struct FSOut {
|
|
114
|
-
@location(0) color: vec4f,
|
|
115
|
-
@location(1) mask: f32,
|
|
116
|
-
};
|
|
117
|
-
|
|
118
22
|
@fragment fn fs(input: VertexOutput) -> FSOut {
|
|
119
23
|
let n = normalize(input.normal);
|
|
120
24
|
let v = normalize(camera.viewPos - input.worldPos);
|
|
@@ -128,8 +32,8 @@ struct FSOut {
|
|
|
128
32
|
let out_alpha = material.alpha * tex_s.a;
|
|
129
33
|
if (out_alpha < 0.001) { discard; }
|
|
130
34
|
|
|
35
|
+
// ═══ NPR STACK ═══
|
|
131
36
|
let lum_shade = shader_to_rgb_diffuse(n, l, sun, amb, shadow);
|
|
132
|
-
// ramp_constant_edge_aa: avoids binary fac shimmer on terminator (fwidth + smoothstep).
|
|
133
37
|
let ramp008 = ramp_constant_edge_aa(lum_shade, CLOTH_R_TOON_EDGE, vec4f(0,0,0,1), vec4f(1,1,1,1));
|
|
134
38
|
let mix04_fac = math_multiply(ramp008.r, CLOTH_R_MIX04_MUL);
|
|
135
39
|
|
|
@@ -143,37 +47,22 @@ struct FSOut {
|
|
|
143
47
|
let npr_rgb = mix_overlay(1.0, mix03, hue004);
|
|
144
48
|
let npr_emission = npr_rgb * CLOTH_R_EMIT_STR;
|
|
145
49
|
|
|
146
|
-
//
|
|
50
|
+
// ═══ PRINCIPLED BSDF with noise bump (live in this preset) ═══
|
|
147
51
|
let noise_val = tex_noise_d2(input.worldPos, CLOTH_R_NOISE_SCALE);
|
|
148
52
|
let noise_ramp = ramp_linear(noise_val, 0.0, vec4f(0,0,0,1), 1.0, vec4f(1,1,1,1)).r;
|
|
149
53
|
let bumped_n = bump_lh(CLOTH_R_BUMP_STR, noise_ramp, n, input.worldPos);
|
|
150
54
|
|
|
151
|
-
// 原理化BSDF (EEVEE port): metallic=0, specular=0.8, roughness=0.8187, specular_tint=0.
|
|
152
55
|
let principled_base = hue_sat_id(1.0, 0.800000011920929, 1.0, tex_rgb);
|
|
153
|
-
let
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
let f90 = mix(f0, vec3f(1.0), sqrt(CLOTH_R_SPECULAR));
|
|
158
|
-
let brdf_lut = brdf_lut_sample(NV, CLOTH_R_ROUGHNESS);
|
|
159
|
-
let reflection_color = F_brdf_multi_scatter(f0, f90, brdf_lut.xy);
|
|
160
|
-
|
|
161
|
-
let spec_direct_raw = bsdf_ggx(bumped_n, l, v, NL, NV, CLOTH_R_ROUGHNESS) * sun * shadow * ltc_brdf_scale_from_lut(brdf_lut);
|
|
162
|
-
let spec_direct = min(spec_direct_raw, vec3f(CLOTH_R_SPEC_CLAMP));
|
|
163
|
-
let spec_indirect = amb;
|
|
164
|
-
let spec_radiance = (spec_direct + spec_indirect) * reflection_color;
|
|
165
|
-
|
|
166
|
-
// Indirect diffuse = base_color × L_w per Blender closure_eval_surface_lib.glsl line 302;
|
|
167
|
-
// probe_evaluate_world_diff returns radiance (SH-projected, not cosine-convolved).
|
|
168
|
-
let diffuse_radiance = principled_base * (sun * NL * shadow / PI_CR + amb);
|
|
169
|
-
let principled = diffuse_radiance + spec_radiance;
|
|
56
|
+
let principled = eval_principled(
|
|
57
|
+
PrincipledIn(principled_base, 0.0, CLOTH_R_SPECULAR, CLOTH_R_ROUGHNESS, CLOTH_R_SPEC_CLAMP, 0.0, 0.0),
|
|
58
|
+
bumped_n, l, v, sun, amb, shadow
|
|
59
|
+
);
|
|
170
60
|
|
|
171
|
-
// 混合着色器.001 Fac=0.9: Shader=自发光.005, Shader_001=原理化BSDF
|
|
172
61
|
let final_color = mix(npr_emission, principled, CLOTH_R_MIX_SHADER_FAC);
|
|
173
62
|
|
|
174
63
|
var out: FSOut;
|
|
175
64
|
out.color = vec4f(final_color, out_alpha);
|
|
176
|
-
out.mask = 1.0;
|
|
65
|
+
out.mask = vec4f(1.0, 1.0, 0.0, out.color.a);
|
|
177
66
|
return out;
|
|
178
67
|
}
|
|
179
68
|
|