@woosh/meep-engine 2.109.20 → 2.109.22
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/build/bundle-worker-image-decoder.js +1 -1
- package/build/bundle-worker-terrain.js +1 -1
- package/build/meep.cjs +66 -33
- package/build/meep.min.js +1 -1
- package/build/meep.module.js +66 -33
- package/package.json +1 -1
- package/src/core/bvh2/bvh3/query/bvh_query_leaves_ray_segment.js +1 -1
- package/src/core/bvh2/bvh3/query/bvh_query_user_data_ray_segment.js +1 -1
- package/src/core/collection/array/isArrayEqualStrict.d.ts.map +1 -1
- package/src/core/collection/array/isArrayEqualStrict.js +1 -3
- package/src/core/collection/array/isArraysEqualWithComparator.d.ts.map +1 -1
- package/src/core/collection/array/isArraysEqualWithComparator.js +3 -2
- package/src/core/collection/array/typed/is_typed_array_equals.d.ts +1 -1
- package/src/core/collection/array/typed/is_typed_array_equals.d.ts.map +1 -1
- package/src/core/collection/array/typed/is_typed_array_equals.js +8 -2
- package/src/core/geom/3d/aabb/aabb3_array_near_distance_to_intersection_ray_segment.d.ts +16 -0
- package/src/core/geom/3d/aabb/aabb3_array_near_distance_to_intersection_ray_segment.d.ts.map +1 -0
- package/src/core/geom/3d/aabb/aabb3_array_near_distance_to_intersection_ray_segment.js +30 -0
- package/src/core/geom/3d/aabb/aabb3_intersects_ray_segment.d.ts +4 -5
- package/src/core/geom/3d/aabb/aabb3_intersects_ray_segment.d.ts.map +1 -1
- package/src/core/geom/3d/aabb/aabb3_intersects_ray_segment.js +6 -9
- package/src/core/geom/3d/aabb/aabb3_near_distance_to_intersection_ray_segment.d.ts +20 -0
- package/src/core/geom/3d/aabb/aabb3_near_distance_to_intersection_ray_segment.d.ts.map +1 -0
- package/src/core/geom/3d/aabb/aabb3_near_distance_to_intersection_ray_segment.js +67 -0
- package/src/core/geom/3d/line/line3_compute_nearest_point_to_point.d.ts.map +1 -1
- package/src/core/geom/3d/line/line3_compute_nearest_point_to_point.js +15 -1
- package/src/core/geom/3d/normal/octahedron/decode_octahedron_to_unit.d.ts +2 -1
- package/src/core/geom/3d/normal/octahedron/decode_octahedron_to_unit.d.ts.map +1 -1
- package/src/core/geom/3d/normal/octahedron/decode_octahedron_to_unit.js +6 -1
- package/src/core/geom/3d/triangle/computeTriangleClosestPointToPointBarycentric.d.ts +20 -0
- package/src/core/geom/3d/triangle/computeTriangleClosestPointToPointBarycentric.d.ts.map +1 -0
- package/src/core/geom/3d/triangle/computeTriangleClosestPointToPointBarycentric.js +147 -0
- package/src/core/geom/3d/triangle/computeTriangleClosestPointToPointBarycentric.spec.d.ts +2 -0
- package/src/core/geom/3d/triangle/computeTriangleClosestPointToPointBarycentric.spec.d.ts.map +1 -0
- package/src/core/geom/3d/triangle/computeTriangleClosestPointToPointBarycentric.spec.js +100 -0
- package/src/core/geom/octahedral_uv_crease_distance.d.ts +8 -0
- package/src/core/geom/octahedral_uv_crease_distance.d.ts.map +1 -0
- package/src/core/geom/octahedral_uv_crease_distance.js +26 -0
- package/src/core/math/random/generate_halton_jitter.js +2 -2
- package/src/core/math/statistics/generate_hammersley_jitter.d.ts +7 -0
- package/src/core/math/statistics/generate_hammersley_jitter.d.ts.map +1 -0
- package/src/core/math/statistics/generate_hammersley_jitter.js +16 -0
- package/src/core/math/statistics/hammersley_sequence_2d.js +2 -1
- package/src/core/model/object/objectDeepEquals.d.ts +1 -1
- package/src/core/model/object/objectDeepEquals.d.ts.map +1 -1
- package/src/core/model/object/objectDeepEquals.js +54 -26
- package/src/engine/graphics/geometry/buffered/computeGeometryEquality.d.ts.map +1 -1
- package/src/engine/graphics/geometry/buffered/computeGeometryEquality.js +4 -0
- package/src/engine/graphics/sh3/gi/material/common.glsl +1 -1
- package/src/engine/graphics/sh3/lpv/LightProbeVolume.d.ts +0 -7
- package/src/engine/graphics/sh3/lpv/LightProbeVolume.d.ts.map +1 -1
- package/src/engine/graphics/sh3/lpv/LightProbeVolume.js +0 -11
- package/src/engine/graphics/sh3/lpv/LightProbeVolumeBaker.d.ts +7 -0
- package/src/engine/graphics/sh3/lpv/LightProbeVolumeBaker.d.ts.map +1 -1
- package/src/engine/graphics/sh3/lpv/LightProbeVolumeBaker.js +39 -25
- package/src/engine/graphics/sh3/lpv/PathTracerProbeRenderer.js +1 -1
- package/src/engine/graphics/sh3/lpv/depth/octahedral/bake_octahedral_depth_map.d.ts.map +1 -1
- package/src/engine/graphics/sh3/lpv/depth/octahedral/bake_octahedral_depth_map.js +34 -35
- package/src/engine/graphics/sh3/path_tracer/BufferedGeometryBVH.d.ts +18 -0
- package/src/engine/graphics/sh3/path_tracer/BufferedGeometryBVH.d.ts.map +1 -1
- package/src/engine/graphics/sh3/path_tracer/BufferedGeometryBVH.js +421 -21
- package/src/engine/graphics/sh3/path_tracer/PathTracedMesh.js +1 -1
- package/src/engine/graphics/sh3/path_tracer/prototypePathTracer.js +4 -4
- package/src/engine/graphics/sh3/prototypeSH3Probe.js +4 -2
- package/src/engine/graphics/texture/virtual/prototype.js +3 -1
|
@@ -1,15 +1,20 @@
|
|
|
1
|
+
import { assert } from "../../../../../../core/assert.js";
|
|
2
|
+
import { UINT32_MAX } from "../../../../../../core/binary/UINT32_MAX.js";
|
|
1
3
|
import { array_copy } from "../../../../../../core/collection/array/array_copy.js";
|
|
2
4
|
import {
|
|
3
5
|
decode_octahedron_to_unit
|
|
4
6
|
} from "../../../../../../core/geom/3d/normal/octahedron/decode_octahedron_to_unit.js";
|
|
5
7
|
import { Ray3 } from "../../../../../../core/geom/3d/Ray3.js";
|
|
6
8
|
import { v3_distance } from "../../../../../../core/geom/vec3/v3_distance.js";
|
|
7
|
-
import { v3_dot } from "../../../../../../core/geom/vec3/v3_dot.js";
|
|
8
9
|
import { v3_dot_array_array } from "../../../../../../core/geom/vec3/v3_dot_array_array.js";
|
|
9
|
-
import { clamp01 } from "../../../../../../core/math/clamp01.js";
|
|
10
10
|
import { max2 } from "../../../../../../core/math/max2.js";
|
|
11
|
-
import {
|
|
12
|
-
|
|
11
|
+
import { generate_hammersley_jitter } from "../../../../../../core/math/statistics/generate_hammersley_jitter.js";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Weights of rays that are aligned with the probe direction get exponentially weighted by this exponent
|
|
15
|
+
* @type {number}
|
|
16
|
+
*/
|
|
17
|
+
const DEPTH_SHARPNESS = 40;
|
|
13
18
|
|
|
14
19
|
const scratch_ray = new Ray3();
|
|
15
20
|
|
|
@@ -23,9 +28,8 @@ const ray_hit = [];
|
|
|
23
28
|
*
|
|
24
29
|
* @type {number}
|
|
25
30
|
*/
|
|
26
|
-
const SUB_SAMPLE_COUNT =
|
|
31
|
+
const SUB_SAMPLE_COUNT = 4;
|
|
27
32
|
|
|
28
|
-
const DEPTH_SHARPNESS = 7;
|
|
29
33
|
|
|
30
34
|
/**
|
|
31
35
|
*
|
|
@@ -45,9 +49,16 @@ export function bake_octahedral_depth_map(
|
|
|
45
49
|
max_depth
|
|
46
50
|
) {
|
|
47
51
|
|
|
52
|
+
assert.lessThan(result_offset + resolution * resolution, UINT32_MAX, 'Result overflow');
|
|
53
|
+
|
|
48
54
|
scratch_ray.tMax = max_depth;
|
|
49
55
|
array_copy(position, position_offset, scratch_ray, 0, 3);
|
|
50
56
|
|
|
57
|
+
/**
|
|
58
|
+
* In radians, how wide of an arc does a single texel cover
|
|
59
|
+
* @type {number}
|
|
60
|
+
*/
|
|
61
|
+
const texel_angular_coverage = (Math.PI) / resolution;
|
|
51
62
|
|
|
52
63
|
/**
|
|
53
64
|
* Resolution bias is to compensate for discontinuities between samples
|
|
@@ -58,9 +69,9 @@ export function bake_octahedral_depth_map(
|
|
|
58
69
|
* xMath.SQRT2 is to allow for diagonals between pixels
|
|
59
70
|
* @type {number}
|
|
60
71
|
*/
|
|
61
|
-
const RESOLUTION_BIAS = Math.sin(
|
|
72
|
+
const RESOLUTION_BIAS = Math.sin(texel_angular_coverage) * Math.SQRT2 * 2;
|
|
62
73
|
|
|
63
|
-
const NORMAL_BIAS = max_depth * 0.01 + 1e-6;
|
|
74
|
+
const NORMAL_BIAS = max2(0.01, max_depth * 0.01) + 1e-6;
|
|
64
75
|
|
|
65
76
|
const ray_direction = scratch_ray.direction;
|
|
66
77
|
|
|
@@ -68,7 +79,7 @@ export function bake_octahedral_depth_map(
|
|
|
68
79
|
|
|
69
80
|
const texel_uv_scale = 0.5 / (resolution);
|
|
70
81
|
|
|
71
|
-
const jittered_sub_samples =
|
|
82
|
+
const jittered_sub_samples = generate_hammersley_jitter(SUB_SAMPLE_COUNT);
|
|
72
83
|
|
|
73
84
|
|
|
74
85
|
for (let oct_x = 0; oct_x < resolution; oct_x++) {
|
|
@@ -78,23 +89,18 @@ export function bake_octahedral_depth_map(
|
|
|
78
89
|
let weight_sum = 0;
|
|
79
90
|
|
|
80
91
|
// offset position by half a pixel, as we are storing values for pixel centers
|
|
81
|
-
const u = (oct_x ) / (resolution);
|
|
82
|
-
const v = (oct_y ) / (resolution);
|
|
83
|
-
|
|
84
|
-
// const u = (oct_x + 0.5) / (resolution - 1);
|
|
85
|
-
// const v = (oct_y + 0.5) / (resolution - 1);
|
|
86
|
-
|
|
87
|
-
decode_octahedron_to_unit(
|
|
88
|
-
probe_direction, 0,
|
|
89
|
-
u * 2 - 1, v * 2 - 1
|
|
90
|
-
);
|
|
92
|
+
const u = (oct_x + 0.5) / (resolution);
|
|
93
|
+
const v = (oct_y + 0.5) / (resolution);
|
|
91
94
|
|
|
92
95
|
for (let sub_sample_index = 0; sub_sample_index < SUB_SAMPLE_COUNT; sub_sample_index++) {
|
|
93
96
|
|
|
94
97
|
const sample_index2 = sub_sample_index * 2;
|
|
95
98
|
|
|
96
|
-
const
|
|
97
|
-
const
|
|
99
|
+
const sample_u = jittered_sub_samples[sample_index2];
|
|
100
|
+
const sample_v = jittered_sub_samples[sample_index2 + 1];
|
|
101
|
+
|
|
102
|
+
const ray_u = u + (sample_u * 2 - 1) * texel_uv_scale;
|
|
103
|
+
const ray_v = v + (sample_v * 2 - 1) * texel_uv_scale;
|
|
98
104
|
|
|
99
105
|
decode_octahedron_to_unit(
|
|
100
106
|
ray_direction, 0,
|
|
@@ -115,27 +121,18 @@ export function bake_octahedral_depth_map(
|
|
|
115
121
|
const surface_position_y = ray_hit[1];
|
|
116
122
|
const surface_position_z = ray_hit[2];
|
|
117
123
|
|
|
118
|
-
|
|
119
|
-
const hit_angle_cos = -v3_dot(
|
|
120
|
-
surface_normal_x, surface_normal_y, surface_normal_z,
|
|
121
|
-
ray_direction[0], ray_direction[1], ray_direction[2]
|
|
122
|
-
);
|
|
123
|
-
|
|
124
|
-
const resolution_bias_offset = max_depth * RESOLUTION_BIAS;
|
|
125
|
-
|
|
126
|
-
const hit_normal_bias = clamp01( 1-hit_angle_cos) * (resolution_bias_offset) + NORMAL_BIAS;
|
|
124
|
+
const hit_normal_bias = -NORMAL_BIAS;
|
|
127
125
|
|
|
128
126
|
// sink the contact into the surface along the hit normal
|
|
129
|
-
const biased_hit_x = surface_position_x
|
|
130
|
-
const biased_hit_y = surface_position_y
|
|
131
|
-
const biased_hit_z = surface_position_z
|
|
127
|
+
const biased_hit_x = surface_position_x + surface_normal_x * hit_normal_bias;
|
|
128
|
+
const biased_hit_y = surface_position_y + surface_normal_y * hit_normal_bias;
|
|
129
|
+
const biased_hit_z = surface_position_z + surface_normal_z * hit_normal_bias;
|
|
132
130
|
|
|
133
131
|
distance = v3_distance(
|
|
134
132
|
scratch_ray[0], scratch_ray[1], scratch_ray[2],
|
|
135
133
|
biased_hit_x, biased_hit_y, biased_hit_z
|
|
136
134
|
);
|
|
137
135
|
|
|
138
|
-
// distance += resolution_bias_offset;
|
|
139
136
|
}
|
|
140
137
|
|
|
141
138
|
const direction_dot_product = v3_dot_array_array(ray_direction, 0, probe_direction, 0);
|
|
@@ -155,7 +152,9 @@ export function bake_octahedral_depth_map(
|
|
|
155
152
|
|
|
156
153
|
const address = result_offset + pixel_index;
|
|
157
154
|
|
|
158
|
-
|
|
155
|
+
const distance = distance_sum / weight_sum;
|
|
156
|
+
|
|
157
|
+
result[address] = distance;
|
|
159
158
|
}
|
|
160
159
|
}
|
|
161
160
|
|
|
@@ -40,6 +40,23 @@ export class BufferedGeometryBVH {
|
|
|
40
40
|
* @returns {boolean}
|
|
41
41
|
*/
|
|
42
42
|
occluded(ray: Ray3): boolean;
|
|
43
|
+
/**
|
|
44
|
+
*
|
|
45
|
+
* @param {SurfacePoint3} result
|
|
46
|
+
* @param {number} x
|
|
47
|
+
* @param {number} y
|
|
48
|
+
* @param {number} z
|
|
49
|
+
* @returns {boolean} true if result is found, only false when geometry is empty
|
|
50
|
+
*/
|
|
51
|
+
nearestSurfacePoint(result: SurfacePoint3, x: number, y: number, z: number): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Code is largely inlined, to avoid extra checks
|
|
54
|
+
* NOTE: raycast is performed in local coordinate space
|
|
55
|
+
* @param {number[]} output
|
|
56
|
+
* @param {number[]|Ray3} ray
|
|
57
|
+
* @returns {number} distance along the ray, negative if no hit
|
|
58
|
+
*/
|
|
59
|
+
raycast2(output: number[], ray: number[] | Ray3): number;
|
|
43
60
|
/**
|
|
44
61
|
* NOTE: raycast is performed in local coordinate space
|
|
45
62
|
* @param {number[]} output
|
|
@@ -50,4 +67,5 @@ export class BufferedGeometryBVH {
|
|
|
50
67
|
#private;
|
|
51
68
|
}
|
|
52
69
|
import { AABB3 } from "../../../../core/geom/3d/aabb/AABB3.js";
|
|
70
|
+
import { SurfacePoint3 } from "../../../../core/geom/3d/SurfacePoint3.js";
|
|
53
71
|
//# sourceMappingURL=BufferedGeometryBVH.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BufferedGeometryBVH.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/sh3/path_tracer/BufferedGeometryBVH.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"BufferedGeometryBVH.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/sh3/path_tracer/BufferedGeometryBVH.js"],"names":[],"mappings":"AA+CA;IAkBI;;;OAGG;IACH,eAFW,KAAK,GAAC,MAAM,EAAE,QAIxB;IAIG;;;;OAIG;IACH,mBAAsB;IAEtB;;;;OAIG;IACH,yBAA4B;IAE5B;;;;OAIG;IACH,6BAAgC;IAGhC;;;;OAIG;IACH,yBAAyB;IAG7B;;;OAGG;IACH,WAFW,MAAM,cAAc,QAwC9B;IAED;;;;;OAKG;IACH,qBAFa,OAAO,CAmHnB;IAED;;;;;;;OAOG;IACH,4BANW,aAAa,KACb,MAAM,KACN,MAAM,KACN,MAAM,GACJ,OAAO,CAqKnB;IAGD;;;;;;OAMG;IACH,iBAJW,MAAM,EAAE,OACR,MAAM,EAAE,OAAK,GACX,MAAM,CAoIlB;IAED;;;;;OAKG;IACH,gBAJW,MAAM,EAAE,OACR,MAAM,EAAE,OAAK,GACX,MAAM,CA2ElB;;CACJ;sBA3oBqB,wCAAwC;8BAKhC,2CAA2C"}
|
|
@@ -1,12 +1,30 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
BVH,
|
|
3
|
+
COLUMN_CHILD_1,
|
|
4
|
+
COLUMN_CHILD_2,
|
|
5
|
+
COLUMN_USER_DATA,
|
|
6
|
+
ELEMENT_WORD_COUNT,
|
|
7
|
+
NULL_NODE
|
|
8
|
+
} from "../../../../core/bvh2/bvh3/BVH.js";
|
|
2
9
|
import { ebvh_build_for_geometry_morton } from "../../../../core/bvh2/bvh3/ebvh_build_for_geometry_morton.js";
|
|
3
10
|
import { bvh_query_user_data_ray_segment } from "../../../../core/bvh2/bvh3/query/bvh_query_user_data_ray_segment.js";
|
|
4
11
|
import { array_copy } from "../../../../core/collection/array/array_copy.js";
|
|
12
|
+
import { SCRATCH_UINT32_TRAVERSAL_STACK } from "../../../../core/collection/SCRATCH_UINT32_TRAVERSAL_STACK.js";
|
|
5
13
|
import { AABB3 } from "../../../../core/geom/3d/aabb/AABB3.js";
|
|
14
|
+
import { aabb3_intersects_ray_segment } from "../../../../core/geom/3d/aabb/aabb3_intersects_ray_segment.js";
|
|
15
|
+
import {
|
|
16
|
+
aabb3_unsigned_distance_sqr_to_point
|
|
17
|
+
} from "../../../../core/geom/3d/aabb/aabb3_unsigned_distance_sqr_to_point.js";
|
|
18
|
+
import { SurfacePoint3 } from "../../../../core/geom/3d/SurfacePoint3.js";
|
|
19
|
+
import {
|
|
20
|
+
computeTriangleClosestPointToPointBarycentric
|
|
21
|
+
} from "../../../../core/geom/3d/triangle/computeTriangleClosestPointToPointBarycentric.js";
|
|
6
22
|
|
|
7
23
|
import {
|
|
8
24
|
computeTriangleRayIntersectionBarycentricGeometry
|
|
9
25
|
} from "../../../../core/geom/3d/triangle/computeTriangleRayIntersectionBarycentricGeometry.js";
|
|
26
|
+
import { v3_compute_triangle_normal } from "../../../../core/geom/3d/v3_compute_triangle_normal.js";
|
|
27
|
+
import { v3_distance_sqr } from "../../../../core/geom/vec3/v3_distance_sqr.js";
|
|
10
28
|
import Vector4 from "../../../../core/geom/Vector4.js";
|
|
11
29
|
import { makeGeometryIndexed } from "../../geometry/buffered/makeGeometryIndexed.js";
|
|
12
30
|
import { computeBoundingSphereFromVertexData } from "../../geometry/computeBoundingSphereFromVertexData.js";
|
|
@@ -23,6 +41,10 @@ const scratch_uint32_array = new Uint32Array(4096);
|
|
|
23
41
|
*/
|
|
24
42
|
const v3_scratch_0 = [];
|
|
25
43
|
|
|
44
|
+
const scratch_contact = new SurfacePoint3();
|
|
45
|
+
|
|
46
|
+
const stack = SCRATCH_UINT32_TRAVERSAL_STACK;
|
|
47
|
+
|
|
26
48
|
export class BufferedGeometryBVH {
|
|
27
49
|
/**
|
|
28
50
|
* @type {Uint32Array}
|
|
@@ -147,40 +169,418 @@ export class BufferedGeometryBVH {
|
|
|
147
169
|
|
|
148
170
|
const bvh = this.#bvh;
|
|
149
171
|
|
|
150
|
-
const
|
|
151
|
-
bvh, bvh.root,
|
|
152
|
-
scratch_uint32_array, 0,
|
|
153
|
-
origin_x, origin_y, origin_z,
|
|
154
|
-
direction_x, direction_y, direction_z,
|
|
155
|
-
0, max_distance
|
|
156
|
-
);
|
|
172
|
+
const root = bvh.root;
|
|
157
173
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
174
|
+
if (root === NULL_NODE) {
|
|
175
|
+
return -1;
|
|
176
|
+
}
|
|
161
177
|
|
|
162
|
-
|
|
163
|
-
|
|
178
|
+
/**
|
|
179
|
+
* Move stack pointer to local variable scope to avoid de-referencing inside the loop
|
|
180
|
+
* @type {number}
|
|
181
|
+
*/
|
|
182
|
+
let pointer = stack.pointer;
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
*
|
|
186
|
+
* @type {number}
|
|
187
|
+
*/
|
|
188
|
+
const stack_top = pointer;
|
|
189
|
+
|
|
190
|
+
stack[pointer++] = root;
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
/*
|
|
194
|
+
For performance, we bind data directly to avoid extra copies required to read out AABB
|
|
195
|
+
*/
|
|
196
|
+
const float32 = bvh.__data_float32;
|
|
197
|
+
const uint32 = bvh.__data_uint32;
|
|
198
|
+
|
|
199
|
+
const inv_direction_x = 1 / direction_x;
|
|
200
|
+
const inv_direction_y = 1 / direction_y;
|
|
201
|
+
const inv_direction_z = 1 / direction_z;
|
|
202
|
+
|
|
203
|
+
do {
|
|
204
|
+
|
|
205
|
+
--pointer;
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
*
|
|
209
|
+
* @type {number}
|
|
210
|
+
*/
|
|
211
|
+
const node = stack[pointer];
|
|
212
|
+
|
|
213
|
+
const address = node * ELEMENT_WORD_COUNT;
|
|
214
|
+
|
|
215
|
+
// test node against the ray
|
|
216
|
+
const intersects = aabb3_intersects_ray_segment(
|
|
217
|
+
float32[address], float32[address + 1], float32[address + 2],
|
|
218
|
+
float32[address + 3], float32[address + 4], float32[address + 5],
|
|
164
219
|
origin_x, origin_y, origin_z,
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
positions
|
|
220
|
+
inv_direction_x, inv_direction_y, inv_direction_z,
|
|
221
|
+
0, max_distance
|
|
168
222
|
);
|
|
169
223
|
|
|
170
|
-
if (!
|
|
224
|
+
if (!intersects) {
|
|
171
225
|
continue;
|
|
172
226
|
}
|
|
173
227
|
|
|
174
|
-
|
|
228
|
+
// get fist child to check if this is a leaf node or not
|
|
229
|
+
const child_1 = uint32[address + COLUMN_CHILD_1];
|
|
230
|
+
|
|
231
|
+
if (child_1 !== NULL_NODE) {
|
|
232
|
+
|
|
233
|
+
// this is not a leaf node, push children onto traversal stack
|
|
234
|
+
const child_2 = uint32[address + COLUMN_CHILD_2];
|
|
235
|
+
|
|
236
|
+
stack[pointer++] = child_2;
|
|
237
|
+
stack[pointer++] = child_1;
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
} else {
|
|
241
|
+
// leaf node
|
|
242
|
+
|
|
243
|
+
const triangle_index = uint32[address + COLUMN_USER_DATA];
|
|
244
|
+
|
|
245
|
+
const intersection_found = computeTriangleRayIntersectionBarycentricGeometry(
|
|
246
|
+
v3_scratch_0,
|
|
247
|
+
origin_x, origin_y, origin_z,
|
|
248
|
+
direction_x, direction_y, direction_z,
|
|
249
|
+
indices, triangle_index,
|
|
250
|
+
positions
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
if (!intersection_found) {
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const t = v3_scratch_0[0];
|
|
258
|
+
|
|
259
|
+
if (t < max_distance && t > 0) {
|
|
260
|
+
return true;
|
|
261
|
+
|
|
262
|
+
}
|
|
175
263
|
|
|
176
|
-
if (t < max_distance && t > 0) {
|
|
177
|
-
return true;
|
|
178
264
|
}
|
|
179
|
-
}
|
|
265
|
+
} while (pointer > stack_top);
|
|
266
|
+
|
|
180
267
|
|
|
181
268
|
return false;
|
|
182
269
|
}
|
|
183
270
|
|
|
271
|
+
/**
|
|
272
|
+
*
|
|
273
|
+
* @param {SurfacePoint3} result
|
|
274
|
+
* @param {number} x
|
|
275
|
+
* @param {number} y
|
|
276
|
+
* @param {number} z
|
|
277
|
+
* @returns {boolean} true if result is found, only false when geometry is empty
|
|
278
|
+
*/
|
|
279
|
+
nearestSurfacePoint(result, x, y, z) {
|
|
280
|
+
|
|
281
|
+
const indices = this.__geometry_index;
|
|
282
|
+
const positions = this.__geometry_positions;
|
|
283
|
+
|
|
284
|
+
const bvh = this.#bvh;
|
|
285
|
+
|
|
286
|
+
const root = bvh.root;
|
|
287
|
+
|
|
288
|
+
if (root === NULL_NODE) {
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Move stack pointer to local variable scope to avoid de-referencing inside the loop
|
|
294
|
+
* @type {number}
|
|
295
|
+
*/
|
|
296
|
+
let pointer = stack.pointer;
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
*
|
|
300
|
+
* @type {number}
|
|
301
|
+
*/
|
|
302
|
+
const stack_top = pointer;
|
|
303
|
+
|
|
304
|
+
stack[pointer++] = root;
|
|
305
|
+
|
|
306
|
+
/*
|
|
307
|
+
For performance, we bind data directly to avoid extra copies required to read out AABB
|
|
308
|
+
*/
|
|
309
|
+
const float32 = bvh.__data_float32;
|
|
310
|
+
const uint32 = bvh.__data_uint32;
|
|
311
|
+
|
|
312
|
+
let nearest_distance_sqr = Infinity;
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
do {
|
|
316
|
+
--pointer;
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
*
|
|
320
|
+
* @type {number}
|
|
321
|
+
*/
|
|
322
|
+
const node = stack[pointer];
|
|
323
|
+
|
|
324
|
+
const address = node * ELEMENT_WORD_COUNT;
|
|
325
|
+
|
|
326
|
+
// test node against the ray
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
// get fist child to check if this is a leaf node or not
|
|
330
|
+
const child_1 = uint32[address + COLUMN_CHILD_1];
|
|
331
|
+
|
|
332
|
+
if (child_1 !== NULL_NODE) {
|
|
333
|
+
|
|
334
|
+
// this is not a leaf node, push children onto traversal stack
|
|
335
|
+
const child_2 = uint32[address + COLUMN_CHILD_2];
|
|
336
|
+
|
|
337
|
+
// to achieve faster convergence, we sort children before adding them to the stack by their proximity to the reference point
|
|
338
|
+
const child_1_address = child_1 * ELEMENT_WORD_COUNT;
|
|
339
|
+
|
|
340
|
+
const distance_sqr_to_child1 = aabb3_unsigned_distance_sqr_to_point(
|
|
341
|
+
float32[child_1_address], float32[child_1_address + 1], float32[child_1_address + 2],
|
|
342
|
+
float32[child_1_address + 3], float32[child_1_address + 4], float32[child_1_address + 5],
|
|
343
|
+
x, y, z
|
|
344
|
+
);
|
|
345
|
+
|
|
346
|
+
const child_2_address = child_2 * ELEMENT_WORD_COUNT;
|
|
347
|
+
|
|
348
|
+
const distance_sqr_to_child2 = aabb3_unsigned_distance_sqr_to_point(
|
|
349
|
+
float32[child_2_address], float32[child_2_address + 1], float32[child_2_address + 2],
|
|
350
|
+
float32[child_2_address + 3], float32[child_2_address + 4], float32[child_2_address + 5],
|
|
351
|
+
x, y, z
|
|
352
|
+
);
|
|
353
|
+
|
|
354
|
+
if (distance_sqr_to_child1 < distance_sqr_to_child2) {
|
|
355
|
+
|
|
356
|
+
if (distance_sqr_to_child2 < nearest_distance_sqr) {
|
|
357
|
+
stack[pointer++] = child_2;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if (distance_sqr_to_child1 < nearest_distance_sqr) {
|
|
361
|
+
stack[pointer++] = child_1;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
} else {
|
|
365
|
+
|
|
366
|
+
if (distance_sqr_to_child1 < nearest_distance_sqr) {
|
|
367
|
+
stack[pointer++] = child_1;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
if (distance_sqr_to_child2 < nearest_distance_sqr) {
|
|
371
|
+
stack[pointer++] = child_2;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
} else {
|
|
378
|
+
// leaf node
|
|
379
|
+
// read triangle data
|
|
380
|
+
const triangle_index = uint32[address + COLUMN_USER_DATA];
|
|
381
|
+
|
|
382
|
+
const a = indices[triangle_index];
|
|
383
|
+
const b = indices[triangle_index + 1];
|
|
384
|
+
const c = indices[triangle_index + 2];
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
const a_address = a * 3;
|
|
388
|
+
const b_address = b * 3;
|
|
389
|
+
const c_address = c * 3;
|
|
390
|
+
|
|
391
|
+
const ax = positions[a_address];
|
|
392
|
+
const ay = positions[a_address + 1];
|
|
393
|
+
const az = positions[a_address + 2];
|
|
394
|
+
|
|
395
|
+
const bx = positions[b_address];
|
|
396
|
+
const by = positions[b_address + 1];
|
|
397
|
+
const bz = positions[b_address + 2];
|
|
398
|
+
|
|
399
|
+
const cx = positions[c_address];
|
|
400
|
+
const cy = positions[c_address + 1];
|
|
401
|
+
const cz = positions[c_address + 2];
|
|
402
|
+
|
|
403
|
+
computeTriangleClosestPointToPointBarycentric(
|
|
404
|
+
v3_scratch_0, 0,
|
|
405
|
+
x, y, z,
|
|
406
|
+
ax, ay, az,
|
|
407
|
+
bx, by, bz,
|
|
408
|
+
cx, cy, cz
|
|
409
|
+
);
|
|
410
|
+
|
|
411
|
+
const u = v3_scratch_0[0];
|
|
412
|
+
const v = v3_scratch_0[1];
|
|
413
|
+
|
|
414
|
+
// construct edge
|
|
415
|
+
|
|
416
|
+
const contact_x = (bx - ax) * u + (cx - ax) * v + ax;
|
|
417
|
+
const contact_y = (by - ay) * u + (cy - ay) * v + ay;
|
|
418
|
+
const contact_z = (bz - az) * u + (cz - az) * v + az;
|
|
419
|
+
|
|
420
|
+
const distance_to_triangle_sqr = v3_distance_sqr(contact_x, contact_y, contact_z, x, y, z);
|
|
421
|
+
|
|
422
|
+
if (distance_to_triangle_sqr >= nearest_distance_sqr) {
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
nearest_distance_sqr = distance_to_triangle_sqr;
|
|
427
|
+
|
|
428
|
+
result.position.set(contact_x, contact_y, contact_z);
|
|
429
|
+
|
|
430
|
+
v3_compute_triangle_normal(result.normal, 0,
|
|
431
|
+
ax, ay, az,
|
|
432
|
+
bx, by, bz,
|
|
433
|
+
cx, cy, cz
|
|
434
|
+
);
|
|
435
|
+
|
|
436
|
+
result.index = triangle_index;
|
|
437
|
+
}
|
|
438
|
+
} while (pointer > stack_top);
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
return true;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Code is largely inlined, to avoid extra checks
|
|
447
|
+
* NOTE: raycast is performed in local coordinate space
|
|
448
|
+
* @param {number[]} output
|
|
449
|
+
* @param {number[]|Ray3} ray
|
|
450
|
+
* @returns {number} distance along the ray, negative if no hit
|
|
451
|
+
*/
|
|
452
|
+
raycast2(output, ray) {
|
|
453
|
+
|
|
454
|
+
const indices = this.__geometry_index;
|
|
455
|
+
const positions = this.__geometry_positions;
|
|
456
|
+
|
|
457
|
+
const origin_x = ray[0];
|
|
458
|
+
const origin_y = ray[1];
|
|
459
|
+
const origin_z = ray[2];
|
|
460
|
+
|
|
461
|
+
const direction_x = ray[3];
|
|
462
|
+
const direction_y = ray[4];
|
|
463
|
+
const direction_z = ray[5];
|
|
464
|
+
|
|
465
|
+
const max_distance = ray[6];
|
|
466
|
+
|
|
467
|
+
const bvh = this.#bvh;
|
|
468
|
+
|
|
469
|
+
const root = bvh.root;
|
|
470
|
+
|
|
471
|
+
if (root === NULL_NODE) {
|
|
472
|
+
return -1;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Move stack pointer to local variable scope to avoid de-referencing inside the loop
|
|
477
|
+
* @type {number}
|
|
478
|
+
*/
|
|
479
|
+
let pointer = stack.pointer;
|
|
480
|
+
|
|
481
|
+
let nearest_hit_distance = max_distance;
|
|
482
|
+
|
|
483
|
+
let best_index = -1;
|
|
484
|
+
let best_u = 0;
|
|
485
|
+
let best_v = 0;
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
*
|
|
489
|
+
* @type {number}
|
|
490
|
+
*/
|
|
491
|
+
const stack_top = pointer;
|
|
492
|
+
|
|
493
|
+
stack[pointer++] = root;
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
/*
|
|
497
|
+
For performance, we bind data directly to avoid extra copies required to read out AABB
|
|
498
|
+
*/
|
|
499
|
+
const float32 = bvh.__data_float32;
|
|
500
|
+
const uint32 = bvh.__data_uint32;
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
const inv_direction_x = 1 / direction_x;
|
|
504
|
+
const inv_direction_y = 1 / direction_y;
|
|
505
|
+
const inv_direction_z = 1 / direction_z;
|
|
506
|
+
|
|
507
|
+
do {
|
|
508
|
+
|
|
509
|
+
--pointer;
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
*
|
|
513
|
+
* @type {number}
|
|
514
|
+
*/
|
|
515
|
+
const node = stack[pointer];
|
|
516
|
+
|
|
517
|
+
const address = node * ELEMENT_WORD_COUNT;
|
|
518
|
+
|
|
519
|
+
// test node against the ray
|
|
520
|
+
const intersects = aabb3_intersects_ray_segment(
|
|
521
|
+
float32[address], float32[address + 1], float32[address + 2],
|
|
522
|
+
float32[address + 3], float32[address + 4], float32[address + 5],
|
|
523
|
+
origin_x, origin_y, origin_z,
|
|
524
|
+
inv_direction_x, inv_direction_y, inv_direction_z,
|
|
525
|
+
0, nearest_hit_distance
|
|
526
|
+
);
|
|
527
|
+
|
|
528
|
+
if (!intersects) {
|
|
529
|
+
continue;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// get fist child to check if this is a leaf node or not
|
|
533
|
+
const child_1 = uint32[address + COLUMN_CHILD_1];
|
|
534
|
+
|
|
535
|
+
if (child_1 !== NULL_NODE) {
|
|
536
|
+
|
|
537
|
+
// this is not a leaf node, push children onto traversal stack
|
|
538
|
+
const child_2 = uint32[address + COLUMN_CHILD_2];
|
|
539
|
+
|
|
540
|
+
stack[pointer++] = child_2;
|
|
541
|
+
stack[pointer++] = child_1;
|
|
542
|
+
|
|
543
|
+
} else {
|
|
544
|
+
// leaf node
|
|
545
|
+
|
|
546
|
+
const triangle_index = uint32[address + COLUMN_USER_DATA];
|
|
547
|
+
|
|
548
|
+
const intersection_found = computeTriangleRayIntersectionBarycentricGeometry(
|
|
549
|
+
v3_scratch_0,
|
|
550
|
+
origin_x, origin_y, origin_z,
|
|
551
|
+
direction_x, direction_y, direction_z,
|
|
552
|
+
indices, triangle_index,
|
|
553
|
+
positions
|
|
554
|
+
);
|
|
555
|
+
|
|
556
|
+
if (!intersection_found) {
|
|
557
|
+
continue;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
const t = v3_scratch_0[0];
|
|
561
|
+
|
|
562
|
+
if (t < nearest_hit_distance && t > 0) {
|
|
563
|
+
nearest_hit_distance = t;
|
|
564
|
+
|
|
565
|
+
best_index = triangle_index;
|
|
566
|
+
best_u = v3_scratch_0[1];
|
|
567
|
+
best_v = v3_scratch_0[2];
|
|
568
|
+
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
}
|
|
572
|
+
} while (pointer > stack_top);
|
|
573
|
+
|
|
574
|
+
if (nearest_hit_distance === max_distance) {
|
|
575
|
+
// no hit
|
|
576
|
+
return -1;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
construct_ray_hit_from_geometry(output, indices, positions, best_index, nearest_hit_distance, best_u, best_v);
|
|
580
|
+
|
|
581
|
+
return nearest_hit_distance;
|
|
582
|
+
}
|
|
583
|
+
|
|
184
584
|
/**
|
|
185
585
|
* NOTE: raycast is performed in local coordinate space
|
|
186
586
|
* @param {number[]} output
|
|
@@ -67,8 +67,8 @@ vCanvas.css({
|
|
|
67
67
|
* How many rays to use per-pixel
|
|
68
68
|
* @type {number}
|
|
69
69
|
*/
|
|
70
|
-
const PIXEL_SAMPLE_COUNT =
|
|
71
|
-
const PIXEL_RENDER_RATIO =
|
|
70
|
+
const PIXEL_SAMPLE_COUNT = 16;
|
|
71
|
+
const PIXEL_RENDER_RATIO = 1;
|
|
72
72
|
|
|
73
73
|
const scene = new PathTracedScene();
|
|
74
74
|
const pt = new PathTracer();
|
|
@@ -534,8 +534,8 @@ async function start_renderer(camera) {
|
|
|
534
534
|
// await prepare_scene_lucy(scene, camera);
|
|
535
535
|
// await prepare_scene_rtiow(pt, camera);
|
|
536
536
|
// await prepare_scene_sphere_01(pt, camera);
|
|
537
|
-
|
|
538
|
-
await prepare_sponza(scene, camera);
|
|
537
|
+
await prepare_gi_box_scene(scene, camera);
|
|
538
|
+
// await prepare_sponza(scene, camera);
|
|
539
539
|
// await prepare_attic_scene(scene, camera);
|
|
540
540
|
// await prepare_scene_gltf({scene, camera, path, url: path});
|
|
541
541
|
|