@woosh/meep-engine 2.33.24 → 2.33.28

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 (126) hide show
  1. package/core/binary/BitSet.js +151 -167
  2. package/core/binary/BitSet.spec.js +99 -1
  3. package/core/binary/ValidatingBitSetWrapper.js +81 -0
  4. package/core/bvh2/aabb3/AABB3.js +3 -10
  5. package/core/bvh2/binary/IndexedBinaryBVH.js +1 -1
  6. package/core/bvh2/traversal/ThreeClippingPlaneComputingBVHVisitor.js +5 -1
  7. package/core/bvh2/traversal/__detailed_box_volume_intersection.js +22 -5
  8. package/core/cache/Cache.d.ts +4 -2
  9. package/core/cache/Cache.js +5 -2
  10. package/core/collection/HashMap.d.ts +9 -2
  11. package/core/collection/HashSet.d.ts +7 -2
  12. package/core/collection/HashSet.js +7 -2
  13. package/core/collection/array/binarySearchHighIndex.js +1 -1
  14. package/core/collection/array/copyArray.js +2 -2
  15. package/core/collection/array/typed/typed_array_copy.js +1 -1
  16. package/core/geom/3d/frustum/array_setFromProjectionMatrix.js +3 -3
  17. package/core/geom/3d/normal/hemioct/unit_hemioct.spec.js +1 -1
  18. package/core/geom/3d/shape/AbstractShape3D.js +37 -1
  19. package/core/geom/3d/shape/TransformedShape3D.js +121 -10
  20. package/core/geom/3d/shape/TransformedShape3D.spec.js +33 -0
  21. package/core/geom/3d/shape/UnionShape3D.js +255 -0
  22. package/core/geom/3d/shape/UnitCubeShape3D.js +88 -0
  23. package/core/geom/3d/shape/UnitCubeShape3D.spec.js +42 -0
  24. package/core/geom/3d/shape/UnitSphereShape3D.js +39 -0
  25. package/core/geom/3d/shape/util/compute_signed_distance_gradient_by_sampling.js +48 -0
  26. package/core/geom/3d/shape/util/shape_to_visual_entity.js +159 -0
  27. package/core/geom/random/randomPointInSphere.js +3 -2
  28. package/core/json/resolvePathByArray.js +2 -2
  29. package/core/model/ObservedBoolean.d.ts +2 -0
  30. package/core/parser/simple/Token.d.ts +13 -0
  31. package/core/parser/simple/Token.js +61 -27
  32. package/{engine/graphics/render/forward_plus/materials → core/primitives/strings}/insert_after.js +3 -0
  33. package/core/primitives/strings/insert_after_or_replace.js +27 -0
  34. package/editor/process/symbolic/makeHelperBoxGeometry.js +44 -0
  35. package/editor/tools/FoliagePaintTool.js +4 -4
  36. package/editor/view/ecs/EntityEditor.js +2 -2
  37. package/editor/view/ecs/components/particles/ParticleEmitterController.js +2 -2
  38. package/engine/EngineHarness.js +1 -0
  39. package/engine/animation/AnimationUtils.js +5 -5
  40. package/engine/asset/loaders/GLTFAssetLoader.js +52 -1
  41. package/engine/asset/loaders/image/ImageDecoderWorker.js +4 -3
  42. package/engine/asset/loaders/image/ImageRGBADataAsset.js +3 -2
  43. package/engine/asset/loaders/image/ImageRGBADataLoader.js +3 -3
  44. package/engine/asset/loaders/image/codec/NativeImageDecoder.js +2 -1
  45. package/engine/asset/loaders/image/png/PNG.js +113 -6
  46. package/engine/asset/loaders/image/png/PNGReader.js +5 -0
  47. package/engine/asset/loaders/material/bitmap2sampler_gl.js +1 -1
  48. package/engine/asset/loaders/material/computeImageBitmapEquality.js +6 -1
  49. package/engine/asset/loaders/material/computeTextureEquality.js +40 -49
  50. package/engine/ecs/EntityBuilder.js +25 -5
  51. package/engine/ecs/EntityComponentDataset.js +1 -1
  52. package/engine/ecs/attachment/AttachmentBinding.js +8 -0
  53. package/engine/ecs/attachment/AttachmentSystem.js +4 -0
  54. package/engine/ecs/attachment/TransformAttachmentBinding.js +14 -44
  55. package/engine/ecs/components/Tag.js +27 -6
  56. package/engine/ecs/foliage/InstancedFoliage.js +277 -266
  57. package/engine/ecs/foliage/ecs/Foliage2System.js +7 -7
  58. package/engine/ecs/foliage/ecs/InstancedMeshComponent.js +37 -0
  59. package/engine/ecs/foliage/ecs/{Foliage2.js → InstancedMeshLayer.js} +3 -45
  60. package/engine/ecs/foliage/ecs/InstancedMeshSerializationAdapter.js +6 -5
  61. package/engine/ecs/foliage/ecs/InstancedMeshUtils.js +7 -6
  62. package/engine/ecs/fow/FogOfWar.js +4 -0
  63. package/engine/ecs/fow/FogOfWarSystem.js +2 -0
  64. package/engine/ecs/gui/hud/HeadsUpDisplaySystem.js +2 -0
  65. package/engine/ecs/storage/binary/BinarySerializationRegistry.js +1 -1
  66. package/engine/ecs/system/AbstractContextSystem.js +1 -1
  67. package/engine/ecs/systems/TagSystem.js +17 -0
  68. package/engine/ecs/terrain/ecs/layers/TerrainLayer.js +12 -16
  69. package/engine/ecs/transform/Transform.js +19 -6
  70. package/engine/graphics/GraphicsEngine.js +11 -6
  71. package/engine/graphics/composit/CompositLayer.js +17 -4
  72. package/engine/graphics/composit/CompositingStages.js +8 -0
  73. package/engine/graphics/composit/LayerCompositer.js +35 -6
  74. package/engine/graphics/ecs/highlight/plugin/OutlineRenderPlugin.js +11 -7
  75. package/engine/graphics/ecs/light/Light.js +2 -0
  76. package/engine/graphics/ecs/light/binding/three/ThreeLightBinding.js +5 -1
  77. package/engine/graphics/ecs/mesh-v2/DrawMode.js +5 -0
  78. package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +32 -18
  79. package/engine/graphics/geometry/instancing/InstancedMeshGroup.js +14 -72
  80. package/engine/graphics/geometry/instancing/rewriteMaterial.js +70 -0
  81. package/engine/graphics/material/manager/MaterialManager.js +2 -1
  82. package/engine/graphics/micron/render/instanced/AttributeDataTexture.js +6 -4
  83. package/engine/graphics/micron/render/instanced/ThreeInstancedAdapter.js +0 -2
  84. package/engine/graphics/particles/ParticleEmitterLibrary.js +3 -0
  85. package/engine/graphics/particles/ecs/{ParticleEmitterSystem2.js → ParticleEmitterSystem.js} +17 -9
  86. package/engine/graphics/particles/particular/engine/ParticularEngine.js +8 -2
  87. package/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.js +14 -25
  88. package/engine/graphics/particles/particular/engine/emitter/ParticleEmitterFlag.js +5 -0
  89. package/engine/graphics/particles/particular/engine/emitter/ParticlePool.js +90 -2
  90. package/engine/graphics/particles/particular/engine/emitter/ParticlePool.spec.js +7 -7
  91. package/engine/graphics/particles/particular/engine/renderers/billboard/BILLBOARD_PARTICLE_SPECIFICATION.js +15 -12
  92. package/engine/graphics/particles/particular/engine/renderers/billboard/ParticleBillboardMaterial.js +262 -51
  93. package/engine/graphics/particles/particular/engine/shader/ShaderManager.js +81 -48
  94. package/engine/graphics/particles/particular/engine/shader/debugAtlas.js +14 -0
  95. package/engine/graphics/particles/particular/engine/utils/volume/AttributeValue.js +141 -0
  96. package/engine/graphics/particles/particular/engine/utils/volume/ParticleVolume.js +148 -54
  97. package/engine/graphics/particles/particular/engine/utils/volume/lut_to_sampler.js +27 -0
  98. package/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +544 -164
  99. package/engine/graphics/render/buffer/simple-fx/ao/AmbientOcclusionPostProcessEffect.js +15 -10
  100. package/engine/graphics/render/forward_plus/materials/FP_INJECTION_POINT_ACCUMULATION.js +1 -0
  101. package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_ACCUMULATION.js +32 -0
  102. package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_DECODE_PARS.js +51 -0
  103. package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_PREAMBLE.js +25 -0
  104. package/engine/graphics/render/forward_plus/materials/FPlusDebugMaterial.js +3 -3
  105. package/engine/graphics/render/forward_plus/materials/ForwardPlusThreeMaterial.js +1 -1
  106. package/engine/graphics/render/forward_plus/materials/fp_build_fragment_shader.js +31 -120
  107. package/engine/graphics/render/forward_plus/materials/fp_build_vertex_lighting_shared.js +35 -0
  108. package/engine/graphics/render/forward_plus/materials/fp_build_vertex_shader.js +4 -5
  109. package/engine/graphics/render/forward_plus/plugin/MaterialTransformer.js +10 -3
  110. package/engine/graphics/render/forward_plus/plugin/ptototypeFPPlugin.js +588 -53
  111. package/engine/graphics/render/forward_plus/prototypeLightManager.js +31 -6
  112. package/engine/graphics/render/forward_plus/query/point_light_inside_volume.js +10 -9
  113. package/engine/graphics/shaders/TerrainShader.js +4 -5
  114. package/engine/graphics/shadows/ShadowMapRenderer.js +8 -2
  115. package/engine/graphics/texture/atlas/ManagedTextureAtlas.js +12 -1
  116. package/engine/graphics/texture/sampler/Sampler2D.js +3 -1
  117. package/engine/graphics/texture/sampler/convertTexture2Sampler2D.js +1 -1
  118. package/engine/graphics/texture/sampler/copy_Sampler2D_channel_data.js +66 -0
  119. package/engine/graphics/util/composeMatrix4.js +33 -23
  120. package/engine/graphics/util/decompose_matrix_4_array.js +61 -0
  121. package/engine/intelligence/behavior/ecs/BehaviorComponent.js +30 -14
  122. package/engine/knowledge/database/StaticKnowledgeDataTable.js +6 -1
  123. package/engine/navigation/ecs/components/Path.js +0 -5
  124. package/package.json +1 -1
  125. package/view/minimap/gl/MinimapWorldGL.js +12 -5
  126. package/core/geom/3d/shape/CompositeShape.js +0 -60
