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.
Files changed (71) hide show
  1. package/README.md +30 -14
  2. package/dist/engine.d.ts +0 -1
  3. package/dist/engine.d.ts.map +1 -1
  4. package/dist/engine.js +12 -12
  5. package/dist/graph/compile.d.ts +3 -3
  6. package/dist/graph/compile.d.ts.map +1 -1
  7. package/dist/graph/presets/body.d.ts +2 -2
  8. package/dist/graph/presets/body.d.ts.map +1 -1
  9. package/dist/graph/presets/body.js +1 -1
  10. package/dist/graph/presets/cloth_rough.d.ts +2 -2
  11. package/dist/graph/presets/cloth_rough.d.ts.map +1 -1
  12. package/dist/graph/presets/cloth_rough.js +1 -1
  13. package/dist/graph/presets/cloth_smooth.d.ts +2 -2
  14. package/dist/graph/presets/cloth_smooth.d.ts.map +1 -1
  15. package/dist/graph/presets/cloth_smooth.js +1 -1
  16. package/dist/graph/presets/default.d.ts +2 -2
  17. package/dist/graph/presets/default.d.ts.map +1 -1
  18. package/dist/graph/presets/eye.d.ts +2 -2
  19. package/dist/graph/presets/eye.d.ts.map +1 -1
  20. package/dist/graph/presets/eye.js +1 -1
  21. package/dist/graph/presets/face.d.ts +2 -2
  22. package/dist/graph/presets/face.d.ts.map +1 -1
  23. package/dist/graph/presets/face.js +1 -1
  24. package/dist/graph/presets/hair.d.ts +2 -2
  25. package/dist/graph/presets/hair.d.ts.map +1 -1
  26. package/dist/graph/presets/hair.js +1 -1
  27. package/dist/graph/presets/metal.d.ts +2 -2
  28. package/dist/graph/presets/metal.d.ts.map +1 -1
  29. package/dist/graph/presets/metal.js +1 -1
  30. package/dist/graph/presets/stockings.d.ts +2 -2
  31. package/dist/graph/presets/stockings.d.ts.map +1 -1
  32. package/dist/graph/presets/stockings.js +1 -1
  33. package/dist/graph/render-class.js +1 -1
  34. package/dist/graph/schema.d.ts +1 -1
  35. package/dist/graph/schema.d.ts.map +1 -1
  36. package/dist/graph/schema.js +1 -1
  37. package/dist/graph/style-group.d.ts +3 -3
  38. package/dist/graph/style-group.d.ts.map +1 -1
  39. package/dist/graph/style-group.js +1 -1
  40. package/dist/index.d.ts +2 -2
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/shaders/materials/common.d.ts +1 -1
  43. package/dist/shaders/materials/common.d.ts.map +1 -1
  44. package/dist/shaders/materials/common.js +5 -4
  45. package/package.json +1 -1
  46. package/src/engine.ts +14 -21
  47. package/src/graph/compile.ts +3 -3
  48. package/src/graph/presets/body.ts +3 -3
  49. package/src/graph/presets/cloth_rough.ts +3 -3
  50. package/src/graph/presets/cloth_smooth.ts +3 -3
  51. package/src/graph/presets/default.ts +2 -2
  52. package/src/graph/presets/eye.ts +3 -3
  53. package/src/graph/presets/face.ts +3 -3
  54. package/src/graph/presets/hair.ts +3 -3
  55. package/src/graph/presets/metal.ts +3 -3
  56. package/src/graph/presets/stockings.ts +3 -3
  57. package/src/graph/render-class.ts +1 -1
  58. package/src/graph/schema.ts +2 -2
  59. package/src/graph/style-group.ts +4 -4
  60. package/src/index.ts +61 -62
  61. package/src/shaders/materials/common.ts +5 -4
  62. package/src/shaders/materials/body.ts +0 -97
  63. package/src/shaders/materials/cloth_rough.ts +0 -71
  64. package/src/shaders/materials/cloth_smooth.ts +0 -63
  65. package/src/shaders/materials/default.ts +0 -45
  66. package/src/shaders/materials/eye.ts +0 -62
  67. package/src/shaders/materials/face.ts +0 -97
  68. package/src/shaders/materials/hair.ts +0 -92
  69. package/src/shaders/materials/metal.ts +0 -79
  70. package/src/shaders/materials/mmd_classic.ts +0 -68
  71. package/src/shaders/materials/stockings.ts +0 -124
