@woosh/meep-engine 3.14.3 → 3.14.5

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 (137) hide show
  1. package/package.json +1 -1
  2. package/src/core/geom/3d/mat4/m4_rigidity_defect.d.ts +30 -0
  3. package/src/core/geom/3d/mat4/m4_rigidity_defect.d.ts.map +1 -0
  4. package/src/core/geom/3d/mat4/m4_rigidity_defect.js +71 -0
  5. package/src/engine/Engine.d.ts.map +1 -1
  6. package/src/engine/Engine.js +733 -726
  7. package/src/engine/network/NetworkSession.d.ts +24 -4
  8. package/src/engine/network/NetworkSession.d.ts.map +1 -1
  9. package/src/engine/network/NetworkSession.js +28 -4
  10. package/src/engine/network/orchestrator/NetworkPeer.d.ts +96 -7
  11. package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
  12. package/src/engine/network/orchestrator/NetworkPeer.js +392 -68
  13. package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts +6 -1
  14. package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts.map +1 -1
  15. package/src/engine/network/orchestrator/ServerAuthoritativeClient.js +6 -0
  16. package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts +105 -13
  17. package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts.map +1 -1
  18. package/src/engine/network/orchestrator/ServerAuthoritativeServer.js +306 -59
  19. package/src/engine/network/replication/Replicator.d.ts +43 -7
  20. package/src/engine/network/replication/Replicator.d.ts.map +1 -1
  21. package/src/engine/network/replication/Replicator.js +309 -111
  22. package/src/engine/network/sim/ActionLog.d.ts +23 -3
  23. package/src/engine/network/sim/ActionLog.d.ts.map +1 -1
  24. package/src/engine/network/sim/ActionLog.js +26 -3
  25. package/src/engine/network/sim/ActionRecordCursor.d.ts +82 -0
  26. package/src/engine/network/sim/ActionRecordCursor.d.ts.map +1 -0
  27. package/src/engine/network/sim/ActionRecordCursor.js +120 -0
  28. package/src/engine/network/sim/RewindEngine.d.ts.map +1 -1
  29. package/src/engine/network/sim/RewindEngine.js +13 -29
  30. package/src/engine/network/sim/SimAction.d.ts +15 -0
  31. package/src/engine/network/sim/SimAction.d.ts.map +1 -1
  32. package/src/engine/network/sim/SimAction.js +15 -0
  33. package/src/engine/network/sim/SimActionExecutor.d.ts +51 -2
  34. package/src/engine/network/sim/SimActionExecutor.d.ts.map +1 -1
  35. package/src/engine/network/sim/SimActionExecutor.js +74 -7
  36. package/src/engine/network/transport/Channel.d.ts +1 -1
  37. package/src/engine/network/transport/Channel.js +1 -1
  38. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  39. package/src/engine/simulation/Ticker.d.ts.map +1 -1
  40. package/src/engine/simulation/Ticker.js +4 -1
  41. package/src/engine/ui/GUIEngine.d.ts.map +1 -1
  42. package/src/engine/ui/GUIEngine.js +6 -0
  43. package/src/shade/playground/particle_system/README.md +98 -0
  44. package/src/shade/playground/particle_system/index.html +124 -0
  45. package/src/shade/playground/particle_system/main.d.ts +2 -0
  46. package/src/shade/playground/particle_system/main.d.ts.map +1 -0
  47. package/src/shade/playground/particle_system/main.js +180 -0
  48. package/src/shade/playground/particle_system/particle_scene.d.ts +52 -0
  49. package/src/shade/playground/particle_system/particle_scene.d.ts.map +1 -0
  50. package/src/shade/playground/particle_system/particle_scene.js +553 -0
  51. package/src/shade/playground/skinned_mesh_soup/README.md +143 -0
  52. package/src/shade/playground/skinned_mesh_soup/index.html +202 -0
  53. package/src/shade/playground/skinned_mesh_soup/main.d.ts +7 -0
  54. package/src/shade/playground/skinned_mesh_soup/main.d.ts.map +1 -0
  55. package/src/shade/playground/skinned_mesh_soup/main.js +567 -0
  56. package/src/shade/playground/skinned_mesh_soup/verify_clone_vertices.d.ts +29 -0
  57. package/src/shade/playground/skinned_mesh_soup/verify_clone_vertices.d.ts.map +1 -0
  58. package/src/shade/playground/skinned_mesh_soup/verify_clone_vertices.js +428 -0
  59. package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
  60. package/src/shade/renderer/animation/GPUAnimationManager.js +1958 -1796
  61. package/src/shade/renderer/animation/SKINNING_FRAME_PLAN.md +357 -0
  62. package/src/shade/renderer/animation/skin_bind_transform.d.ts +25 -0
  63. package/src/shade/renderer/animation/skin_bind_transform.d.ts.map +1 -0
  64. package/src/shade/renderer/animation/skin_bind_transform.js +33 -0
  65. package/src/shade/renderer/animation/skin_clip_scale_conflicts.d.ts +67 -0
  66. package/src/shade/renderer/animation/skin_clip_scale_conflicts.d.ts.map +1 -0
  67. package/src/shade/renderer/animation/skin_clip_scale_conflicts.js +199 -0
  68. package/src/shade/renderer/animation/skin_frame_defect.d.ts +34 -0
  69. package/src/shade/renderer/animation/skin_frame_defect.d.ts.map +1 -0
  70. package/src/shade/renderer/animation/skin_frame_defect.js +132 -0
  71. package/src/shade/renderer/animation/skin_joint_matrix.d.ts +24 -0
  72. package/src/shade/renderer/animation/skin_joint_matrix.d.ts.map +1 -0
  73. package/src/shade/renderer/animation/skin_joint_matrix.js +46 -0
  74. package/src/shade/renderer/animation/skin_normalize_mesh_frame.d.ts +70 -0
  75. package/src/shade/renderer/animation/skin_normalize_mesh_frame.d.ts.map +1 -0
  76. package/src/shade/renderer/animation/skin_normalize_mesh_frame.js +216 -0
  77. package/src/shade/renderer/animation/skin_test_fixtures.d.ts +86 -0
  78. package/src/shade/renderer/animation/skin_test_fixtures.d.ts.map +1 -0
  79. package/src/shade/renderer/animation/skin_test_fixtures.js +250 -0
  80. package/src/shade/renderer/animation/skinning/chunk_skin_blend_mesh_local.d.ts +18 -4
  81. package/src/shade/renderer/animation/skinning/chunk_skin_blend_mesh_local.d.ts.map +1 -1
  82. package/src/shade/renderer/animation/skinning/chunk_skin_blend_mesh_local.js +18 -4
  83. package/src/shade/renderer/particles/DESIGN.md +5 -5
  84. package/src/shade/renderer/particles/cull/chunk_particle_cull.d.ts.map +1 -1
  85. package/src/shade/renderer/particles/cull/chunk_particle_cull.js +3 -1
  86. package/src/shade/renderer/particles/data/chunk_particle_emitter.js +1 -1
  87. package/src/shade/renderer/particles/graph/ParticleNodeDescription.d.ts +43 -0
  88. package/src/shade/renderer/particles/graph/ParticleNodeDescription.d.ts.map +1 -0
  89. package/src/shade/renderer/particles/graph/ParticleNodeDescription.js +44 -0
  90. package/src/shade/renderer/particles/graph/ParticleNodeRegistry.d.ts +33 -59
  91. package/src/shade/renderer/particles/graph/ParticleNodeRegistry.d.ts.map +1 -1
  92. package/src/shade/renderer/particles/graph/ParticleNodeRegistry.js +185 -118
  93. package/src/shade/renderer/particles/graph/compile_particle_graph.d.ts +15 -10
  94. package/src/shade/renderer/particles/graph/compile_particle_graph.d.ts.map +1 -1
  95. package/src/shade/renderer/particles/graph/compile_particle_graph.js +205 -170
  96. package/src/shade/renderer/particles/graph/particle_graph_authoring.d.ts +44 -0
  97. package/src/shade/renderer/particles/graph/particle_graph_authoring.d.ts.map +1 -0
  98. package/src/shade/renderer/particles/graph/particle_graph_authoring.js +108 -0
  99. package/src/shade/renderer/particles/isa/InstructionStream.d.ts +89 -0
  100. package/src/shade/renderer/particles/isa/InstructionStream.d.ts.map +1 -0
  101. package/src/shade/renderer/particles/isa/InstructionStream.js +162 -0
  102. package/src/shade/renderer/particles/isa/ParticleAssembler.d.ts +1 -48
  103. package/src/shade/renderer/particles/isa/ParticleAssembler.d.ts.map +1 -1
  104. package/src/shade/renderer/particles/isa/ParticleAssembler.js +25 -114
  105. package/src/shade/renderer/particles/particle_prototype.d.ts.map +1 -1
  106. package/src/shade/renderer/particles/particle_prototype.js +181 -180
  107. package/src/shade/renderer/particles/runtime/create_particle_effect.d.ts +4 -4
  108. package/src/shade/renderer/particles/runtime/create_particle_effect.d.ts.map +1 -1
  109. package/src/shade/renderer/particles/runtime/create_particle_effect.js +19 -19
  110. package/src/shade/renderer/particles/shaders/chunk_particle_curve_animation.d.ts.map +1 -1
  111. package/src/shade/renderer/particles/shaders/chunk_particle_curve_animation.js +4 -2
  112. package/src/shade/renderer/particles/shaders/chunk_particle_lighting.d.ts +4 -4
  113. package/src/shade/renderer/particles/shaders/chunk_particle_lighting.d.ts.map +1 -1
  114. package/src/shade/renderer/particles/shaders/chunk_particle_lighting.js +7 -5
  115. package/src/shade/renderer/particles/shaders/chunk_particle_render_math.d.ts.map +1 -1
  116. package/src/shade/renderer/particles/shaders/chunk_particle_render_math.js +3 -1
  117. package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts.map +1 -1
  118. package/src/shade/renderer/particles/shaders/shader_particle_emit.js +3 -1
  119. package/src/shade/renderer/particles/shaders/shader_particle_finalize.d.ts.map +1 -1
  120. package/src/shade/renderer/particles/shaders/shader_particle_finalize.js +5 -2
  121. package/src/shade/renderer/particles/shaders/shader_particle_render.d.ts.map +1 -1
  122. package/src/shade/renderer/particles/shaders/shader_particle_render.js +9 -2
  123. package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts.map +1 -1
  124. package/src/shade/renderer/particles/shaders/shader_particle_simulate.js +3 -1
  125. package/src/shade/renderer/particles/vm/chunk_particle_vm.js +1 -1
  126. package/src/shade/renderer/scene/SkinnedMesh.d.ts +11 -0
  127. package/src/shade/renderer/scene/SkinnedMesh.d.ts.map +1 -1
  128. package/src/shade/renderer/scene/SkinnedMesh.js +11 -0
  129. package/src/shade/renderer/shader/chunk/geometry/quaternion/dual/chunk_dual_quat_from_m4.d.ts +33 -3
  130. package/src/shade/renderer/shader/chunk/geometry/quaternion/dual/chunk_dual_quat_from_m4.d.ts.map +1 -1
  131. package/src/shade/renderer/shader/chunk/geometry/quaternion/dual/chunk_dual_quat_from_m4.js +58 -37
  132. package/src/shade/renderer/particles/graph/ParticleGraph.d.ts +0 -54
  133. package/src/shade/renderer/particles/graph/ParticleGraph.d.ts.map +0 -1
  134. package/src/shade/renderer/particles/graph/ParticleGraph.js +0 -99
  135. package/src/shade/renderer/particles/prototypeParticleSystem.d.ts +0 -2
  136. package/src/shade/renderer/particles/prototypeParticleSystem.d.ts.map +0 -1
  137. package/src/shade/renderer/particles/prototypeParticleSystem.js +0 -448