@@ -0,0 +1,81 @@
1
+ //
2
+
3
+ /**
4
+ * Debug tool to verify correct behavior of a BitSet
5
+ */
6
+ export class ValidatingBitSetWrapper {
7
+ /**
8
+ *
9
+ * @param {BitSet} source
10
+ */
11
+ constructor(source) {
12
+ this.__source = source;
13
+ }
14
+
15
+ preventShrink() {
16
+ this.__source.preventShrink();
17
+ }
18
+
19
+ setShrinkFactor(x) {
20
+ this.__source.setShrinkFactor(x);
21
+ }
22
+
23
+ setCapacity(x) {
24
+ this.__source.setCapacity(x);
25
+ }
26
+
27
+ size() {
28
+ return this.__source.size();
29
+ }
30
+
31
+ capacity() {
32
+ return this.__source.capacity();
33
+ }
34
+
35
+ previousSetBit(i) {
36
+ const bit = this.__source.previousSetBit(i);
37
+
38
+ if (bit !== -1 && (this.__source.get(bit) !== true || bit > i)) {
39
+ debugger;
40
+ }
41
+
42
+ return bit;
43
+ }
44
+
45
+ nextSetBit(i) {
46
+ const bit = this.__source.nextSetBit(i);
47
+
48
+ if (bit !== -1 && (this.__source.get(bit) !== true || bit < i)) {
49
+ debugger;
50
+ }
51
+
52
+ return bit;
53
+ }
54
+
55
+ nextClearBit(i) {
56
+ const bit = this.__source.nextClearBit(i);
57
+
58
+ if (bit !== -1 && (this.__source.get(bit) !== false || bit < i)) {
59
+ debugger;
60
+ }
61
+
62
+ return bit;
63
+ }
64
+
65
+ set(x, y) {
66
+ this.__source.set(x, y);
67
+ }
68
+
69
+ clear(i) {
70
+ this.__source.clear(i);
71
+ }
72
+
73
+ get(i) {
74
+ return this.__source.get(i);
75
+ }
76
+
77
+
78
+ reset() {
79
+ this.__source.reset();
80
+ }
81
+ }
@@ -761,16 +761,9 @@ AABB3.prototype.computePlaneSide = function computePlaneSide(plane) {
761
761
  const normal = plane.normal;
762
762
 
763
763
  return computeAABB3PlaneSide(
764
- normal.x,
765
- normal.y,
766
- normal.z,
767
- plane.constant,
768
- this.x0,
769
- this.y0,
770
- this.z0,
771
- this.x1,
772
- this.y1,
773
- this.z1
764
+ normal.x, normal.y, normal.z, plane.constant,
765
+ this.x0, this.y0, this.z0,
766
+ this.x1, this.y1, this.z1
774
767
  );
775
768
  };
