reze-engine 0.18.0 → 0.18.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.
@@ -0,0 +1,3 @@
1
+ import type { StyleGraph } from "../schema";
2
+ export declare const EYE_GRAPH: StyleGraph;
3
+ //# sourceMappingURL=eye.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eye.d.ts","sourceRoot":"","sources":["../../../src/graph/presets/eye.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAE3C,eAAO,MAAM,SAAS,EAAE,UAqBvB,CAAA"}
@@ -0,0 +1,30 @@
1
+ // Eye as a StyleGraph — port of shaders/materials/eye.ts. The published preset
2
+ // author's instruction: "keep eyes in the default nodegraph, add emission 1.5".
3
+ // So it's the default Principled BSDF plus an Emission of the diffuse texture at
4
+ // 1.5× (Blender's Principled Emission socket, decomposed as a separate Emission +
5
+ // Add Shader — the emission feeds bloom pre-tonemap).
6
+ //
7
+ // The rear-view gate and the see-through stencil stamp are slot-owned (built-in eye
8
+ // behavior, see EYE_TEMPLATE in slots.ts + createSlotPipeline) — not in this graph.
9
+ export const EYE_GRAPH = {
10
+ version: 1,
11
+ name: "Eye",
12
+ slot: "eye",
13
+ nodes: [
14
+ { id: "tex", type: "texture" },
15
+ {
16
+ id: "principled",
17
+ type: "principled",
18
+ inputs: { metallic: 0.0, specular: 0.5, roughness: 0.5, spec_clamp: 1e30, sheen: 0.0, sheen_tint: 0.0 },
19
+ },
20
+ { id: "emission", type: "emission", inputs: { strength: 1.5 } },
21
+ { id: "add", type: "add_shader" },
22
+ ],
23
+ links: [
24
+ { from: { node: "tex", socket: "color" }, to: { node: "principled", socket: "base" } },
25
+ { from: { node: "tex", socket: "color" }, to: { node: "emission", socket: "color" } },
26
+ { from: { node: "principled", socket: "color" }, to: { node: "add", socket: "a" } },
27
+ { from: { node: "emission", socket: "color" }, to: { node: "add", socket: "b" } },
28
+ ],
29
+ output: { node: "add", socket: "color" },
30
+ };
@@ -0,0 +1,3 @@
1
+ import type { StyleGraph } from "../schema";
2
+ export declare const FACE_GRAPH: StyleGraph;
3
+ //# sourceMappingURL=face.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"face.d.ts","sourceRoot":"","sources":["../../../src/graph/presets/face.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAE3C,eAAO,MAAM,UAAU,EAAE,UA6HxB,CAAA"}
@@ -0,0 +1,125 @@
1
+ // M_Face as a StyleGraph — port of shaders/materials/face.ts (仿深空之眼 "M_Face").
2
+ // Toon + warm rim + dual fresnel rim + BT.601 bright-tex gate, mixed 50/50 against a
3
+ // Principled BSDF with noise bump. Structurally close to body, but: the toon uses the
4
+ // edge-AA ramp, hue tints are 0.46 (full hue_sat, not the 0.5 _id specialization),
5
+ // rim2 is the hair-style fresnel×layer_weight_fresnel rim, and there's an extra
6
+ // near-white texture gate that emits (freckle/highlight paint). Plain material — no
7
+ // built-in slot effect, so it uses the default prelude/epilogue.
8
+ export const FACE_GRAPH = {
9
+ version: 1,
10
+ name: "Face",
11
+ slot: "face",
12
+ nodes: [
13
+ { id: "tex", type: "texture" },
14
+ { id: "geo", type: "geometry" },
15
+ // ── toon shading ──
16
+ { id: "str", type: "shader_to_rgb_diffuse" },
17
+ { id: "toon", type: "ramp_constant_aa", inputs: { edge: 0.2966 } },
18
+ { id: "shadow_tint", type: "hue_sat", inputs: { hue: 0.46000000834465027, saturation: 2.0, value: 0.3499999940395355, fac: 1.0 } },
19
+ { id: "lit_tint", type: "hue_sat", inputs: { hue: 0.46000000834465027, saturation: 1.600000023841858, value: 1.5, fac: 1.0 } },
20
+ { id: "toon_color", type: "mix/blend" },
21
+ { id: "bc", type: "bright_contrast", inputs: { bright: 0.1, contrast: 0.2 } },
22
+ { id: "emission3", type: "emission", inputs: { strength: 2.5 } },
23
+ // ── warm rim (toon*0.5+0.5 → cardinal ramp) ──
24
+ { id: "warm_mul", type: "math/multiply", inputs: { b: 0.5 } },
25
+ { id: "warm_add", type: "math/add", inputs: { b: 0.5 } },
26
+ { id: "warm_clamp", type: "math/clamp01" },
27
+ {
28
+ id: "warm_ramp",
29
+ type: "ramp_cardinal",
30
+ inputs: {
31
+ pos0: 0.2409,
32
+ color0: [0.2426, 0.068, 0.0588, 1.0],
33
+ pos1: 0.4663,
34
+ color1: [0.6677, 0.5024, 0.5126, 1.0],
35
+ },
36
+ },
37
+ { id: "warm_emit", type: "emission", inputs: { strength: 0.30000001192092896 } },
38
+ // ── rim1: fresnel × facing ──
39
+ { id: "rim1_fres", type: "fresnel", inputs: { ior: 2.0 } },
40
+ { id: "rim1_lw", type: "layer_weight/facing", inputs: { blend: 0.24 } },
41
+ { id: "rim1_str", type: "math/multiply" },
42
+ { id: "rim1", type: "emission", inputs: { color: [0.984157919883728, 0.6110184788703918, 0.5736401677131653] } },
43
+ // ── rim2: fresnel × fresnel-layer-weight, powered (hair-style) ──
44
+ { id: "rim2_fres", type: "fresnel", inputs: { ior: 1.45 } },
45
+ { id: "rim2_lw", type: "layer_weight/fresnel", inputs: { blend: 0.61 } },
46
+ { id: "rim2_raw", type: "math/multiply" },
47
+ { id: "rim2_pow", type: "math/power", inputs: { b: 0.6300000548362732 } },
48
+ { id: "rim2_mix", type: "mix_shader", inputs: { b: [1.0, 0.4684903025627136, 0.3698573112487793] } },
49
+ // ── near-white texture gate emission ──
50
+ { id: "gate", type: "math/greater_than", inputs: { b: 0.9300000071525574 } },
51
+ { id: "gate_scale", type: "math/multiply", inputs: { b: 3.0 } },
52
+ // ── npr stack (rim1 + rim2 + bright_emit + warm) ──
53
+ { id: "npr_add1", type: "add_shader" },
54
+ { id: "npr_add2", type: "add_shader" },
55
+ { id: "npr_stack", type: "add_shader" },
56
+ // ── principled with noise bump ──
57
+ { id: "map", type: "mapping", inputs: { scl: [1.0, 1.0, 1.5] } },
58
+ { id: "noise", type: "tex_noise", inputs: { scale: 1.0 } },
59
+ { id: "noise_ramp", type: "ramp_linear", inputs: { pos0: 0.0, pos1: 1.0 } },
60
+ { id: "bump", type: "bump", inputs: { strength: 0.324644535779953 } },
61
+ { id: "principled_base", type: "mix/blend", inputs: { b: [0.6832, 0.1947, 0.1373] } },
62
+ { id: "p_emit", type: "emission", inputs: { strength: 0.2 } },
63
+ {
64
+ id: "principled",
65
+ type: "principled",
66
+ inputs: { metallic: 0.0, specular: 0.5, roughness: 0.3, spec_clamp: 10.0, sheen: 0.0, sheen_tint: 0.0 },
67
+ },
68
+ { id: "p_sum", type: "add_shader" },
69
+ { id: "mix_shader_001", type: "mix_shader", inputs: { fac: 0.5 } },
70
+ ],
71
+ links: [
72
+ // toon
73
+ { from: { node: "str", socket: "value" }, to: { node: "toon", socket: "fac" } },
74
+ { from: { node: "tex", socket: "color" }, to: { node: "shadow_tint", socket: "color" } },
75
+ { from: { node: "tex", socket: "color" }, to: { node: "lit_tint", socket: "color" } },
76
+ { from: { node: "toon", socket: "fac_out" }, to: { node: "toon_color", socket: "fac" } },
77
+ { from: { node: "shadow_tint", socket: "color" }, to: { node: "toon_color", socket: "a" } },
78
+ { from: { node: "lit_tint", socket: "color" }, to: { node: "toon_color", socket: "b" } },
79
+ { from: { node: "toon_color", socket: "color" }, to: { node: "bc", socket: "color" } },
80
+ { from: { node: "bc", socket: "color" }, to: { node: "emission3", socket: "color" } },
81
+ // warm rim
82
+ { from: { node: "toon", socket: "fac_out" }, to: { node: "warm_mul", socket: "a" } },
83
+ { from: { node: "warm_mul", socket: "value" }, to: { node: "warm_add", socket: "a" } },
84
+ { from: { node: "warm_add", socket: "value" }, to: { node: "warm_clamp", socket: "a" } },
85
+ { from: { node: "warm_clamp", socket: "value" }, to: { node: "warm_ramp", socket: "fac" } },
86
+ { from: { node: "warm_ramp", socket: "color" }, to: { node: "warm_emit", socket: "color" } },
87
+ // rim1
88
+ { from: { node: "rim1_fres", socket: "value" }, to: { node: "rim1_str", socket: "a" } },
89
+ { from: { node: "rim1_lw", socket: "value" }, to: { node: "rim1_str", socket: "b" } },
90
+ { from: { node: "rim1_str", socket: "value" }, to: { node: "rim1", socket: "strength" } },
91
+ // rim2
92
+ { from: { node: "rim2_fres", socket: "value" }, to: { node: "rim2_raw", socket: "a" } },
93
+ { from: { node: "rim2_lw", socket: "value" }, to: { node: "rim2_raw", socket: "b" } },
94
+ { from: { node: "rim2_raw", socket: "value" }, to: { node: "rim2_pow", socket: "a" } },
95
+ { from: { node: "emission3", socket: "color" }, to: { node: "rim2_mix", socket: "a" } },
96
+ { from: { node: "rim2_pow", socket: "value" }, to: { node: "rim2_mix", socket: "fac" } },
97
+ // gate
98
+ { from: { node: "tex", socket: "color" }, to: { node: "gate", socket: "a" } },
99
+ { from: { node: "gate", socket: "value" }, to: { node: "gate_scale", socket: "a" } },
100
+ // npr stack
101
+ { from: { node: "rim1", socket: "color" }, to: { node: "npr_add1", socket: "a" } },
102
+ { from: { node: "rim2_mix", socket: "color" }, to: { node: "npr_add1", socket: "b" } },
103
+ { from: { node: "npr_add1", socket: "color" }, to: { node: "npr_add2", socket: "a" } },
104
+ { from: { node: "gate_scale", socket: "value" }, to: { node: "npr_add2", socket: "b" } },
105
+ { from: { node: "npr_add2", socket: "color" }, to: { node: "npr_stack", socket: "a" } },
106
+ { from: { node: "warm_emit", socket: "color" }, to: { node: "npr_stack", socket: "b" } },
107
+ // principled + noise bump
108
+ { from: { node: "geo", socket: "rest_pos" }, to: { node: "map", socket: "vector" } },
109
+ { from: { node: "map", socket: "vector" }, to: { node: "noise", socket: "vector" } },
110
+ { from: { node: "noise", socket: "value" }, to: { node: "noise_ramp", socket: "fac" } },
111
+ { from: { node: "noise_ramp", socket: "fac_out" }, to: { node: "bump", socket: "height" } },
112
+ { from: { node: "geo", socket: "normal" }, to: { node: "bump", socket: "normal" } },
113
+ { from: { node: "noise_ramp", socket: "fac_out" }, to: { node: "principled_base", socket: "fac" } },
114
+ { from: { node: "bc", socket: "color" }, to: { node: "principled_base", socket: "a" } },
115
+ { from: { node: "bc", socket: "color" }, to: { node: "p_emit", socket: "color" } },
116
+ { from: { node: "principled_base", socket: "color" }, to: { node: "principled", socket: "base" } },
117
+ { from: { node: "bump", socket: "vector" }, to: { node: "principled", socket: "normal" } },
118
+ { from: { node: "principled", socket: "color" }, to: { node: "p_sum", socket: "a" } },
119
+ { from: { node: "p_emit", socket: "color" }, to: { node: "p_sum", socket: "b" } },
120
+ // final mix
121
+ { from: { node: "npr_stack", socket: "color" }, to: { node: "mix_shader_001", socket: "a" } },
122
+ { from: { node: "p_sum", socket: "color" }, to: { node: "mix_shader_001", socket: "b" } },
123
+ ],
124
+ output: { node: "mix_shader_001", socket: "color" },
125
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"slots.d.ts","sourceRoot":"","sources":["../../src/graph/slots.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAE/C,MAAM,MAAM,YAAY,GAAG;IACzB,2EAA2E;IAC3E,KAAK,EAAE,MAAM,CAAA;IACb,mFAAmF;IACnF,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,4EAA4E;IAC5E,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAgFD,eAAO,MAAM,cAAc,EAAE,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,YAAY,CAAC,CAGxE,CAAA;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,cAAc,GAAG,YAAY,CAE/D;AAID,eAAO,MAAM,mBAAmB,gHAG/B,CAAA;AAqBD,wBAAgB,cAAc,CAAC,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,EAAE,OAAO,GAAG,MAAM,CAa1G"}
1
+ {"version":3,"file":"slots.d.ts","sourceRoot":"","sources":["../../src/graph/slots.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAE/C,MAAM,MAAM,YAAY,GAAG;IACzB,2EAA2E;IAC3E,KAAK,EAAE,MAAM,CAAA;IACb,mFAAmF;IACnF,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,4EAA4E;IAC5E,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAgHD,eAAO,MAAM,cAAc,EAAE,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,YAAY,CAAC,CAIxE,CAAA;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,cAAc,GAAG,YAAY,CAE/D;AAID,eAAO,MAAM,mBAAmB,gHAG/B,CAAA;AAqBD,wBAAgB,cAAc,CAAC,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,EAAE,OAAO,GAAG,MAAM,CAa1G"}
@@ -78,9 +78,41 @@ fn hashed_alpha_threshold(co: vec3f) -> f32 {
78
78
  return out;
79
79
  `,
80
80
  };
81
+ // Eye's built-in rear-view gate (see eye.ts): open-shell PMX heads don't occlude
82
+ // the eye from behind, so it would draw (and stamp the see-through stencil) through
83
+ // the back of the head. Gate by camera-vs-face hemisphere via the 頭 bone's skinning
84
+ // matrix. Discarding here drops color, depth, and the stencil stamp together. The
85
+ // stencil-stamp pipeline state + front-face cull are slot-owned in createSlotPipeline;
86
+ // the graph only computes the eye's shading (Principled + emission).
87
+ const EYE_TEMPLATE = {
88
+ decls: "",
89
+ prelude: `@fragment fn fs(input: VertexOutput) -> FSOut {
90
+ let tex_s = textureSample(diffuseTexture, diffuseSampler, input.uv);
91
+ let alpha = material.alpha * tex_s.a;
92
+ if (alpha < 0.001) { discard; }
93
+
94
+ let n = safe_normal(input.normal);
95
+ let v = normalize(camera.viewPos - input.worldPos);
96
+
97
+ if (material.headBoneIndex >= 0.0) {
98
+ let hm = skinMats[u32(material.headBoneIndex)];
99
+ let faceDir = -normalize(hm[2].xyz);
100
+ if (dot(faceDir, v) < -0.15) { discard; }
101
+ }
102
+
103
+ let l = -light.lights[0].direction.xyz;
104
+ let sun = light.lights[0].color.xyz * light.lights[0].color.w;
105
+ let amb = light.ambientColor.xyz;
106
+ let shadow = sampleShadow(input.worldPos, n);
107
+ let tex_color = tex_s.rgb;
108
+
109
+ `,
110
+ epilogue: DEFAULT_EPILOGUE,
111
+ };
81
112
  export const SLOT_TEMPLATES = {
82
113
  hair: HAIR_TEMPLATE,
83
114
  stockings: STOCKINGS_TEMPLATE,
115
+ eye: EYE_TEMPLATE,
84
116
  };
85
117
  export function slotTemplate(slot) {
86
118
  return SLOT_TEMPLATES[slot] ?? DEFAULT_TEMPLATE;
package/dist/index.d.ts CHANGED
@@ -10,6 +10,8 @@ export { CLOTH_ROUGH_GRAPH } from "./graph/presets/cloth_rough";
10
10
  export { METAL_GRAPH } from "./graph/presets/metal";
11
11
  export { BODY_GRAPH } from "./graph/presets/body";
12
12
  export { STOCKINGS_GRAPH } from "./graph/presets/stockings";
13
+ export { EYE_GRAPH } from "./graph/presets/eye";
14
+ export { FACE_GRAPH } from "./graph/presets/face";
13
15
  export { Model } from "./model";
14
16
  export { Vec3, Quat, Mat4 } from "./math";
15
17
  export type { AnimationClip, AnimationPlayOptions, AnimationProgress, BoneKeyframe, MorphKeyframe, BoneInterpolation, ControlPoint, } from "./animation";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EACN,qBAAqB,EACrB,sBAAsB,EACtB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,oBAAoB,EACzB,KAAK,yBAAyB,EAC9B,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,aAAa,GACnB,MAAM,UAAU,CAAA;AACjB,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,KAAK,oBAAoB,EAAE,MAAM,iBAAiB,CAAA;AACvG,OAAO,EACL,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,SAAS,GACf,MAAM,iBAAiB,CAAA;AACxB,YAAY,EACV,UAAU,EACV,SAAS,EACT,SAAS,EACT,YAAY,EACZ,WAAW,EACX,UAAU,GACX,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,aAAa,EAAE,KAAK,QAAQ,EAAE,KAAK,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAC3E,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAA;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAA;AAC/D,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAC3D,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAC/B,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AACzC,YAAY,EACV,aAAa,EACb,oBAAoB,EACpB,iBAAiB,EACjB,YAAY,EACZ,aAAa,EACb,iBAAiB,EACjB,YAAY,GACb,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAA;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EACN,qBAAqB,EACrB,sBAAsB,EACtB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,oBAAoB,EACzB,KAAK,yBAAyB,EAC9B,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,aAAa,GACnB,MAAM,UAAU,CAAA;AACjB,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,KAAK,oBAAoB,EAAE,MAAM,iBAAiB,CAAA;AACvG,OAAO,EACL,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,SAAS,GACf,MAAM,iBAAiB,CAAA;AACxB,YAAY,EACV,UAAU,EACV,SAAS,EACT,SAAS,EACT,YAAY,EACZ,WAAW,EACX,UAAU,GACX,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,aAAa,EAAE,KAAK,QAAQ,EAAE,KAAK,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAC3E,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAA;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAA;AAC/D,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAC/B,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AACzC,YAAY,EACV,aAAa,EACb,oBAAoB,EACpB,iBAAiB,EACjB,YAAY,EACZ,aAAa,EACb,iBAAiB,EACjB,YAAY,GACb,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAA;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA"}
package/dist/index.js CHANGED
@@ -9,6 +9,8 @@ export { CLOTH_ROUGH_GRAPH } from "./graph/presets/cloth_rough";
9
9
  export { METAL_GRAPH } from "./graph/presets/metal";
10
10
  export { BODY_GRAPH } from "./graph/presets/body";
11
11
  export { STOCKINGS_GRAPH } from "./graph/presets/stockings";
12
+ export { EYE_GRAPH } from "./graph/presets/eye";
13
+ export { FACE_GRAPH } from "./graph/presets/face";
12
14
  export { Model } from "./model";
13
15
  export { Vec3, Quat, Mat4 } from "./math";
14
16
  export { FPS } from "./animation";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reze-engine",
3
- "version": "0.18.0",
3
+ "version": "0.18.1",
4
4
  "description": "A lightweight WebGPU engine for real-time 3D MMD/PMX model rendering",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -0,0 +1,33 @@
1
+ // Eye as a StyleGraph — port of shaders/materials/eye.ts. The published preset
2
+ // author's instruction: "keep eyes in the default nodegraph, add emission 1.5".
3
+ // So it's the default Principled BSDF plus an Emission of the diffuse texture at
4
+ // 1.5× (Blender's Principled Emission socket, decomposed as a separate Emission +
5
+ // Add Shader — the emission feeds bloom pre-tonemap).
6
+ //
7
+ // The rear-view gate and the see-through stencil stamp are slot-owned (built-in eye
8
+ // behavior, see EYE_TEMPLATE in slots.ts + createSlotPipeline) — not in this graph.
9
+
10
+ import type { StyleGraph } from "../schema"
11
+
12
+ export const EYE_GRAPH: StyleGraph = {
13
+ version: 1,
14
+ name: "Eye",
15
+ slot: "eye",
16
+ nodes: [
17
+ { id: "tex", type: "texture" },
18
+ {
19
+ id: "principled",
20
+ type: "principled",
21
+ inputs: { metallic: 0.0, specular: 0.5, roughness: 0.5, spec_clamp: 1e30, sheen: 0.0, sheen_tint: 0.0 },
22
+ },
23
+ { id: "emission", type: "emission", inputs: { strength: 1.5 } },
24
+ { id: "add", type: "add_shader" },
25
+ ],
26
+ links: [
27
+ { from: { node: "tex", socket: "color" }, to: { node: "principled", socket: "base" } },
28
+ { from: { node: "tex", socket: "color" }, to: { node: "emission", socket: "color" } },
29
+ { from: { node: "principled", socket: "color" }, to: { node: "add", socket: "a" } },
30
+ { from: { node: "emission", socket: "color" }, to: { node: "add", socket: "b" } },
31
+ ],
32
+ output: { node: "add", socket: "color" },
33
+ }
@@ -0,0 +1,136 @@
1
+ // M_Face as a StyleGraph — port of shaders/materials/face.ts (仿深空之眼 "M_Face").
2
+ // Toon + warm rim + dual fresnel rim + BT.601 bright-tex gate, mixed 50/50 against a
3
+ // Principled BSDF with noise bump. Structurally close to body, but: the toon uses the
4
+ // edge-AA ramp, hue tints are 0.46 (full hue_sat, not the 0.5 _id specialization),
5
+ // rim2 is the hair-style fresnel×layer_weight_fresnel rim, and there's an extra
6
+ // near-white texture gate that emits (freckle/highlight paint). Plain material — no
7
+ // built-in slot effect, so it uses the default prelude/epilogue.
8
+
9
+ import type { StyleGraph } from "../schema"
10
+
11
+ export const FACE_GRAPH: StyleGraph = {
12
+ version: 1,
13
+ name: "Face",
14
+ slot: "face",
15
+ nodes: [
16
+ { id: "tex", type: "texture" },
17
+ { id: "geo", type: "geometry" },
18
+
19
+ // ── toon shading ──
20
+ { id: "str", type: "shader_to_rgb_diffuse" },
21
+ { id: "toon", type: "ramp_constant_aa", inputs: { edge: 0.2966 } },
22
+ { id: "shadow_tint", type: "hue_sat", inputs: { hue: 0.46000000834465027, saturation: 2.0, value: 0.3499999940395355, fac: 1.0 } },
23
+ { id: "lit_tint", type: "hue_sat", inputs: { hue: 0.46000000834465027, saturation: 1.600000023841858, value: 1.5, fac: 1.0 } },
24
+ { id: "toon_color", type: "mix/blend" },
25
+ { id: "bc", type: "bright_contrast", inputs: { bright: 0.1, contrast: 0.2 } },
26
+ { id: "emission3", type: "emission", inputs: { strength: 2.5 } },
27
+
28
+ // ── warm rim (toon*0.5+0.5 → cardinal ramp) ──
29
+ { id: "warm_mul", type: "math/multiply", inputs: { b: 0.5 } },
30
+ { id: "warm_add", type: "math/add", inputs: { b: 0.5 } },
31
+ { id: "warm_clamp", type: "math/clamp01" },
32
+ {
33
+ id: "warm_ramp",
34
+ type: "ramp_cardinal",
35
+ inputs: {
36
+ pos0: 0.2409,
37
+ color0: [0.2426, 0.068, 0.0588, 1.0],
38
+ pos1: 0.4663,
39
+ color1: [0.6677, 0.5024, 0.5126, 1.0],
40
+ },
41
+ },
42
+ { id: "warm_emit", type: "emission", inputs: { strength: 0.30000001192092896 } },
43
+
44
+ // ── rim1: fresnel × facing ──
45
+ { id: "rim1_fres", type: "fresnel", inputs: { ior: 2.0 } },
46
+ { id: "rim1_lw", type: "layer_weight/facing", inputs: { blend: 0.24 } },
47
+ { id: "rim1_str", type: "math/multiply" },
48
+ { id: "rim1", type: "emission", inputs: { color: [0.984157919883728, 0.6110184788703918, 0.5736401677131653] } },
49
+
50
+ // ── rim2: fresnel × fresnel-layer-weight, powered (hair-style) ──
51
+ { id: "rim2_fres", type: "fresnel", inputs: { ior: 1.45 } },
52
+ { id: "rim2_lw", type: "layer_weight/fresnel", inputs: { blend: 0.61 } },
53
+ { id: "rim2_raw", type: "math/multiply" },
54
+ { id: "rim2_pow", type: "math/power", inputs: { b: 0.6300000548362732 } },
55
+ { id: "rim2_mix", type: "mix_shader", inputs: { b: [1.0, 0.4684903025627136, 0.3698573112487793] } },
56
+
57
+ // ── near-white texture gate emission ──
58
+ { id: "gate", type: "math/greater_than", inputs: { b: 0.9300000071525574 } },
59
+ { id: "gate_scale", type: "math/multiply", inputs: { b: 3.0 } },
60
+
61
+ // ── npr stack (rim1 + rim2 + bright_emit + warm) ──
62
+ { id: "npr_add1", type: "add_shader" },
63
+ { id: "npr_add2", type: "add_shader" },
64
+ { id: "npr_stack", type: "add_shader" },
65
+
66
+ // ── principled with noise bump ──
67
+ { id: "map", type: "mapping", inputs: { scl: [1.0, 1.0, 1.5] } },
68
+ { id: "noise", type: "tex_noise", inputs: { scale: 1.0 } },
69
+ { id: "noise_ramp", type: "ramp_linear", inputs: { pos0: 0.0, pos1: 1.0 } },
70
+ { id: "bump", type: "bump", inputs: { strength: 0.324644535779953 } },
71
+ { id: "principled_base", type: "mix/blend", inputs: { b: [0.6832, 0.1947, 0.1373] } },
72
+ { id: "p_emit", type: "emission", inputs: { strength: 0.2 } },
73
+ {
74
+ id: "principled",
75
+ type: "principled",
76
+ inputs: { metallic: 0.0, specular: 0.5, roughness: 0.3, spec_clamp: 10.0, sheen: 0.0, sheen_tint: 0.0 },
77
+ },
78
+ { id: "p_sum", type: "add_shader" },
79
+
80
+ { id: "mix_shader_001", type: "mix_shader", inputs: { fac: 0.5 } },
81
+ ],
82
+ links: [
83
+ // toon
84
+ { from: { node: "str", socket: "value" }, to: { node: "toon", socket: "fac" } },
85
+ { from: { node: "tex", socket: "color" }, to: { node: "shadow_tint", socket: "color" } },
86
+ { from: { node: "tex", socket: "color" }, to: { node: "lit_tint", socket: "color" } },
87
+ { from: { node: "toon", socket: "fac_out" }, to: { node: "toon_color", socket: "fac" } },
88
+ { from: { node: "shadow_tint", socket: "color" }, to: { node: "toon_color", socket: "a" } },
89
+ { from: { node: "lit_tint", socket: "color" }, to: { node: "toon_color", socket: "b" } },
90
+ { from: { node: "toon_color", socket: "color" }, to: { node: "bc", socket: "color" } },
91
+ { from: { node: "bc", socket: "color" }, to: { node: "emission3", socket: "color" } },
92
+ // warm rim
93
+ { from: { node: "toon", socket: "fac_out" }, to: { node: "warm_mul", socket: "a" } },
94
+ { from: { node: "warm_mul", socket: "value" }, to: { node: "warm_add", socket: "a" } },
95
+ { from: { node: "warm_add", socket: "value" }, to: { node: "warm_clamp", socket: "a" } },
96
+ { from: { node: "warm_clamp", socket: "value" }, to: { node: "warm_ramp", socket: "fac" } },
97
+ { from: { node: "warm_ramp", socket: "color" }, to: { node: "warm_emit", socket: "color" } },
98
+ // rim1
99
+ { from: { node: "rim1_fres", socket: "value" }, to: { node: "rim1_str", socket: "a" } },
100
+ { from: { node: "rim1_lw", socket: "value" }, to: { node: "rim1_str", socket: "b" } },
101
+ { from: { node: "rim1_str", socket: "value" }, to: { node: "rim1", socket: "strength" } },
102
+ // rim2
103
+ { from: { node: "rim2_fres", socket: "value" }, to: { node: "rim2_raw", socket: "a" } },
104
+ { from: { node: "rim2_lw", socket: "value" }, to: { node: "rim2_raw", socket: "b" } },
105
+ { from: { node: "rim2_raw", socket: "value" }, to: { node: "rim2_pow", socket: "a" } },
106
+ { from: { node: "emission3", socket: "color" }, to: { node: "rim2_mix", socket: "a" } },
107
+ { from: { node: "rim2_pow", socket: "value" }, to: { node: "rim2_mix", socket: "fac" } },
108
+ // gate
109
+ { from: { node: "tex", socket: "color" }, to: { node: "gate", socket: "a" } },
110
+ { from: { node: "gate", socket: "value" }, to: { node: "gate_scale", socket: "a" } },
111
+ // npr stack
112
+ { from: { node: "rim1", socket: "color" }, to: { node: "npr_add1", socket: "a" } },
113
+ { from: { node: "rim2_mix", socket: "color" }, to: { node: "npr_add1", socket: "b" } },
114
+ { from: { node: "npr_add1", socket: "color" }, to: { node: "npr_add2", socket: "a" } },
115
+ { from: { node: "gate_scale", socket: "value" }, to: { node: "npr_add2", socket: "b" } },
116
+ { from: { node: "npr_add2", socket: "color" }, to: { node: "npr_stack", socket: "a" } },
117
+ { from: { node: "warm_emit", socket: "color" }, to: { node: "npr_stack", socket: "b" } },
118
+ // principled + noise bump
119
+ { from: { node: "geo", socket: "rest_pos" }, to: { node: "map", socket: "vector" } },
120
+ { from: { node: "map", socket: "vector" }, to: { node: "noise", socket: "vector" } },
121
+ { from: { node: "noise", socket: "value" }, to: { node: "noise_ramp", socket: "fac" } },
122
+ { from: { node: "noise_ramp", socket: "fac_out" }, to: { node: "bump", socket: "height" } },
123
+ { from: { node: "geo", socket: "normal" }, to: { node: "bump", socket: "normal" } },
124
+ { from: { node: "noise_ramp", socket: "fac_out" }, to: { node: "principled_base", socket: "fac" } },
125
+ { from: { node: "bc", socket: "color" }, to: { node: "principled_base", socket: "a" } },
126
+ { from: { node: "bc", socket: "color" }, to: { node: "p_emit", socket: "color" } },
127
+ { from: { node: "principled_base", socket: "color" }, to: { node: "principled", socket: "base" } },
128
+ { from: { node: "bump", socket: "vector" }, to: { node: "principled", socket: "normal" } },
129
+ { from: { node: "principled", socket: "color" }, to: { node: "p_sum", socket: "a" } },
130
+ { from: { node: "p_emit", socket: "color" }, to: { node: "p_sum", socket: "b" } },
131
+ // final mix
132
+ { from: { node: "npr_stack", socket: "color" }, to: { node: "mix_shader_001", socket: "a" } },
133
+ { from: { node: "p_sum", socket: "color" }, to: { node: "mix_shader_001", socket: "b" } },
134
+ ],
135
+ output: { node: "mix_shader_001", socket: "color" },
136
+ }
@@ -94,9 +94,42 @@ fn hashed_alpha_threshold(co: vec3f) -> f32 {
94
94
  `,
95
95
  }
96
96
 
97
+ // Eye's built-in rear-view gate (see eye.ts): open-shell PMX heads don't occlude
98
+ // the eye from behind, so it would draw (and stamp the see-through stencil) through
99
+ // the back of the head. Gate by camera-vs-face hemisphere via the 頭 bone's skinning
100
+ // matrix. Discarding here drops color, depth, and the stencil stamp together. The
101
+ // stencil-stamp pipeline state + front-face cull are slot-owned in createSlotPipeline;
102
+ // the graph only computes the eye's shading (Principled + emission).
103
+ const EYE_TEMPLATE: SlotTemplate = {
104
+ decls: "",
105
+ prelude: `@fragment fn fs(input: VertexOutput) -> FSOut {
106
+ let tex_s = textureSample(diffuseTexture, diffuseSampler, input.uv);
107
+ let alpha = material.alpha * tex_s.a;
108
+ if (alpha < 0.001) { discard; }
109
+
110
+ let n = safe_normal(input.normal);
111
+ let v = normalize(camera.viewPos - input.worldPos);
112
+
113
+ if (material.headBoneIndex >= 0.0) {
114
+ let hm = skinMats[u32(material.headBoneIndex)];
115
+ let faceDir = -normalize(hm[2].xyz);
116
+ if (dot(faceDir, v) < -0.15) { discard; }
117
+ }
118
+
119
+ let l = -light.lights[0].direction.xyz;
120
+ let sun = light.lights[0].color.xyz * light.lights[0].color.w;
121
+ let amb = light.ambientColor.xyz;
122
+ let shadow = sampleShadow(input.worldPos, n);
123
+ let tex_color = tex_s.rgb;
124
+
125
+ `,
126
+ epilogue: DEFAULT_EPILOGUE,
127
+ }
128
+
97
129
  export const SLOT_TEMPLATES: Partial<Record<MaterialPreset, SlotTemplate>> = {
98
130
  hair: HAIR_TEMPLATE,
99
131
  stockings: STOCKINGS_TEMPLATE,
132
+ eye: EYE_TEMPLATE,
100
133
  }
101
134
 
102
135
  export function slotTemplate(slot: MaterialPreset): SlotTemplate {
package/src/index.ts CHANGED
@@ -40,6 +40,8 @@ export { CLOTH_ROUGH_GRAPH } from "./graph/presets/cloth_rough"
40
40
  export { METAL_GRAPH } from "./graph/presets/metal"
41
41
  export { BODY_GRAPH } from "./graph/presets/body"
42
42
  export { STOCKINGS_GRAPH } from "./graph/presets/stockings"
43
+ export { EYE_GRAPH } from "./graph/presets/eye"
44
+ export { FACE_GRAPH } from "./graph/presets/face"
43
45
  export { Model } from "./model"
44
46
  export { Vec3, Quat, Mat4 } from "./math"
45
47
  export type {