@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.
- package/core/assert.js +3 -1
- package/core/bvh2/aabb3/aabb3_intersects_ray.js +14 -9
- package/core/bvh2/aabb3/aabb3_intersects_ray_branchless.js +52 -0
- package/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.d.ts +2 -0
- package/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.js +214 -5
- package/core/bvh2/bvh3/bvh_query_leaves_ray.js +32 -29
- package/core/collection/array/typed/typed_array_copy.js +2 -2
- package/core/geom/3d/aabb/compute_aabb_from_points.js +4 -3
- package/core/geom/3d/compute_triangle_normal.js +76 -0
- package/core/geom/3d/topology/samples/sampleFloodFill.js +1 -1
- package/core/geom/3d/topology/simplify/compute_face_normal_change_dot_product.js +1 -1
- package/core/geom/3d/topology/simplify/quadratic/Quadratic3.js +1 -1
- package/core/geom/3d/topology/struct/TopoTriangle.js +1 -57
- package/core/geom/3d/topology/tm_face_normal.js +1 -1
- package/core/geom/3d/topology/tm_vertex_compute_normal.js +1 -1
- package/core/geom/3d/triangle/computeTriangleRayIntersection.js +195 -27
- package/core/geom/Vector3.js +12 -12
- package/core/math/physics/brdf/D_GGX.js +13 -0
- package/editor/tools/v2/prototypeTransformControls.js +14 -2
- package/engine/ecs/parent/EntityNode.js +80 -7
- package/engine/ecs/parent/EntityNodeFlags.js +8 -0
- package/engine/ecs/terrain/tiles/TerrainTile.js +7 -9
- package/engine/graphics/ecs/path/PathDisplaySystem.d.ts +3 -0
- package/engine/graphics/ecs/path/PathDisplaySystem.js +10 -0
- package/engine/graphics/geometry/AttributeSpec.js +18 -3
- package/engine/graphics/geometry/VertexDataSpec.js +53 -3
- package/engine/graphics/micron/format/VirtualGeometry.js +7 -0
- package/engine/graphics/micron/render/VirtualGeometryBuilder.js +1 -1
- package/engine/graphics/micron/render/refinement/get_geometry_patch_cut.js +5 -2
- package/engine/graphics/particles/particular/engine/parameter/sample/RGBA_LUT_HEATMAP_IR.js +11 -0
- package/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +2 -9
- package/engine/graphics/sh3/README.md +1 -0
- package/engine/graphics/sh3/path_tracer/GeometryBVHBatched.js +324 -0
- package/engine/graphics/sh3/path_tracer/PathTracedMesh.js +85 -0
- package/engine/graphics/sh3/path_tracer/PathTracer.js +469 -0
- package/engine/graphics/sh3/path_tracer/apply_texture_clamping_to_coordinate.js +22 -0
- package/engine/graphics/sh3/path_tracer/compute_triangle_group_aabb3.js +36 -0
- package/engine/graphics/sh3/path_tracer/getBiasedNormalSample.js +55 -0
- package/engine/graphics/sh3/path_tracer/make_sky_hosek.js +44 -0
- package/engine/graphics/sh3/path_tracer/make_sky_rtiw.js +15 -0
- package/engine/graphics/sh3/path_tracer/prototypePathTracer.js +619 -0
- package/engine/graphics/sh3/path_tracer/random_in_hemisphere.js +39 -0
- package/engine/graphics/sh3/path_tracer/ray_hit_apply_transform.js +42 -0
- package/engine/graphics/sh3/path_tracer/ray_reflect.js +27 -0
- package/engine/graphics/sh3/path_tracer/sample_triangle_attribute.js +35 -0
- package/engine/graphics/sh3/path_tracer/vec3_uint8_to_float.js +12 -0
- package/engine/graphics/sh3/sky/hosek/README.md +4 -0
- package/engine/graphics/sh3/sky/hosek/prototype_hosek.js +71 -0
- package/engine/graphics/sh3/sky/hosek/sky_hosek_compute_irradiance_by_direction.js +4171 -0
- package/engine/graphics/texture/sampler/convertTexture2Sampler2D.js +2 -0
- package/package.json +1 -1
- package/view/elements/progress/SmoothProgressBar.js +1 -1
- 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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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++] =
|
|
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 =
|
|
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
|
+
}
|