776
769
 
@@ -344,7 +344,7 @@ function writeBox(array, address, x0, y0, z0, x1, y1, z1) {
344
344
  * @param {Float32Array} array
345
345
  */
346
346
  function copyBox(from, to, array) {
347
- array_copy(data, from, scratch_aabb_0, to, 6);
347
+ array_copy(array, from, array, to, 6);
348
348
  }
349
349
 
350
350
  /**
@@ -40,7 +40,11 @@ export class ThreeClippingPlaneComputingBVHVisitor extends BVHVisitor {
40
40
  */
41
41
  this.__nearPlaneConstant = 0;
42
42
 
43
-
43
+ /**
44
+ *
45
+ * @type {Float32Array}
46
+ * @private
47
+ */
44
48
  this.__planes_f32 = new Float32Array(24);
45
49
 
46
50
  this.near = 0;
@@ -7,37 +7,54 @@ import { __process_point_if_within_planes } from "./__process_point_if_within_pl
7
7
  import { plane_computeConvex3PlaneIntersection } from "../../geom/3d/plane/plane_computeConvex3PlaneIntersection.js";
8
8
  import { EPSILON } from "../../math/MathUtils.js";
9
9
 
10
+ /**
11
+ * Common piece of continuous memory for better cache coherence
12
+ * @type {ArrayBuffer}
13
+ * @private
14
+ */
15
+ const __scratch_buffer = new ArrayBuffer(
16
+ 24 * 4
17
+ + 24 * 4
18
+ + 8 * 4
19
+ + 3 * 4
20
+ );
21
+
10
22
  /**
11
23
  *
12
24
  * @type {number[]}
13
25
  */
14
- const scratch_aabb_corners = new Float32Array(24);
26
+ const scratch_aabb_corners = new Float32Array(__scratch_buffer, 0, 24);
15
27
 
16
28
  /**
17
29
  *
18
30
  * @type {number[]}
19
31
  */
20
- const scratch_aabb_planes = new Float32Array(24);
32
+ const scratch_aabb_planes = new Float32Array(__scratch_buffer, 96, 24);
21
33
 
22
34
  /**
23
35
  *
24
36
  * @type {number[]}
25
37
  */
26
- const scratch_corner_out_bitfields = new Uint32Array(8);
38
+ const scratch_corner_out_bitfields = new Uint32Array(__scratch_buffer, 192, 8);
27
39
 
28
40
  /**
29
41
  *
30
42
  * @type {number[]}
31
43
  */
32
- const scratch_v3_array = new Float32Array(3);
44
+ const scratch_v3_array = new Float32Array(__scratch_buffer, 224, 3);
33
45
 
34
46
  /**
47
+ * Figures out intersection volume between an AABB and a frustum for much tighter bounds
48
+ *
49
+ * Especially beneficial when trying to intersect a large AABB against a small frustum,
50
+ * where where traditionally only AABB corners would be considered,
51
+ * we're instead able to compute minimum bounds of the overlap of the two
35
52
  *
36
53
  * @param {AABB3} box
37
54
  * @param {number[]} planes
38
55
  * @param {number} plane_count
39
56
  * @param {number} plane_mask
40
- * @param {function} callback
57
+ * @param {function(x:number,y:number,z:number)} callback
41
58
  * @param {*} [thisArg]
42
59
  * @private
43
60
  */
@@ -4,13 +4,15 @@ export class Cache<K, V> {
4
4
  keyWeigher,
5
5
  valueWeigher,
6
6
  keyHashFunction,
7
- keyEqualityFunction
7
+ keyEqualityFunction,
8
+ capacity
8
9
  }?: {
9
10
  maxWeight?: number,
10
11
  keyWeigher?: (key: K) => number,
11
12
  valueWeigher?: (value: V) => number,
12
13
  keyHashFunction?: (key: K) => number,
13
- keyEqualityFunction?: (a: K, b: K) => boolean
14
+ keyEqualityFunction?: (a: K, b: K) => boolean,
15
+ capacity?: number
14
16
  })
