reze-engine 0.16.1 → 0.16.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 +139 -284
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +5 -5
- package/dist/model.d.ts +4 -1
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +14 -1
- package/dist/physics/body.d.ts +1 -0
- package/dist/physics/body.d.ts.map +1 -1
- package/dist/physics/body.js +2 -0
- package/dist/physics/constraint.d.ts +8 -1
- package/dist/physics/constraint.d.ts.map +1 -1
- package/dist/physics/constraint.js +13 -1
- package/dist/physics/physics.d.ts +15 -1
- package/dist/physics/physics.d.ts.map +1 -1
- package/dist/physics/physics.js +413 -48
- package/dist/physics/solver.d.ts.map +1 -1
- package/dist/physics/solver.js +223 -39
- package/dist/physics/types.d.ts +2 -1
- package/dist/physics/types.d.ts.map +1 -1
- package/dist/physics/types.js +5 -0
- package/dist/physics/world.d.ts +3 -0
- package/dist/physics/world.d.ts.map +1 -1
- package/dist/physics/world.js +31 -4
- package/dist/physics-debug.d.ts +30 -0
- package/dist/physics-debug.d.ts.map +1 -0
- package/dist/physics-debug.js +526 -0
- package/dist/pmx-loader.d.ts +2 -0
- package/dist/pmx-loader.d.ts.map +1 -1
- package/dist/pmx-loader.js +37 -20
- 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 +90 -85
- 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 +1 -1
- 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 +2 -2
- package/dist/shaders/materials/common.d.ts +1 -1
- package/dist/shaders/materials/common.d.ts.map +1 -1
- package/dist/shaders/materials/common.js +10 -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 +37 -32
- 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 +40 -35
- 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 +90 -85
- 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 +85 -75
- 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 +1 -1
- 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 +1 -1
- package/dist/shaders/passes/physics-debug.d.ts +2 -0
- package/dist/shaders/passes/physics-debug.d.ts.map +1 -0
- package/dist/shaders/passes/physics-debug.js +69 -0
- package/package.json +1 -1
- package/src/engine.ts +36 -21
- package/src/model.ts +18 -1
- package/src/physics/body.ts +5 -0
- package/src/physics/constraint.ts +35 -6
- package/src/physics/physics.ts +423 -56
- package/src/physics/solver.ts +213 -38
- package/src/physics/types.ts +10 -2
- package/src/physics/world.ts +33 -4
- package/src/pmx-loader.ts +38 -20
- package/src/shaders/materials/body.ts +97 -92
- package/src/shaders/materials/cloth_rough.ts +1 -1
- package/src/shaders/materials/cloth_smooth.ts +2 -2
- package/src/shaders/materials/common.ts +10 -0
- package/src/shaders/materials/default.ts +45 -40
- package/src/shaders/materials/eye.ts +48 -43
- package/src/shaders/materials/face.ts +97 -92
- package/src/shaders/materials/hair.ts +92 -82
- package/src/shaders/materials/metal.ts +1 -1
- package/src/shaders/materials/stockings.ts +1 -1
- package/dist/gpu-profile.d.ts +0 -19
- package/dist/gpu-profile.d.ts.map +0 -1
- package/dist/gpu-profile.js +0 -120
- package/dist/physics/profile.d.ts +0 -18
- package/dist/physics/profile.d.ts.map +0 -1
- package/dist/physics/profile.js +0 -44
|
@@ -1,92 +1,97 @@
|
|
|
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
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
let
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
let
|
|
38
|
-
|
|
39
|
-
let
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
let
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
let
|
|
48
|
-
let
|
|
49
|
-
|
|
50
|
-
let
|
|
51
|
-
|
|
52
|
-
let
|
|
53
|
-
let
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
let
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
let
|
|
62
|
-
|
|
63
|
-
let
|
|
64
|
-
let
|
|
65
|
-
|
|
66
|
-
let
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
let
|
|
78
|
-
|
|
79
|
-
let
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
let
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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 tex_s = textureSample(diffuseTexture, diffuseSampler, input.uv);
|
|
30
|
+
// MMD alpha semantics: material alpha × texture alpha. Hair/lace/accessory
|
|
31
|
+
// textures cut their shapes in the alpha channel — ignoring it renders each
|
|
32
|
+
// card's full quad with the texture's padding color (white shimmer on dark
|
|
33
|
+
// hair for models whose textures pad with white).
|
|
34
|
+
let alpha = material.alpha * tex_s.a;
|
|
35
|
+
if (alpha < 0.001) { discard; }
|
|
36
|
+
|
|
37
|
+
let n = safe_normal(input.normal);
|
|
38
|
+
let v = normalize(camera.viewPos - input.worldPos);
|
|
39
|
+
let l = -light.lights[0].direction.xyz;
|
|
40
|
+
let sun = light.lights[0].color.xyz * light.lights[0].color.w;
|
|
41
|
+
let amb = light.ambientColor.xyz;
|
|
42
|
+
let shadow = sampleShadow(input.worldPos, n);
|
|
43
|
+
|
|
44
|
+
let tex_color = tex_s.rgb;
|
|
45
|
+
|
|
46
|
+
// ═══ NPR STACK ═══
|
|
47
|
+
let ndotl_raw = shader_to_rgb_diffuse(n, l, sun, amb, shadow);
|
|
48
|
+
let toon = ramp_constant(ndotl_raw, 0.0, vec4f(0,0,0,1), 0.2966, vec4f(1,1,1,1)).r;
|
|
49
|
+
|
|
50
|
+
let shadow_tint = hue_sat_id(2.0, 0.3499999940395355, 1.0, tex_color);
|
|
51
|
+
let lit_tint = hue_sat_id(1.5, 1.0, 1.0, tex_color);
|
|
52
|
+
let toon_color = mix_blend(toon, shadow_tint, lit_tint);
|
|
53
|
+
let bc = bright_contrast(toon_color, 0.1, 0.2);
|
|
54
|
+
|
|
55
|
+
let emission3 = bc * 4.0;
|
|
56
|
+
|
|
57
|
+
let warm_input = clamp(toon + 0.5, 0.0, 1.0);
|
|
58
|
+
let warm_color = ramp_cardinal(warm_input, 0.2409,
|
|
59
|
+
vec4f(0.2426, 0.068, 0.0588, 1.0), 0.4663,
|
|
60
|
+
vec4f(0.6677, 0.5024, 0.5126, 1.0)).rgb;
|
|
61
|
+
let warm_emission = warm_color * BODY_WARM_STR;
|
|
62
|
+
|
|
63
|
+
let rim1_str = fresnel(2.0, n, v) * layer_weight_facing(0.24000005424022675, n, v);
|
|
64
|
+
let rim1 = vec3f(0.984157919883728, 0.6110184788703918, 0.5736401677131653) * rim1_str;
|
|
65
|
+
|
|
66
|
+
let facing_raw = layer_weight_facing(BODY_RIM2_LAYER_BLEND, n, v);
|
|
67
|
+
let facing_pow = math_power(facing_raw, BODY_RIM2_POW);
|
|
68
|
+
let rim2_fac = ramp_ease(facing_pow, 0.0, vec4f(0,0,0,1), 0.5052, vec4f(1,1,1,1)).r;
|
|
69
|
+
let rim2_mixed = mix(emission3, BODY_RIM2_BG, rim2_fac);
|
|
70
|
+
|
|
71
|
+
let npr_stack = rim1 + rim2_mixed + warm_emission;
|
|
72
|
+
|
|
73
|
+
// ═══ PRINCIPLED BSDF with noise bump ═══
|
|
74
|
+
// Mapping loc=rot=0 in the Blender graph folds to a plain scale multiply.
|
|
75
|
+
// Height in rest space (restPos) so the bump rides with the skin; geometric basis stays
|
|
76
|
+
// worldPos so the perturbed normal matches the world-space n (see face.ts note).
|
|
77
|
+
let noise_val = tex_noise_d2(input.restPos * vec3f(1.0, 1.0, 1.5), 1.0);
|
|
78
|
+
let noise_ramp = ramp_linear(noise_val, 0.0, vec4f(0,0,0,1), 1.0, vec4f(1,1,1,1)).r;
|
|
79
|
+
let bumped_n = bump_lh(0.324644535779953, noise_ramp, n, input.worldPos);
|
|
80
|
+
|
|
81
|
+
let principled_base = mix_blend(noise_ramp, bc, vec3f(0.6831911206245422, 0.19474034011363983, 0.13732507824897766));
|
|
82
|
+
let p_emission = bc * 0.2;
|
|
83
|
+
|
|
84
|
+
let principled = eval_principled(
|
|
85
|
+
PrincipledIn(principled_base, 0.0, BODY_SPECULAR, BODY_ROUGHNESS, BODY_SPEC_CLAMP, 0.0, 0.0),
|
|
86
|
+
bumped_n, l, v, sun, amb, shadow
|
|
87
|
+
) + p_emission;
|
|
88
|
+
|
|
89
|
+
let final_color = mix(npr_stack, principled, BODY_MIX_NPR);
|
|
90
|
+
|
|
91
|
+
var out: FSOut;
|
|
92
|
+
out.color = vec4f(final_color, alpha);
|
|
93
|
+
out.mask = vec4f(1.0, 1.0, 0.0, out.color.a);
|
|
94
|
+
return out;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
`
|
|
@@ -20,7 +20,7 @@ const CLOTH_R_BUMP_STR: f32 = 1.0;
|
|
|
20
20
|
const CLOTH_R_SPEC_CLAMP: f32 = 10.0;
|
|
21
21
|
|
|
22
22
|
@fragment fn fs(input: VertexOutput) -> FSOut {
|
|
23
|
-
let n =
|
|
23
|
+
let n = safe_normal(input.normal);
|
|
24
24
|
let v = normalize(camera.viewPos - input.worldPos);
|
|
25
25
|
let l = -light.lights[0].direction.xyz;
|
|
26
26
|
let sun = light.lights[0].color.xyz * light.lights[0].color.w;
|
|
@@ -17,7 +17,7 @@ const NPR_EMIT_STR: f32 = 18.200000762939453;
|
|
|
17
17
|
const NPR_MIX_SHADER_FAC: f32 = 0.8999999761581421;
|
|
18
18
|
|
|
19
19
|
@fragment fn fs(input: VertexOutput) -> FSOut {
|
|
20
|
-
let n =
|
|
20
|
+
let n = safe_normal(input.normal);
|
|
21
21
|
let v = normalize(camera.viewPos - input.worldPos);
|
|
22
22
|
let l = -light.lights[0].direction.xyz;
|
|
23
23
|
let sun = light.lights[0].color.xyz * light.lights[0].color.w;
|
|
@@ -47,7 +47,7 @@ const NPR_MIX_SHADER_FAC: f32 = 0.8999999761581421;
|
|
|
47
47
|
// ═══ PRINCIPLED BSDF ═══
|
|
48
48
|
let principled_base = hue_sat_id(1.0, 0.800000011920929, 1.0, tex_rgb);
|
|
49
49
|
let principled = eval_principled(
|
|
50
|
-
PrincipledIn(principled_base, 0.0, CLOTH_SPECULAR, CLOTH_ROUGHNESS,
|
|
50
|
+
PrincipledIn(principled_base, 0.0, CLOTH_SPECULAR, CLOTH_ROUGHNESS, 10.0, 0.0, 0.0),
|
|
51
51
|
n, l, v, sun, amb, shadow
|
|
52
52
|
);
|
|
53
53
|
|
|
@@ -73,6 +73,16 @@ struct LightVP { viewProj: mat4x4f, };
|
|
|
73
73
|
@group(2) @binding(0) var diffuseTexture: texture_2d<f32>;
|
|
74
74
|
@group(2) @binding(1) var<uniform> material: MaterialUniforms;
|
|
75
75
|
|
|
76
|
+
// Four-bone blended normals can cancel to ~zero on physics-driven parts
|
|
77
|
+
// (opposing bone rotations at 50/50 weights) — normalize(0) is 0/0 = NaN,
|
|
78
|
+
// which poisons the whole shading stack and flashes through bloom. Fall
|
|
79
|
+
// back to up for degenerate normals instead.
|
|
80
|
+
fn safe_normal(nIn: vec3f) -> vec3f {
|
|
81
|
+
let l2 = dot(nIn, nIn);
|
|
82
|
+
if (l2 < 1e-12) { return vec3f(0.0, 1.0, 0.0); }
|
|
83
|
+
return nIn * inverseSqrt(l2);
|
|
84
|
+
}
|
|
85
|
+
|
|
76
86
|
`;
|
|
77
87
|
|
|
78
88
|
// ─── Shadow sampler (3×3 PCF) ───────────────────────────────────────
|
|
@@ -1,40 +1,45 @@
|
|
|
1
|
-
// Default material — Blender 3.6 Principled BSDF defaults, no NPR stack.
|
|
2
|
-
// Metallic=0, Specular=0.5 (F0=0.04), Roughness=0.5. Serves as the EEVEE reference
|
|
3
|
-
// path that every NPR material mixes against in its final stage.
|
|
4
|
-
|
|
5
|
-
import { NODES_WGSL } from "./nodes"
|
|
6
|
-
import { COMMON_MATERIAL_PRELUDE_WGSL } from "./common"
|
|
7
|
-
|
|
8
|
-
export const DEFAULT_SHADER_WGSL = /* wgsl */ `
|
|
9
|
-
|
|
10
|
-
${NODES_WGSL}
|
|
11
|
-
${COMMON_MATERIAL_PRELUDE_WGSL}
|
|
12
|
-
|
|
13
|
-
const DEFAULT_SPECULAR: f32 = 0.5;
|
|
14
|
-
const DEFAULT_ROUGHNESS: f32 = 0.5;
|
|
15
|
-
|
|
16
|
-
@fragment fn fs(input: VertexOutput) -> FSOut {
|
|
17
|
-
let
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
let
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
let
|
|
26
|
-
|
|
27
|
-
let
|
|
28
|
-
|
|
29
|
-
let
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
1
|
+
// Default material — Blender 3.6 Principled BSDF defaults, no NPR stack.
|
|
2
|
+
// Metallic=0, Specular=0.5 (F0=0.04), Roughness=0.5. Serves as the EEVEE reference
|
|
3
|
+
// path that every NPR material mixes against in its final stage.
|
|
4
|
+
|
|
5
|
+
import { NODES_WGSL } from "./nodes"
|
|
6
|
+
import { COMMON_MATERIAL_PRELUDE_WGSL } from "./common"
|
|
7
|
+
|
|
8
|
+
export const DEFAULT_SHADER_WGSL = /* wgsl */ `
|
|
9
|
+
|
|
10
|
+
${NODES_WGSL}
|
|
11
|
+
${COMMON_MATERIAL_PRELUDE_WGSL}
|
|
12
|
+
|
|
13
|
+
const DEFAULT_SPECULAR: f32 = 0.5;
|
|
14
|
+
const DEFAULT_ROUGHNESS: f32 = 0.5;
|
|
15
|
+
|
|
16
|
+
@fragment fn fs(input: VertexOutput) -> FSOut {
|
|
17
|
+
let tex_s = textureSample(diffuseTexture, diffuseSampler, input.uv);
|
|
18
|
+
// MMD alpha semantics: material alpha × texture alpha. Hair/lace/accessory
|
|
19
|
+
// textures cut their shapes in the alpha channel — ignoring it renders each
|
|
20
|
+
// card's full quad with the texture's padding color (white shimmer on dark
|
|
21
|
+
// hair for models whose textures pad with white).
|
|
22
|
+
let alpha = material.alpha * tex_s.a;
|
|
23
|
+
if (alpha < 0.001) { discard; }
|
|
24
|
+
|
|
25
|
+
let n = safe_normal(input.normal);
|
|
26
|
+
let v = normalize(camera.viewPos - input.worldPos);
|
|
27
|
+
let l = -light.lights[0].direction.xyz;
|
|
28
|
+
let sun = light.lights[0].color.xyz * light.lights[0].color.w;
|
|
29
|
+
let amb = light.ambientColor.xyz;
|
|
30
|
+
let shadow = sampleShadow(input.worldPos, n);
|
|
31
|
+
|
|
32
|
+
let albedo = tex_s.rgb;
|
|
33
|
+
|
|
34
|
+
let color = eval_principled(
|
|
35
|
+
PrincipledIn(albedo, 0.0, DEFAULT_SPECULAR, DEFAULT_ROUGHNESS, 10.0, 0.0, 0.0),
|
|
36
|
+
n, l, v, sun, amb, shadow
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
var out: FSOut;
|
|
40
|
+
out.color = vec4f(color, alpha);
|
|
41
|
+
out.mask = vec4f(1.0, 1.0, 0.0, out.color.a);
|
|
42
|
+
return out;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
`
|
|
@@ -1,43 +1,48 @@
|
|
|
1
|
-
// Eye preset — default Principled BSDF + Emission socket set to albedo × 1.5.
|
|
2
|
-
// Matches the published preset author's instruction: "keep eyes in the default
|
|
3
|
-
// nodegraph, add emission 1.5". Emission feeds bloom pre-tonemap.
|
|
4
|
-
|
|
5
|
-
import { NODES_WGSL } from "./nodes"
|
|
6
|
-
import { COMMON_MATERIAL_PRELUDE_WGSL } from "./common"
|
|
7
|
-
|
|
8
|
-
export const EYE_SHADER_WGSL = /* wgsl */ `
|
|
9
|
-
|
|
10
|
-
${NODES_WGSL}
|
|
11
|
-
${COMMON_MATERIAL_PRELUDE_WGSL}
|
|
12
|
-
|
|
13
|
-
const EYE_SPECULAR: f32 = 0.5;
|
|
14
|
-
const EYE_ROUGHNESS: f32 = 0.5;
|
|
15
|
-
const EYE_EMISSION_STRENGTH: f32 = 1.5;
|
|
16
|
-
|
|
17
|
-
@fragment fn fs(input: VertexOutput) -> FSOut {
|
|
18
|
-
let
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
let
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
let
|
|
27
|
-
|
|
28
|
-
let
|
|
29
|
-
|
|
30
|
-
let
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
let
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
1
|
+
// Eye preset — default Principled BSDF + Emission socket set to albedo × 1.5.
|
|
2
|
+
// Matches the published preset author's instruction: "keep eyes in the default
|
|
3
|
+
// nodegraph, add emission 1.5". Emission feeds bloom pre-tonemap.
|
|
4
|
+
|
|
5
|
+
import { NODES_WGSL } from "./nodes"
|
|
6
|
+
import { COMMON_MATERIAL_PRELUDE_WGSL } from "./common"
|
|
7
|
+
|
|
8
|
+
export const EYE_SHADER_WGSL = /* wgsl */ `
|
|
9
|
+
|
|
10
|
+
${NODES_WGSL}
|
|
11
|
+
${COMMON_MATERIAL_PRELUDE_WGSL}
|
|
12
|
+
|
|
13
|
+
const EYE_SPECULAR: f32 = 0.5;
|
|
14
|
+
const EYE_ROUGHNESS: f32 = 0.5;
|
|
15
|
+
const EYE_EMISSION_STRENGTH: f32 = 1.5;
|
|
16
|
+
|
|
17
|
+
@fragment fn fs(input: VertexOutput) -> FSOut {
|
|
18
|
+
let tex_s = textureSample(diffuseTexture, diffuseSampler, input.uv);
|
|
19
|
+
// MMD alpha semantics: material alpha × texture alpha. Hair/lace/accessory
|
|
20
|
+
// textures cut their shapes in the alpha channel — ignoring it renders each
|
|
21
|
+
// card's full quad with the texture's padding color (white shimmer on dark
|
|
22
|
+
// hair for models whose textures pad with white).
|
|
23
|
+
let alpha = material.alpha * tex_s.a;
|
|
24
|
+
if (alpha < 0.001) { discard; }
|
|
25
|
+
|
|
26
|
+
let n = safe_normal(input.normal);
|
|
27
|
+
let v = normalize(camera.viewPos - input.worldPos);
|
|
28
|
+
let l = -light.lights[0].direction.xyz;
|
|
29
|
+
let sun = light.lights[0].color.xyz * light.lights[0].color.w;
|
|
30
|
+
let amb = light.ambientColor.xyz;
|
|
31
|
+
let shadow = sampleShadow(input.worldPos, n);
|
|
32
|
+
|
|
33
|
+
let albedo = tex_s.rgb;
|
|
34
|
+
|
|
35
|
+
let shaded = eval_principled(
|
|
36
|
+
PrincipledIn(albedo, 0.0, EYE_SPECULAR, EYE_ROUGHNESS, 1e30, 0.0, 0.0),
|
|
37
|
+
n, l, v, sun, amb, shadow
|
|
38
|
+
);
|
|
39
|
+
// Principled Emission socket: emissive = emission_color × strength, added on top.
|
|
40
|
+
let emission = albedo * EYE_EMISSION_STRENGTH;
|
|
41
|
+
|
|
42
|
+
var out: FSOut;
|
|
43
|
+
out.color = vec4f(shaded + emission, alpha);
|
|
44
|
+
out.mask = vec4f(1.0, 1.0, 0.0, out.color.a);
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
`
|
|
@@ -1,92 +1,97 @@
|
|
|
1
|
-
// M_Face — 仿深空之眼渲染预设v1.0_by_小绿毛猫 "M_Face". Toon + warm rim + dual fresnel
|
|
2
|
-
// rim + BT.601 bright-tex gate, mixed 50/50 against a Principled BSDF with noise bump.
|
|
3
|
-
|
|
4
|
-
import { NODES_WGSL } from "./nodes"
|
|
5
|
-
import { COMMON_MATERIAL_PRELUDE_WGSL } from "./common"
|
|
6
|
-
|
|
7
|
-
export const FACE_SHADER_WGSL = /* wgsl */ `
|
|
8
|
-
|
|
9
|
-
${NODES_WGSL}
|
|
10
|
-
${COMMON_MATERIAL_PRELUDE_WGSL}
|
|
11
|
-
|
|
12
|
-
const FACE_SPECULAR: f32 = 0.5;
|
|
13
|
-
const FACE_ROUGHNESS: f32 = 0.3;
|
|
14
|
-
const FACE_MIX_NPR: f32 = 0.5;
|
|
15
|
-
const FACE_SPEC_CLAMP: f32 = 10.0;
|
|
16
|
-
const FACE_RIM2_POW: f32 = 0.6300000548362732;
|
|
17
|
-
const FACE_RIM2_BG: vec3f = vec3f(1.0, 0.4684903025627136, 0.3698573112487793);
|
|
18
|
-
const FACE_WARM_STR: f32 = 0.30000001192092896;
|
|
19
|
-
const FACE_BRIGHT_TEX_THRESH: f32 = 0.9300000071525574;
|
|
20
|
-
|
|
21
|
-
@fragment fn fs(input: VertexOutput) -> FSOut {
|
|
22
|
-
let
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
let
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
let
|
|
31
|
-
|
|
32
|
-
let
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
let
|
|
36
|
-
|
|
37
|
-
let
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
let
|
|
41
|
-
|
|
42
|
-
let
|
|
43
|
-
|
|
44
|
-
let
|
|
45
|
-
|
|
46
|
-
let
|
|
47
|
-
let
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
let
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
let
|
|
56
|
-
|
|
57
|
-
let
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
let
|
|
78
|
-
|
|
79
|
-
let
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
let
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
1
|
+
// M_Face — 仿深空之眼渲染预设v1.0_by_小绿毛猫 "M_Face". Toon + warm rim + dual fresnel
|
|
2
|
+
// rim + BT.601 bright-tex gate, mixed 50/50 against a Principled BSDF with noise bump.
|
|
3
|
+
|
|
4
|
+
import { NODES_WGSL } from "./nodes"
|
|
5
|
+
import { COMMON_MATERIAL_PRELUDE_WGSL } from "./common"
|
|
6
|
+
|
|
7
|
+
export const FACE_SHADER_WGSL = /* wgsl */ `
|
|
8
|
+
|
|
9
|
+
${NODES_WGSL}
|
|
10
|
+
${COMMON_MATERIAL_PRELUDE_WGSL}
|
|
11
|
+
|
|
12
|
+
const FACE_SPECULAR: f32 = 0.5;
|
|
13
|
+
const FACE_ROUGHNESS: f32 = 0.3;
|
|
14
|
+
const FACE_MIX_NPR: f32 = 0.5;
|
|
15
|
+
const FACE_SPEC_CLAMP: f32 = 10.0;
|
|
16
|
+
const FACE_RIM2_POW: f32 = 0.6300000548362732;
|
|
17
|
+
const FACE_RIM2_BG: vec3f = vec3f(1.0, 0.4684903025627136, 0.3698573112487793);
|
|
18
|
+
const FACE_WARM_STR: f32 = 0.30000001192092896;
|
|
19
|
+
const FACE_BRIGHT_TEX_THRESH: f32 = 0.9300000071525574;
|
|
20
|
+
|
|
21
|
+
@fragment fn fs(input: VertexOutput) -> FSOut {
|
|
22
|
+
let tex_s = textureSample(diffuseTexture, diffuseSampler, input.uv);
|
|
23
|
+
// MMD alpha semantics: material alpha × texture alpha. Hair/lace/accessory
|
|
24
|
+
// textures cut their shapes in the alpha channel — ignoring it renders each
|
|
25
|
+
// card's full quad with the texture's padding color (white shimmer on dark
|
|
26
|
+
// hair for models whose textures pad with white).
|
|
27
|
+
let alpha = material.alpha * tex_s.a;
|
|
28
|
+
if (alpha < 0.001) { discard; }
|
|
29
|
+
|
|
30
|
+
let n = safe_normal(input.normal);
|
|
31
|
+
let v = normalize(camera.viewPos - input.worldPos);
|
|
32
|
+
let l = -light.lights[0].direction.xyz;
|
|
33
|
+
let sun = light.lights[0].color.xyz * light.lights[0].color.w;
|
|
34
|
+
let amb = light.ambientColor.xyz;
|
|
35
|
+
let shadow = sampleShadow(input.worldPos, n);
|
|
36
|
+
|
|
37
|
+
let tex_color = tex_s.rgb;
|
|
38
|
+
|
|
39
|
+
// ═══ NPR STACK ═══
|
|
40
|
+
let ndotl_raw = shader_to_rgb_diffuse(n, l, sun, amb, shadow);
|
|
41
|
+
// ramp_constant_edge_aa: avoids binary fac shimmer on terminator (fwidth + smoothstep).
|
|
42
|
+
let toon = ramp_constant_edge_aa(ndotl_raw, 0.2966, vec4f(0,0,0,1), vec4f(1,1,1,1)).r;
|
|
43
|
+
|
|
44
|
+
let shadow_tint = hue_sat(0.46000000834465027, 2.0, 0.3499999940395355, 1.0, tex_color);
|
|
45
|
+
let lit_tint = hue_sat(0.46000000834465027, 1.600000023841858, 1.5, 1.0, tex_color);
|
|
46
|
+
let toon_color = mix_blend(toon, shadow_tint, lit_tint);
|
|
47
|
+
let bc = bright_contrast(toon_color, 0.1, 0.2);
|
|
48
|
+
|
|
49
|
+
let emission3 = bc * 2.5;
|
|
50
|
+
|
|
51
|
+
let warm_input = clamp(toon * 0.5 + 0.5, 0.0, 1.0);
|
|
52
|
+
let warm_color = ramp_cardinal(warm_input, 0.2409,
|
|
53
|
+
vec4f(0.2426, 0.068, 0.0588, 1.0), 0.4663,
|
|
54
|
+
vec4f(0.6677, 0.5024, 0.5126, 1.0)).rgb;
|
|
55
|
+
let warm_emission = warm_color * FACE_WARM_STR;
|
|
56
|
+
|
|
57
|
+
let rim1_str = fresnel(2.0, n, v) * layer_weight_facing(0.24, n, v);
|
|
58
|
+
let rim1 = vec3f(0.984157919883728, 0.6110184788703918, 0.5736401677131653) * rim1_str;
|
|
59
|
+
|
|
60
|
+
let rim2_raw = fresnel(1.45, n, v) * layer_weight_fresnel(0.61, n, v);
|
|
61
|
+
let rim2_fac = math_power(rim2_raw, FACE_RIM2_POW);
|
|
62
|
+
let rim2_mixed = mix(emission3, FACE_RIM2_BG, rim2_fac);
|
|
63
|
+
|
|
64
|
+
// Blender implicitly converts Color → Float via BT.601 grayscale when a color output
|
|
65
|
+
// feeds a Math node's Value input. Using tex_color.r instead fires on R-dominant skin
|
|
66
|
+
// and produces firefly speckles on near-white R pixels — color_to_value matches the
|
|
67
|
+
// Blender socket semantic and only gates genuinely near-white painted features.
|
|
68
|
+
let tex_gate = math_greater_than(color_to_value(tex_color), FACE_BRIGHT_TEX_THRESH);
|
|
69
|
+
let bright_emit = vec3f(tex_gate) * 3.0;
|
|
70
|
+
|
|
71
|
+
let npr_stack = rim1 + rim2_mixed + bright_emit + warm_emission;
|
|
72
|
+
|
|
73
|
+
// ═══ PRINCIPLED BSDF with noise bump ═══
|
|
74
|
+
// Height sampled in rest space (restPos) so the micro-bump doesn't swim under motion;
|
|
75
|
+
// bump_lh's geometric basis stays in worldPos so the perturbed normal lands in the same
|
|
76
|
+
// world frame as n (screen-space height gradient still pairs correctly with it).
|
|
77
|
+
let noise_val = tex_noise_d2(input.restPos * vec3f(1.0, 1.0, 1.5), 1.0);
|
|
78
|
+
let noise_ramp = ramp_linear(noise_val, 0.0, vec4f(0,0,0,1), 1.0, vec4f(1,1,1,1)).r;
|
|
79
|
+
let bumped_n = bump_lh(0.324644535779953, noise_ramp, n, input.worldPos);
|
|
80
|
+
|
|
81
|
+
let principled_base = mix_blend(noise_ramp, bc, vec3f(0.6832, 0.1947, 0.1373));
|
|
82
|
+
let p_emission = bc * 0.2;
|
|
83
|
+
|
|
84
|
+
let principled = eval_principled(
|
|
85
|
+
PrincipledIn(principled_base, 0.0, FACE_SPECULAR, FACE_ROUGHNESS, FACE_SPEC_CLAMP, 0.0, 0.0),
|
|
86
|
+
bumped_n, l, v, sun, amb, shadow
|
|
87
|
+
) + p_emission;
|
|
88
|
+
|
|
89
|
+
let final_color = mix(npr_stack, principled, FACE_MIX_NPR);
|
|
90
|
+
|
|
91
|
+
var out: FSOut;
|
|
92
|
+
out.color = vec4f(final_color, alpha);
|
|
93
|
+
out.mask = vec4f(1.0, 1.0, 0.0, out.color.a);
|
|
94
|
+
return out;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
`
|