reze-engine 0.57.2 → 0.57.4
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trails.d.ts","sourceRoot":"","sources":["../../../src/shaders/passes/trails.ts"],"names":[],"mappings":"AA4BA,KAAK,WAAW,GAAG;IACjB,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAA;IACb;oEACgE;IAChE,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,6CAA6C;IAC7C,UAAU,EAAE,MAAM,CAAA;IAClB,8DAA8D;IAC9D,KAAK,EAAE,OAAO,GAAG,UAAU,CAAA;IAC3B,KAAK,EAAE,OAAO,CAAA;CACf,CAAA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,IAAI,CAAA;AAEnC,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAKjF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,WAAW,EAChB,IAAI,EAAE;IACJ,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,EAAE,CAAA;IACf;;;;kFAI8E;IAC9E,SAAS,EAAE,OAAO,CAAA;CACnB,GACA,MAAM,
|
|
1
|
+
{"version":3,"file":"trails.d.ts","sourceRoot":"","sources":["../../../src/shaders/passes/trails.ts"],"names":[],"mappings":"AA4BA,KAAK,WAAW,GAAG;IACjB,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAA;IACb;oEACgE;IAChE,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,6CAA6C;IAC7C,UAAU,EAAE,MAAM,CAAA;IAClB,8DAA8D;IAC9D,KAAK,EAAE,OAAO,GAAG,UAAU,CAAA;IAC3B,KAAK,EAAE,OAAO,CAAA;CACf,CAAA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,IAAI,CAAA;AAEnC,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAKjF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,WAAW,EAChB,IAAI,EAAE;IACJ,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,EAAE,CAAA;IACf;;;;kFAI8E;IAC9E,SAAS,EAAE,OAAO,CAAA;CACnB,GACA,MAAM,CAyZR"}
|
|
@@ -69,6 +69,10 @@ const SUB: i32 = ${TRAIL_SUBDIVISIONS};
|
|
|
69
69
|
// scaling width pinches the strip shut at exactly the moments a hand decelerates,
|
|
70
70
|
// which is every turn — and a ribbon that closes to nothing at each turn reads as
|
|
71
71
|
// dark breaks in the middle of it.
|
|
72
|
+
/** How far a bone may travel between two trail samples, as a fraction of its
|
|
73
|
+
* owner's bounding radius. Generous on purpose: a hard swing covers a fraction
|
|
74
|
+
* of this, and the only things above it are cuts. */
|
|
75
|
+
const RZ_TRAIL_MAX_STEP: f32 = 0.5;
|
|
72
76
|
const RZ_REF_SPAN: f32 = 0.37;
|
|
73
77
|
|
|
74
78
|
struct CameraU {
|
|
@@ -124,18 +128,62 @@ fn _rzCastLive() -> i32 {
|
|
|
124
128
|
}
|
|
125
129
|
return n;
|
|
126
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* CENTRIPETAL knot spacing: the square root of the chord.
|
|
133
|
+
*
|
|
134
|
+
* The whole reason the spline below is not the textbook one-liner. Uniform
|
|
135
|
+
* Catmull-Rom takes the tangent at p1 to be (p2 - p0)/2 — a quantity that knows
|
|
136
|
+
* nothing about how far apart those samples actually are. Trails are sampled at
|
|
137
|
+
* a FIXED RATE, so a hand that accelerates leaves one segment far longer than
|
|
138
|
+
* its neighbours, and a tangent sized for the long one applied over the short
|
|
139
|
+
* one swings the curve far outside the control polygon: the ribbon bulges out
|
|
140
|
+
* to a place no sample ever was, which reads as the trail teleporting, and it
|
|
141
|
+
* happens precisely on the quick moves.
|
|
142
|
+
*
|
|
143
|
+
* Spacing the knots by sqrt(chord) — alpha = 0.5, the centripetal variant — is
|
|
144
|
+
* the standard cure, and it is the only alpha proven to produce no cusp and no
|
|
145
|
+
* self-intersection whatever the samples do.
|
|
146
|
+
*/
|
|
147
|
+
fn rzKnot(a: vec3f, b: vec3f) -> f32 {
|
|
148
|
+
return max(sqrt(distance(a, b)), 1e-4);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** The two Hermite tangents of the segment p1..p2, sized by real chord lengths. */
|
|
152
|
+
fn rzSplineTangents(p0: vec3f, p1: vec3f, p2: vec3f, p3: vec3f) -> mat2x3f {
|
|
153
|
+
let d0 = rzKnot(p0, p1);
|
|
154
|
+
let d1 = rzKnot(p1, p2);
|
|
155
|
+
let d2 = rzKnot(p2, p3);
|
|
156
|
+
let m1 = ((p1 - p0) / d0 - (p2 - p0) / (d0 + d1) + (p2 - p1) / d1) * d1;
|
|
157
|
+
let m2 = ((p2 - p1) / d1 - (p3 - p1) / (d1 + d2) + (p3 - p2) / d2) * d1;
|
|
158
|
+
return mat2x3f(m1, m2);
|
|
159
|
+
}
|
|
160
|
+
|
|
127
161
|
/** Catmull-Rom through four samples — passes through p1 and p2. */
|
|
128
162
|
fn rzSpline(p0: vec3f, p1: vec3f, p2: vec3f, p3: vec3f, t: f32) -> vec3f {
|
|
163
|
+
let m = rzSplineTangents(p0, p1, p2, p3);
|
|
129
164
|
let t2 = t * t;
|
|
130
165
|
let t3 = t2 * t;
|
|
131
|
-
return
|
|
132
|
-
|
|
166
|
+
return (2.0 * t3 - 3.0 * t2 + 1.0) * p1
|
|
167
|
+
+ (t3 - 2.0 * t2 + t) * m[0]
|
|
168
|
+
+ (-2.0 * t3 + 3.0 * t2) * p2
|
|
169
|
+
+ (t3 - t2) * m[1];
|
|
133
170
|
}
|
|
134
|
-
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Its derivative — the ribbon's direction, smooth by construction.
|
|
174
|
+
*
|
|
175
|
+
* Still exact at the knots, which is what the shared edge depends on: at t = 1
|
|
176
|
+
* this is m2 and at t = 0 it is m1, and the two segments meeting at a sample
|
|
177
|
+
* derive those from the same three points. They differ only by a positive
|
|
178
|
+
* scale, and this normalises, so both quads get the identical direction.
|
|
179
|
+
*/
|
|
135
180
|
fn rzSplineTangent(p0: vec3f, p1: vec3f, p2: vec3f, p3: vec3f, t: f32) -> vec3f {
|
|
181
|
+
let m = rzSplineTangents(p0, p1, p2, p3);
|
|
136
182
|
let t2 = t * t;
|
|
137
|
-
let d =
|
|
138
|
-
|
|
183
|
+
let d = (6.0 * t2 - 6.0 * t) * p1
|
|
184
|
+
+ (3.0 * t2 - 4.0 * t + 1.0) * m[0]
|
|
185
|
+
+ (-6.0 * t2 + 6.0 * t) * p2
|
|
186
|
+
+ (3.0 * t2 - 2.0 * t) * m[1];
|
|
139
187
|
if (length(d) < 1e-6) { return vec3f(0.0, 1.0, 0.0); }
|
|
140
188
|
return normalize(d);
|
|
141
189
|
}
|
|
@@ -262,9 +310,28 @@ fn vs(@builtin(vertex_index) vi: u32, @builtin(instance_index) ii: u32) -> VSOut
|
|
|
262
310
|
// where the hand slows — aggregation the width taper never clamps, because
|
|
263
311
|
// width follows AGE, not speed. Where the hand is not moving there is no path,
|
|
264
312
|
// and a path effect should draw nothing there at all.
|
|
313
|
+
// AND A GATE AT THE OTHER END, for the same reason. The minimum says "the
|
|
314
|
+
// hand is not moving"; this says "the hand did not move THERE". A bone cannot
|
|
315
|
+
// cross a sizeable fraction of its owner between two samples, so a span that
|
|
316
|
+
// large is not a motion — it is a cut: a seek, a clip boundary, a model
|
|
317
|
+
// repositioned, a motion that jumps. Joined anyway, the two samples either
|
|
318
|
+
// side are bridged by one enormous quad flung across the gap and drawn at full
|
|
319
|
+
// strength, which is the "trail teleports on a fast move" report. A path
|
|
320
|
+
// effect should draw nothing across a discontinuity, exactly as it draws
|
|
321
|
+
// nothing where there is no path.
|
|
322
|
+
//
|
|
323
|
+
// Measured against the subject's own bounding radius rather than in world
|
|
324
|
+
// units, so it holds for a doll and for a giant, and it is checked in WORLD
|
|
325
|
+
// space rather than in pixels — a camera cut moves every projected point at
|
|
326
|
+
// once and must not shred every ribbon on screen.
|
|
327
|
+
//
|
|
328
|
+
// Zero radius means the cast slot is not live, and then there is nothing to
|
|
329
|
+
// measure against: the test stands down rather than rejecting everything.
|
|
330
|
+
let reach = rzSubject(subject).bounds.w * RZ_TRAIL_MAX_STEP;
|
|
265
331
|
let c1 = cam.proj * cam.view * vec4f(p1, 1.0);
|
|
266
332
|
let c2 = cam.proj * cam.view * vec4f(p2, 1.0);
|
|
267
333
|
if (c1.w <= 0.01 || c2.w <= 0.01 ||
|
|
334
|
+
(reach > 0.0 && distance(p1, p2) > reach) ||
|
|
268
335
|
distance(c1.xy / c1.w * toPx, c2.xy / c2.w * toPx) < 0.7 * (H / 1080.0)) {
|
|
269
336
|
out.clip = vec4f(0.0, 0.0, -2.0, 1.0);
|
|
270
337
|
out.uv = vec2f(0.0);
|
package/package.json
CHANGED
|
@@ -120,6 +120,10 @@ const SUB: i32 = ${TRAIL_SUBDIVISIONS};
|
|
|
120
120
|
// scaling width pinches the strip shut at exactly the moments a hand decelerates,
|
|
121
121
|
// which is every turn — and a ribbon that closes to nothing at each turn reads as
|
|
122
122
|
// dark breaks in the middle of it.
|
|
123
|
+
/** How far a bone may travel between two trail samples, as a fraction of its
|
|
124
|
+
* owner's bounding radius. Generous on purpose: a hard swing covers a fraction
|
|
125
|
+
* of this, and the only things above it are cuts. */
|
|
126
|
+
const RZ_TRAIL_MAX_STEP: f32 = 0.5;
|
|
123
127
|
const RZ_REF_SPAN: f32 = 0.37;
|
|
124
128
|
|
|
125
129
|
struct CameraU {
|
|
@@ -175,18 +179,62 @@ fn _rzCastLive() -> i32 {
|
|
|
175
179
|
}
|
|
176
180
|
return n;
|
|
177
181
|
}
|
|
182
|
+
/**
|
|
183
|
+
* CENTRIPETAL knot spacing: the square root of the chord.
|
|
184
|
+
*
|
|
185
|
+
* The whole reason the spline below is not the textbook one-liner. Uniform
|
|
186
|
+
* Catmull-Rom takes the tangent at p1 to be (p2 - p0)/2 — a quantity that knows
|
|
187
|
+
* nothing about how far apart those samples actually are. Trails are sampled at
|
|
188
|
+
* a FIXED RATE, so a hand that accelerates leaves one segment far longer than
|
|
189
|
+
* its neighbours, and a tangent sized for the long one applied over the short
|
|
190
|
+
* one swings the curve far outside the control polygon: the ribbon bulges out
|
|
191
|
+
* to a place no sample ever was, which reads as the trail teleporting, and it
|
|
192
|
+
* happens precisely on the quick moves.
|
|
193
|
+
*
|
|
194
|
+
* Spacing the knots by sqrt(chord) — alpha = 0.5, the centripetal variant — is
|
|
195
|
+
* the standard cure, and it is the only alpha proven to produce no cusp and no
|
|
196
|
+
* self-intersection whatever the samples do.
|
|
197
|
+
*/
|
|
198
|
+
fn rzKnot(a: vec3f, b: vec3f) -> f32 {
|
|
199
|
+
return max(sqrt(distance(a, b)), 1e-4);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/** The two Hermite tangents of the segment p1..p2, sized by real chord lengths. */
|
|
203
|
+
fn rzSplineTangents(p0: vec3f, p1: vec3f, p2: vec3f, p3: vec3f) -> mat2x3f {
|
|
204
|
+
let d0 = rzKnot(p0, p1);
|
|
205
|
+
let d1 = rzKnot(p1, p2);
|
|
206
|
+
let d2 = rzKnot(p2, p3);
|
|
207
|
+
let m1 = ((p1 - p0) / d0 - (p2 - p0) / (d0 + d1) + (p2 - p1) / d1) * d1;
|
|
208
|
+
let m2 = ((p2 - p1) / d1 - (p3 - p1) / (d1 + d2) + (p3 - p2) / d2) * d1;
|
|
209
|
+
return mat2x3f(m1, m2);
|
|
210
|
+
}
|
|
211
|
+
|
|
178
212
|
/** Catmull-Rom through four samples — passes through p1 and p2. */
|
|
179
213
|
fn rzSpline(p0: vec3f, p1: vec3f, p2: vec3f, p3: vec3f, t: f32) -> vec3f {
|
|
214
|
+
let m = rzSplineTangents(p0, p1, p2, p3);
|
|
180
215
|
let t2 = t * t;
|
|
181
216
|
let t3 = t2 * t;
|
|
182
|
-
return
|
|
183
|
-
|
|
217
|
+
return (2.0 * t3 - 3.0 * t2 + 1.0) * p1
|
|
218
|
+
+ (t3 - 2.0 * t2 + t) * m[0]
|
|
219
|
+
+ (-2.0 * t3 + 3.0 * t2) * p2
|
|
220
|
+
+ (t3 - t2) * m[1];
|
|
184
221
|
}
|
|
185
|
-
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Its derivative — the ribbon's direction, smooth by construction.
|
|
225
|
+
*
|
|
226
|
+
* Still exact at the knots, which is what the shared edge depends on: at t = 1
|
|
227
|
+
* this is m2 and at t = 0 it is m1, and the two segments meeting at a sample
|
|
228
|
+
* derive those from the same three points. They differ only by a positive
|
|
229
|
+
* scale, and this normalises, so both quads get the identical direction.
|
|
230
|
+
*/
|
|
186
231
|
fn rzSplineTangent(p0: vec3f, p1: vec3f, p2: vec3f, p3: vec3f, t: f32) -> vec3f {
|
|
232
|
+
let m = rzSplineTangents(p0, p1, p2, p3);
|
|
187
233
|
let t2 = t * t;
|
|
188
|
-
let d =
|
|
189
|
-
|
|
234
|
+
let d = (6.0 * t2 - 6.0 * t) * p1
|
|
235
|
+
+ (3.0 * t2 - 4.0 * t + 1.0) * m[0]
|
|
236
|
+
+ (-6.0 * t2 + 6.0 * t) * p2
|
|
237
|
+
+ (3.0 * t2 - 2.0 * t) * m[1];
|
|
190
238
|
if (length(d) < 1e-6) { return vec3f(0.0, 1.0, 0.0); }
|
|
191
239
|
return normalize(d);
|
|
192
240
|
}
|
|
@@ -313,9 +361,28 @@ fn vs(@builtin(vertex_index) vi: u32, @builtin(instance_index) ii: u32) -> VSOut
|
|
|
313
361
|
// where the hand slows — aggregation the width taper never clamps, because
|
|
314
362
|
// width follows AGE, not speed. Where the hand is not moving there is no path,
|
|
315
363
|
// and a path effect should draw nothing there at all.
|
|
364
|
+
// AND A GATE AT THE OTHER END, for the same reason. The minimum says "the
|
|
365
|
+
// hand is not moving"; this says "the hand did not move THERE". A bone cannot
|
|
366
|
+
// cross a sizeable fraction of its owner between two samples, so a span that
|
|
367
|
+
// large is not a motion — it is a cut: a seek, a clip boundary, a model
|
|
368
|
+
// repositioned, a motion that jumps. Joined anyway, the two samples either
|
|
369
|
+
// side are bridged by one enormous quad flung across the gap and drawn at full
|
|
370
|
+
// strength, which is the "trail teleports on a fast move" report. A path
|
|
371
|
+
// effect should draw nothing across a discontinuity, exactly as it draws
|
|
372
|
+
// nothing where there is no path.
|
|
373
|
+
//
|
|
374
|
+
// Measured against the subject's own bounding radius rather than in world
|
|
375
|
+
// units, so it holds for a doll and for a giant, and it is checked in WORLD
|
|
376
|
+
// space rather than in pixels — a camera cut moves every projected point at
|
|
377
|
+
// once and must not shred every ribbon on screen.
|
|
378
|
+
//
|
|
379
|
+
// Zero radius means the cast slot is not live, and then there is nothing to
|
|
380
|
+
// measure against: the test stands down rather than rejecting everything.
|
|
381
|
+
let reach = rzSubject(subject).bounds.w * RZ_TRAIL_MAX_STEP;
|
|
316
382
|
let c1 = cam.proj * cam.view * vec4f(p1, 1.0);
|
|
317
383
|
let c2 = cam.proj * cam.view * vec4f(p2, 1.0);
|
|
318
384
|
if (c1.w <= 0.01 || c2.w <= 0.01 ||
|
|
385
|
+
(reach > 0.0 && distance(p1, p2) > reach) ||
|
|
319
386
|
distance(c1.xy / c1.w * toPx, c2.xy / c2.w * toPx) < 0.7 * (H / 1080.0)) {
|
|
320
387
|
out.clip = vec4f(0.0, 0.0, -2.0, 1.0);
|
|
321
388
|
out.uv = vec2f(0.0);
|