reze-engine 0.64.0 → 0.65.0

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 (56) hide show
  1. package/dist/engine.d.ts +146 -54
  2. package/dist/engine.d.ts.map +1 -1
  3. package/dist/engine.js +734 -582
  4. package/dist/graph/slots.d.ts.map +1 -1
  5. package/dist/graph/slots.js +7 -1
  6. package/dist/index.d.ts +1 -1
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/model.d.ts +10 -1
  9. package/dist/model.d.ts.map +1 -1
  10. package/dist/model.js +15 -1
  11. package/dist/outline-normals.d.ts +12 -0
  12. package/dist/outline-normals.d.ts.map +1 -0
  13. package/dist/outline-normals.js +100 -0
  14. package/dist/pmx-loader.d.ts +3 -0
  15. package/dist/pmx-loader.d.ts.map +1 -1
  16. package/dist/pmx-loader.js +7 -2
  17. package/dist/shaders/materials/common.d.ts.map +1 -1
  18. package/dist/shaders/materials/common.js +4 -2
  19. package/dist/shaders/passes/bloom.d.ts +4 -3
  20. package/dist/shaders/passes/bloom.d.ts.map +1 -1
  21. package/dist/shaders/passes/bloom.js +58 -87
  22. package/dist/shaders/passes/composite.d.ts.map +1 -1
  23. package/dist/shaders/passes/composite.js +118 -72
  24. package/dist/shaders/passes/mirror.d.ts +18 -12
  25. package/dist/shaders/passes/mirror.d.ts.map +1 -1
  26. package/dist/shaders/passes/mirror.js +59 -13
  27. package/dist/shaders/passes/outline.d.ts.map +1 -1
  28. package/dist/shaders/passes/outline.js +71 -14
  29. package/dist/unity/host.d.ts +15 -0
  30. package/dist/unity/host.d.ts.map +1 -1
  31. package/dist/unity/host.js +103 -63
  32. package/dist/unity/looks.d.ts +5 -0
  33. package/dist/unity/looks.d.ts.map +1 -1
  34. package/dist/unity/looks.js +19 -2
  35. package/dist/unity/skin.d.ts.map +1 -1
  36. package/dist/unity/skin.js +5 -2
  37. package/dist/unity/stage.d.ts +7 -0
  38. package/dist/unity/stage.d.ts.map +1 -1
  39. package/dist/unity/stage.js +37 -2
  40. package/package.json +1 -1
  41. package/src/engine.ts +1042 -798
  42. package/src/graph/slots.ts +7 -1
  43. package/src/index.ts +1 -0
  44. package/src/model.ts +18 -1
  45. package/src/outline-normals.ts +110 -0
  46. package/src/pmx-loader.ts +8 -2
  47. package/src/shaders/materials/common.ts +4 -2
  48. package/src/shaders/passes/bloom.ts +59 -87
  49. package/src/shaders/passes/composite.ts +118 -72
  50. package/src/shaders/passes/mirror.ts +60 -13
  51. package/src/shaders/passes/outline.ts +71 -14
  52. package/src/unity/host.ts +57 -14
  53. package/src/unity/looks.ts +21 -2
  54. package/src/unity/skin.ts +5 -2
  55. package/src/unity/stage.ts +38 -2
  56. package/src/shaders/agx-lut.ts +0 -30
@@ -69,14 +69,39 @@ struct VertexOutput {
69
69
  /** The triangle's own threshold, flat — see the material VertexOutput. The
70
70
  * hull traces the body's faces, so it has to lose the same ones. */
71
71
  @location(2) @interpolate(flat) faceT: f32,
72
+ /** How much of a pixel-wide line this one really is (1 = all of it): a line
73
+ * held at the minimum width fades by what it was short. */
74
+ @location(3) coverage: f32,
72
75
  };
73
76
 
