@woosh/meep-engine 2.43.16 → 2.43.18

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 (53) hide show
  1. package/core/assert.js +3 -1
  2. package/core/bvh2/aabb3/aabb3_intersects_ray.js +14 -9
  3. package/core/bvh2/aabb3/aabb3_intersects_ray_branchless.js +52 -0
  4. package/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.d.ts +2 -0
  5. package/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.js +214 -5
  6. package/core/bvh2/bvh3/bvh_query_leaves_ray.js +32 -29
  7. package/core/collection/array/typed/typed_array_copy.js +2 -2
  8. package/core/geom/3d/aabb/compute_aabb_from_points.js +4 -3
  9. package/core/geom/3d/compute_triangle_normal.js +76 -0
  10. package/core/geom/3d/topology/samples/sampleFloodFill.js +1 -1
  11. package/core/geom/3d/topology/simplify/compute_face_normal_change_dot_product.js +1 -1
  12. package/core/geom/3d/topology/simplify/quadratic/Quadratic3.js +1 -1
  13. package/core/geom/3d/topology/struct/TopoTriangle.js +1 -57
  14. package/core/geom/3d/topology/tm_face_normal.js +1 -1
  15. package/core/geom/3d/topology/tm_vertex_compute_normal.js +1 -1
  16. package/core/geom/3d/triangle/computeTriangleRayIntersection.js +195 -27
  17. package/core/geom/Vector3.js +12 -12
  18. package/core/math/physics/brdf/D_GGX.js +13 -0
  19. package/editor/tools/v2/prototypeTransformControls.js +14 -2
  20. package/engine/ecs/parent/EntityNode.js +80 -7
  21. package/engine/ecs/parent/EntityNodeFlags.js +8 -0
  22. package/engine/ecs/terrain/tiles/TerrainTile.js +7 -9
  23. package/engine/graphics/ecs/path/PathDisplaySystem.d.ts +3 -0
  24. package/engine/graphics/ecs/path/PathDisplaySystem.js +10 -0
  25. package/engine/graphics/geometry/AttributeSpec.js +18 -3
  26. package/engine/graphics/geometry/VertexDataSpec.js +53 -3
  27. package/engine/graphics/micron/format/VirtualGeometry.js +7 -0
  28. package/engine/graphics/micron/render/VirtualGeometryBuilder.js +1 -1
  29. package/engine/graphics/micron/render/refinement/get_geometry_patch_cut.js +5 -2
  30. package/engine/graphics/particles/particular/engine/parameter/sample/RGBA_LUT_HEATMAP_IR.js +11 -0
  31. package/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +2 -9
  32. package/engine/graphics/sh3/README.md +1 -0
  33. package/engine/graphics/sh3/path_tracer/GeometryBVHBatched.js +324 -0
  34. package/engine/graphics/sh3/path_tracer/PathTracedMesh.js +85 -0
  35. package/engine/graphics/sh3/path_tracer/PathTracer.js +469 -0
  36. package/engine/graphics/sh3/path_tracer/apply_texture_clamping_to_coordinate.js +22 -0
  37. package/engine/graphics/sh3/path_tracer/compute_triangle_group_aabb3.js +36 -0
  38. package/engine/graphics/sh3/path_tracer/getBiasedNormalSample.js +55 -0
  39. package/engine/graphics/sh3/path_tracer/make_sky_hosek.js +44 -0
  40. package/engine/graphics/sh3/path_tracer/make_sky_rtiw.js +15 -0
  41. package/engine/graphics/sh3/path_tracer/prototypePathTracer.js +619 -0
  42. package/engine/graphics/sh3/path_tracer/random_in_hemisphere.js +39 -0
  43. package/engine/graphics/sh3/path_tracer/ray_hit_apply_transform.js +42 -0
  44. package/engine/graphics/sh3/path_tracer/ray_reflect.js +27 -0
  45. package/engine/graphics/sh3/path_tracer/sample_triangle_attribute.js +35 -0
  46. package/engine/graphics/sh3/path_tracer/vec3_uint8_to_float.js +12 -0
  47. package/engine/graphics/sh3/sky/hosek/README.md +4 -0
  48. package/engine/graphics/sh3/sky/hosek/prototype_hosek.js +71 -0
  49. package/engine/graphics/sh3/sky/hosek/sky_hosek_compute_irradiance_by_direction.js +4171 -0
  50. package/engine/graphics/texture/sampler/convertTexture2Sampler2D.js +2 -0
  51. package/package.json +1 -1
  52. package/view/elements/progress/SmoothProgressBar.js +1 -1
  53. package/view/task/TaskProgressView.js +6 -8