@@ -52,7 +52,8 @@ resources.createGroup()
52
52
  // Only textureLoad-ed (soft depth), so it can be unfilterable — matches an r32float scene depth.
53
53
  .addTexture("scene_depth", "unfilterable-float");
54
54
 
55
- const body = CodeChunk.from(/* wgsl */ `
55
+ const body = CodeChunk.from(
56
+ /* language=wgsl */ `
56
57
  const PARTICLE_RECORD_WORDS : u32 = ${PARTICLE_RECORD_WORD_COUNT}u;
57
58
  const PARTICLE_HEADER_EMITTER : u32 = ${PARTICLE_RECORD_HEADER_EMITTER}u;
58
59
  const PARTICLE_ATTRIBUTE_ABSENT : u32 = ${EMITTER_ATTRIBUTE_ABSENT}u;
@@ -165,7 +166,12 @@ const descriptor = ShaderDescriptor.from({ label: "Particle Billboard", body, re
165
166
  * reverse-Z scenes (the engine convention), "less"/"less-equal" for a standard-Z scene
166
167
  * @returns {RenderPipelineDescriptor}
167
168
  */
168
- export function create_particle_billboard_pipeline({ color_format = "rgba16float", depth_format = "depth32float", depth_compare = "greater" } = {}) {
169
+ export function create_particle_billboard_pipeline({
170
+ color_format = "rgba16float",
171
+ depth_format = "depth32float",
172
+ depth_compare = "greater"
173
+ } = {}) {
174
+
169
175
  const code = descriptor.source;
170
176
 
171
177
  return RenderPipelineDescriptor.from({
@@ -184,6 +190,7 @@ export function create_particle_billboard_pipeline({ color_format = "rgba16float
184
190
  : DepthStencilState.from({ format: depth_format, depthWriteEnabled: false, depthCompare: depth_compare }),
185
191
  primitive: { topology: "triangle-list", cullMode: "none" },
186
192
  });
193
+
187
194
  }
188
195
 
189
196
  /** The billboard shader's resource set (for building bind groups + the draw command). */
@@ -1 +1 @@
1
- {"version":3,"file":"shader_particle_simulate.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/shader_particle_simulate.js"],"names":[],"mappings":"AAcA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,+CAHU,aAAa,CAG4B;AAqEnD,qDAIG;8BA3G2B,+BAA+B"}
1
+ {"version":3,"file":"shader_particle_simulate.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/shader_particle_simulate.js"],"names":[],"mappings":"AAcA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,+CAHU,aAAa,CAG4B;AAuEnD,qDAIG;8BA7G2B,+BAA+B"}
@@ -62,7 +62,9 @@ resources.createGroup()
62
62
  .addStorageBuffer("alive_out", WebGPUArray.u32, true)
63
63
  .addStorageBuffer("dead", WebGPUArray.u32, true)
64
64
  .addStorageBuffer("counters", WebGPUArray.from(atomic_u32), true);
65
- const body = CodeChunk.from(/* wgsl */ `
65
+
66
+
67
+ const body = CodeChunk.from(/* language=wgsl */ `
66
68
  const PARTICLE_RECORD_WORDS : u32 = ${PARTICLE_RECORD_WORD_COUNT}u;
67
69
  const PARTICLE_HEADER_EMITTER : u32 = ${PARTICLE_RECORD_HEADER_EMITTER}u;
68
70
  const PARTICLE_INSTRUCTION_WORDS : u32 = ${PARTICLE_VM_INSTRUCTION_WORDS}u;
@@ -33,7 +33,7 @@ import { VM_BUILTIN, VM_OP, VM_RANDOM_MODE } from "../isa/ParticleVMISA.js";
33
33
 
34
34
  const R = PARTICLE_VM_REGISTER_COUNT;
35
35
 
36
- const source = /* wgsl */ `
36
+ const source = /* language=wgsl */ `
37
37
  const PARTICLE_VM_REGISTER_COUNT : u32 = ${R}u;
38
38
  const PARTICLE_VM_MAX_INSTRUCTIONS : u32 = ${PARTICLE_VM_MAX_INSTRUCTIONS}u;
39
39
  const PARTICLE_VM_TWO_PI : f32 = 6.28318530717958647692;
@@ -28,6 +28,17 @@
28
28
  * see {@link chunk_skin_blend_mesh_local} for why it goes into each
29
29
  * matrix rather than onto the blended position.
30
30
  *
31
+ * **`transform_global` on a skinned mesh is the engine's, not the
32
+ * asset's.** It cancels out of the rendered position, so glTF declares
33
+ * it meaningless — and the one meaning it does have is the frame the
34
+ * clone's vertices are written in, which the fold above requires to be
35
+ * rigid against the skin. {@link GPUAnimationManager#register_skin}
36
+ * therefore overwrites it, by way of
37
+ * {@link skin_normalize_mesh_frame}, with the skin's own bind
38
+ * transform. Whatever the file put there is discarded, and anything
39
+ * reading this expecting the file's value is reading the wrong thing.
40
+ * See `renderer/animation/SKINNING_FRAME_PLAN.md`.
41
+ *
31
42
  * The mesh's **skin id** — a row in a GPU table — lives in
32
43
  * {@link GPUMeshSkinningContext} and nowhere else. The CPU-side
33
44
  * {@link Skin} it was registered with is a different thing, pure data
@@ -1 +1 @@
1
- {"version":3,"file":"SkinnedMesh.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/scene/SkinnedMesh.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH;IAEI;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,MAFU,OAAK,IAAI,CAEP;IAEZ;;OAEG;IACH,SAFa,WAAW,CAMvB;IAED;;OAEG;IACH,YAFW,WAAW,QAYrB;IA4CL;;;OAGG;IACH,wBAFU,OAAO,CAEkB;CANlC;qBAnJoB,WAAW"}
1
+ {"version":3,"file":"SkinnedMesh.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/scene/SkinnedMesh.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgEG;AACH;IAEI;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,MAFU,OAAK,IAAI,CAEP;IAEZ;;OAEG;IACH,SAFa,WAAW,CAMvB;IAED;;OAEG;IACH,YAFW,WAAW,QAYrB;IA4CL;;;OAGG;IACH,wBAFU,OAAO,CAEkB;CANlC;qBA9JoB,WAAW"}
@@ -31,6 +31,17 @@ import { Mesh } from "./Mesh.js";
31
31
  * see {@link chunk_skin_blend_mesh_local} for why it goes into each
32
32
  * matrix rather than onto the blended position.
33
33
  *
34
+ * **`transform_global` on a skinned mesh is the engine's, not the
35
+ * asset's.** It cancels out of the rendered position, so glTF declares
36
+ * it meaningless — and the one meaning it does have is the frame the
37
+ * clone's vertices are written in, which the fold above requires to be
38
+ * rigid against the skin. {@link GPUAnimationManager#register_skin}
39
+ * therefore overwrites it, by way of
40
+ * {@link skin_normalize_mesh_frame}, with the skin's own bind
41
+ * transform. Whatever the file put there is discarded, and anything
42
+ * reading this expecting the file's value is reading the wrong thing.
43
+ * See `renderer/animation/SKINNING_FRAME_PLAN.md`.
44
+ *
34
45
  * The mesh's **skin id** — a row in a GPU table — lives in
35
46
  * {@link GPUMeshSkinningContext} and nowhere else. The CPU-side
36
47
  * {@link Skin} it was registered with is a different thing, pure data
@@ -1,7 +1,37 @@
1
1
  /**
2
- * @see https://github.com/KosRud/DQ-skinning-for-Unity/blob/9d096e2db57677f0f67a823432f8b735ad622404/Code/DQ%20skinning/Shaders/Compute/DQ.cginc#L59
3
- * @see http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
4
- * Alternative Method by Christian
2
+ * A rigid transform as a dual quaternion: the rotation in the real part, the translation carried in
3
+ * the dual part as `0.5 · t · real`.
4
+ *
5
+ * The matrix's upper 3×3 is read as a rotation and its fourth column as a translation. Anything else
6
+ * in the matrix — a scale, a shear — has nowhere to go, and comes back as neither itself nor a
7
+ * warning: see {@link m4_rigidity_defect} for the number that says so and
8
+ * `renderer/animation/SKINNING_FRAME_PLAN.md` for the frame arrangement that keeps a skinning
9
+ * matrix rigid in the first place.
10
+ *
11
+ * ## Why the rotation goes through `quat_from_m3`
12
+ *
13
+ * This used to take all four quaternion components as `sqrt(max(0, 1 ± m00 ± m11 ± m22)) · 0.5` and
14
+ * recover their signs from the off-diagonal differences. That is exact in exact arithmetic and
15
+ * badly conditioned in floating point: near the identity three of those radicands are near zero, and
16
+ * a square root turns an input error of `e` into an output error of `sqrt(e)`. A matrix that is the
17
+ * identity to `1e-6` — which is what a skin's folded joint matrices are at bind pose — yielded
18
+ * quaternion components off by `9e-4`, an angular error of `1.8e-3` radians, and a millimetre and a
19
+ * half of vertex displacement on a 1.66 m character. Measured, on `Michelle.glb`.
20
+ *
21
+ * {@link chunk_quat_from_m3} is Shoemake's branch-picking form: it computes whichever component the
22
+ * matrix's diagonal says is largest, and derives the other three from it by division. Every branch
23
+ * divides by at least 2, so the components come out **linear** in the input error rather than as its
24
+ * square root — the same `1e-6` matrix now gives `2.5e-7`, three and a half orders better — and the
25
+ * near-180° case, where the trace form is ill-conditioned for the opposite reason, is a branch of its
26
+ * own. One `sqrt` and a reciprocal where there were four `sqrt`s.
27
+ *
28
+ * The normalize stays, on top of that. It is a no-op for the orthonormal input this is meant to be
29
+ * given; what it earns its rsqrt for is the input that is not — a degenerate 3×3 leaves
30
+ * `quat_from_m3` on a branch whose answer has length 0.5, and this is what keeps the documented
31
+ * postcondition, a unit real part, true anyway.
32
+ *
33
+ * @see https://gitlab.com/libeigen/eigen/-/blob/master/Eigen/src/Geometry/Quaternion.h#L813
34
+ * @type {CodeChunk}
5
35
  */
6
36
  export const chunk_dual_quat_from_m4: CodeChunk;
7
37
  import { CodeChunk } from "../../../../compiler/CodeChunk.js";
@@ -1 +1 @@
1
- {"version":3,"file":"chunk_dual_quat_from_m4.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/shade/renderer/shader/chunk/geometry/quaternion/dual/chunk_dual_quat_from_m4.js"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,gDA2BC;0BApCyB,mCAAmC"}
1
+ {"version":3,"file":"chunk_dual_quat_from_m4.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/shade/renderer/shader/chunk/geometry/quaternion/dual/chunk_dual_quat_from_m4.js"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,sCAFU,SAAS,CAoBlB;0BAzDyB,mCAAmC"}
@@ -1,37 +1,58 @@
1
- import { CodeChunk } from "../../../../compiler/CodeChunk.js";
2
- import { chunk_sign_not_zero } from "../../../math/chunk_sign_not_zero.js";
3
- import { chunk_quat_multiply } from "../chunk_quat_multiply.js";
4
-
5
- /**
6
- * @see https://github.com/KosRud/DQ-skinning-for-Unity/blob/9d096e2db57677f0f67a823432f8b735ad622404/Code/DQ%20skinning/Shaders/Compute/DQ.cginc#L59
7
- * @see http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
8
- * Alternative Method by Christian
9
- */
10
- export const chunk_dual_quat_from_m4 = CodeChunk.from(
11
- //language=WGSL
12
- `
13
- fn dual_quat_from_m4(m: mat4x4<f32>) -> mat2x4<f32> {
14
-
15
- var dq: mat2x4<f32>;
16
-
17
- dq[0].w = sqrt(max(0, 1.0 + m[0][0] + m[1][1] + m[2][2])) * 0.5;
18
- dq[0].x = sqrt(max(0, 1.0 + m[0][0] - m[1][1] - m[2][2])) * 0.5;
19
- dq[0].y = sqrt(max(0, 1.0 - m[0][0] + m[1][1] - m[2][2])) * 0.5;
20
- dq[0].z = sqrt(max(0, 1.0 - m[0][0] - m[1][1] + m[2][2])) * 0.5;
21
-
22
- dq[0].x *= sign_not_zero(m[1][2] - m[2][1]);
23
- dq[0].y *= sign_not_zero(m[2][0] - m[0][2]);
24
- dq[0].z *= sign_not_zero(m[0][1] - m[1][0]);
25
-
26
- dq[0] = normalize(dq[0]); // ensure unit quaternion
27
-
28
- dq[1] = vec4(m[3][0], m[3][1], m[3][2], 0);
29
- dq[1] = quat_multiply(dq[1], dq[0]) * 0.5;
30
-
31
- return dq;
32
- }
33
- `,[
34
- chunk_quat_multiply,
35
- chunk_sign_not_zero
36
- ]
37
- )
1
+ import { CodeChunk } from "../../../../compiler/CodeChunk.js";
2
+ import { chunk_quat_from_m3 } from "../chunk_quat_from_m3.js";
3
+ import { chunk_quat_multiply } from "../chunk_quat_multiply.js";
4
+
5
+ /**
6
+ * A rigid transform as a dual quaternion: the rotation in the real part, the translation carried in
7
+ * the dual part as `0.5 · t · real`.
8
+ *
9
+ * The matrix's upper 3×3 is read as a rotation and its fourth column as a translation. Anything else
10
+ * in the matrix — a scale, a shear — has nowhere to go, and comes back as neither itself nor a
11
+ * warning: see {@link m4_rigidity_defect} for the number that says so and
12
+ * `renderer/animation/SKINNING_FRAME_PLAN.md` for the frame arrangement that keeps a skinning
13
+ * matrix rigid in the first place.
14
+ *
15
+ * ## Why the rotation goes through `quat_from_m3`
16
+ *
17
+ * This used to take all four quaternion components as `sqrt(max(0, 1 ± m00 ± m11 ± m22)) · 0.5` and
18
+ * recover their signs from the off-diagonal differences. That is exact in exact arithmetic and
19
+ * badly conditioned in floating point: near the identity three of those radicands are near zero, and
20
+ * a square root turns an input error of `e` into an output error of `sqrt(e)`. A matrix that is the
21
+ * identity to `1e-6` — which is what a skin's folded joint matrices are at bind pose — yielded
22
+ * quaternion components off by `9e-4`, an angular error of `1.8e-3` radians, and a millimetre and a
23
+ * half of vertex displacement on a 1.66 m character. Measured, on `Michelle.glb`.
24
+ *
25
+ * {@link chunk_quat_from_m3} is Shoemake's branch-picking form: it computes whichever component the
26
+ * matrix's diagonal says is largest, and derives the other three from it by division. Every branch
27
+ * divides by at least 2, so the components come out **linear** in the input error rather than as its
28
+ * square root — the same `1e-6` matrix now gives `2.5e-7`, three and a half orders better — and the
29
+ * near-180° case, where the trace form is ill-conditioned for the opposite reason, is a branch of its
30
+ * own. One `sqrt` and a reciprocal where there were four `sqrt`s.
31
+ *
32
+ * The normalize stays, on top of that. It is a no-op for the orthonormal input this is meant to be
33
+ * given; what it earns its rsqrt for is the input that is not — a degenerate 3×3 leaves
34
+ * `quat_from_m3` on a branch whose answer has length 0.5, and this is what keeps the documented
35
+ * postcondition, a unit real part, true anyway.
36
+ *
37
+ * @see https://gitlab.com/libeigen/eigen/-/blob/master/Eigen/src/Geometry/Quaternion.h#L813
38
+ * @type {CodeChunk}
39
+ */
40
+ export const chunk_dual_quat_from_m4 = CodeChunk.from(
41
+ //language=WGSL
42
+ `
43
+ fn dual_quat_from_m4(m: mat4x4<f32>) -> mat2x4<f32> {
44
+
45
+ var dq: mat2x4<f32>;
46
+
47
+ dq[0] = normalize(quat_from_m3(mat3x3<f32>(m[0].xyz, m[1].xyz, m[2].xyz)));
48
+
49
+ dq[1] = vec4(m[3][0], m[3][1], m[3][2], 0);
50
+ dq[1] = quat_multiply(dq[1], dq[0]) * 0.5;
51
+
52
+ return dq;
53
+ }
54
+ `, [
55
+ chunk_quat_from_m3,
56
+ chunk_quat_multiply,
57
+ ]
58
+ )
@@ -1,54 +0,0 @@
1
- /**
2
- * Wrap a scalar or vector as a literal source (so it is unambiguous vs. a node id).
3
- * @param {...number} components
4
- * @returns {number[]}
5
- */
6
- export function literal(...components: number[]): number[];
7
- /**
8
- * A directed acyclic graph describing one lifecycle phase (SPAWN or UPDATE) of a particle effect.
9
- *
10
- * Nodes are value-producing operations (constants, builtins, attribute reads, math, curves, random)
11
- * or sinks (attribute writes, kill). Edges wire a producing node's single `out` port to a consuming
12
- * node's named input port. Inputs may also be literal `vec4` values, which the compiler lowers to
13
- * constant loads.
14
- *
15
- * The graph is pure data + a small builder; {@link ../graph/compile_particle_graph.js} lowers it to
16
- * VM bytecode.
17
- */
18
- export class ParticleGraph {
19
- /** @type {Map<number, {id: number, type: string, params: object, inputs: Map<string, object>}>} */
20
- nodes: Map<number, {
21
- id: number;
22
- type: string;
23
- params: object;
24
- inputs: Map<string, object>;
25
- }>;
26
- /** @type {number} */
27
- next_id: number;
28
- /**
29
- * Add a node.
30
- * @param {string} type a key in {@link PARTICLE_NODE_TYPES}
31
- * @param {object} [params] static parameters (attribute name, builtin id, constant value, …)
32
- * @returns {number} the new node id
33
- */
34
- add(type: string, params?: object): number;
35
- /**
36
- * Bind an input port of a node to a source.
37
- *
38
- * The source may be:
39
- * - a node id (number) → that node's `out` port,
40
- * - `{ node, port }` → an explicit port,
41
- * - a number or array → a literal `vec4` (scalars broadcast is NOT applied; `5` means `[5,0,0,0]`).
42
- *
43
- * @param {number} node_id
44
- * @param {string} port
45
- * @param {number|number[]|{node: number, port?: string}} source
46
- * @returns {ParticleGraph} this, for chaining
47
- */
48
- wire(node_id: number, port: string, source: number | number[] | {
49
- node: number;
50
- port?: string;
51
- }): ParticleGraph;
52
- #private;
53
- }
54
- //# sourceMappingURL=ParticleGraph.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ParticleGraph.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/graph/ParticleGraph.js"],"names":[],"mappings":"AA2FA;;;;GAIG;AACH,uCAHc,MAAM,KACP,MAAM,EAAE,CAIpB;AA/FD;;;;;;;;;;GAUG;AACH;IAEQ,mGAAmG;IACnG,OADW,IAAI,MAAM,EAAE;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,IAAI,MAAM,EAAE,MAAM,CAAC,CAAA;KAAC,CAAC,CACzE;IACtB,qBAAqB;IACrB,SADW,MAAM,CACD;IAGpB;;;;;OAKG;IACH,UAJW,MAAM,WACN,MAAM,GACJ,MAAM,CAWlB;IAED;;;;;;;;;;;;OAYG;IACH,cALW,MAAM,QACN,MAAM;cACiB,MAAM;eAAS,MAAM;QAC1C,aAAa,CAYzB;;CAQJ"}
@@ -1,99 +0,0 @@
1
- import { assert } from "../../../../core/assert.js";
2
- import { PARTICLE_NODE_TYPES } from "./ParticleNodeRegistry.js";
3
-
4
- /**
5
- * A directed acyclic graph describing one lifecycle phase (SPAWN or UPDATE) of a particle effect.
6
- *
7
- * Nodes are value-producing operations (constants, builtins, attribute reads, math, curves, random)
8
- * or sinks (attribute writes, kill). Edges wire a producing node's single `out` port to a consuming
9
- * node's named input port. Inputs may also be literal `vec4` values, which the compiler lowers to
10
- * constant loads.
11
- *
12
- * The graph is pure data + a small builder; {@link ../graph/compile_particle_graph.js} lowers it to
13
- * VM bytecode.
14
- */
15
- export class ParticleGraph {
16
- constructor() {
17
- /** @type {Map<number, {id: number, type: string, params: object, inputs: Map<string, object>}>} */
18
- this.nodes = new Map();
19
- /** @type {number} */
20
- this.next_id = 0;
21
- }
22
-
23
- /**
24
- * Add a node.
25
- * @param {string} type a key in {@link PARTICLE_NODE_TYPES}
26
- * @param {object} [params] static parameters (attribute name, builtin id, constant value, …)
27
- * @returns {number} the new node id
28
- */
29
- add(type, params = {}) {
30
- const definition = PARTICLE_NODE_TYPES[type];
31
- if (definition === undefined) {
32
- throw new Error(`Unknown particle node type '${type}'`);
33
- }
34
-
35
- const id = this.next_id++;
36
- this.nodes.set(id, { id, type, params, inputs: new Map() });
37
- return id;
38
- }
39
-
40
- /**
41
- * Bind an input port of a node to a source.
42
- *
43
- * The source may be:
44
- * - a node id (number) → that node's `out` port,
45
- * - `{ node, port }` → an explicit port,
46
- * - a number or array → a literal `vec4` (scalars broadcast is NOT applied; `5` means `[5,0,0,0]`).
47
- *
48
- * @param {number} node_id
49
- * @param {string} port
50
- * @param {number|number[]|{node: number, port?: string}} source
51
- * @returns {ParticleGraph} this, for chaining
52
- */
53
- wire(node_id, port, source) {
54
- const node = this.#require(node_id);
55
-
56
- const definition = PARTICLE_NODE_TYPES[node.type];
57
- if (!definition.inputs.includes(port)) {
58
- throw new Error(`Node '${node.type}' has no input port '${port}'`);
59
- }
60
-
61
- node.inputs.set(port, normalize_source(source));
62
- return this;
63
- }
64
-
65
- /** @param {number} id @returns {{id, type, params, inputs}} */
66
- #require(id) {
67
- const node = this.nodes.get(id);
68
- assert.defined(node, `node ${id}`);
69
- return node;
70
- }
71
- }
72
-
73
- /**
74
- * @param {number|number[]|{node:number,port?:string}} source
75
- * @returns {{kind: "node", node: number, port: string} | {kind: "literal", value: number[]}}
76
- */
77
- function normalize_source(source) {
78
- if (typeof source === "number") {
79
- // Could be a node id or a scalar literal — ambiguous, so require explicit forms for literals.
80
- return { kind: "node", node: source, port: "out" };
81
- }
82
- if (Array.isArray(source)) {
83
- const value = [source[0] ?? 0, source[1] ?? 0, source[2] ?? 0, source[3] ?? 0];
84
- return { kind: "literal", value };
85
- }
86
- if (source !== null && typeof source === "object" && typeof source.node === "number") {
87
- return { kind: "node", node: source.node, port: source.port ?? "out" };
88
- }
89
- throw new Error(`Invalid input source: ${JSON.stringify(source)}`);
90
- }
91
-
92
- /**
93
- * Wrap a scalar or vector as a literal source (so it is unambiguous vs. a node id).
94
- * @param {...number} components
95
- * @returns {number[]}
96
- */
97
- export function literal(...components) {
98
- return components;
99
- }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=prototypeParticleSystem.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"prototypeParticleSystem.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/particles/prototypeParticleSystem.js"],"names":[],"mappings":""}