77
+ /**
78
+ * Half the frame height (engine units, at the subject) below which a line keeps
79
+ * its constant screen width; wider than that it thins as a world-size line.
80
+ * 12.5 = a frame 25 units tall — a full figure (an MMD model is ~20) with
81
+ * room around her.
82
+ *
83
+ * Not the game's own break (w = 1 game unit = 8 engine units). The game's
84
+ * near width is ~3× MMD's 2·edgeSize px; its world-size line comes down to
85
+ * MMD's width only at a full-figure framing, so that is where the break goes:
86
+ * close-ups and full figures keep today's width, and past that the game's rule
87
+ * holds — NDC offset ∝ 1/w, scaled by the zoom as its projection._m11 scales
88
+ * it. At the game's 8 the demo's own camera (33 units) drew a quarter of
89
+ * today's width, which put every line on the faded minimum.
90
+ */
91
+ const RZ_OUTLINE_FULL_FIGURE = 12.5;
92
+ /** The thinnest a line is drawn, in pixels at 1080p (and never under this many
93
+ * device pixels). A line due to be thinner is drawn this wide and faded by
94
+ * the shortfall, so far lines thin out without aliasing into dashes. */
95
+ const RZ_OUTLINE_MIN_PX = 1.5;
96
+
74
97
  @vertex fn vs(
75
98
  @location(0) position: vec3f,
76
99
  @location(1) normal: vec3f,
77
100
  @location(2) uv: vec2f,
78
101
  @location(3) joints0: vec4<u32>,
79
- @location(4) weights0: vec4<f32>
102
+ @location(4) weights0: vec4<f32>,
103
+ /** xyz: the smoothed rest normal (outline-normals.ts), w: PMX edge scale. */
104
+ @location(5) outlineNormal: vec4f
80
105
  ) -> VertexOutput {
81
106
  var output: VertexOutput;
82
107
  let pos4 = vec4f(position, 1.0);
@@ -93,30 +118,58 @@ struct VertexOutput {
93
118
  let m = skinMats[j];
94
119
  skinnedPos += (m * pos4) * w;
95
120
  let r3 = mat3x3f(m[0].xyz, m[1].xyz, m[2].xyz);
96
- skinnedNrm += (r3 * normal) * w;
121
+ skinnedNrm += (r3 * outlineNormal.xyz) * w;
97
122
  }
98
123
  let worldPos = skinnedPos.xyz;
99
124
  let worldNormal = normalize(skinnedNrm);
100
125
 
101
126
  let clipPos = camera.projection * camera.view * vec4f(worldPos, 1.0);
102
127
 
103
- // babylon-mmd: screenNormal = normalize((view * worldNormal).xy)
128
+ // The push direction is the view-space normal's XY, NOT renormalized — the
129
+ // game's: full length at the silhouette, where the normal lies across the
130
+ // view, and shrinking on surfaces turned toward the camera, so creases
131
+ // facing her draw finer than the rim. Skinned exactly as the colour pass
132
+ // skins the normal, from the smoothed rest normal, so every vertex sharing a
133
+ // position pushes the same way and the hull stays closed over hard edges
134
+ // and UV seams.
104
135
  let viewNormal = (camera.view * vec4f(worldNormal, 0.0)).xyz;
105
- let snLen = length(viewNormal.xy);
106
- let screenNormal = select(vec2f(0.0, 0.0), viewNormal.xy / snLen, snLen > 1e-5);
107
136
 
108
137
  // Reference-height normalization (babylon-mmd ships this variant commented
109
- // out as \`renderHeight = 1080\`): thickness is a constant FRACTION of the
110
- // frame — 2·edgeSize px at 1080p — so retina DPR and 4K export don't thin
111
- // the rims to sub-pixel. Width follows the projection aspect.
138
+ // out as \`renderHeight = 1080\`): the near width is a constant FRACTION of
139
+ // the frame — 2·edgeSize px at 1080p — so retina DPR and 4K export don't
140
+ // thin the rims to sub-pixel. Width follows the projection aspect.
112
141
  // projection[1][1]/projection[0][0] = width/height for a symmetric frustum.
113
142
  let aspect = camera.projection[1][1] / camera.projection[0][0];
114
- let viewport = vec2f(1080.0 * aspect, 1080.0);
143
+ let refViewport = vec2f(1080.0 * aspect, 1080.0);
144
+ let deviceViewport = vec2f(camera.viewportHeight * aspect, camera.viewportHeight);
145
+
146
+ // The game's width (Character/Debug.shader, pass "Outline"): the clip offset
147
+ // is the near offset × min(w, break depth). Up close the ×w cancels the
148
+ // perspective divide — constant screen width; past the break it stops
149
+ // growing, so the NDC offset falls as 1/w like a line of fixed world width.
150
+ // The break is the depth at which the frame is a full figure tall, so a
151
+ // zoomed lens moves it out (see RZ_OUTLINE_FULL_FIGURE). Under an
152
+ // orthographic camera w is 1 and the same min() makes the line world-size
153
+ // once the frame is taller than a figure. The PMX per-vertex edge scale
154
+ // multiplies it all, as vertex colour alpha does in the game.
155
+ let w = max(clipPos.w, 1e-4);
156
+ let breakDepth = RZ_OUTLINE_FULL_FIGURE * camera.projection[1][1];
157
+ let nearNdc = viewNormal.xy * (material.edgeSize * outlineNormal.w * 4.0 / refViewport);
158
+ var ndc = nearNdc * (min(w, breakDepth) / w);
115
159
 
116
- // NDC offset = edgeSize · 4/viewport, ×w so the perspective divide cancels:
117
- // constant screen thickness at any distance (babylon-mmd parity).
118
- let offset = screenNormal * (material.edgeSize * 4.0 / viewport) * clipPos.w;
119
- output.position = vec4f(clipPos.xy + offset, clipPos.z, clipPos.w);
160
+ // Antialiased minimum (the game's _OutlineAntialias): held at the minimum
161
+ // width and faded by the shortfall, never thinner. The game fades by
162
+ // sqrt(coverage.x · coverage.y), per axis; for one width that is the ratio
163
+ // itself.
164
+ let px = length(ndc * deviceViewport * 0.5);
165
+ let minPx = RZ_OUTLINE_MIN_PX * max(1.0, camera.viewportHeight / 1080.0);
166
+ var coverage = 1.0;
167
+ if (px < minPx) {
168
+ coverage = px / minPx;
169
+ ndc = select(vec2f(0.0), ndc * (minPx / px), px > 1e-6);
170
+ }
171
+ output.coverage = coverage;
172
+ output.position = vec4f(clipPos.xy + ndc * w, clipPos.z, clipPos.w);
120
173
  output.uv = uv;
121
174
  output.restPos = position;
122
175
  output.faceT = rz_dissolve_threshold(position);
@@ -151,7 +204,11 @@ ${sceneFsOutWgsl({ name: "FSOut", aux: "mask" })}
151
204
  discard;
152
205
  }
