reze-engine 0.20.0 → 0.21.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/README.md +30 -14
- package/dist/engine.d.ts +0 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +12 -12
- package/dist/graph/compile.d.ts +3 -3
- package/dist/graph/compile.d.ts.map +1 -1
- package/dist/graph/presets/body.d.ts +2 -2
- package/dist/graph/presets/body.d.ts.map +1 -1
- package/dist/graph/presets/body.js +1 -1
- package/dist/graph/presets/cloth_rough.d.ts +2 -2
- package/dist/graph/presets/cloth_rough.d.ts.map +1 -1
- package/dist/graph/presets/cloth_rough.js +1 -1
- package/dist/graph/presets/cloth_smooth.d.ts +2 -2
- package/dist/graph/presets/cloth_smooth.d.ts.map +1 -1
- package/dist/graph/presets/cloth_smooth.js +1 -1
- package/dist/graph/presets/default.d.ts +2 -2
- package/dist/graph/presets/default.d.ts.map +1 -1
- package/dist/graph/presets/eye.d.ts +2 -2
- package/dist/graph/presets/eye.d.ts.map +1 -1
- package/dist/graph/presets/eye.js +1 -1
- package/dist/graph/presets/face.d.ts +2 -2
- package/dist/graph/presets/face.d.ts.map +1 -1
- package/dist/graph/presets/face.js +1 -1
- package/dist/graph/presets/hair.d.ts +2 -2
- package/dist/graph/presets/hair.d.ts.map +1 -1
- package/dist/graph/presets/hair.js +1 -1
- package/dist/graph/presets/metal.d.ts +2 -2
- package/dist/graph/presets/metal.d.ts.map +1 -1
- package/dist/graph/presets/metal.js +1 -1
- package/dist/graph/presets/stockings.d.ts +2 -2
- package/dist/graph/presets/stockings.d.ts.map +1 -1
- package/dist/graph/presets/stockings.js +1 -1
- package/dist/graph/render-class.js +1 -1
- package/dist/graph/schema.d.ts +1 -1
- package/dist/graph/schema.d.ts.map +1 -1
- package/dist/graph/schema.js +1 -1
- package/dist/graph/style-group.d.ts +3 -3
- package/dist/graph/style-group.d.ts.map +1 -1
- package/dist/graph/style-group.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- 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 +5 -4
- package/package.json +1 -1
- package/src/engine.ts +14 -21
- package/src/graph/compile.ts +3 -3
- package/src/graph/presets/body.ts +3 -3
- package/src/graph/presets/cloth_rough.ts +3 -3
- package/src/graph/presets/cloth_smooth.ts +3 -3
- package/src/graph/presets/default.ts +2 -2
- package/src/graph/presets/eye.ts +3 -3
- package/src/graph/presets/face.ts +3 -3
- package/src/graph/presets/hair.ts +3 -3
- package/src/graph/presets/metal.ts +3 -3
- package/src/graph/presets/stockings.ts +3 -3
- package/src/graph/render-class.ts +1 -1
- package/src/graph/schema.ts +2 -2
- package/src/graph/style-group.ts +4 -4
- package/src/index.ts +61 -62
- package/src/shaders/materials/common.ts +5 -4
- package/src/shaders/materials/body.ts +0 -97
- package/src/shaders/materials/cloth_rough.ts +0 -71
- package/src/shaders/materials/cloth_smooth.ts +0 -63
- package/src/shaders/materials/default.ts +0 -45
- package/src/shaders/materials/eye.ts +0 -62
- package/src/shaders/materials/face.ts +0 -97
- package/src/shaders/materials/hair.ts +0 -92
- package/src/shaders/materials/metal.ts +0 -79
- package/src/shaders/materials/mmd_classic.ts +0 -68
- package/src/shaders/materials/stockings.ts +0 -124
|
@@ -1,71 +0,0 @@
|
|
|
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
|
-
|
|
4
|
-
import { NODES_WGSL } from "./nodes"
|
|
5
|
-
import { COMMON_MATERIAL_PRELUDE_WGSL } from "./common"
|
|
6
|
-
|
|
7
|
-
export const CLOTH_ROUGH_SHADER_WGSL = /* wgsl */ `
|
|
8
|
-
|
|
9
|
-
${NODES_WGSL}
|
|
10
|
-
${COMMON_MATERIAL_PRELUDE_WGSL}
|
|
11
|
-
|
|
12
|
-
const CLOTH_R_SPECULAR: f32 = 0.8;
|
|
13
|
-
const CLOTH_R_ROUGHNESS: f32 = 0.8187;
|
|
14
|
-
const CLOTH_R_TOON_EDGE: f32 = 0.2966;
|
|
15
|
-
const CLOTH_R_MIX04_MUL: f32 = 0.5;
|
|
16
|
-
const CLOTH_R_EMIT_STR: f32 = 18.200000762939453;
|
|
17
|
-
const CLOTH_R_MIX_SHADER_FAC: f32 = 0.8999999761581421;
|
|
18
|
-
const CLOTH_R_NOISE_SCALE: f32 = 17.7;
|
|
19
|
-
const CLOTH_R_BUMP_STR: f32 = 1.0;
|
|
20
|
-
const CLOTH_R_SPEC_CLAMP: f32 = 10.0;
|
|
21
|
-
|
|
22
|
-
@fragment fn fs(input: VertexOutput) -> FSOut {
|
|
23
|
-
let n = safe_normal(input.normal);
|
|
24
|
-
let v = normalize(camera.viewPos - input.worldPos);
|
|
25
|
-
let l = -light.lights[0].direction.xyz;
|
|
26
|
-
let sun = light.lights[0].color.xyz * light.lights[0].color.w;
|
|
27
|
-
let amb = light.ambientColor.xyz;
|
|
28
|
-
let shadow = sampleShadow(input.worldPos, n);
|
|
29
|
-
|
|
30
|
-
let tex_s = textureSample(diffuseTexture, diffuseSampler, input.uv);
|
|
31
|
-
let tex_rgb = tex_s.rgb;
|
|
32
|
-
let out_alpha = material.alpha * tex_s.a;
|
|
33
|
-
if (out_alpha < 0.001) { discard; }
|
|
34
|
-
|
|
35
|
-
// ═══ NPR STACK ═══
|
|
36
|
-
let lum_shade = shader_to_rgb_diffuse(n, l, sun, amb, shadow);
|
|
37
|
-
let ramp008 = ramp_constant_edge_aa(lum_shade, CLOTH_R_TOON_EDGE, vec4f(0,0,0,1), vec4f(1,1,1,1));
|
|
38
|
-
let mix04_fac = math_multiply(ramp008.r, CLOTH_R_MIX04_MUL);
|
|
39
|
-
|
|
40
|
-
let dark_tex = hue_sat_id(1.0, 0.19999998807907104, 1.0, tex_rgb);
|
|
41
|
-
let mix04 = mix_blend(mix04_fac, dark_tex, tex_rgb);
|
|
42
|
-
|
|
43
|
-
let bevel_z = clamp(n.y, 0.0, 1.0);
|
|
44
|
-
let mix03 = mix_blend(bevel_z, mix04, dark_tex);
|
|
45
|
-
|
|
46
|
-
let hue004 = hue_sat_id(0.800000011920929, 2.0, 1.0, mix03);
|
|
47
|
-
let npr_rgb = mix_overlay(1.0, mix03, hue004);
|
|
48
|
-
let npr_emission = npr_rgb * CLOTH_R_EMIT_STR;
|
|
49
|
-
|
|
50
|
-
// ═══ PRINCIPLED BSDF with noise bump (live in this preset) ═══
|
|
51
|
-
// Height in rest space (restPos) so the weave doesn't swim; geometric basis stays
|
|
52
|
-
// worldPos so the perturbed normal matches the world-space n (see face.ts note).
|
|
53
|
-
let noise_val = tex_noise_d2(input.restPos, CLOTH_R_NOISE_SCALE);
|
|
54
|
-
let noise_ramp = ramp_linear(noise_val, 0.0, vec4f(0,0,0,1), 1.0, vec4f(1,1,1,1)).r;
|
|
55
|
-
let bumped_n = bump_lh(CLOTH_R_BUMP_STR, noise_ramp, n, input.worldPos);
|
|
56
|
-
|
|
57
|
-
let principled_base = hue_sat_id(1.0, 0.800000011920929, 1.0, tex_rgb);
|
|
58
|
-
let principled = eval_principled(
|
|
59
|
-
PrincipledIn(principled_base, 0.0, CLOTH_R_SPECULAR, CLOTH_R_ROUGHNESS, CLOTH_R_SPEC_CLAMP, 0.0, 0.0),
|
|
60
|
-
bumped_n, l, v, sun, amb, shadow
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
let final_color = mix(npr_emission, principled, CLOTH_R_MIX_SHADER_FAC);
|
|
64
|
-
|
|
65
|
-
var out: FSOut;
|
|
66
|
-
out.color = vec4f(final_color, out_alpha);
|
|
67
|
-
out.mask = vec4f(1.0, 1.0, 0.0, out.color.a);
|
|
68
|
-
return out;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
`
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
// M_Smooth_Cloth — NPR toon + bevel + overlay-boosted emission mixed 10/90 against
|
|
2
|
-
// a plain Principled BSDF. Bump subtree is dead in the Blender graph.
|
|
3
|
-
|
|
4
|
-
import { NODES_WGSL } from "./nodes"
|
|
5
|
-
import { COMMON_MATERIAL_PRELUDE_WGSL } from "./common"
|
|
6
|
-
|
|
7
|
-
export const CLOTH_SMOOTH_SHADER_WGSL = /* wgsl */ `
|
|
8
|
-
|
|
9
|
-
${NODES_WGSL}
|
|
10
|
-
${COMMON_MATERIAL_PRELUDE_WGSL}
|
|
11
|
-
|
|
12
|
-
const CLOTH_SPECULAR: f32 = 0.8;
|
|
13
|
-
const CLOTH_ROUGHNESS: f32 = 0.5;
|
|
14
|
-
const CLOTH_TOON_EDGE: f32 = 0.2966;
|
|
15
|
-
const CLOTH_MIX04_MUL: f32 = 0.5;
|
|
16
|
-
const NPR_EMIT_STR: f32 = 18.200000762939453;
|
|
17
|
-
const NPR_MIX_SHADER_FAC: f32 = 0.8999999761581421;
|
|
18
|
-
|
|
19
|
-
@fragment fn fs(input: VertexOutput) -> FSOut {
|
|
20
|
-
let n = safe_normal(input.normal);
|
|
21
|
-
let v = normalize(camera.viewPos - input.worldPos);
|
|
22
|
-
let l = -light.lights[0].direction.xyz;
|
|
23
|
-
let sun = light.lights[0].color.xyz * light.lights[0].color.w;
|
|
24
|
-
let amb = light.ambientColor.xyz;
|
|
25
|
-
let shadow = sampleShadow(input.worldPos, n);
|
|
26
|
-
|
|
27
|
-
let tex_s = textureSample(diffuseTexture, diffuseSampler, input.uv);
|
|
28
|
-
let tex_rgb = tex_s.rgb;
|
|
29
|
-
let out_alpha = material.alpha * tex_s.a;
|
|
30
|
-
if (out_alpha < 0.001) { discard; }
|
|
31
|
-
|
|
32
|
-
// ═══ NPR STACK ═══
|
|
33
|
-
let lum_shade = shader_to_rgb_diffuse(n, l, sun, amb, shadow);
|
|
34
|
-
let ramp008 = ramp_constant_edge_aa(lum_shade, CLOTH_TOON_EDGE, vec4f(0,0,0,1), vec4f(1,1,1,1));
|
|
35
|
-
let mix04_fac = math_multiply(ramp008.r, CLOTH_MIX04_MUL);
|
|
36
|
-
|
|
37
|
-
let dark_tex = hue_sat_id(1.0, 0.19999998807907104, 1.0, tex_rgb);
|
|
38
|
-
let mix04 = mix_blend(mix04_fac, dark_tex, tex_rgb);
|
|
39
|
-
|
|
40
|
-
let bevel_z = clamp(n.y, 0.0, 1.0);
|
|
41
|
-
let mix03 = mix_blend(bevel_z, mix04, dark_tex);
|
|
42
|
-
|
|
43
|
-
let hue004 = hue_sat_id(0.800000011920929, 2.0, 1.0, mix03);
|
|
44
|
-
let npr_rgb = mix_overlay(1.0, mix03, hue004);
|
|
45
|
-
let npr_emission = npr_rgb * NPR_EMIT_STR;
|
|
46
|
-
|
|
47
|
-
// ═══ PRINCIPLED BSDF ═══
|
|
48
|
-
let principled_base = hue_sat_id(1.0, 0.800000011920929, 1.0, tex_rgb);
|
|
49
|
-
let principled = eval_principled(
|
|
50
|
-
PrincipledIn(principled_base, 0.0, CLOTH_SPECULAR, CLOTH_ROUGHNESS, 10.0, 0.0, 0.0),
|
|
51
|
-
n, l, v, sun, amb, shadow
|
|
52
|
-
);
|
|
53
|
-
|
|
54
|
-
// MixShader.001: Shader=自发光.005, Shader_001=原理化BSDF, Fac=0.9
|
|
55
|
-
let final_color = mix(npr_emission, principled, NPR_MIX_SHADER_FAC);
|
|
56
|
-
|
|
57
|
-
var out: FSOut;
|
|
58
|
-
out.color = vec4f(final_color, out_alpha);
|
|
59
|
-
out.mask = vec4f(1.0, 1.0, 0.0, out.color.a);
|
|
60
|
-
return out;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
`
|
|
@@ -1,45 +0,0 @@
|
|
|
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,62 +0,0 @@
|
|
|
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
|
-
|
|
29
|
-
// Rear-view gate for the post-alpha eye. Many PMX heads are open shells
|
|
30
|
-
// (no skull mesh), so from behind nothing occludes the eye — it would draw
|
|
31
|
-
// and stamp the see-through stencil straight through the back hair. Mesh
|
|
32
|
-
// normals/winding are unreliable (double-sided eye geometry), so gate by
|
|
33
|
-
// camera-vs-face hemisphere instead: the 頭 bone's skinning matrix carries
|
|
34
|
-
// the head's world rotation (PMX bind pose is rotationless), and PMX
|
|
35
|
-
// models face −Z locally. Discard drops color, depth, and stencil.
|
|
36
|
-
if (material.headBoneIndex >= 0.0) {
|
|
37
|
-
let hm = skinMats[u32(material.headBoneIndex)];
|
|
38
|
-
let faceDir = -normalize(hm[2].xyz);
|
|
39
|
-
if (dot(faceDir, v) < -0.15) { discard; }
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
let l = -light.lights[0].direction.xyz;
|
|
43
|
-
let sun = light.lights[0].color.xyz * light.lights[0].color.w;
|
|
44
|
-
let amb = light.ambientColor.xyz;
|
|
45
|
-
let shadow = sampleShadow(input.worldPos, n);
|
|
46
|
-
|
|
47
|
-
let albedo = tex_s.rgb;
|
|
48
|
-
|
|
49
|
-
let shaded = eval_principled(
|
|
50
|
-
PrincipledIn(albedo, 0.0, EYE_SPECULAR, EYE_ROUGHNESS, 1e30, 0.0, 0.0),
|
|
51
|
-
n, l, v, sun, amb, shadow
|
|
52
|
-
);
|
|
53
|
-
// Principled Emission socket: emissive = emission_color × strength, added on top.
|
|
54
|
-
let emission = albedo * EYE_EMISSION_STRENGTH;
|
|
55
|
-
|
|
56
|
-
var out: FSOut;
|
|
57
|
-
out.color = vec4f(shaded + emission, alpha);
|
|
58
|
-
out.mask = vec4f(1.0, 1.0, 0.0, out.color.a);
|
|
59
|
-
return out;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
`
|
|
@@ -1,97 +0,0 @@
|
|
|
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
|
-
`
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
// M_Hair — 仿深空之眼渲染预设v1.0_by_小绿毛猫 "M_Hair". Toon + fresnel rim + bevel +
|
|
2
|
-
// bright-tex gate, mixed 80/20 NPR/PBR. MixShader.001 Fac=0.2 keeps Principled subtle.
|
|
3
|
-
|
|
4
|
-
import { NODES_WGSL } from "./nodes"
|
|
5
|
-
import { COMMON_MATERIAL_PRELUDE_WGSL } from "./common"
|
|
6
|
-
|
|
7
|
-
export const HAIR_SHADER_WGSL = /* wgsl */ `
|
|
8
|
-
|
|
9
|
-
${NODES_WGSL}
|
|
10
|
-
${COMMON_MATERIAL_PRELUDE_WGSL}
|
|
11
|
-
|
|
12
|
-
// Pipeline-override: the engine compiles two variants — the normal opaque hair pipeline
|
|
13
|
-
// (IS_OVER_EYES=false) and a second pipeline that re-draws hair fragments stencil-matched
|
|
14
|
-
// against the eye stamp with 25% alpha so eyes read through the hair silhouette. Resolved
|
|
15
|
-
// at pipeline-compile time; the dead branch is dropped by the shader compiler.
|
|
16
|
-
override IS_OVER_EYES: bool = false;
|
|
17
|
-
|
|
18
|
-
const HAIR_SPECULAR: f32 = 1.0;
|
|
19
|
-
const HAIR_ROUGHNESS: f32 = 0.3;
|
|
20
|
-
// EEVEE Light Clamp equivalent (same value as body/face/cloth_rough). Hair
|
|
21
|
-
// is the firefly-prone material: physics-animated with the noisiest blended
|
|
22
|
-
// normals, so grazing NV spikes the GGX term and flashes white through
|
|
23
|
-
// bloom without this.
|
|
24
|
-
const HAIR_SPEC_CLAMP: f32 = 10.0;
|
|
25
|
-
const HAIR_TEX_GATE_THRESH: f32 = 0.15000000596046448;
|
|
26
|
-
const HAIR_RIM2_POW: f32 = 0.6300000548362732;
|
|
27
|
-
const HAIR_MIX_BG: vec3f = vec3f(0.1673291176557541);
|
|
28
|
-
const HAIR_MIX_NPR: f32 = 0.2;
|
|
29
|
-
|
|
30
|
-
@fragment fn fs(input: VertexOutput) -> FSOut {
|
|
31
|
-
let tex_s = textureSample(diffuseTexture, diffuseSampler, input.uv);
|
|
32
|
-
// MMD alpha semantics: material alpha × texture alpha. Hair/lace/accessory
|
|
33
|
-
// textures cut their shapes in the alpha channel — ignoring it renders each
|
|
34
|
-
// card's full quad with the texture's padding color (white shimmer on dark
|
|
35
|
-
// hair for models whose textures pad with white).
|
|
36
|
-
let alpha = material.alpha * tex_s.a;
|
|
37
|
-
if (alpha < 0.001) { discard; }
|
|
38
|
-
|
|
39
|
-
let n = safe_normal(input.normal);
|
|
40
|
-
let v = normalize(camera.viewPos - input.worldPos);
|
|
41
|
-
let l = -light.lights[0].direction.xyz;
|
|
42
|
-
let sun = light.lights[0].color.xyz * light.lights[0].color.w;
|
|
43
|
-
let amb = light.ambientColor.xyz;
|
|
44
|
-
let shadow = sampleShadow(input.worldPos, n);
|
|
45
|
-
|
|
46
|
-
let tex_color = tex_s.rgb;
|
|
47
|
-
|
|
48
|
-
// ═══ NPR STACK ═══
|
|
49
|
-
let hue_sat_shadow = hue_sat_id(1.2, 0.5, 1.0, tex_color);
|
|
50
|
-
let hue_sat_002 = hue_sat(0.48, 1.2, 0.7, 1.0, hue_sat_shadow);
|
|
51
|
-
let hue_sat_001 = hue_sat_id(1.5, 1.0, 1.0, tex_color);
|
|
52
|
-
|
|
53
|
-
let ndotl_raw = shader_to_rgb_diffuse(n, l, sun, amb, shadow);
|
|
54
|
-
let ramp_008 = ramp_constant(ndotl_raw, 0.0, vec4f(0,0,0,1), 0.2966, vec4f(1,1,1,1)).r;
|
|
55
|
-
|
|
56
|
-
let mix_004 = mix_blend(ramp_008, hue_sat_002, hue_sat_001);
|
|
57
|
-
let bc = bright_contrast(mix_004, 0.1, 0.2);
|
|
58
|
-
|
|
59
|
-
let bevel_z = clamp(n.y, 0.0, 1.0);
|
|
60
|
-
let mix_003 = mix_blend(bevel_z, bc, hue_sat_002);
|
|
61
|
-
|
|
62
|
-
let rim2_raw = fresnel(1.45, n, v) * layer_weight_fresnel(0.61, n, v);
|
|
63
|
-
let rim2_fac = math_power(rim2_raw, HAIR_RIM2_POW);
|
|
64
|
-
let mix_shader_002 = mix(mix_003, HAIR_MIX_BG, rim2_fac);
|
|
65
|
-
|
|
66
|
-
// GREATER_THAN on a color input uses BT.601 luminance — same socket-semantic fix as face.ts.
|
|
67
|
-
let tex_gate = math_greater_than(color_to_value(tex_color), HAIR_TEX_GATE_THRESH);
|
|
68
|
-
let gate_emit = vec3f(tex_gate) * 0.1;
|
|
69
|
-
|
|
70
|
-
let npr_stack = mix_shader_002 + gate_emit;
|
|
71
|
-
|
|
72
|
-
// ═══ PRINCIPLED BSDF ═══
|
|
73
|
-
// Graph has a noise→normal_map bump (Strength=0.1) on Principled.Normal, but MixShader.001
|
|
74
|
-
// weights Principled at only 0.2 — the bumped spec × that weight is imperceptible, so we
|
|
75
|
-
// drop the subtree and keep plain n (saves a tex_noise + bump_lh per hair fragment).
|
|
76
|
-
let principled = eval_principled(
|
|
77
|
-
PrincipledIn(bc, 0.0, HAIR_SPECULAR, HAIR_ROUGHNESS, HAIR_SPEC_CLAMP, 0.0, 0.0),
|
|
78
|
-
n, l, v, sun, amb, shadow
|
|
79
|
-
);
|
|
80
|
-
|
|
81
|
-
let final_color = mix(npr_stack, principled, HAIR_MIX_NPR);
|
|
82
|
-
|
|
83
|
-
var outAlpha = alpha;
|
|
84
|
-
if (IS_OVER_EYES) { outAlpha = alpha * 0.25; }
|
|
85
|
-
|
|
86
|
-
var out: FSOut;
|
|
87
|
-
out.color = vec4f(final_color, outAlpha);
|
|
88
|
-
out.mask = vec4f(1.0, 1.0, 0.0, out.color.a);
|
|
89
|
-
return out;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
`
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
// M_Metal — Metallic Principled (Metallic=1.0, Specular=1.0, Roughness=0.3) with a
|
|
2
|
-
// reflection-coord Voronoi pattern driving base color for metallic sparkle, plus an
|
|
3
|
-
// NPR toon/overlay emission stack mixed at MixShader Fac=0.6967.
|
|
4
|
-
//
|
|
5
|
-
// Graph's base color chain: 纹理坐标.Reflection → 矢量运算.007(CROSS, Vec2=(0,1,0)) →
|
|
6
|
-
// 沃罗诺伊纹理(F1, Color out) → 颜色渐变(linear) → 混合.005. The dumper did not capture
|
|
7
|
-
// the VectorMath op — CROSS is assumed based on the hardcoded (0,1,0) Vector_001
|
|
8
|
-
// constant (MULTIPLY would zero X/Z producing 1D bands; CROSS produces horizontal ring
|
|
9
|
-
// patterns consistent with metallic anisotropy).
|
|
10
|
-
|
|
11
|
-
import { NODES_WGSL } from "./nodes"
|
|
12
|
-
import { COMMON_MATERIAL_PRELUDE_WGSL } from "./common"
|
|
13
|
-
|
|
14
|
-
export const METAL_SHADER_WGSL = /* wgsl */ `
|
|
15
|
-
|
|
16
|
-
${NODES_WGSL}
|
|
17
|
-
${COMMON_MATERIAL_PRELUDE_WGSL}
|
|
18
|
-
|
|
19
|
-
const METAL_SPECULAR: f32 = 1.0;
|
|
20
|
-
const METAL_METALLIC: f32 = 1.0;
|
|
21
|
-
const METAL_ROUGHNESS: f32 = 0.3;
|
|
22
|
-
const METAL_TOON_EDGE: f32 = 0.2966;
|
|
23
|
-
const METAL_MIX04_MUL: f32 = 0.5;
|
|
24
|
-
const METAL_EMIT_STR: f32 = 8.100000381469727;
|
|
25
|
-
const METAL_MIX_SHADER_FAC: f32 = 0.6967;
|
|
26
|
-
const METAL_VORONOI_SCALE: f32 = 4.3;
|
|
27
|
-
|
|
28
|
-
@fragment fn fs(input: VertexOutput) -> FSOut {
|
|
29
|
-
let n = safe_normal(input.normal);
|
|
30
|
-
let v = normalize(camera.viewPos - input.worldPos);
|
|
31
|
-
let l = -light.lights[0].direction.xyz;
|
|
32
|
-
let sun = light.lights[0].color.xyz * light.lights[0].color.w;
|
|
33
|
-
let amb = light.ambientColor.xyz;
|
|
34
|
-
let shadow = sampleShadow(input.worldPos, n);
|
|
35
|
-
|
|
36
|
-
let tex_s = textureSample(diffuseTexture, diffuseSampler, input.uv);
|
|
37
|
-
let tex_rgb = tex_s.rgb;
|
|
38
|
-
let out_alpha = material.alpha * tex_s.a;
|
|
39
|
-
if (out_alpha < 0.001) { discard; }
|
|
40
|
-
|
|
41
|
-
// ═══ NPR STACK ═══
|
|
42
|
-
let tex_tint = hue_sat_id(1.0, 0.800000011920929, 1.0, tex_rgb);
|
|
43
|
-
let lum_shade = shader_to_rgb_diffuse(n, l, sun, amb, shadow);
|
|
44
|
-
let ramp008 = ramp_constant_edge_aa(lum_shade, METAL_TOON_EDGE, vec4f(0,0,0,1), vec4f(1,1,1,1));
|
|
45
|
-
let mix04_fac = math_multiply(ramp008.r, METAL_MIX04_MUL);
|
|
46
|
-
|
|
47
|
-
let dark_tex = hue_sat_id(1.0, 0.19999998807907104, 1.0, tex_tint);
|
|
48
|
-
let mix04 = mix_blend(mix04_fac, dark_tex, tex_tint);
|
|
49
|
-
|
|
50
|
-
let hue004 = hue_sat_id(1.0, 2.0, 1.0, mix04);
|
|
51
|
-
let npr_rgb = mix_overlay(1.0, mix04, hue004);
|
|
52
|
-
let npr_emission = npr_rgb * METAL_EMIT_STR;
|
|
53
|
-
|
|
54
|
-
// ═══ PRINCIPLED BSDF (metallic=1, voronoi-driven base) ═══
|
|
55
|
-
// Reflection-coord Voronoi produces the metallic sparkle variation.
|
|
56
|
-
// VALTORGB takes Color → Fac via Blender's BT.601 implicit color_to_value.
|
|
57
|
-
let refl_dir = reflect(-v, n);
|
|
58
|
-
let voro_input = cross(refl_dir, vec3f(0.0, 1.0, 0.0));
|
|
59
|
-
let voro_rgb = tex_voronoi_color(voro_input, METAL_VORONOI_SCALE);
|
|
60
|
-
let voro_scalar = color_to_value(voro_rgb);
|
|
61
|
-
let voro_ramp = ramp_linear(voro_scalar, 0.0, vec4f(0,0,0,1), 1.0, vec4f(1,1,1,1)).r;
|
|
62
|
-
let hue006 = hue_sat_id(1.5, 1.2999999523162842, 1.0, tex_tint);
|
|
63
|
-
let albedo = mix_blend(voro_ramp, vec3f(voro_ramp), hue006);
|
|
64
|
-
|
|
65
|
-
// metallic=1 collapses f0 = mix(dielectric, albedo, 1) = albedo; diffuse_weight = 0.
|
|
66
|
-
let principled = eval_principled(
|
|
67
|
-
PrincipledIn(albedo, METAL_METALLIC, METAL_SPECULAR, METAL_ROUGHNESS, 1e30, 0.0, 0.0),
|
|
68
|
-
n, l, v, sun, amb, shadow
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
let final_color = mix(npr_emission, principled, METAL_MIX_SHADER_FAC);
|
|
72
|
-
|
|
73
|
-
var out: FSOut;
|
|
74
|
-
out.color = vec4f(final_color, out_alpha);
|
|
75
|
-
out.mask = vec4f(1.0, 1.0, 0.0, out.color.a);
|
|
76
|
-
return out;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
`
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
// M_MMDClassic — authentic MMD/MikuMikuDance fixed-pipeline material. Uses the
|
|
2
|
-
// PMX material data every model author actually tuned: ambient + diffuse×light
|
|
3
|
-
// base, toon-ramp shading (ramp carries the terminator, NOT an N·L multiply),
|
|
4
|
-
// sphere map (sph multiply / spa add), and Blinn-Phong specular with the PMX
|
|
5
|
-
// shininess. This is the universal fallback for materials no preset map or
|
|
6
|
-
// name heuristic covers — it renders what the author saw in MMD/PMXEditor.
|
|
7
|
-
|
|
8
|
-
import { COMMON_MATERIAL_PRELUDE_WGSL } from "./common"
|
|
9
|
-
|
|
10
|
-
export const MMD_CLASSIC_SHADER_WGSL = /* wgsl */ `
|
|
11
|
-
|
|
12
|
-
${COMMON_MATERIAL_PRELUDE_WGSL}
|
|
13
|
-
|
|
14
|
-
@fragment fn fs(input: VertexOutput) -> FSOut {
|
|
15
|
-
let tex_s = textureSample(diffuseTexture, diffuseSampler, input.uv);
|
|
16
|
-
// MMD alpha semantics: material alpha × texture alpha.
|
|
17
|
-
let alpha = material.alpha * tex_s.a;
|
|
18
|
-
if (alpha < 0.001) { discard; }
|
|
19
|
-
|
|
20
|
-
let n = safe_normal(input.normal);
|
|
21
|
-
let v = normalize(camera.viewPos - input.worldPos);
|
|
22
|
-
let l = -light.lights[0].direction.xyz;
|
|
23
|
-
let sun = light.lights[0].color.xyz * light.lights[0].color.w;
|
|
24
|
-
let amb = light.ambientColor.xyz;
|
|
25
|
-
let shadow = sampleShadow(input.worldPos, n);
|
|
26
|
-
|
|
27
|
-
// Sphere-map UV from the view-space normal — sampled up front to keep the
|
|
28
|
-
// texture reads in uniform control flow.
|
|
29
|
-
let vn = normalize((camera.view * vec4f(n, 0.0)).xyz);
|
|
30
|
-
let sph_uv = vec2f(vn.x * 0.5 + 0.5, 0.5 - vn.y * 0.5);
|
|
31
|
-
let sphere_rgb = textureSample(sphereTexture, diffuseSampler, sph_uv).rgb;
|
|
32
|
-
|
|
33
|
-
// Toon ramp: v runs light (0) → shadow (1); the ramp texture carries the
|
|
34
|
-
// terminator shape and shadow tint. Self-shadow pushes toward the shadow
|
|
35
|
-
// end by attenuating N·L. Sampled up front for the same uniformity reason.
|
|
36
|
-
let ndl = dot(n, l) * shadow;
|
|
37
|
-
let toon_v = clamp(0.5 - 0.5 * ndl, 0.0, 1.0);
|
|
38
|
-
let toon_rgb = textureSample(toonTexture, diffuseSampler, vec2f(0.5, toon_v)).rgb;
|
|
39
|
-
|
|
40
|
-
// MMD base: saturate(ambient + diffuse × light color), modulated by texture.
|
|
41
|
-
// The engine's ambient light scales the material-ambient floor so scene
|
|
42
|
-
// lighting still has authority over overall exposure.
|
|
43
|
-
let base = clamp(material.ambient * max(amb, vec3f(0.35)) + material.diffuseColor * sun, vec3f(0.0), vec3f(1.0));
|
|
44
|
-
var color = base * tex_s.rgb * toon_rgb;
|
|
45
|
-
|
|
46
|
-
// Sphere map: 1 = sph (multiply), 2 = spa (add). Mode 3 (sub-texture) and
|
|
47
|
-
// 0 fall through unchanged.
|
|
48
|
-
if (material.sphereMode == 1.0) {
|
|
49
|
-
color *= sphere_rgb;
|
|
50
|
-
} else if (material.sphereMode == 2.0) {
|
|
51
|
-
color += sphere_rgb;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Blinn-Phong specular with PMX shininess. shininess 0 disables (many
|
|
55
|
-
// rigs author 0 to mean "no highlight").
|
|
56
|
-
if (material.shininess > 0.0) {
|
|
57
|
-
let h = normalize(l + v);
|
|
58
|
-
let spec = pow(max(dot(n, h), 0.0), max(material.shininess, 1.0));
|
|
59
|
-
color += material.specular * sun * (spec * shadow);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
var out: FSOut;
|
|
63
|
-
out.color = vec4f(color, alpha);
|
|
64
|
-
out.mask = vec4f(1.0, 1.0, 0.0, out.color.a);
|
|
65
|
-
return out;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
`
|