@@ -3,22 +3,28 @@ import { computeStringHash } from "../../../core/primitives/strings/computeStrin
3
3
  import { DataTypeByteSizes } from "../../../core/collection/table/DataTypeByteSizes.js";
4
4
  import { assert } from "../../../core/assert.js";
5
5
 
6
+ /**
7
+ * Describes data structure of a single data attribute, such as a scalar, or a vector
8
+ * This structure is designed to map well to GPU shader formats and is intended for larger datasets, such as meshes or particle clouds
9
+ */
6
10
  export class AttributeSpec {
7
11
  constructor() {
8
12
  /**
9
- *
13
+ * Typically unique within a given set, used to identify the attribute
10
14
  * @type {string}
11
15
  */
12
16
  this.name = "";
13
17
 
14
18
  /**
15
- *
19
+ * How the attribute is stored in memory and interpreted
16
20
  * @type {DataType}
17
21
  */
18
22
  this.type = DataType.Float32;
19
23
 
20
24
  /**
21
- *
25
+ * How many elements the attribute uses. This is cardinality of a vector.
26
+ * 1 means the attribute is a scalar
27
+ * must be greater or equal to 1
22
28
  * @type {number}
23
29
  */
24
30
  this.itemSize = 1;
@@ -62,6 +68,15 @@ export class AttributeSpec {
62
68
  this.normalized = normalized;
63
69
  }
64
70
 
71
+ toJSON() {
72
+ return {
73
+ name: this.name,
74
+ type: this.type,
75
+ itemSize: this.itemSize,
76
+ normalized: this.normalized
77
+ };
78
+ }
79
+
65
80
  hash() {
66
81
  return computeStringHash(this.name);
67
82
  }
@@ -1,9 +1,19 @@
1
1
  import { invokeObjectHash } from "../../../core/model/object/invokeObjectHash.js";
2
2
  import { computeHashArray } from "../../../core/collection/array/computeHashArray.js";
3
3
  import { isArrayEqual } from "../../../core/collection/array/isArrayEqual.js";
4
+ import { AttributeSpec } from "./AttributeSpec.js";
5
+ import { assert } from "../../../core/assert.js";
4
6
 
5
- const DEFAULT_HASH = 123456;
7
+ /**
8
+ * @readonly
9
+ * @type {number}
10
+ */
11
+ const DEFAULT_HASH = 1234567;
6
12
 
13
+ /**
14
+ * Describes a set of data attributes. A good analogy would be "all data associated with geometry vertex"
15
+ * @example "uv","position" and "normal" attributes of geometry vertices
16
+ */
7
17
  export class VertexDataSpec {
8
18
  constructor() {
9
19
  /**
@@ -13,7 +23,7 @@ export class VertexDataSpec {
13
23
  this.attributes = [];
14
24
 
15
25
  /**
16
- *
26
+ * Cached hash for speed
17
27
  * @type {number}
18
28
  * @private
19
29
  */
@@ -92,6 +102,8 @@ export class VertexDataSpec {
92
102
  */
93
103
  add(attribute) {
94
104
 
105
+ assert.equal(attribute.isAttributeSpec, true, 'attribute.isAttributeSpec !== true');
106
+
95
107
  //check uniqueness of name
96
108
  if (this.getAttributeByName(attribute.name) !== undefined) {
97
109
  throw new Error(`Attribute named '${attribute.name}' already exists`);
@@ -111,7 +123,19 @@ export class VertexDataSpec {
111
123
  * @param {AttributeSpec[]} attributes
112
124
  */
113
125
  setAttributes(attributes) {
114
- this.attributes = attributes;
126
+
127
+ this.clear();
128
+
129
+ const n = attributes.length;
130
+
131
+ for (let i = 0; i < n; i++) {
132
+ this.add(attributes[i]);
133
+ }
134
+
135
+ }
136
+
137
+ clear() {
138
+ this.attributes.splice(0, this.attributes.length);
115
139
 
116
140
  // reset hash to trigger hash update
117
141
  this.__hash = DEFAULT_HASH;
@@ -142,6 +166,32 @@ export class VertexDataSpec {
142
166
  return this.__hash;
143
167
  }
144
168
 
169
+ toJSON() {
170
+ return {
171
+ attributes: JSON.stringify(this.attributes)
172
+ };
173
+ }
174
+
175
+ fromJSON({
176
+ attributes = []
177
+ }) {
178
+
179
+ this.clear();
180
+
181
+ const n = attributes.length;
182
+
183
+ for (let i = 0; i < n; i++) {
184
+
185
+ const aj = attributes[i];
186
+
187
+ const attribute = AttributeSpec.fromJSON(aj);
188
+
189
+ this.add(attribute);
190
+
191
+ }
192
+
193
+ }
194
+
145
195
  /**
146
196
  *
147
197
  * @returns {number}
@@ -57,8 +57,15 @@ export class VirtualGeometry {
57
57
  this.stats_source_byte_size = 0;
58
58
  }
59
59
 
60
+ /**
61
+ *
62
+ * @param {number} patch_count how much must be supported
63
+ * @return {boolean} true if capacity was sufficient, false if had to be resized
64
+ */
60
65
  ensureCapacity(patch_count) {
61
66
  if (this.__capacity < patch_count) {
67
+ // grow capacity
68
+
62
69
  const new_capacity = Math.ceil(max3(
63
70
  patch_count,
64
71
  patch_count * CAPACITY_GROW_FACTOR,
@@ -149,7 +149,7 @@ export class VirtualGeometryBuilder {
149
149
  output.loolup_geometries[geometry.id] = geometry;
150
150
  output.lookup_instance_transforms[instance_id] = transform;
151
151
 
152
- // build up occurances
152
+ // build up occurrences
153
153
  get_geometry_patch_cut(
154
154
  output,
155
155
  refinement_spec,
@@ -95,11 +95,13 @@ export function get_geometry_patch_cut(
95
95
  for (i = 0; i < child_count; i++) {
96
96
  const child = children[i];
97
97
 
98
- if (included_set.getAndSet(child.id)) {
98
+ const child_id = child.id;
99
+
100
+ if (included_set.getAndSet(child_id)) {
99
101
  continue;
100
102
  }
101
103
 
102
- stack[stack_cursor++] = child.id;
104
+ stack[stack_cursor++] = child_id;
103
105
  }
104
106
 
105
107
  continue;
@@ -122,6 +124,7 @@ export function get_geometry_patch_cut(
122
124
  if (!destination.ensureCapacity(output_patch_cursor)) {
123
125
  // redo the work
124
126
  get_geometry_patch_cut(destination, spec, geometry, instance_id, transform);
127
+
125
128
  } else {
126
129
 
127
130
  destination.patch_count = output_patch_cursor;
@@ -0,0 +1,11 @@
1
+ import { ParameterLookupTable } from "../ParameterLookupTable.js";
2
+
3
+ export const RGBA_LUT_HEATMAP_IR = new ParameterLookupTable(4);
4
+ RGBA_LUT_HEATMAP_IR.write([
5
+ 0, 0, 255, 10,
6
+ 0, 179, 179, 10,
7
+ 0, 255, 0, 10,
8
+ 255, 255, 0, 10,
9
+ 255, 5, 5, 10
10
+ ]);
11
+ RGBA_LUT_HEATMAP_IR.computeUniformPositions();
@@ -81,6 +81,7 @@ import { pick } from "../../../../../../../ecs/grid/pick.js";
81
81
  import { clamp01 } from "../../../../../../../core/math/clamp01.js";
82
82
  import { randomFromArray } from "../../../../../../../core/math/random/randomFromArray.js";
83
83
  import { SamplingFunctionKind } from "./SamplingFunctionKind.js";
84
+ import { RGBA_LUT_HEATMAP_IR } from "../../parameter/sample/RGBA_LUT_HEATMAP_IR.js";
84
85
 
85
86
  const engineHarness = new EngineHarness();
86
87
 
@@ -168,15 +169,7 @@ async function init(harness) {
168
169
  }
169
170
 
170
171
 
171
- const heatmap_lut_0 = new ParameterLookupTable(4);
172
- heatmap_lut_0.write([
173
- 0, 0, 255, 10,
174
- 0, 179, 179, 10,
175
- 0, 255, 0, 10,
176
- 255, 255, 0, 10,
177
- 255, 5, 5, 10
178
- ]);
179
- heatmap_lut_0.computeUniformPositions();
172
+ const heatmap_lut_0 = RGBA_LUT_HEATMAP_IR;
180
173
 
181
174
  const heatmap_lut_orange_to_red = new ParameterLookupTable(4);
182
175
  heatmap_lut_orange_to_red.write([
@@ -2,3 +2,4 @@ Path tracing ideas:
2
2
  * https://raytracing.github.io/books/RayTracingInOneWeekend.html
3
3
  * [smallpt](https://www.kevinbeason.com/smallpt/) (100 line c implementation of path tracer)
4
4
  * [three path tracer](https://github.com/gkjohnson/three-gpu-pathtracer)
5
+ * http://blog.hvidtfeldts.net/index.php/2015/01/path-tracing-3d-fractals/
@@ -0,0 +1,324 @@
1
+ import {
2
+ ExplicitBinaryBoundingVolumeHierarchy
3
+ } from "../../../../core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.js";
4
+ import { min2 } from "../../../../core/math/min2.js";
5
+ import { compute_triangle_group_aabb3 } from "./compute_triangle_group_aabb3.js";
6
+ import { bvh_query_leaves_ray } from "../../../../core/bvh2/bvh3/bvh_query_leaves_ray.js";
7
+ import { aabb3_signed_distance_sqr_to_point } from "../../../../core/bvh2/aabb3/aabb3_signed_distance_sqr_to_point.js";
8
+ import {
9
+ computeTriangleRayIntersectionBarycentric
10
+ } from "../../../../core/geom/3d/triangle/computeTriangleRayIntersection.js";
11
+
12
+ /**
13
+ *
14
+ * @type {number[]}
15
+ */
16
+ const leaf_buffer = [];
17
+ /**
18
+ *
19
+ * @type {number[]}
20
+ */
21
+ const v3_scratch_0 = [];
22
+ const BVH_BATCH_SIZE = 1;
23
+
24
+ const temp_aabb3 = new Float32Array(6);
25
+
26
+ export class GeometryBVHBatched {
27
+ constructor() {
28
+ /**
29
+ *
30
+ * @type {ExplicitBinaryBoundingVolumeHierarchy}
31
+ * @private
32
+ */
33
+ this.__bvh = new ExplicitBinaryBoundingVolumeHierarchy();
34
+
35
+ /**
36
+ *
37
+ * @type {THREE.BufferGeometry|null}
38
+ * @private
39
+ */
40
+ this.__geometry = null;
41
+
42
+ /**
43
+ *
44
+ * @type {number[]|null}
45
+ * @private
46
+ */
47
+ this.__geometry_index = null;
48
+
49
+ /**
50
+ *
51
+ * @type {number[]|null}
52
+ * @private
53
+ */
54
+ this.__geometry_positions = null;
55
+
56
+
57
+ /**
58
+ *
59
+ * @type {number}
60
+ * @private
61
+ */
62
+ this.__triangle_count = 0;
63
+ }
64
+
65
+ /**
66
+ *
67
+ * @param {THREE.BufferGeometry} geometry
68
+ */
69
+ build(geometry) {
70
+ this.__geometry = geometry;
71
+
72
+ const bvh = this.__bvh;
73
+
74
+ bvh.release_all();
75
+
76
+ const index = geometry.getIndex();
77
+ const index_array = index.array;
78
+
79
+
80
+ const attribute_position = geometry.getAttribute('position');
81
+ const array_positions = attribute_position.array;
82
+
83
+ this.__geometry_positions = array_positions;
84
+ this.__geometry_index = index_array;
85
+
86
+ const triangle_count = index_array.length / 3;
87
+
88
+ this.__triangle_count = triangle_count;
89
+
90
+ const leaf_node_count = Math.ceil(triangle_count / BVH_BATCH_SIZE);
91
+
92
+ const leaf_aabb = [];
93
+
94
+ for (let i = 0; i < leaf_node_count; i++) {
95
+
96
+ const index_start = i * BVH_BATCH_SIZE;
97
+ const index_end = min2(triangle_count, index_start + BVH_BATCH_SIZE);
98
+
99
+ const group_size = index_end - index_start;
100
+
101
+ compute_triangle_group_aabb3(leaf_aabb, 0, index_array, array_positions, index_start * 3, group_size, 3);
102
+
103
+ const node_index = bvh.allocate_node();
104
+ bvh.node_set_aabb(node_index, leaf_aabb);
105
+ bvh.node_set_user_data(node_index, i);
106
+
107
+ bvh.insert_leaf(node_index);
108
+ }
109
+
110
+ bvh.trim();
111
+ bvh.sort_for_traversal_depth_first();
112
+ }
113
+
114
+ /**
115
+ *
116
+ * @param {number[]} output
117
+ * @param {number} face_index
118
+ * @param {number} t
119
+ * @param {number} u
120
+ * @param {number} v
121
+ */
122
+ construct_output(output, face_index, t, u, v) {
123
+ const indices = this.__geometry_index;
124
+ const positions = this.__geometry_positions;
125
+
126
+ const index_offset = face_index * 3;
127
+
128
+ const a = indices[index_offset];
129
+ const b = indices[index_offset + 1];
130
+ const c = indices[index_offset + 2];
131
+
132
+
133
+ const a_address = a * 3;
134
+ const b_address = b * 3;
135
+ const c_address = c * 3;
136
+
137
+ const ax = positions[a_address];
138
+ const ay = positions[a_address + 1];
139
+ const az = positions[a_address + 2];
140
+
141
+ const bx = positions[b_address];
142
+ const by = positions[b_address + 1];
143
+ const bz = positions[b_address + 2];
144
+
145
+ const cx = positions[c_address];
146
+ const cy = positions[c_address + 1];
147
+ const cz = positions[c_address + 2];
148
+
149
+ // read out interpolated buffer values
150
+ // const w = 1 - u - v;
151
+
152
+ // output[0] = ax * u + bx * v + cx * w;
153
+ // output[1] = ay * u + by * v + cy * w;
154
+ // output[2] = az * u + bz * v + cz * w;
155
+
156
+ // normal
157
+ // v3_compute_triangle_normal(output, 3, ax, ay, ax, bx, by, bz, cx, cy, cz);
158
+
159
+ // edge1 = a - b
160
+ const edge1_x = bx - ax;
161
+ const edge1_y = by - ay;
162
+ const edge1_z = bz - az;
163
+
164
+ // edge2 = c - a
165
+ const edge2_x = cx - ax;
166
+ const edge2_y = cy - ay;
167
+ const edge2_z = cz - az;
168
+
169
+ // Compute triangle normal
170
+
171
+ // normal = edge1 x edge2
172
+ const normal_x = edge1_y * edge2_z - edge1_z * edge2_y;
173
+ const normal_y = edge1_z * edge2_x - edge1_x * edge2_z;
174
+ const normal_z = edge1_x * edge2_y - edge1_y * edge2_x
175
+
176
+
177
+ output[3] = normal_x;
178
+ output[4] = normal_y;
179
+ output[5] = normal_z;
180
+
181
+ output[6] = t;
182
+ output[7] = u;
183
+ output[8] = v;
184
+ output[9] = face_index;
185
+ }
186
+
187
+ /**
188
+ *
189
+ * @param {number[]} output
190
+ * @param {number[]} ray
191
+ * @param {number} min_distance
192
+ * @param {number} max_distance
193
+ * @returns {number} distance along the ray, negative if no hit
194
+ */
195
+ raycast(output, ray, min_distance, max_distance) {
196
+
197
+ const indices = this.__geometry_index;
198
+ const positions = this.__geometry_positions;
199
+
200
+ const origin_x = ray[0];
201
+ const origin_y = ray[1];
202
+ const origin_z = ray[2];
203
+
204
+ const direction_x = ray[3];
205
+ const direction_y = ray[4];
206
+ const direction_z = ray[5];
207
+
208
+ const bvh = this.__bvh;
209
+
210
+ const count = bvh_query_leaves_ray(
211
+ bvh, leaf_buffer, 0,
212
+ origin_x, origin_y, origin_z,
213
+ direction_x, direction_y, direction_z
214
+ );
215
+
216
+ let best_t = max_distance;
217
+
218
+ let best_index = -1;
219
+ let best_u = 0;
220
+ let best_v = 0;
221
+
222
+ for (let i = 0; i < count; i++) {
223
+ const leaf_node_id = leaf_buffer[i];
224
+
225
+ const triangle_batch_index = bvh.node_get_user_data(leaf_node_id);
226
+
227
+ const index_start = triangle_batch_index * BVH_BATCH_SIZE;
228
+
229
+ const index_end = min2(index_start + BVH_BATCH_SIZE, this.__triangle_count);
230
+
231
+ if (best_t < max_distance) {
232
+ // early bail-out
233
+
234
+ bvh.node_get_aabb(leaf_node_id, temp_aabb3);
235
+
236
+ const distance = aabb3_signed_distance_sqr_to_point(temp_aabb3[0], temp_aabb3[1], temp_aabb3[2], temp_aabb3[3], temp_aabb3[4], temp_aabb3[5], ray[0], ray[1], ray[2]);
237
+
238
+ if (distance > best_t * best_t) {
239
+ // whole AABB is too far
240
+ continue;
241
+ }
242
+ }
243
+
244
+ for (let j = index_start; j < index_end; j++) {
245
+ const index_offset = j * 3;
246
+
247
+ const a = indices[index_offset];
248
+ const b = indices[index_offset + 1];
249
+ const c = indices[index_offset + 2];
250
+
251
+
252
+ const a_address = a * 3;
253
+ const b_address = b * 3;
254
+ const c_address = c * 3;
255
+
256
+
257
+ const ax = positions[a_address];
258
+ const ay = positions[a_address + 1];
259
+ const az = positions[a_address + 2];
260
+
261
+ const bx = positions[b_address];
262
+ const by = positions[b_address + 1];
263
+ const bz = positions[b_address + 2];
264
+
265
+ const cx = positions[c_address];
266
+ const cy = positions[c_address + 1];
267
+ const cz = positions[c_address + 2];
268
+
269
+ // const sp3 = new SurfacePoint3();
270
+ //
271
+ // const intersection_found = computeTriangleRayIntersection(
272
+ // sp3,
273
+ // origin_x, origin_y, origin_z,
274
+ // direction_x, direction_y, direction_z,
275
+ // ax, ay, az,
276
+ // bx, by, bz,
277
+ // cx, cy, cz);
278
+ //
279
+ // v3_scratch_0[0] = sp3.position.distanceTo(new Vector3(origin_x, origin_y, origin_z));
280
+
281
+ const intersection_found = computeTriangleRayIntersectionBarycentric(
282
+ v3_scratch_0,
283
+ origin_x, origin_y, origin_z,
284
+ direction_x, direction_y, direction_z,
285
+ ax, ay, az,
286
+ bx, by, bz,
287
+ cx, cy, cz
288
+ );
289
+
290
+ if (intersection_found && v3_scratch_0[0] < best_t && v3_scratch_0[0] > min_distance) {
291
+ best_t = v3_scratch_0[0];
292
+
293
+ best_index = j;
294
+ best_u = v3_scratch_0[1];
295
+ best_v = v3_scratch_0[2];
296
+
297
+
298
+ // output[0] = v3_scratch_0[0];
299
+ // output[1] = v3_scratch_0[1];
300
+ // output[2] = v3_scratch_0[2];
301
+ //
302
+ // output[3] = v3_scratch_0[3];
303
+ // output[4] = v3_scratch_0[4];
304
+ // output[5] = v3_scratch_0[5];
305
+
306
+ // uv
307
+ //TODO
308
+ }
309
+ }
310
+ }
311
+
312
+ if (best_t === max_distance) {
313
+ return -1;
314
+ }
315
+
316
+ output[0] = origin_x + direction_x * best_t;
317
+ output[1] = origin_y + direction_y * best_t;
318
+ output[2] = origin_z + direction_z * best_t;
319
+
320
+ this.construct_output(output, best_index, best_t, best_u, best_v);
321
+
322
+ return best_t;
323
+ }
324
+ }
@@ -0,0 +1,85 @@
1
+ import { array_copy } from "../../../../core/collection/array/copyArray.js";
2
+ import { mat4 } from "gl-matrix";
3
+ import { ray3_array_apply_matrix4 } from "../../../../core/geom/3d/ray/ray3_array_apply_matrix4.js";
4
+ import { ray_hit_apply_transform } from "./ray_hit_apply_transform.js";
5
+
6
+ const local_ray = new Float32Array(6);
7
+ let mesh_id_counter = 0;
8
+
9
+ export class PathTracedMesh {
10
+ constructor() {
11
+
12
+ /**
13
+ *
14
+ * @type {GeometryBVHBatched|null}
15
+ */
16
+ this.geo_bvh = null;
17
+
18
+ /**
19
+ *
20
+ * @type {THREE.BufferGeometry|null}
21
+ */
22
+ this.geometry = null;
23
+
24
+ /**
25
+ *
26
+ * @type {THREE.Material|null}
27
+ */
28
+ this.material = null;
29
+
30
+ const buffer = new ArrayBuffer(16 * 2 * 4);
31
+
32
+ this.__transform_inverse = new Float32Array(buffer, 0, 16);
33
+ this.__transform = new Float32Array(buffer, 16 * 4, 16);
34
+ this.__local_scale_inverse = 1;
35
+
36
+ /**
37
+ *
38
+ * @type {number}
39
+ */
40
+ this.id = mesh_id_counter++;
41
+ }
42
+
43
+ set transform(m) {
44
+ array_copy(m, 0, this.__transform, 0, 16);
45
+ mat4.invert(this.__transform_inverse, m);
46
+
47
+ // precompute scaling factor for rays
48
+ const m4 = this.__transform_inverse;
49
+
50
+ const scale_x = Math.hypot(m4[0], m4[1], m4[2]);
51
+ const scale_y = Math.hypot(m4[4], m4[5], m4[6]);
52
+ const scale_z = Math.hypot(m4[8], m4[9], m4[10]);
53
+
54
+ this.__local_scale_inverse = Math.hypot(scale_x, scale_y, scale_z);
55
+ }
56
+
57
+ /**
58
+ *
59
+ * @param {number[]} out
60
+ * @param {number[]} ray
61
+ * @param {number} min_distance
62
+ * @param {number} max_distance
63
+ * @returns {number} distance along the ray to contact
64
+ */
65
+ hit(out, ray, min_distance, max_distance) {
66
+ //transform ray
67
+ const m4 = this.__transform_inverse;
68
+ ray3_array_apply_matrix4(local_ray, ray, m4);
69
+
70
+ const scale_d = this.__local_scale_inverse;
71
+
72
+ let distance_to_hit = this.geo_bvh.raycast(out, local_ray, min_distance * scale_d, max_distance * scale_d);
73
+
74
+ if (distance_to_hit >= 0) {
75
+ // transform output
76
+ ray_hit_apply_transform(out, out, this.__transform);
77
+
78
+ out[10] = this.id;
79
+
80
+ distance_to_hit /= scale_d;
81
+ }
82
+
83
+ return distance_to_hit;
84
+ }
85
+ }