153
206
  var out: FSOut;
154
- out.color = vec4f(material.edgeColor.rgb, material.edgeColor.a * texA);
207
+ // Blended, not alpha-to-coverage: this pass already blends (the texture
208
+ // alpha above), it is drawn right after the surface it traces so what lies
209
+ // under a faded line is already there, and 4× MSAA would quantize a fade to
210
+ // four steps.
211
+ out.color = vec4f(material.edgeColor.rgb, material.edgeColor.a * texA * input.coverage);
155
212
  out.mask = vec4f(1.0, 1.0, 0.0, out.color.a);
156
213
  ${sceneIdPadWgsl("out")} return out;
157
214
  }
@@ -95,6 +95,8 @@ export declare class NativeHost {
95
95
  private fallback;
96
96
  private prepared;
97
97
  private pipelines;
98
+ /** Pipelines being compiled (see warm). */
99
+ private pending;
98
100
  private draws;
99
101
  private shared;
100
102
  private frame;
@@ -117,7 +119,20 @@ export declare class NativeHost {
117
119
  location: number;
118
120
  semantic: string;
119
121
  }[];
122
+ private pipelineKey;
123
+ /**
124
+ * Compile a draw's pipeline ahead of the draw — what a stage or a look calls
125
+ * for every pass it will draw, the moment it knows the shader, the state and
126
+ * the streams. Async: a synchronous build holds the GPU process for the
127
+ * whole compile, which was a one-to-two-second frozen frame at the first
128
+ * draw of each new shader. Resolves when the pipeline is ready or has
129
+ * failed (into `errors`); never rejects.
130
+ */
131
+ warm(shader: string, state: PassState, streams: NativeStream[]): Promise<void>;
132
+ /** The draw's pipeline if it is ready. Never built here: one that is not
133
+ * ready is started and the draw sits this frame out. */
120
134
  private pipeline;
135
+ private describe;
121
136
  private lookup;
122
137
  /** A new frame: shared blocks are brought up to date once in it. */
123
138
  beginFrame(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/unity/host.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAmE,KAAK,SAAS,EAAE,MAAM,SAAS,CAAA;AAEzG,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB,CAAA;AACD,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AACD,MAAM,MAAM,YAAY,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,YAAY,EAAE,CAAA;CAAE,CAAA;AACpE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;IACvC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;IACrC,YAAY,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CACjE,CAAA;AACD,4EAA4E;AAC5E,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,gBAAgB,CAAA;CACvB,CAAA;AAED;+EAC+E;AAC/E,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAA;AACnF,4DAA4D;AAC5D,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,CAAC,CAAA;AAEjE,4EAA4E;AAC5E,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,SAAS,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,eAAe,CAAA;CACxB,CAAA;AAKD,2EAA2E;AAC3E,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAKlD;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,MAAM,CAiB/D;AAqCD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,4EAA4E;IAC5E,YAAY,EAAE,gBAAgB,EAAE,CAAA;IAChC,WAAW,EAAE,gBAAgB,CAAA;IAC7B,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,SAAS,CAAA;IAChB,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB,KAAK,EAAE;QACL,MAAM,EAAE,SAAS,CAAA;QACjB,MAAM,EAAE,cAAc,CAAA;QACtB,MAAM,EAAE,MAAM,CAAA;QACd,KAAK,EAAE,MAAM,CAAA;KACd,CAAA;IACD,uCAAuC;IACvC,OAAO,EAAE,WAAW,EAAE,CAAA;IACtB,sEAAsE;IACtE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,SAAS,CAAC,CAAA;IACpD;8DAC0D;IAC1D,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG,SAAS,CAAC,CAAA;IACjD,uEAAuE;IACvE,GAAG,EAAE,MAAM,CAAA;IACX;;4BAEwB;IACxB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,CAAA;AAED,qBAAa,UAAU;IAYnB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,QAAQ;IAblB,OAAO,CAAC,QAAQ,CAA8B;IAC9C,OAAO,CAAC,SAAS,CAAgF;IACjG,OAAO,CAAC,KAAK,CAA+B;IAC5C,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,KAAK,CAAI;IACjB,OAAO,CAAC,OAAO,CAAY;IAC3B,oFAAoF;IACpF,QAAQ,CAAC,OAAO,sBAA4B;IAC5C,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAK;gBAGpB,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,EAAE;QAChB,KAAK,EAAE,cAAc,CAAA;QACrB,KAAK,EAAE,cAAc,CAAA;QACrB,SAAS,EAAE,cAAc,CAAA;QACzB,KAAK,EAAE,cAAc,CAAA;QACrB,UAAU,EAAE,UAAU,CAAA;KACvB;IAaH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI1B,wDAAwD;IACxD,QAAQ,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IA8DpC,8EAA8E;IAC9E,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EAAE;IAU9D,OAAO,CAAC,QAAQ;IAiGhB,OAAO,CAAC,MAAM;IAUd,oEAAoE;IACpE,UAAU,IAAI,IAAI;IAIlB,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,QAAQ;IAehB,sEAAsE;IACtE,OAAO,CAAC,IAAI;IA+CZ,2CAA2C;IAC3C,IAAI,CAAC,IAAI,EAAE,oBAAoB,EAAE,CAAC,EAAE,UAAU,GAAG,IAAI;IAmFrD,wFAAwF;IACxF,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,WAAW;IAQnB,gDAAgD;IAChD,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;CAS9B;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,GAAG,OAAO,CAM/D"}
1
+ {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/unity/host.ts"],"names":[],"mappings":"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"}
@@ -67,6 +67,8 @@ export class NativeHost {
67
67
  this.fallback = fallback;
68
68
  this.prepared = new Map();
69
69
  this.pipelines = new Map();
70
+ /** Pipelines being compiled (see warm). */
71
+ this.pending = new Map();
70
72
  this.draws = new Map();
71
73
  this.shared = new Map();
72
74
  this.frame = 0;
@@ -160,10 +162,57 @@ export class NativeHost {
160
162
  }))
161
163
  : [];
162
164
  }
163
- pipeline(p, state, streams) {
164
- const key = `${p.shader.name}|${JSON.stringify(state)}|${streams.map((s) => s.format).join(",")}`;
165
+ pipelineKey(p, state, streams) {
166
+ return `${p.shader.name}|${JSON.stringify(state)}|${streams.map((s) => `${s.format}/${s.stride}`).join(",")}`;
167
+ }
168
+ /**
169
+ * Compile a draw's pipeline ahead of the draw — what a stage or a look calls
170
+ * for every pass it will draw, the moment it knows the shader, the state and
171
+ * the streams. Async: a synchronous build holds the GPU process for the
172
+ * whole compile, which was a one-to-two-second frozen frame at the first
173
+ * draw of each new shader. Resolves when the pipeline is ready or has
174
+ * failed (into `errors`); never rejects.
175
+ */
176
+ warm(shader, state, streams) {
177
+ const p = this.prepared.get(shader);
178
+ if (!p)
179
+ return Promise.resolve();
180
+ const key = this.pipelineKey(p, state, streams);
165
181
  if (this.pipelines.has(key))
166
- return this.pipelines.get(key);
182
+ return Promise.resolve();
183
+ let job = this.pending.get(key);
184
+ if (job)
185
+ return job;
186
+ let built;
187
+ try {
188
+ built = this.describe(p, state, streams);
189
+ }
190
+ catch (e) {
191
+ this.errors.push(`pipeline ${p.shader.name}: ${e.message}`);
192
+ this.pipelines.set(key, null);
193
+ return Promise.resolve();
194
+ }
195
+ job = this.device.createRenderPipelineAsync(built.desc).then((pipeline) => {
196
+ this.pipelines.set(key, { pipeline, stencilRef: built.stencilRef });
197
+ this.pending.delete(key);
198
+ }, (e) => {
199
+ this.errors.push(`pipeline ${p.shader.name}: ${e.message}`);
200
+ this.pipelines.set(key, null);
201
+ this.pending.delete(key);
202
+ });
203
+ this.pending.set(key, job);
204
+ return job;
205
+ }
206
+ /** The draw's pipeline if it is ready. Never built here: one that is not
207
+ * ready is started and the draw sits this frame out. */
208
+ pipeline(p, state, streams) {
209
+ const ready = this.pipelines.get(this.pipelineKey(p, state, streams));
210
+ if (ready !== undefined)
211
+ return ready;
212
+ void this.warm(p.shader.name, state, streams);
213
+ return null;
214
+ }
215
+ describe(p, state, streams) {
167
216
  const t = this.targets;
168
217
  const stencil = stencilState(state);
169
218
  const blend = blendState(state);
@@ -198,66 +247,57 @@ export class NativeHost {
198
247
  if (t.colorFormats[2])
199
248
  targets.push({ format: t.colorFormats[2], writeMask: 0 });
200
249
  const offset = state.Offset;
201
- let result;
202
- try {
203
- result = {
204
- pipeline: this.device.createRenderPipeline({
205
- label: `${p.shader.name} pipeline`,
206
- layout: p.layout,
207
- vertex: {
208
- module: p.vert,
209
- entryPoint: "vert",
210
- buffers: p.shader.info.vertexInputs.map((vi, k) => ({
211
- arrayStride: streams[k].stride,
212
- stepMode: "vertex",
213
- attributes: [
214
- {
215
- shaderLocation: vi.location,
216
- offset: 0,
217
- format: streams[k].format,
218
- },
219
- ],
220
- })),
221
- },
222
- fragment: { module: p.frag, entryPoint: "frag", targets },
223
- // Unity's D3D winding, which is PMX's too: clockwise is the front.
224
- primitive: {
225
- topology: "triangle-list",
226
- cullMode: cull(state.Cull?.[0]),
227
- frontFace: "cw",
228
- },
229
- depthStencil: {
230
- format: t.depthFormat,
231
- depthWriteEnabled: zwrite(state.ZWrite?.[0]),
232
- depthCompare: depthCompare(state.ZTest?.[0], t.reversedZ),
233
- ...(stencil
234
- ? {
235
- stencilFront: stencil.face,
236
- stencilBack: stencil.face,
237
- stencilReadMask: stencil.read,
238
- stencilWriteMask: stencil.write,
239
- }
240
- : {}),
241
- // Offset (factor, units): pulls toward the viewer, which under
242
- // reversed depth is the other sign.
243
- ...(offset
244
- ? {
245
- depthBias: Math.round((+offset[1] || 0) * (t.reversedZ ? 1 : -1)),
246
- depthBiasSlopeScale: (+offset[0] || 0) * (t.reversedZ ? 1 : -1),
247
- }
248
- : {}),
249
- },
250
- multisample: { count: t.sampleCount },
251
- }),
252
- stencilRef: stencil?.ref ?? 0,
253
- };
254
- }
255
- catch (e) {
256
- this.errors.push(`pipeline ${p.shader.name}: ${e.message}`);
257
- result = null;
258
- }
259
- this.pipelines.set(key, result);
260
- return result;
250
+ return {
251
+ desc: {
252
+ label: `${p.shader.name} pipeline`,
253
+ layout: p.layout,
254
+ vertex: {
255
+ module: p.vert,
256
+ entryPoint: "vert",
257
+ buffers: p.shader.info.vertexInputs.map((vi, k) => ({
258
+ arrayStride: streams[k].stride,
259
+ stepMode: "vertex",
260
+ attributes: [
261
+ {
262
+ shaderLocation: vi.location,
263
+ offset: 0,
264
+ format: streams[k].format,
265
+ },
266
+ ],
267
+ })),
268
+ },
269
+ fragment: { module: p.frag, entryPoint: "frag", targets },
270
+ // Unity's D3D winding, which is PMX's too: clockwise is the front.
271
+ primitive: {
272
+ topology: "triangle-list",
273
+ cullMode: cull(state.Cull?.[0]),
274
+ frontFace: "cw",
275
+ },
276
+ depthStencil: {
277
+ format: t.depthFormat,
278
+ depthWriteEnabled: zwrite(state.ZWrite?.[0]),
279
+ depthCompare: depthCompare(state.ZTest?.[0], t.reversedZ),
280
+ ...(stencil
281
+ ? {
282
+ stencilFront: stencil.face,
283
+ stencilBack: stencil.face,
284
+ stencilReadMask: stencil.read,
285
+ stencilWriteMask: stencil.write,
286
+ }
287
+ : {}),
288
+ // Offset (factor, units): pulls toward the viewer, which under
289
+ // reversed depth is the other sign.
290
+ ...(offset
291
+ ? {
292
+ depthBias: Math.round((+offset[1] || 0) * (t.reversedZ ? 1 : -1)),
293
+ depthBiasSlopeScale: (+offset[0] || 0) * (t.reversedZ ? 1 : -1),
294
+ }
295
+ : {}),
296
+ },
297
+ multisample: { count: t.sampleCount },
298
+ },
299
+ stencilRef: stencil?.ref ?? 0,
300
+ };
261
301
  }
262
302
  lookup(name, sources) {
263
303
  for (const s of sources) {
@@ -58,6 +58,8 @@ export declare class NativeLooks {
58
58
  private device;
59
59
  readonly host: NativeHost;
60
60
  private installs;
61
+ /** Per model: its passes' pipelines compiling (see install). */
62
+ private warming;
61
63
  private skinPipeline;
62
64
  private zero;
63
65
  private white;
@@ -67,6 +69,9 @@ export declare class NativeLooks {
67
69
  constructor(device: GPUDevice, host: NativeHost);
68
70
  get size(): number;
69
71
  has(model: string): boolean;
72
+ /** Resolves once every pass of the model's look has its pipeline — until
73
+ * then those draws sit out (NativeHost never compiles at a draw). */
74
+ ready(model: string): Promise<void>;
70
75
  /** Is this model's material drawn by its native look? */
71
76
  dresses(model: string, material: string): boolean;
72
77
  install(model: NativeModel, look: NativeLook): void;
@@ -1 +1 @@
1
- {"version":3,"file":"looks.d.ts","sourceRoot":"","sources":["../../src/unity/looks.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,UAAU,EAAE,KAAK,YAAY,EAAqB,KAAK,WAAW,EAAoB,MAAM,QAAQ,CAAA;AAC7G,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAExC,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,aAAa,CAAA;AAG/D,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,6BAA6B;IAC7B,IAAI,EAAE,UAAU,CAAA;IAChB,0EAA0E;IAC1E,IAAI,EAAE,OAAO,CAAA;CACd,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,mDAAmD;IACnD,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,EAAE,CAAA;IACjE,4EAA4E;IAC5E,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;IACnC;kCAC8B;IAC9B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACjC,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;IACvC,SAAS,EAAE,kBAAkB,EAAE,CAAA;IAC/B,GAAG,CAAC,EAAE,YAAY,CAAA;CACnB,CAAA;AAED,2CAA2C;AAC3C,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,YAAY,CAAA;IACtB,OAAO,EAAE,WAAW,CAAA;IACpB,YAAY,EAAE,SAAS,CAAA;IACvB,YAAY,EAAE,SAAS,CAAA;IACvB,aAAa,EAAE,SAAS,CAAA;IACxB,gBAAgB,EAAE,SAAS,CAAA;IAC3B,WAAW,EAAE,SAAS,CAAA;IACtB,KAAK,EAAE;QACL,YAAY,EAAE,MAAM,CAAA;QACpB,UAAU,EAAE,MAAM,CAAA;QAClB,KAAK,EAAE,MAAM,CAAA;QACb,OAAO,EAAE,cAAc,CAAA;KACxB,EAAE,CAAA;IACH,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAA;IACrC,wDAAwD;IACxD,QAAQ,EAAE,MAAM,SAAS,CAAC,MAAM,CAAC,GAAG,IAAI,CAAA;IACxC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAClC,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAsBD,qBAAa,WAAW;IAWpB,OAAO,CAAC,MAAM;IAVhB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;IACzB,OAAO,CAAC,QAAQ,CAA6B;IAC7C,OAAO,CAAC,YAAY,CAAoB;IACxC,OAAO,CAAC,IAAI,CAAW;IACvB,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,aAAa,CAAiD;IACtE,OAAO,CAAC,KAAK,CAAI;gBAGP,MAAM,EAAE,SAAS,EACzB,IAAI,EAAE,UAAU;IA6BlB,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAI3B,yDAAyD;IACzD,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO;IAKjD,OAAO,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI;IAwEnD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAc1B;;;OAGG;IACH,OAAO,CACL,OAAO,EAAE,iBAAiB,EAC1B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACpC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,SAAS,CAAC,GACnD,IAAI;IAmBP,OAAO,CAAC,OAAO;IAgDf,OAAO,CAAC,QAAQ;IAoChB,sEAAsE;IACtE,OAAO,CAAC,IAAI;IAMZ,+EAA+E;IAC/E,UAAU,CAAC,IAAI,EAAE,oBAAoB,GAAG,IAAI;IAQ5C,yCAAyC;IACzC,eAAe,CAAC,IAAI,EAAE,oBAAoB,GAAG,IAAI;CAKlD"}
1
+ {"version":3,"file":"looks.d.ts","sourceRoot":"","sources":["../../src/unity/looks.ts"],"names":[],"mappings":"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"}
@@ -24,6 +24,8 @@ export class NativeLooks {
24
24
  constructor(device, host) {
25
25
  this.device = device;
26
26
  this.installs = new Map();
27
+ /** Per model: its passes' pipelines compiling (see install). */
28
+ this.warming = new Map();
27
29
  this.globals = {};
28
30
  this.frameTextures = {};
29
31
  this.scale = 8;
@@ -59,6 +61,11 @@ export class NativeLooks {
59
61
  has(model) {
60
62
  return this.installs.has(model);
61
63
  }
64
+ /** Resolves once every pass of the model's look has its pipeline — until
65
+ * then those draws sit out (NativeHost never compiles at a draw). */
66
+ ready(model) {
67
+ return this.warming.get(model) ?? Promise.resolve();
68
+ }
62
69
  /** Is this model's material drawn by its native look? */
63
70
  dresses(model, material) {
64
71
  const i = this.installs.get(model);
@@ -121,7 +128,7 @@ export class NativeLooks {
121
128
  if (spec)
122
129
  dressed.push({ draw, spec });
123
130
  }
124
- this.installs.set(model.name, {
131
+ const install = {
125
132
  model,
126
133
  look,
127
134
  views,
@@ -134,7 +141,17 @@ export class NativeLooks {
134
141
  skinBind,
135
142
  dressed,
136
143
  block: {},
137
- });
144
+ };
145
+ this.installs.set(model.name, install);
146
+ // Every pass this look will draw, compiled now and side by side — the
147
+ // shader, its state and the streams are all known here.
148
+ const drawn = [...OPAQUE_MODES, ...CHARACTER_MODES, ...OVERRIDE_MODES];
149
+ const jobs = [];
150
+ for (const d of dressed)
151
+ for (const p of d.spec.passes)
152
+ if (drawn.includes(p.lightMode))
153
+ jobs.push(this.host.warm(p.shader, p.state, this.streams(install, p.shader)));
154
+ this.warming.set(model.name, Promise.all(jobs).then(() => { }));
138
155
  }
139
156
  remove(name) {
140
157
  const i = this.installs.get(name);
@@ -1 +1 @@
1
- {"version":3,"file":"skin.d.ts","sourceRoot":"","sources":["../../src/unity/skin.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,eAAe,g0EA8C3B,CAAA;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,GAAG,WAAW,GAAG,YAAY,CA0DjG"}
1
+ {"version":3,"file":"skin.d.ts","sourceRoot":"","sources":["../../src/unity/skin.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,eAAe,g0EA8C3B,CAAA;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,GAAG,WAAW,GAAG,YAAY,CA6DjG"}
@@ -74,8 +74,11 @@ export function tangentsFor(verts, indices) {
74
74
  const p = (v, k) => verts[v * 8 + k];
75
75
  const e1 = [p(b, 0) - p(a, 0), p(b, 1) - p(a, 1), p(b, 2) - p(a, 2)];
76
76
  const e2 = [p(c, 0) - p(a, 0), p(c, 1) - p(a, 1), p(c, 2) - p(a, 2)];
77
- const du1 = p(b, 6) - p(a, 6), dv1 = p(b, 7) - p(a, 7);
78
- const du2 = p(c, 6) - p(a, 6), dv2 = p(c, 7) - p(a, 7);
77
+ // v measured upward, as Unity builds tangent space: a PMX uv runs v down,
78
+ // and taken as it is the bitangent — the handedness in w — comes out
79
+ // reversed, which a game normal map reads as its green channel inverted.
80
+ const du1 = p(b, 6) - p(a, 6), dv1 = p(a, 7) - p(b, 7);
81
+ const du2 = p(c, 6) - p(a, 6), dv2 = p(a, 7) - p(c, 7);
79
82
  const det = du1 * dv2 - du2 * dv1;
80
83
  if (Math.abs(det) < 1e-12)
81
84
  continue;
@@ -135,6 +135,13 @@ export declare class NativeStage {
135
135
  /** Every renderer's draws, resolved once: the stage does not move. */
136
136
  private build;
137
137
  private addItems;
138
+ /**
139
+ * Every pass's pipeline, compiled before the stage reports loaded (see
140
+ * NativeHost.warm) — side by side, and never at the first draw. Needs only
141
+ * the meshes' stream layouts, so it runs while the pictures decode. The
142
+ * passes are the ones build() keeps: casters that cast, and the main modes.
143
+ */
144
+ private warm;
138
145
  private streams;
139
146
  private draw;
140
147
  /** One cascade tile of the engine's atlas: every caster's SHADOWCASTER pass. */
@@ -1 +1 @@
1
- {"version":3,"file":"stage.d.ts","sourceRoot":"","sources":["../../src/unity/stage.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"stage.d.ts","sourceRoot":"","sources":["../../src/unity/stage.ts"],"names":[],"mappings":"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"}
@@ -98,6 +98,9 @@ export class NativeStage {
98
98
  meshes.set(m.id, { info: m, buffer });
99
99
  tick();
100
100
  }));
101
+ // Loaded means drawable: every pass's pipeline is compiled before this
102
+ // resolves, rather than one at a time in the frames after it.
103
+ const warming = st.warm(hosts, meshes);
101
104
  const textures = new Map();
102
105
  await Promise.all(pkg.textures.map(async (t) => {
103
106
  try {
@@ -109,6 +112,7 @@ export class NativeStage {
109
112
  tick(texWeight(t));
110
113
  }));
111
114
  st.build(meshes, textures, tools.fallback);
115
+ await warming;
112
116
  return st;
113
117
  }
114
118
  async loadTexture(t, read, mipmaps) {
@@ -257,9 +261,12 @@ export class NativeStage {
257
261
  const samplers = {
258
262
  ...globalSamplers,
259
263
  };
260
- // an empty slot reads what the shader declared it defaults to
264
+ // an empty slot reads what the shader declared it defaults to. A default
265
+ // with no name ("") is no picture at all — a cube's, usually — and is
266
+ // left to the host, which stands in by the binding's own kind.
261
267
  for (const [slot, def] of Object.entries(mat.defaults ?? {}))
262
- views[slot] = fallback[def] ?? fallback.white;
268
+ if (def && fallback[def])
269
+ views[slot] = fallback[def];
263
270
  for (const [slot, id] of [...Object.entries(mat.textures), ...Object.entries(r.textures)]) {
264
271
  const t = textures.get(id);
265
272
  if (!t)
@@ -291,6 +298,34 @@ export class NativeStage {
291
298
  }
292
299
  });
293
300
  }
301
+ /**
302
+ * Every pass's pipeline, compiled before the stage reports loaded (see
303
+ * NativeHost.warm) — side by side, and never at the first draw. Needs only
304
+ * the meshes' stream layouts, so it runs while the pictures decode. The
305
+ * passes are the ones build() keeps: casters that cast, and the main modes.
306
+ */
307
+ warm(hosts, meshes) {
308
+ const jobs = [];
309
+ const mats = new Map(this.pkg.materials.map((m) => [m.id, m]));
310
+ for (const r of this.pkg.renderers) {
311
+ const mesh = meshes.get(r.mesh);
312
+ if (!mesh)
313
+ continue;
314
+ r.materials.forEach((mid, sub) => {
315
+ const mat = mid ? mats.get(mid) : undefined;
316
+ if (!mat || sub >= mesh.info.submeshes.length)
317
+ return;
318
+ for (const pass of mat.passes) {
319
+ const caster = pass.lightMode === "SHADOWCASTER";
320
+ if (caster ? !r.castShadows : !MAIN_MODES.includes(pass.lightMode))
321
+ continue;
322
+ const host = caster ? hosts.shadow : hosts.scene;
323
+ jobs.push(host.warm(pass.shader, pass.state, this.streams(host, { mesh, pass })));
324
+ }
325
+ });
326
+ }
327
+ return Promise.all(jobs).then(() => { });
328
+ }
294
329
  streams(host, it) {
295
330
  const info = it.mesh.info;
296
331
  return host.inputs(it.pass.shader).map(({ semantic }) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reze-engine",
3
- "version": "0.64.0",
3
+ "version": "0.65.0",
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",