15
17
 
16
18
  size(): number
@@ -16,6 +16,7 @@ export class Cache {
16
16
  * @param {function(key:Key, value:Value)} [removeListener] will be notified when element is either explicitly removed or evicted
17
17
  * @param {function(Key):number} [keyHashFunction]
18
18
  * @param {function(Key, Key):boolean} [keyEqualityFunction]
19
+ * @param {number} capacity initial capacity for the cache, helps prevent early resizing
19
20
  * @constructor
20
21
  * @template Key, Value
21
22
  */
@@ -25,7 +26,8 @@ export class Cache {
25
26
  valueWeigher = returnOne,
26
27
  removeListener = noop,
27
28
  keyHashFunction = returnZero,
28
- keyEqualityFunction = strictEquals
29
+ keyEqualityFunction = strictEquals,
30
+ capacity
29
31
  } = {}) {
30
32
 
31
33
  assert.isNumber(maxWeight, 'maxWeight');
@@ -95,7 +97,8 @@ export class Cache {
95
97
  */
96
98
  this.data = new HashMap({
97
99
  keyHashFunction,
98
- keyEqualityFunction
100
+ keyEqualityFunction,
101
+ capacity
99
102
  });
100
103
 
101
104
  /**
@@ -1,7 +1,14 @@
1
1
  export class HashMap<K, V> implements Iterable<[V, K]> {
2
- constructor({keyHashFunction, keyEqualityFunction}: {
2
+ constructor({
3
+ keyHashFunction,
4
+ keyEqualityFunction,
5
+ capacity,
6
+ loadFactor
7
+ }: {
3
8
  keyHashFunction: (k: K) => number,
4
- keyEqualityFunction: (a: K, b: K) => boolean
9
+ keyEqualityFunction: (a: K, b: K) => boolean,
10
+ capacity?: number,
11
+ loadFactor?: number
5
12
  })
6
13
 
7
14
  constructor()
@@ -1,7 +1,12 @@
1
1
  export class HashSet<T> {
2
- constructor({keyHashFunction, keyEqualityFunction}: {
2
+ constructor({
3
+ keyHashFunction,
4
+ keyEqualityFunction,
5
+ capacity
6
+ }: {
3
7
  keyHashFunction: (k: T) => number,
4
- keyEqualityFunction: (a: T, b: T) => boolean
8
+ keyEqualityFunction: (a: T, b: T) => boolean,
9
+ capacity?: number
5
10
  })
6
11
 
7
12
  constructor()
@@ -11,7 +11,11 @@ export class HashSet {
11
11
  /**
12
12
  * @template T
13
13
  */
14
- constructor({ keyHashFunction = invokeObjectHash, keyEqualityFunction = invokeObjectEquals } = {}) {
14
+ constructor({
15
+ keyHashFunction = invokeObjectHash,
16
+ keyEqualityFunction = invokeObjectEquals,
17
+ capacity
18
+ } = {}) {
15
19
 
16
20
  /**
17
21
  * Using HashMap as a backing, this is not the most efficient approach, but it works
@@ -20,7 +24,8 @@ export class HashSet {
20
24
  */
21
25
  this.__map = new HashMap({
22
26
  keyHashFunction,
23
- keyEqualityFunction
27
+ keyEqualityFunction,
28
+ capacity
24
29
  });
25
30
  }
26
31
 
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @template T,V
3
- * @param {T[]} array
3
+ * @param {T[]|ArrayLike<T>|Float32Array} array
4
4
  * @param {V} el
5
5
  * @param {function(V,T):number} compareFunction
6
6
  * @param {number} [minIndex]
@@ -25,9 +25,9 @@ export function copyArray(source, target) {
25
25
  * Follows Java System.arraycopy interface
26
26
  * Copy data from one array to another
27
27
  * @template T
28
- * @param {T[]|ArrayLike<T>|TypedArray|Uint8ClampedArray|Uint8Array} source The source array
28
+ * @param {T[]|ArrayLike<T>|TypedArray|Uint8ClampedArray|Uint8Array|Float32Array|Float64Array} source The source array
29
29
  * @param {number} source_position Starting position where to copy from inside the source array
30
- * @param {T[]|ArrayLike<T>|TypedArray|Uint8ClampedArray|Uint8Array} destination The destination array
30
+ * @param {T[]|ArrayLike<T>|TypedArray|Uint8ClampedArray|Uint8Array|Float32Array|Float64Array} destination The destination array
31
31
  * @param {number} destination_position Starting position where to copy to inside the destination array
32
32
  * @param {number} length How many elements should be copied
33
33
  */
@@ -2,7 +2,7 @@ import { array_copy } from "../copyArray.js";
2
2
 
3
3
 
4
4
  /**
5
- *
5
+ * Assumes arrays have the same type
6
6
  * @param {TypedArray|Float32Array} source
7
7
  * @param {TypedArray|Float32Array} destination
8
8
  */
@@ -1,5 +1,3 @@
1
- import { v3_length } from "../../v3_length.js";
2
-
3
1
  /**
4
2
  *
5
3
  * @param {number[]} destination
@@ -10,10 +8,12 @@ import { v3_length } from "../../v3_length.js";
10
8
  * @param {number} w
11
9
  */
12
10
  function array_set_plane_normalized(destination, destination_offset, x, y, z, w) {
13
- const length = v3_length(x, y, z);
11
+ // compute vector length
12
+ const length = Math.hypot(x, y, z);
14
13
 
15
14
  const inverseNormalLength = 1.0 / length;
16
15
 
16
+ // apply normalization
17
17
  destination[destination_offset] = x * inverseNormalLength;
18
18
  destination[destination_offset + 1] = y * inverseNormalLength;
19
19
  destination[destination_offset + 2] = z * inverseNormalLength;
@@ -1,5 +1,5 @@
1
1
  import { decode_hemioct_to_unit, encode_unit_to_hemioct } from "./encode_unit3_hemioct.js";
2
- import { v3_length } from "../../../Vector3.d.ts";
2
+ import { v3_length } from "../../../v3_length.js";
3
3
 
4
4
  test('encode-decode', () => {
5
5
  const v0 = [];
@@ -1,5 +1,31 @@
1
1
  export class AbstractShape3D {
2
- constructor() {
2
+ /**
3
+ * Signed distance to boundary of the shape from the given point
4
+ * @param {number[]} point
5
+ * @returns {number}
6
+ */
7
+ signed_distance_at_point(point) {
8
+ throw new Error('Not Implemented');
9
+ }
10
+
11
+ /**
12
+ * Samples both distances as well as the gradient
13
+ * @param {number[]} result resulting gradient is written here
14
+ * @param {number[]} point sampling point
15
+ * @returns {number}
16
+ */
17
+ signed_distance_gradient_at_point(result, point) {
18
+ throw new Error('Not Implemented');
19
+ }
20
+
21
+ /**
22
+ *
23
+ * @param {number[]} result where the resulting point is stored
24
+ * @param {number[]} reference reference point from which to go
25
+ * @returns {void}
26
+ */
27
+ nearest_point_on_surface(result, reference) {
28
+ throw new Error('Not Implemented');
3
29
  }
4
30
 
5
31
  /**
@@ -7,11 +33,21 @@ export class AbstractShape3D {
7
33
  * @param {number[]} result
8
34
  * @param {number} result_offset
9
35
  * @param {function} random
36
+ * @returns {void}
10
37
  */
11
38
  sample_random_point_in_volume(result, result_offset, random) {
12
39
  throw new Error('Not Implemented');
13
40
  }
14
41
 
42
+ /**
43
+ * Whether or not given point is inside the shape
44
+ * @param {number[]} point
45
+ * @returns {boolean}
46
+ */
47
+ contains_point(point) {
48
+ throw new Error('Not Implemented');
49
+ }
50
+
15
51
  /**
16
52
  * Total volume of the shape
17
53
  * @returns {number}
@@ -1,11 +1,12 @@
1
1
  import { mat4, vec3 } from "gl-matrix";
2
2
  import { AbstractShape3D } from "./AbstractShape3D.js";
3
+ import { sign } from "../../../math/sign.js";
3
4
 
4
5
  /**
5
6
  *
6
7
  * @type {number[]|Float32Array|vec3}
7
8
  */
8
- const scratch_v3 = [];
9
+ const scratch_v3_0 = [];
9
10
 
10
11
  export class TransformedShape3D extends AbstractShape3D {
11
12
  constructor() {
@@ -17,6 +18,14 @@ export class TransformedShape3D extends AbstractShape3D {
17
18
  * @private
18
19
  */
19
20
  this.__matrix = new Float32Array(16);
21
+
22
+ /**
23
+ *
24
+ * @type {Float32Array|mat4}
25
+ * @private
26
+ */
27
+ this.__inverse_matrix = new Float32Array(16);
28
+
20
29
  /**
21
30
  *
22
31
  * @type {AbstractShape3D|null}
@@ -27,7 +36,15 @@ export class TransformedShape3D extends AbstractShape3D {
27
36
 
28
37
  /**
29
38
  *
30
- * @param {number[]|Float32Array} m4
39
+ * @returns {AbstractShape3D|null}
40
+ */
41
+ get subject() {
42
+ return this.__subject;
43
+ }
44
+
45
+ /**
46
+ *
47
+ * @param {number[]|Float32Array|mat4} m4
31
48
  * @param {AbstractShape3D} subject
32
49
  * @returns {TransformedShape3D}
33
50
  */
@@ -35,36 +52,130 @@ export class TransformedShape3D extends AbstractShape3D {
35
52
  const r = new TransformedShape3D();
36
53
 
37
54
  r.__subject = subject;
38
- r.__matrix = m4;
55
+ r.transform = m4;
39
56
 
40
57
  return r;
41
58
  }
42
59
 
60
+ /**
61
+ *
62
+ * @param {AbstractShape3D} subject
63
+ * @param {number[]} translation
64
+ * @param {number[]} scale
65
+ */
66
+ static from_translation_scale(subject, translation, scale) {
67
+
68
+ const mat = mat4.create();
69
+ mat4.fromRotationTranslationScale(mat, [0, 0, 0, 1], translation, scale);
70
+
71
+ return TransformedShape3D.from_m4(subject, mat);
72
+ }
73
+
74
+ /**
75
+ *
76
+ * @returns {TransformedShape3D}
77
+ * @param {AbstractShape3D} subject
78
+ * @param {number[]|Float32Array|vec3} scale
79
+ */
80
+ static from_scale(subject, scale) {
81
+ const mat = mat4.create();
82
+ mat4.fromScaling(mat, scale);
83
+
84
+ return TransformedShape3D.from_m4(subject, mat);
85
+ }
86
+
43
87
  /**
44
88
  *
45
89
  * @param {number[]|Float32Array} m
46
90
  */
47
91
  set transform(m) {
48
92
  this.__matrix.set(m);
93
+
94
+ mat4.invert(this.__inverse_matrix, this.__matrix);
95
+ }
96
+
97
+ get transform() {
98
+ return this.__matrix;
49
99
  }
50
100
 
51
101
  get volume() {
52
- mat4.getScaling(scratch_v3, this.__matrix);
102
+ mat4.getScaling(scratch_v3_0, this.__matrix);
53
103
 
54
- const scale_modifier = scratch_v3[0] * scratch_v3[1] * scratch_v3[2];
104
+ const scale_modifier = scratch_v3_0[0] * scratch_v3_0[1] * scratch_v3_0[2];
55
105
 
56
106
  return this.__subject.volume * scale_modifier;
57
107
  }
58
108
 
109
+ signed_distance_gradient_at_point(result, point) {
110
+ // transform point to subject's local space
111
+ vec3.transformMat4(scratch_v3_0, point, this.__inverse_matrix);
112
+
113
+ const subject = this.__subject;
114
+
115
+ // sample gradient at the point
116
+ const distance = subject.signed_distance_gradient_at_point(scratch_v3_0, scratch_v3_0);
117
+
118
+ const m = this.__matrix;
119
+
120
+ const m11 = m[0];
121
+ const m12 = m[1];
122
+ const m13 = m[2];
123
+
124
+ const m21 = m[4];
125
+ const m22 = m[5];
126
+ const m23 = m[6];
127
+
128
+ const m31 = m[8];
129
+ const m32 = m[9];
130
+ const m33 = m[10];
131
+
132
+ const scale_x = Math.hypot(m11, m12, m13);
133
+ const scale_y = Math.hypot(m21, m22, m23);
134
+ const scale_z = Math.hypot(m31, m32, m33);
135
+
136
+ const scaled_gx = scratch_v3_0[0] * scale_x;
137
+ const scaled_gy = scratch_v3_0[1] * scale_y;
138
+ const scaled_gz = scratch_v3_0[2] * scale_z;
139
+
140
+ // normalize gradient
141
+ const gd = distance / Math.hypot(scratch_v3_0[0], scratch_v3_0[1], scratch_v3_0[2]);
142
+
143
+ const scaled_dx = scaled_gx * gd ;
144
+ const scaled_dy = scaled_gy * gd ;
145
+ const scaled_dz = scaled_gz * gd ;
146
+
147
+ // determine sign
148
+ const result_sign = sign(distance);
149
+
150
+ const scaled_distance = result_sign * Math.sqrt(scaled_dx * scaled_dx + scaled_dy * scaled_dy + scaled_dz * scaled_dz);
151
+
152
+ result[0] = scaled_gx;
153
+ result[1] = scaled_gy;
154
+ result[2] = scaled_gz;
155
+
156
+ return scaled_distance;
157
+ }
158
+
159
+ signed_distance_at_point(point) {
160
+ return this.signed_distance_gradient_at_point(scratch_v3_0, point);
161
+ }
162
+
163
+ contains_point(point) {
164
+ // transform point to subject's local space
165
+ vec3.transformMat4(scratch_v3_0, point, this.__inverse_matrix);
166
+
167
+ return this.__subject.contains_point(scratch_v3_0);
168
+ }
169
+
59
170
  sample_random_point_in_volume(result, result_offset, random) {
60
- this.__subject.sample_random_point_in_volume(scratch_v3, 0, random);
171
+ this.__subject.sample_random_point_in_volume(scratch_v3_0, 0, random);
61
172
 
62
173
  // apply transform
63
- vec3.transformMat4(scratch_v3, scratch_v3, this.__matrix);
174
+ vec3.transformMat4(scratch_v3_0, scratch_v3_0, this.__matrix);
64
175
 
65
176
  // write out
66
- result[0] = scratch_v3[0];
67
- result[1] = scratch_v3[1];
68
- result[2] = scratch_v3[2];
177
+ result[0] = scratch_v3_0[0];
178
+ result[1] = scratch_v3_0[1];
179
+ result[2] = scratch_v3_0[2];
69
180
  }
70
181
  }
@@ -0,0 +1,33 @@
1
+ import { UnitCubeShape3D } from "./UnitCubeShape3D.js";
2
+ import { TransformedShape3D } from "./TransformedShape3D.js";
3
+
4
+ test('signed distance identity transform', () => {
5
+
6
+ const s = TransformedShape3D.from_translation_scale(new UnitCubeShape3D(), [0, 0, 0], [1, 1, 1]);
7
+
8
+ expect(s.signed_distance_at_point([0, 0, 0])).toBeCloseTo(-0.5);
9
+
10
+ expect(s.signed_distance_at_point([1, 0, 0])).toBeCloseTo(0.5);
11
+ });
12
+
13
+ test('signed distance translation', () => {
14
+
15
+ const s = TransformedShape3D.from_translation_scale(new UnitCubeShape3D(), [1, 0, 0], [1, 1, 1]);
16
+
17
+ expect(s.signed_distance_at_point([0, 0, 0])).toBeCloseTo(0.5);
18
+
19
+ expect(s.signed_distance_at_point([-1, 0, 0])).toBeCloseTo(1.5);
20
+
21
+ expect(s.signed_distance_at_point([1, 0, 0])).toBeCloseTo(-0.5);
22
+ });
23
+
24
+ test('signed distance scale', () => {
25
+
26
+ const s = TransformedShape3D.from_translation_scale(new UnitCubeShape3D(), [0, 0, 0], [2, 2, 2]);
27
+
28
+ expect(s.signed_distance_at_point([0, 0, 0])).toBeCloseTo(-1);
29
+
30
+ expect(s.signed_distance_at_point([1, 0, 0])).toBeCloseTo(0);
31
+
32
+ expect(s.signed_distance_at_point([2, 0, 0])).toBeCloseTo(1);
33
+ });