@@ -39,10 +39,10 @@ struct LightUniforms {
39
39
 
40
40
  // Per-material uniforms. Every material binds this layout even if it ignores fields;
41
41
  // the engine keeps one bind group layout across all material pipelines. The PMX
42
- // classic-material fields (ambient/specular/toon/sphere) are consumed by the
43
- // mmd_classic preset; NPR presets ignore them.
42
+ // classic-material fields (ambient/specular/shininess) are carried for graph nodes that
43
+ // want them; most graphs read only diffuseColor + alpha.
44
44
  struct MaterialUniforms {
45
- diffuseColor: vec3f, // PMX diffuse rgb (mmd_classic); reserved for others
45
+ diffuseColor: vec3f, // PMX diffuse rgb the material_diffuse node reads this
46
46
  alpha: f32, // 0 → discard; <1 → transparent draw call
47
47
  ambient: vec3f, // PMX ambient rgb
48
48
  shininess: f32, // PMX specular power
@@ -82,7 +82,8 @@ struct LightVP { viewProj: mat4x4f, };
82
82
  @group(1) @binding(0) var<storage, read> skinMats: array<mat4x4f>;
83
83
  @group(2) @binding(0) var diffuseTexture: texture_2d<f32>;
84
84
  @group(2) @binding(1) var<uniform> material: MaterialUniforms;
85
- // mmd_classic inputs; other presets leave them unread (fallback 1×1 whites).
85
+ // Reserved for future sphere/toon graph nodes; graphs that don't read them get the
86
+ // 1×1 white fallback bound here.
86
87
  @group(2) @binding(2) var toonTexture: texture_2d<f32>;
87
88
  @group(2) @binding(3) var sphereTexture: texture_2d<f32>;
88
89
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reze-engine",
3
- "version": "0.20.0",
3
+ "version": "0.21.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",
package/src/engine.ts CHANGED
@@ -31,7 +31,7 @@ import { COMPOSITE_SHADER_WGSL } from "./shaders/passes/composite"
31
31
  import { PICK_SHADER_WGSL } from "./shaders/passes/pick"
32
32
  import { MIPMAP_BLIT_SHADER_WGSL } from "./shaders/passes/mipmap"
33
33
  import { compileGraph, type CompileOptions, type StyleSlot } from "./graph/compile"
34
- import type { Diagnostic, StyleGraph } from "./graph/schema"
34
+ import type { Diagnostic, ShaderGraph } from "./graph/schema"
35
35
  import type { AlphaMode, RenderClass } from "./graph/render-class"
36
36
  import type {
37
37
  ApplyStyleGroupResult,
@@ -62,20 +62,12 @@ export type MaterialPreset =
62
62
  | "cloth_smooth"
63
63
  | "cloth_rough"
64
64
 
65
- // What a draw call actually resolves to. "mmd_classic" is the automatic
66
- // authentic-MMD fallback for materials no preset map or name heuristic
67
- // covers — deliberately NOT part of MaterialPreset, so consumer-side
68
- // exhaustive Record<MaterialPreset, …> maps and switches don't have to
69
- // carry an option users never assign.
70
- export type ResolvedMaterialPreset = MaterialPreset | "mmd_classic"
71
-
72
65
  export type MaterialPresetMap = Partial<Record<MaterialPreset, string[]>>
73
66
 
74
- // Substring hints mapping common PMX material names (JP/CN/EN) to presets,
75
- // tried when a material isn't in the model's explicit MaterialPresetMap.
76
- // Ordered: more specific families first (靴下 must hit stockings before 靴
77
- // hits cloth). Anything unmatched falls through to mmd_classic, which renders
78
- // the author-tuned PMX material data faithfully.
67
+ // Substring hints mapping common PMX material names (JP/CN/EN) to a style category,
68
+ // tried when a material isn't in the caller's explicit override map. Ordered: more
69
+ // specific families first (靴下 must hit stockings before 靴 hits cloth). A material
70
+ // matching nothing resolves to null it stays ungrouped (neutral default).
79
71
  const PRESET_NAME_HINTS: Array<[MaterialPreset, string[]]> = [
80
72
  ["stockings", ["靴下", "ソックス", "タイツ", "ニーソ", "袜", "stocking", "socks", "tights"]],
81
73
  [
@@ -117,7 +109,9 @@ const PRESET_NAME_HINTS: Array<[MaterialPreset, string[]]> = [
117
109
  ],
118
110
  ]
119
111
 
120
- function resolvePreset(materialName: string, map: MaterialPresetMap | undefined): ResolvedMaterialPreset {
112
+ // Resolve a material name to a style category (override map first, then name hints), or
113
+ // null if nothing matches — a null-resolving material stays ungrouped (neutral default).
114
+ function resolvePreset(materialName: string, map: MaterialPresetMap | undefined): MaterialPreset | null {
121
115
  if (map) {
122
116
  for (const [preset, names] of Object.entries(map)) {
123
117
  if (names && names.includes(materialName)) return preset as MaterialPreset
@@ -129,14 +123,13 @@ function resolvePreset(materialName: string, map: MaterialPresetMap | undefined)
129
123
  if (lower.includes(hint)) return preset
130
124
  }
131
125
  }
132
- return "mmd_classic"
126
+ return null
133
127
  }
134
128
 
135
- // Default-group recipe per preset label: the shipped graph + its natural pass-integration
136
- // (renderClass, alphaMode). This is the auto-default-groups mapping (docs §8) — the same
137
- // label→integration knowledge the old fixed slots encoded, now producing editable groups.
138
- // mmd_classic has no entry those materials stay ungrouped (hand-shader path).
139
- const PRESET_GROUP_INFO: Partial<Record<MaterialPreset, { graph: StyleGraph; renderClass: RenderClass; alphaMode: AlphaMode }>> = {
129
+ // Default-group recipe per style category: the shipped graph + its natural pass-integration
130
+ // (renderClass, alphaMode). This is the auto-default-groups mapping — the same
131
+ // category→integration knowledge the old fixed slots encoded, now producing editable groups.
132
+ const PRESET_GROUP_INFO: Partial<Record<MaterialPreset, { graph: ShaderGraph; renderClass: RenderClass; alphaMode: AlphaMode }>> = {
140
133
  default: { graph: DEFAULT_GRAPH, renderClass: "auto", alphaMode: "opaque" },
141
134
  face: { graph: FACE_GRAPH, renderClass: "auto", alphaMode: "opaque" },
142
135
  hair: { graph: HAIR_GRAPH, renderClass: "hair", alphaMode: "opaque" },
@@ -3972,7 +3965,7 @@ export class Engine {
3972
3965
  for (const dc of inst.drawCalls) {
3973
3966
  if (!dc.baseBindGroupEntries) continue // material draw calls only (skip outlines)
3974
3967
  const preset = resolvePreset(dc.materialName, overrides)
3975
- if (preset === "mmd_classic") continue // unmatched → ungrouped
3968
+ if (!preset) continue // unmatched → stays ungrouped (neutral default)
3976
3969
  const arr = buckets.get(preset) ?? []
3977
3970
  if (!arr.includes(dc.materialName)) arr.push(dc.materialName)
3978
3971
  buckets.set(preset, arr)
@@ -4,7 +4,7 @@
4
4
  // See docs/graph-compiler-spec.md.
5
5
 
6
6
  import { MAX_NODES, MAX_PARAMS } from "./schema"
7
- import type { Diagnostic, ExposedParam, GraphNode, SocketValue, StyleGraph } from "./schema"
7
+ import type { Diagnostic, ExposedParam, GraphNode, SocketValue, ShaderGraph } from "./schema"
8
8
  import { NODE_REGISTRY, canConvert, convert, fmtValue, literalFits } from "./registry"
9
9
  import type { NodeSpec, SockT } from "./registry"
10
10
  import { assembleModule } from "./slots"
@@ -83,7 +83,7 @@ export function assignStyleSlots(params: ExposedParam[]): StyleSlot[] {
83
83
 
84
84
  // ─── Validation ─────────────────────────────────────────────────────
85
85
 
86
- export function validateGraph(graph: StyleGraph, opts: CompileOptions = {}): Diagnostic[] {
86
+ export function validateGraph(graph: ShaderGraph, opts: CompileOptions = {}): Diagnostic[] {
87
87
  const d: Diagnostic[] = []
88
88
  const nodes = new Map<string, GraphNode>()
89
89
 
@@ -188,7 +188,7 @@ export function validateGraph(graph: StyleGraph, opts: CompileOptions = {}): Dia
188
188
 
189
189
  // ─── Compile ────────────────────────────────────────────────────────
190
190
 
191
- export function compileGraph(graph: StyleGraph, opts: CompileOptions = {}): CompileResult {
191
+ export function compileGraph(graph: ShaderGraph, opts: CompileOptions = {}): CompileResult {
192
192
  const fail = (diagnostics: Diagnostic[]): CompileResult => ({
193
193
  ok: false,
194
194
  wgsl: "",
@@ -1,11 +1,11 @@
1
- // M_Body as a StyleGraph — port of shaders/materials/body.ts (仿深空之眼 "M_Body").
1
+ // M_Body as a ShaderGraph — port of shaders/materials/body.ts (仿深空之眼 "M_Body").
2
2
  // Toon + warm rim + rim1/rim2 stack mixed 50/50 against a Principled BSDF with
3
3
  // noise-bumped normal. The hand port's local ramp_ease is ramp_cardinal (identical
4
4
  // smoothstep form); the Mapping node's zero loc/rot folds to a scale multiply.
5
5
 
6
- import type { StyleGraph } from "../schema"
6
+ import type { ShaderGraph } from "../schema"
7
7
 
8
- export const BODY_GRAPH: StyleGraph = {
8
+ export const BODY_GRAPH: ShaderGraph = {
9
9
  version: 1,
10
10
  name: "Body",
11
11
  tags: ["body"],
@@ -1,11 +1,11 @@
1
- // M_Rough_Cloth as a StyleGraph — port of shaders/materials/cloth_rough.ts.
1
+ // M_Rough_Cloth as a ShaderGraph — port of shaders/materials/cloth_rough.ts.
2
2
  // NPR graph identical to M_Smooth_Cloth, but the noise bump subtree IS live on
3
3
  // Principled.Normal (weave bump in rest space) and Roughness is raised to 0.8187.
4
4
  // The tex_noise node hits the detail=2 peephole → tex_noise_d2.
5
5
 
6
- import type { StyleGraph } from "../schema"
6
+ import type { ShaderGraph } from "../schema"
7
7
 
8
- export const CLOTH_ROUGH_GRAPH: StyleGraph = {
8
+ export const CLOTH_ROUGH_GRAPH: ShaderGraph = {
9
9
  version: 1,
10
10
  name: "Rough Cloth",
11
11
  tags: ["cloth_rough"],
@@ -1,11 +1,11 @@
1
- // M_Smooth_Cloth as a StyleGraph — port of shaders/materials/cloth_smooth.ts.
1
+ // M_Smooth_Cloth as a ShaderGraph — port of shaders/materials/cloth_smooth.ts.
2
2
  // NPR toon + bevel + overlay-boosted emission (18.2×) mixed 10/90 against a plain
3
3
  // Principled BSDF. The Blender graph's dead bump subtree is omitted (as in the hand
4
4
  // port). hue_sat nodes with hue=0.5 compile to the hue_sat_id specialization.
5
5
 
6
- import type { StyleGraph } from "../schema"
6
+ import type { ShaderGraph } from "../schema"
7
7
 
8
- export const CLOTH_SMOOTH_GRAPH: StyleGraph = {
8
+ export const CLOTH_SMOOTH_GRAPH: ShaderGraph = {
9
9
  version: 1,
10
10
  name: "Smooth Cloth",
11
11
  tags: ["cloth_smooth"],
@@ -5,9 +5,9 @@
5
5
  // The material-color multiply is what keeps untextured/solid-color materials from
6
6
  // rendering white (they carry their color in material.diffuse, not a texture).
7
7
 
8
- import type { StyleGraph } from "../schema"
8
+ import type { ShaderGraph } from "../schema"
9
9
 
10
- export const DEFAULT_GRAPH: StyleGraph = {
10
+ export const DEFAULT_GRAPH: ShaderGraph = {
11
11
  version: 1,
12
12
  name: "Principled BSDF",
13
13
  tags: ["default"],
@@ -1,4 +1,4 @@
1
- // Eye as a StyleGraph — port of shaders/materials/eye.ts. The published preset
1
+ // Eye as a ShaderGraph — port of shaders/materials/eye.ts. The published preset
2
2
  // author's instruction: "keep eyes in the default nodegraph, add emission 1.5".
3
3
  // So it's the default Principled BSDF plus an Emission of the diffuse texture at
4
4
  // 1.5× (Blender's Principled Emission socket, decomposed as a separate Emission +
@@ -7,9 +7,9 @@
7
7
  // The rear-view gate and the see-through stencil stamp are slot-owned (built-in eye
8
8
  // behavior, see EYE_TEMPLATE in slots.ts + createSlotPipeline) — not in this graph.
9
9
 
10
- import type { StyleGraph } from "../schema"
10
+ import type { ShaderGraph } from "../schema"
11
11
 
12
- export const EYE_GRAPH: StyleGraph = {
12
+ export const EYE_GRAPH: ShaderGraph = {
13
13
  version: 1,
14
14
  name: "Eye",
15
15
  tags: ["eye"],
@@ -1,4 +1,4 @@
1
- // M_Face as a StyleGraph — port of shaders/materials/face.ts (仿深空之眼 "M_Face").
1
+ // M_Face as a ShaderGraph — port of shaders/materials/face.ts (仿深空之眼 "M_Face").
2
2
  // Toon + warm rim + dual fresnel rim + BT.601 bright-tex gate, mixed 50/50 against a
3
3
  // Principled BSDF with noise bump. Structurally close to body, but: the toon uses the
4
4
  // edge-AA ramp, hue tints are 0.46 (full hue_sat, not the 0.5 _id specialization),
@@ -6,9 +6,9 @@
6
6
  // near-white texture gate that emits (freckle/highlight paint). Plain material — no
7
7
  // built-in slot effect, so it uses the default prelude/epilogue.
8
8
 
9
- import type { StyleGraph } from "../schema"
9
+ import type { ShaderGraph } from "../schema"
10
10
 
11
- export const FACE_GRAPH: StyleGraph = {
11
+ export const FACE_GRAPH: ShaderGraph = {
12
12
  version: 1,
13
13
  name: "Face",
14
14
  tags: ["face"],
@@ -1,4 +1,4 @@
1
- // M_Hair — 仿深空之眼渲染预设v1.0_by_小绿毛猫, as a StyleGraph. Node ids mirror the
1
+ // M_Hair — 仿深空之眼渲染预设v1.0_by_小绿毛猫, as a ShaderGraph. Node ids mirror the
2
2
  // Blender node names referenced in shaders/materials/hair.ts comments; compiled with
3
3
  // { inlineParams: true } this graph must reproduce HAIR_SHADER_WGSL's fragment body
4
4
  // (golden test #1 — see tests/graph.test.mjs).
@@ -10,9 +10,9 @@
10
10
  // The object is pure JSON (no functions/undefined) — JSON.stringify round-trips it,
11
11
  // which is how reze.design will ship additional presets.
12
12
 
13
- import type { StyleGraph } from "../schema"
13
+ import type { ShaderGraph } from "../schema"
14
14
 
15
- export const HAIR_GRAPH: StyleGraph = {
15
+ export const HAIR_GRAPH: ShaderGraph = {
16
16
  version: 1,
17
17
  name: "Hair",
18
18
  tags: ["hair"],
@@ -1,12 +1,12 @@
1
- // M_Metal as a StyleGraph — port of shaders/materials/metal.ts.
1
+ // M_Metal as a ShaderGraph — port of shaders/materials/metal.ts.
2
2
  // Metallic Principled (Metallic=1, Specular=1, Roughness=0.3) with a
3
3
  // reflection-coord voronoi driving base color (metallic sparkle), plus an NPR
4
4
  // toon/overlay emission stack mixed at Fac=0.6967. The voronoi Color→ramp Fac
5
5
  // link goes through Blender's implicit BT.601 conversion (color_to_value).
6
6
 
7
- import type { StyleGraph } from "../schema"
7
+ import type { ShaderGraph } from "../schema"
8
8
 
9
- export const METAL_GRAPH: StyleGraph = {
9
+ export const METAL_GRAPH: ShaderGraph = {
10
10
  version: 1,
11
11
  name: "Metal",
12
12
  tags: ["metal"],
@@ -1,4 +1,4 @@
1
- // M_Stockings as a StyleGraph — port of shaders/materials/stockings.ts.
1
+ // M_Stockings as a ShaderGraph — port of shaders/materials/stockings.ts.
2
2
  // A bbox-gradient × facing-rim mask drives a Mix Shader between an HSV-boosted
3
3
  // emission (val 5×) and a sheen Principled. The hashed-alpha discard and the
4
4
  // alpha=1 output are slot-owned (see STOCKINGS_TEMPLATE in slots.ts) — the graph
@@ -6,9 +6,9 @@
6
6
  // as in the hand port. The grayscale mask feeds Mix Shader Fac through Blender's
7
7
  // implicit BT.601 color→float conversion (equal-component vector → same scalar).
8
8
 
9
- import type { StyleGraph } from "../schema"
9
+ import type { ShaderGraph } from "../schema"
10
10
 
11
- export const STOCKINGS_GRAPH: StyleGraph = {
11
+ export const STOCKINGS_GRAPH: ShaderGraph = {
12
12
  version: 1,
13
13
  name: "Stockings",
14
14
  tags: ["stockings"],
@@ -1,5 +1,5 @@
1
1
  // Render-class + alpha-mode: the small, closed, engine-owned vocabularies that carry
2
- // pass integration for a style group. A group's node graph is pure shading; these select
2
+ // pass integration for a style group. A group's shader graph is pure shading; these select
3
3
  // how the engine wires that shading into the passes. Not user-extensible — this is where
4
4
  // rendering correctness lives (stencil, cull, draw order, alpha test). See
5
5
  // docs/style-groups-spec.md §5.
@@ -1,4 +1,4 @@
1
- // Material style graph JSON-serializable node graph compiled to WGSL by compile.ts.
1
+ // ShaderGraph a JSON-serializable graph of shading nodes, compiled to WGSL by compile.ts.
2
2
  // Engine-space (LH, Y-up): porting a Blender graph converts coordinates at authoring
3
3
  // time (Blender Normal Z → engine Y), the compiler never sees Blender conventions.
4
4
  // See docs/graph-compiler-spec.md.
@@ -34,7 +34,7 @@ export type ExposedParam = {
34
34
  default: SocketValue
35
35
  }
36
36
 
37
- export type StyleGraph = {
37
+ export type ShaderGraph = {
38
38
  version: 1
39
39
  name: string
40
40
  nodes: GraphNode[]
@@ -1,10 +1,10 @@
1
1
  // Style groups — the user-facing unit of material styling. A group binds a set of
2
- // materials to a node graph (pure shading) plus the engine-owned pass-integration axes
2
+ // materials to a shader graph (pure shading) plus the engine-owned pass-integration axes
3
3
  // (renderClass + alphaMode). Each material belongs to at most one group; grouped
4
4
  // materials render via the group's compiled-graph pipeline, ungrouped ones fall back to
5
5
  // the hand-written preset path. See docs/style-groups-spec.md.
6
6
 
7
- import type { Diagnostic, StyleGraph } from "./schema"
7
+ import type { Diagnostic, ShaderGraph } from "./schema"
8
8
  import type { AlphaMode, RenderClass } from "./render-class"
9
9
  import type { StyleSlot } from "./compile"
10
10
 
@@ -16,8 +16,8 @@ export type StyleGroup = {
16
16
  label?: string
17
17
  /** Material names in this group; each material is in AT MOST one group. */
18
18
  materials: string[]
19
- /** Pure shading (StyleGraph has no `slot` — integration lives here on the group). */
20
- graph: StyleGraph
19
+ /** Pure shading (ShaderGraph has no `slot` — integration lives here on the group). */
20
+ graph: ShaderGraph
21
21
  /** Pass-integration class: stencil/cull/draw-order. Default "auto". */
22
22
  renderClass?: RenderClass
23
23
  /** Alpha-handling axis, orthogonal to renderClass. Default "opaque". */
package/src/index.ts CHANGED
@@ -1,63 +1,62 @@
1
- export {
2
- Engine,
3
- DEFAULT_BLOOM_OPTIONS,
4
- DEFAULT_VIEW_TRANSFORM,
5
- type EngineStats,
6
- type EngineOptions,
7
- type BloomOptions,
8
- type ViewTransformOptions,
9
- type LoadModelFromFilesOptions,
10
- type MaterialPreset,
11
- type ResolvedMaterialPreset,
12
- type MaterialPresetMap,
13
- type GizmoDragEvent,
14
- type GizmoDragCallback,
15
- type GizmoDragKind,
16
- } from "./engine"
17
- export { parsePmxFolderInput, pmxFileAtRelativePath, type PmxFolderInputResult } from "./folder-upload"
18
- export {
19
- compileGraph,
20
- validateGraph,
21
- assignStyleSlots,
22
- type CompileOptions,
23
- type CompileResult,
24
- type StyleSlot,
25
- } from "./graph/compile"
26
- export type {
27
- StyleGraph,
28
- GraphNode,
29
- GraphLink,
30
- ExposedParam,
31
- SocketValue,
32
- Diagnostic,
33
- } from "./graph/schema"
34
- export { NODE_REGISTRY, type NodeSpec, type SockT } from "./graph/registry"
35
- export { RENDER_CLASSES, type RenderClass, type AlphaMode, type RenderClassInfo } from "./graph/render-class"
36
- export type {
37
- StyleGroup,
38
- GroupDiagnostic,
39
- ApplyStyleGroupsResult,
40
- ApplyStyleGroupResult,
41
- } from "./graph/style-group"
42
- export { HAIR_GRAPH } from "./graph/presets/hair"
43
- export { DEFAULT_GRAPH } from "./graph/presets/default"
44
- export { CLOTH_SMOOTH_GRAPH } from "./graph/presets/cloth_smooth"
45
- export { CLOTH_ROUGH_GRAPH } from "./graph/presets/cloth_rough"
46
- export { METAL_GRAPH } from "./graph/presets/metal"
47
- export { BODY_GRAPH } from "./graph/presets/body"
48
- export { STOCKINGS_GRAPH } from "./graph/presets/stockings"
49
- export { EYE_GRAPH } from "./graph/presets/eye"
50
- export { FACE_GRAPH } from "./graph/presets/face"
51
- export { Model } from "./model"
52
- export { Vec3, Quat, Mat4 } from "./math"
53
- export type {
54
- AnimationClip,
55
- AnimationPlayOptions,
56
- AnimationProgress,
57
- BoneKeyframe,
58
- MorphKeyframe,
59
- BoneInterpolation,
60
- ControlPoint,
61
- } from "./animation"
62
- export { FPS } from "./animation"
1
+ export {
2
+ Engine,
3
+ DEFAULT_BLOOM_OPTIONS,
4
+ DEFAULT_VIEW_TRANSFORM,
5
+ type EngineStats,
6
+ type EngineOptions,
7
+ type BloomOptions,
8
+ type ViewTransformOptions,
9
+ type LoadModelFromFilesOptions,
10
+ type MaterialPreset,
11
+ type MaterialPresetMap,
12
+ type GizmoDragEvent,
13
+ type GizmoDragCallback,
14
+ type GizmoDragKind,
15
+ } from "./engine"
16
+ export { parsePmxFolderInput, pmxFileAtRelativePath, type PmxFolderInputResult } from "./folder-upload"
17
+ export {
18
+ compileGraph,
19
+ validateGraph,
20
+ assignStyleSlots,
21
+ type CompileOptions,
22
+ type CompileResult,
23
+ type StyleSlot,
24
+ } from "./graph/compile"
25
+ export type {
26
+ ShaderGraph,
27
+ GraphNode,
28
+ GraphLink,
29
+ ExposedParam,
30
+ SocketValue,
31
+ Diagnostic,
32
+ } from "./graph/schema"
33
+ export { NODE_REGISTRY, type NodeSpec, type SockT } from "./graph/registry"
34
+ export { RENDER_CLASSES, type RenderClass, type AlphaMode, type RenderClassInfo } from "./graph/render-class"
35
+ export type {
36
+ StyleGroup,
37
+ GroupDiagnostic,
38
+ ApplyStyleGroupsResult,
39
+ ApplyStyleGroupResult,
40
+ } from "./graph/style-group"
41
+ export { HAIR_GRAPH } from "./graph/presets/hair"
42
+ export { DEFAULT_GRAPH } from "./graph/presets/default"
43
+ export { CLOTH_SMOOTH_GRAPH } from "./graph/presets/cloth_smooth"
44
+ export { CLOTH_ROUGH_GRAPH } from "./graph/presets/cloth_rough"
45
+ export { METAL_GRAPH } from "./graph/presets/metal"
46
+ export { BODY_GRAPH } from "./graph/presets/body"
47
+ export { STOCKINGS_GRAPH } from "./graph/presets/stockings"
48
+ export { EYE_GRAPH } from "./graph/presets/eye"
49
+ export { FACE_GRAPH } from "./graph/presets/face"
50
+ export { Model } from "./model"
51
+ export { Vec3, Quat, Mat4 } from "./math"
52
+ export type {
53
+ AnimationClip,
54
+ AnimationPlayOptions,
55
+ AnimationProgress,
56
+ BoneKeyframe,
57
+ MorphKeyframe,
58
+ BoneInterpolation,
59
+ ControlPoint,
60
+ } from "./animation"
61
+ export { FPS } from "./animation"
63
62
  export { RezePhysics } from "./physics"
@@ -41,10 +41,10 @@ struct LightUniforms {
41
41
 
42
42
  // Per-material uniforms. Every material binds this layout even if it ignores fields;
43
43
  // the engine keeps one bind group layout across all material pipelines. The PMX
44
- // classic-material fields (ambient/specular/toon/sphere) are consumed by the
45
- // mmd_classic preset; NPR presets ignore them.
44
+ // classic-material fields (ambient/specular/shininess) are carried for graph nodes that
45
+ // want them; most graphs read only diffuseColor + alpha.
46
46
  struct MaterialUniforms {
47
- diffuseColor: vec3f, // PMX diffuse rgb (mmd_classic); reserved for others
47
+ diffuseColor: vec3f, // PMX diffuse rgb the material_diffuse node reads this
48
48
  alpha: f32, // 0 → discard; <1 → transparent draw call
49
49
  ambient: vec3f, // PMX ambient rgb
50
50
  shininess: f32, // PMX specular power
@@ -84,7 +84,8 @@ struct LightVP { viewProj: mat4x4f, };
84
84
  @group(1) @binding(0) var<storage, read> skinMats: array<mat4x4f>;
85
85
  @group(2) @binding(0) var diffuseTexture: texture_2d<f32>;
86
86
  @group(2) @binding(1) var<uniform> material: MaterialUniforms;
87
- // mmd_classic inputs; other presets leave them unread (fallback 1×1 whites).
87
+ // Reserved for future sphere/toon graph nodes; graphs that don't read them get the
88
+ // 1×1 white fallback bound here.
88
89
  @group(2) @binding(2) var toonTexture: texture_2d<f32>;
89
90
  @group(2) @binding(3) var sphereTexture: texture_2d<f32>;
90
91
 
@@ -1,97 +0,0 @@
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
- `