@woosh/meep-engine 2.33.38 → 2.33.42
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/bvh2/binary/2/BinaryUint32BVH.js +3 -3
- package/core/collection/array/typed/typed_array_copy.js +2 -2
- package/core/geom/3d/aabb/aabb3_matrix4_project_by_corners.js +1 -1
- package/core/geom/3d/morton/mortonEncode_magicbits.js +7 -6
- package/core/geom/3d/morton/v3_morton_encode_transformed.js +15 -11
- package/core/geom/3d/tetrahedra/tetrahedra_collection.js +193 -18
- package/core/geom/3d/tetrahedra/tetrahedron_contains_point.js +2 -1
- package/engine/asset/loaders/GLTFAssetLoader.js +4 -8
- package/engine/ecs/System.d.ts +24 -1
- package/engine/graphics/ecs/light/binding/fp/FPLightBinding.js +1 -1
- package/engine/graphics/particles/particular/engine/parameter/ParameterLookupTable.js +20 -24
- package/engine/graphics/particles/particular/engine/shader/ShaderManager.js +1 -1
- package/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +2 -2
- package/engine/graphics/render/buffer/simple-fx/DepthLimitedBlur.js +9 -4
- package/engine/graphics/render/buffer/simple-fx/ao/AmbientOcclusionPostProcessEffect.js +7 -1
- package/engine/graphics/render/forward_plus/LightManager.js +295 -51
- package/engine/graphics/render/forward_plus/LightManager.spec.js +1 -1
- package/engine/graphics/render/forward_plus/PointLightData.js +9 -13
- package/engine/graphics/render/forward_plus/data/TextureBackedMemoryRegion.js +10 -1
- package/engine/graphics/render/forward_plus/debug/LightClusterVolumeMaterial.js +1 -1
- package/engine/graphics/render/forward_plus/debug/buildLightClusterWidget.js +3 -1
- package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_ACCUMULATION.js +31 -18
- package/engine/graphics/render/forward_plus/materials/fp_build_fragment_shader.js +1 -0
- package/engine/graphics/render/forward_plus/model/AbstractLight.js +50 -0
- package/engine/graphics/render/forward_plus/model/Decal.js +68 -0
- package/engine/graphics/render/forward_plus/{PointLight.js → model/PointLight.js} +19 -11
- package/engine/graphics/render/forward_plus/{SpotLight.js → model/SpotLight.js} +20 -12
- package/engine/graphics/render/forward_plus/plugin/ptototypeFPPlugin.js +6 -5
- package/engine/graphics/render/forward_plus/{prototypeLightManager.js → prototype/prototypeLightManager.js} +100 -25
- package/engine/graphics/render/forward_plus/query/query_bvh_frustum_from_texture.js +29 -20
- package/engine/graphics/render/visibility/IncrementalDeltaSet.d.ts +2 -0
- package/engine/graphics/render/visibility/IncrementalDeltaSet.js +1 -0
- package/engine/graphics/texture/atlas/AbstractTextureAtlas.js +19 -0
- package/engine/graphics/texture/atlas/CachingTextureAtlas.js +99 -0
- package/engine/graphics/texture/atlas/ManagedTextureAtlas.js +19 -39
- package/engine/graphics/texture/atlas/ReferencedTextureAtlas.js +75 -0
- package/engine/graphics/texture/atlas/TextureAtlas.js +22 -2
- package/engine/reference/v2/Reference.d.ts +4 -0
- package/engine/reference/v2/Reference.js +3 -1
- package/package.json +1 -1
|
@@ -434,11 +434,11 @@ export class BinaryUint32BVH {
|
|
|
434
434
|
* Assemble leaf nodes into hierarchy, set binary node bounds iteratively bottom up
|
|
435
435
|
*/
|
|
436
436
|
build() {
|
|
437
|
-
const
|
|
437
|
+
const binary_node_count = this.__node_count_binary;
|
|
438
438
|
|
|
439
|
-
const leaf_node_block_address =
|
|
439
|
+
const leaf_node_block_address = binary_node_count * BVH_BINARY_NODE_SIZE;
|
|
440
440
|
|
|
441
|
-
let level = Math.floor(Math.log(
|
|
441
|
+
let level = Math.floor(Math.log(binary_node_count) / Math.log(2));
|
|
442
442
|
|
|
443
443
|
let i, offset, level_node_count;
|
|
444
444
|
//NOTE: building first level separately allows to avoid some switching logic needed to determine what is the type of lower level node
|
|
@@ -3,8 +3,8 @@ import { array_copy } from "../copyArray.js";
|
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Assumes arrays have the same type
|
|
6
|
-
* @param {TypedArray|Float32Array} source
|
|
7
|
-
* @param {TypedArray|Float32Array} destination
|
|
6
|
+
* @param {TypedArray|Float32Array|Uint8Array} source
|
|
7
|
+
* @param {TypedArray|Float32Array|Uint8Array} destination
|
|
8
8
|
*/
|
|
9
9
|
export function typed_array_copy(source, destination) {
|
|
10
10
|
const destination_size = destination.length;
|
|
@@ -4,7 +4,7 @@ import { assert } from "../../../assert.js";
|
|
|
4
4
|
*
|
|
5
5
|
* @param {number[]|Float32Array} result
|
|
6
6
|
* @param {number[]|Float32Array|Float64Array} aabb_corners
|
|
7
|
-
* @param {number[]|Float32Array} projection_matrix
|
|
7
|
+
* @param {number[]|Float32Array|mat4} projection_matrix
|
|
8
8
|
*/
|
|
9
9
|
export function aabb3_matrix4_project_by_corners(result, aabb_corners, projection_matrix) {
|
|
10
10
|
assert.greaterThanOrEqual(result.length, 6, 'result.length must >= 6');
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* method to separate bits from a given integer 3 positions apart
|
|
3
3
|
* we only look at the first 10 bits
|
|
4
|
+
*
|
|
5
|
+
* @example when input is ABC, output bits are A00B00C
|
|
4
6
|
* @param {number} a
|
|
5
7
|
* @returns {number}
|
|
6
8
|
*/
|
|
7
|
-
function
|
|
9
|
+
function split_by_3(a) {
|
|
8
10
|
let x = a;
|
|
9
11
|
x = (x | x << 16) & 0x30000ff;
|
|
10
12
|
x = (x | x << 8) & 0x0300f00f;
|
|
@@ -25,10 +27,9 @@ function splitBy3(a) {
|
|
|
25
27
|
*/
|
|
26
28
|
export function mortonEncode_magicbits(x, y, z) {
|
|
27
29
|
|
|
28
|
-
const x_bits =
|
|
29
|
-
const y_bits =
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
return x_bits | y_bits | z_bit;
|
|
30
|
+
const x_bits = split_by_3(x);
|
|
31
|
+
const y_bits = split_by_3(y) << 1;
|
|
32
|
+
const z_bits = split_by_3(z) << 2;
|
|
33
33
|
|
|
34
|
+
return x_bits | y_bits | z_bits;
|
|
34
35
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { mortonEncode_magicbits } from "./mortonEncode_magicbits.js";
|
|
2
|
+
import { clamp } from "../../../math/clamp.js";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Assumes that coordinates will be mapped to -1..1 range after transform
|
|
@@ -16,18 +17,21 @@ export function v3_morton_encode_transformed(x, y, z, matrix) {
|
|
|
16
17
|
const _z = matrix[2] * x + matrix[6] * y + matrix[10] * z + matrix[14];
|
|
17
18
|
const _w = matrix[3] * x + matrix[7] * y + matrix[11] * z + matrix[15];
|
|
18
19
|
|
|
19
|
-
const d =
|
|
20
|
+
const d = 511.5 / _w;
|
|
20
21
|
|
|
21
|
-
// apply perspective divide
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
const
|
|
22
|
+
// apply perspective divide as well as scaling to 10 bits
|
|
23
|
+
const ndc_x = _x * d;
|
|
24
|
+
const ndc_y = _y * d;
|
|
25
|
+
const ndc_z = _z * d;
|
|
25
26
|
|
|
26
|
-
//
|
|
27
|
+
// Normalize values (0,1023) and clamp to prevent wrapping
|
|
28
|
+
const px = clamp(ndc_x + 511.5, 0, 1023);
|
|
29
|
+
const py = clamp(ndc_y + 511.5, 0, 1023);
|
|
30
|
+
const pz = clamp(ndc_z + 511.5, 0, 1023);
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
return mortonEncode_magicbits(
|
|
33
|
+
Math.round(px),
|
|
34
|
+
Math.round(py),
|
|
35
|
+
Math.round(pz)
|
|
36
|
+
);
|
|
33
37
|
}
|
|
@@ -2,18 +2,34 @@ import { tetrahedron_contains_point } from "./tetrahedron_contains_point.js";
|
|
|
2
2
|
import { assert } from "../../../assert.js";
|
|
3
3
|
import { point_in_tetrahedron_circumsphere } from "./point_in_tetrahedron_circumsphere.js";
|
|
4
4
|
import { BitSet } from "../../../binary/BitSet.js";
|
|
5
|
+
import { typed_array_copy } from "../../../collection/array/typed/typed_array_copy.js";
|
|
6
|
+
import { max3 } from "../../../math/max3.js";
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* @readonly
|
|
8
10
|
* @type {number}
|
|
9
11
|
*/
|
|
10
12
|
const LAYOUT_TETRA_BYTE_SIZE = 9 * 4;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @readonly
|
|
16
|
+
* @type {number}
|
|
17
|
+
*/
|
|
11
18
|
const INVALID_NEIGHBOUR = 0xFFFFFFFF;
|
|
12
19
|
|
|
13
20
|
class Cavity {
|
|
14
21
|
constructor() {
|
|
15
22
|
this.indices = [];
|
|
16
|
-
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
*
|
|
26
|
+
* @type {number}
|
|
27
|
+
*/
|
|
28
|
+
this.size = 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
update() {
|
|
32
|
+
// compute in/out state for each side of each tetra
|
|
17
33
|
}
|
|
18
34
|
|
|
19
35
|
/**
|
|
@@ -21,7 +37,7 @@ class Cavity {
|
|
|
21
37
|
* @param {number} i
|
|
22
38
|
*/
|
|
23
39
|
push(i) {
|
|
24
|
-
this.indices[this.
|
|
40
|
+
this.indices[this.size++] = i;
|
|
25
41
|
}
|
|
26
42
|
|
|
27
43
|
/**
|
|
@@ -30,7 +46,7 @@ class Cavity {
|
|
|
30
46
|
* @returns {boolean}
|
|
31
47
|
*/
|
|
32
48
|
includes(i) {
|
|
33
|
-
const n = this.
|
|
49
|
+
const n = this.size;
|
|
34
50
|
for (let j = 0; j < n; j++) {
|
|
35
51
|
if (this.indices[j] === i) {
|
|
36
52
|
return true;
|
|
@@ -41,7 +57,7 @@ class Cavity {
|
|
|
41
57
|
}
|
|
42
58
|
|
|
43
59
|
reset() {
|
|
44
|
-
this.
|
|
60
|
+
this.size = 0;
|
|
45
61
|
}
|
|
46
62
|
}
|
|
47
63
|
|
|
@@ -63,7 +79,7 @@ const SCRATCH_CAVITY = new Cavity();
|
|
|
63
79
|
*/
|
|
64
80
|
export class TetrahedraCollection {
|
|
65
81
|
constructor(initial_size) {
|
|
66
|
-
this.__buffer = new ArrayBuffer(initial_size *
|
|
82
|
+
this.__buffer = new ArrayBuffer(initial_size * LAYOUT_TETRA_BYTE_SIZE);
|
|
67
83
|
|
|
68
84
|
this.__view = new DataView(this.__buffer);
|
|
69
85
|
|
|
@@ -79,6 +95,49 @@ export class TetrahedraCollection {
|
|
|
79
95
|
this.__occupancy = new BitSet();
|
|
80
96
|
}
|
|
81
97
|
|
|
98
|
+
/**
|
|
99
|
+
*
|
|
100
|
+
* @param {number} n
|
|
101
|
+
*/
|
|
102
|
+
setCapacity(n) {
|
|
103
|
+
if (n === this.__capacity) {
|
|
104
|
+
// do nothing
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (n < this.__length) {
|
|
109
|
+
throw new Error('Dropping information, not supported');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// allocate new buffer
|
|
113
|
+
const new_buffer = new ArrayBuffer(n * LAYOUT_TETRA_BYTE_SIZE);
|
|
114
|
+
|
|
115
|
+
// move data across from old buffer to the new one
|
|
116
|
+
const destination_uint8 = new Uint8Array(new_buffer);
|
|
117
|
+
const source_uint8 = new Uint8Array(this.__buffer);
|
|
118
|
+
|
|
119
|
+
typed_array_copy(source_uint8, destination_uint8);
|
|
120
|
+
|
|
121
|
+
// set new buffer
|
|
122
|
+
this.__buffer = new_buffer;
|
|
123
|
+
this.__view = new DataView(new_buffer);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
*
|
|
128
|
+
* @param {number} n
|
|
129
|
+
*/
|
|
130
|
+
ensureCapacity(n) {
|
|
131
|
+
|
|
132
|
+
const new_capacity = max3(
|
|
133
|
+
n,
|
|
134
|
+
this.__capacity * 1.2,
|
|
135
|
+
this.__capacity + 32
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
this.setCapacity(new_capacity);
|
|
139
|
+
}
|
|
140
|
+
|
|
82
141
|
/**
|
|
83
142
|
*
|
|
84
143
|
* @param {number} tetra_index
|
|
@@ -90,6 +149,17 @@ export class TetrahedraCollection {
|
|
|
90
149
|
return this.__view.getUint32(tetra_address + (4 + neighbour_index) * 4);
|
|
91
150
|
}
|
|
92
151
|
|
|
152
|
+
/**
|
|
153
|
+
*
|
|
154
|
+
* @param {number} tetra_index
|
|
155
|
+
* @param {number} neighbour_index which neighbour to set (0..11)
|
|
156
|
+
* @param {number} neighbour index of the neighbour
|
|
157
|
+
*/
|
|
158
|
+
setNeighbour(tetra_index, neighbour_index, neighbour) {
|
|
159
|
+
const tetra_address = LAYOUT_TETRA_BYTE_SIZE * tetra_index;
|
|
160
|
+
return this.__view.setUint32(tetra_address + (4 + neighbour_index) * 4, neighbour);
|
|
161
|
+
}
|
|
162
|
+
|
|
93
163
|
/**
|
|
94
164
|
*
|
|
95
165
|
* @param {number[]|Float32Array} points
|
|
@@ -97,12 +167,16 @@ export class TetrahedraCollection {
|
|
|
97
167
|
* @param {number} b
|
|
98
168
|
* @param {number} c
|
|
99
169
|
* @param {number} d
|
|
170
|
+
* @returns {number} index of the new tetra
|
|
100
171
|
*/
|
|
101
172
|
append(points, a, b, c, d) {
|
|
102
|
-
const tetra_index = this.
|
|
173
|
+
const tetra_index = this.__occupancy.nextClearBit(0);
|
|
103
174
|
const address = tetra_index * LAYOUT_TETRA_BYTE_SIZE;
|
|
104
175
|
|
|
105
|
-
|
|
176
|
+
if (tetra_index >= this.__capacity) {
|
|
177
|
+
// needs to be increased in size
|
|
178
|
+
this.ensureCapacity(tetra_index);
|
|
179
|
+
}
|
|
106
180
|
|
|
107
181
|
const view = this.__view;
|
|
108
182
|
|
|
@@ -120,6 +194,8 @@ export class TetrahedraCollection {
|
|
|
120
194
|
this.__occupancy.set(tetra_index, true);
|
|
121
195
|
|
|
122
196
|
this.__length++;
|
|
197
|
+
|
|
198
|
+
return tetra_index;
|
|
123
199
|
}
|
|
124
200
|
|
|
125
201
|
/**
|
|
@@ -127,7 +203,27 @@ export class TetrahedraCollection {
|
|
|
127
203
|
* @param {number} tera_index
|
|
128
204
|
*/
|
|
129
205
|
remove(tera_index) {
|
|
206
|
+
|
|
207
|
+
// find neighbours and remove reference to self
|
|
208
|
+
for (let i = 0; i < 4; i++) {
|
|
209
|
+
const neighbour_encoded = this.getNeighbour(tera_index, i);
|
|
210
|
+
|
|
211
|
+
if (neighbour_encoded === INVALID_NEIGHBOUR) {
|
|
212
|
+
// no neighbour
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// get tetrahedra index and point index
|
|
217
|
+
const neighbour_index = neighbour_encoded >> 2;
|
|
218
|
+
const neighbour_point = neighbour_encoded & 4;
|
|
219
|
+
|
|
220
|
+
// clear reference to self
|
|
221
|
+
this.setNeighbour(neighbour_index, neighbour_point, INVALID_NEIGHBOUR);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// mark as dead
|
|
130
225
|
this.__occupancy.clear(tera_index);
|
|
226
|
+
this.__length--;
|
|
131
227
|
}
|
|
132
228
|
|
|
133
229
|
/**
|
|
@@ -140,12 +236,11 @@ export class TetrahedraCollection {
|
|
|
140
236
|
removeTetrasConnectedToPoints(points, range_start, range_end) {
|
|
141
237
|
const data_view = this.__view;
|
|
142
238
|
|
|
143
|
-
const n = this.__length;
|
|
144
|
-
|
|
145
239
|
let i = 0;
|
|
146
240
|
let j = 0;
|
|
147
241
|
|
|
148
|
-
|
|
242
|
+
const occupancy = this.__occupancy;
|
|
243
|
+
for (i = occupancy.nextSetBit(0); i !== -1; i = occupancy.nextSetBit(i + 1)) {
|
|
149
244
|
|
|
150
245
|
const tet_address = i * LAYOUT_TETRA_BYTE_SIZE;
|
|
151
246
|
|
|
@@ -155,6 +250,7 @@ export class TetrahedraCollection {
|
|
|
155
250
|
if (point_index >= range_start && point_index <= range_end) {
|
|
156
251
|
// point index is in range, tetra should be removed
|
|
157
252
|
this.remove(i);
|
|
253
|
+
break;
|
|
158
254
|
}
|
|
159
255
|
}
|
|
160
256
|
}
|
|
@@ -228,18 +324,19 @@ export class TetrahedraCollection {
|
|
|
228
324
|
|
|
229
325
|
// get neighbours
|
|
230
326
|
for (let i = 0; i < 4; i++) {
|
|
231
|
-
const
|
|
327
|
+
const neighbour_encoded = this.getNeighbour(tetra, i);
|
|
328
|
+
const neighbour_tetra_index = neighbour_encoded >> 2;
|
|
232
329
|
|
|
233
330
|
if (
|
|
234
|
-
(
|
|
235
|
-
|| closed_set.includes(
|
|
236
|
-
|| open_set.includes(
|
|
331
|
+
(neighbour_encoded === INVALID_NEIGHBOUR) // no neighbour
|
|
332
|
+
|| closed_set.includes(neighbour_tetra_index) // already visited
|
|
333
|
+
|| open_set.includes(neighbour_tetra_index) // already in open set
|
|
237
334
|
) {
|
|
238
335
|
|
|
239
336
|
continue;
|
|
240
337
|
}
|
|
241
338
|
|
|
242
|
-
const neighbour_address =
|
|
339
|
+
const neighbour_address = neighbour_tetra_index * LAYOUT_TETRA_BYTE_SIZE;
|
|
243
340
|
|
|
244
341
|
const a = data_view.getUint32(neighbour_address);
|
|
245
342
|
const b = data_view.getUint32(neighbour_address + 4);
|
|
@@ -250,10 +347,10 @@ export class TetrahedraCollection {
|
|
|
250
347
|
const is_in_sphere = point_in_tetrahedron_circumsphere(points, a, b, c, d, index);
|
|
251
348
|
|
|
252
349
|
if (is_in_sphere) {
|
|
253
|
-
open_set.push(
|
|
350
|
+
open_set.push(neighbour_tetra_index);
|
|
254
351
|
} else {
|
|
255
352
|
// move directly to closed set
|
|
256
|
-
closed_set.push(
|
|
353
|
+
closed_set.push(neighbour_tetra_index);
|
|
257
354
|
}
|
|
258
355
|
|
|
259
356
|
|
|
@@ -270,10 +367,88 @@ export class TetrahedraCollection {
|
|
|
270
367
|
// Compute the cavity, that is the set of tetrahedra that need to be removed and rebuilt
|
|
271
368
|
this.computeCavity(SCRATCH_CAVITY, points, index);
|
|
272
369
|
|
|
370
|
+
|
|
273
371
|
// identify cavity "edge" - the set of tetras that are neighbours of the tetras that form the cavity
|
|
372
|
+
const cavity_size = SCRATCH_CAVITY.size;
|
|
373
|
+
const cavity_indices = SCRATCH_CAVITY.indices;
|
|
374
|
+
const data = this.__view;
|
|
375
|
+
|
|
376
|
+
for (let i = 0; i < cavity_size; i++) {
|
|
377
|
+
const cavity_index = cavity_indices[i];
|
|
378
|
+
|
|
379
|
+
// take each side of the tetra
|
|
380
|
+
const tetra_address = cavity_index * LAYOUT_TETRA_BYTE_SIZE;
|
|
381
|
+
|
|
382
|
+
const a = data.getUint32(tetra_address);
|
|
383
|
+
const b = data.getUint32(tetra_address + 4);
|
|
384
|
+
const c = data.getUint32(tetra_address + 8);
|
|
385
|
+
const d = data.getUint32(tetra_address + 12);
|
|
386
|
+
|
|
387
|
+
// attempt to form 4 tetras using the sides of the cavity
|
|
388
|
+
const a_neighbour = data.getUint32(tetra_address + 16);
|
|
389
|
+
const a_neighbour_index = a_neighbour >> 2;
|
|
390
|
+
|
|
391
|
+
const b_neighbour = data.getUint32(tetra_address + 20);
|
|
392
|
+
const b_neighbour_index = b_neighbour >> 2;
|
|
393
|
+
|
|
394
|
+
const c_neighbour = data.getUint32(tetra_address + 24);
|
|
395
|
+
const c_neighbour_index = c_neighbour >> 2;
|
|
396
|
+
|
|
397
|
+
const d_neighbour = data.getUint32(tetra_address + 28);
|
|
398
|
+
const d_neighbour_index = d_neighbour >> 2;
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
if (a_neighbour === INVALID_NEIGHBOUR || cavity_indices.indexOf(a_neighbour_index) === 0) {
|
|
402
|
+
// ABC is a valid side
|
|
403
|
+
const tet = this.append(points, b, d, c, index);
|
|
404
|
+
// patch in neighbours
|
|
405
|
+
if (a_neighbour !== INVALID_NEIGHBOUR) {
|
|
406
|
+
this.setNeighbour(tet, 3, a_neighbour);
|
|
407
|
+
this.setNeighbour(a_neighbour_index, a_neighbour & 3, tet);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
if (b_neighbour === INVALID_NEIGHBOUR || cavity_indices.indexOf(b_neighbour_index) === 0) {
|
|
411
|
+
// ABC is a valid side
|
|
412
|
+
const tet = this.append(points, c, d, a, index);
|
|
413
|
+
if (b_neighbour !== INVALID_NEIGHBOUR) {
|
|
414
|
+
this.setNeighbour(tet, 3, b_neighbour);
|
|
415
|
+
this.setNeighbour(b_neighbour_index, b_neighbour & 3, tet);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
if (c_neighbour === INVALID_NEIGHBOUR || cavity_indices.indexOf(c_neighbour_index) === 0) {
|
|
419
|
+
// ABC is a valid side
|
|
420
|
+
const tet = this.append(points, d, b, a, index);
|
|
421
|
+
if (c_neighbour !== INVALID_NEIGHBOUR) {
|
|
422
|
+
this.setNeighbour(tet, 3, c_neighbour);
|
|
423
|
+
this.setNeighbour(c_neighbour_index, c_neighbour & 3, tet);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
if (d_neighbour === INVALID_NEIGHBOUR || cavity_indices.indexOf(d_neighbour_index) === 0) {
|
|
427
|
+
// ABC is a valid side
|
|
428
|
+
const tet = this.append(points, a, b, c, index);
|
|
429
|
+
if (d_neighbour !== INVALID_NEIGHBOUR) {
|
|
430
|
+
this.setNeighbour(tet, 3, d_neighbour);
|
|
431
|
+
this.setNeighbour(d_neighbour_index, d_neighbour & 3, tet);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
274
436
|
|
|
275
437
|
// 3. remove the cavity tetrahedrons
|
|
438
|
+
for (let i = 0; i < cavity_size; i++) {
|
|
439
|
+
const cavity_index = cavity_indices[i];
|
|
440
|
+
|
|
441
|
+
// clear out cavity, connectivity was already patched in the previous step
|
|
442
|
+
this.__occupancy.set(cavity_index, false);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* optimize tetrahedrons to reduce number of thin and long tetras
|
|
448
|
+
* @see https://gitlab.onelab.info/gmsh/gmsh/-/blob/master/contrib/hxt/tetMesh/src/HXTSPR.c
|
|
449
|
+
*/
|
|
450
|
+
optimize() {
|
|
276
451
|
|
|
277
|
-
|
|
452
|
+
throw new Error('Not Implemented');
|
|
278
453
|
}
|
|
279
454
|
}
|
|
@@ -17,7 +17,8 @@ import { orient3d_fast } from "../plane/orient3d_fast.js";
|
|
|
17
17
|
* @returns {boolean}
|
|
18
18
|
*/
|
|
19
19
|
export function tetrahedron_contains_point(points, a, b, c, d, e) {
|
|
20
|
-
return !(
|
|
20
|
+
return !(
|
|
21
|
+
orient3d_fast(points, b, d, c, e) > 0
|
|
21
22
|
|| orient3d_fast(points, c, d, a, e) > 0
|
|
22
23
|
|| orient3d_fast(points, d, b, a, e) > 0
|
|
23
24
|
|| orient3d_fast(points, a, b, c, e) > 0
|
|
@@ -337,16 +337,12 @@ export class GLTFAssetLoader extends AssetLoader {
|
|
|
337
337
|
return;
|
|
338
338
|
}
|
|
339
339
|
|
|
340
|
-
//find a child that is a mesh
|
|
341
|
-
const meshes = scene.children.filter(isMesh);
|
|
342
340
|
|
|
343
|
-
let root;
|
|
341
|
+
let root = scene;
|
|
344
342
|
|
|
345
|
-
if (
|
|
346
|
-
//use
|
|
347
|
-
root =
|
|
348
|
-
} else {
|
|
349
|
-
root = meshes[0];
|
|
343
|
+
if (children.length === 1 && isMesh(children[0])) {
|
|
344
|
+
// scene only contains a single mesh, use that directly
|
|
345
|
+
root = children[0];
|
|
350
346
|
}
|
|
351
347
|
|
|
352
348
|
traverseThreeObject(root, this.__prepareObjectMaterial, this);
|
package/engine/ecs/System.d.ts
CHANGED
|
@@ -1,3 +1,26 @@
|
|
|
1
|
-
|
|
1
|
+
import {EntityManager} from "./EntityManager";
|
|
2
2
|
|
|
3
|
+
interface Type<T> extends Function {
|
|
4
|
+
new(...args: any[]): T;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export class System<A, B = any, C = any, D = any, E = any> {
|
|
8
|
+
dependencies: Type<any>[]
|
|
9
|
+
|
|
10
|
+
startup(em: EntityManager, ready_callback: () => void, error_callback: () => void): void
|
|
11
|
+
|
|
12
|
+
shutdown(em: EntityManager, ready_callback: () => void, error_callback: () => void): void
|
|
13
|
+
|
|
14
|
+
link(a: A, entity: number): void
|
|
15
|
+
link(a: A, b: B, entity: number): void
|
|
16
|
+
link(a: A, b: B, c: C, entity: number): void
|
|
17
|
+
link(a: A, b: B, c: C, d: D, entity: number): void
|
|
18
|
+
link(a: A, b: B, c: C, d: D, e: E, entity: number): void
|
|
19
|
+
|
|
20
|
+
unlink(a: A, entity: number): void
|
|
21
|
+
unlink(a: A, b: B, entity: number): void
|
|
22
|
+
unlink(a: A, b: B, c: C, d: D, entity: number): void
|
|
23
|
+
unlink(a: A, b: B, c: C, d: D, e: E, entity: number): void
|
|
24
|
+
|
|
25
|
+
update(time_delta: number): void
|
|
3
26
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LightBinding } from "../LightBinding.js";
|
|
2
|
-
import { PointLight } from "../../../../render/forward_plus/PointLight.js";
|
|
2
|
+
import { PointLight } from "../../../../render/forward_plus/model/PointLight.js";
|
|
3
3
|
|
|
4
4
|
export class FPLightBinding extends LightBinding {
|
|
5
5
|
constructor() {
|
|
@@ -2,7 +2,6 @@ import { inverseLerp } from "../../../../../../core/math/inverseLerp.js";
|
|
|
2
2
|
import { assert } from "../../../../../../core/assert.js";
|
|
3
3
|
import { max2 } from "../../../../../../core/math/max2.js";
|
|
4
4
|
import { min2 } from "../../../../../../core/math/min2.js";
|
|
5
|
-
import { mix } from "../../../../../../core/math/mix.js";
|
|
6
5
|
import { ParameterLookupTableFlags } from "./ParameterLookupTableFlags.js";
|
|
7
6
|
import { ParameterLookupTableSerializationAdapter } from "../emitter/serde/ParameterLookupTableSerializationAdapter.js";
|
|
8
7
|
import { computeHashIntegerArray } from "../../../../../../core/collection/array/computeHashIntegerArray.js";
|
|
@@ -125,7 +124,7 @@ export class ParameterLookupTable {
|
|
|
125
124
|
*/
|
|
126
125
|
sample(position, result) {
|
|
127
126
|
assert.isNumber(position, 'position');
|
|
128
|
-
assert.greaterThanOrEqual(position, 0, 'position');
|
|
127
|
+
// assert.greaterThanOrEqual(position, 0, 'position');
|
|
129
128
|
// assert.ok(position >= 0 && position <= 1, `position must be between 0 and 1, instead was ${position}`);
|
|
130
129
|
|
|
131
130
|
const itemSize = this.itemSize;
|
|
@@ -140,32 +139,28 @@ export class ParameterLookupTable {
|
|
|
140
139
|
let highIndex = lowIndex;
|
|
141
140
|
let fraction = 0;
|
|
142
141
|
|
|
143
|
-
|
|
144
|
-
for (i = 0; i < numValues; i++) {
|
|
145
|
-
//NOTE: no complex search is used, since for small data sizes linear scan is typically faster
|
|
146
|
-
const p = positions[i];
|
|
142
|
+
if (position <= positions[0]) {
|
|
147
143
|
|
|
148
|
-
|
|
144
|
+
// special case, seek position is at or before the start of the table
|
|
145
|
+
lowIndex = 0;
|
|
146
|
+
highIndex = 0;
|
|
149
147
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
148
|
+
} else {
|
|
149
|
+
|
|
150
|
+
//find position index
|
|
151
|
+
for (i = 1; i < numValues; i++) {
|
|
152
|
+
//NOTE: no complex search is used, since for small data sizes linear scan is typically faster
|
|
153
|
+
const p = positions[i];
|
|
155
154
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
if (i === 0) {
|
|
160
|
-
lowIndex = i;
|
|
161
|
-
fraction = 0;
|
|
162
|
-
} else {
|
|
155
|
+
if (p >= position) {
|
|
156
|
+
// next position if over the seek position
|
|
157
|
+
highIndex = i;
|
|
163
158
|
lowIndex = i - 1;
|
|
164
|
-
const prevPosition = positions[lowIndex];
|
|
165
|
-
fraction = inverseLerp(prevPosition, p, position);
|
|
166
|
-
}
|
|
167
159
|
|
|
168
|
-
|
|
160
|
+
fraction = inverseLerp(positions[lowIndex], p, position);
|
|
161
|
+
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
169
164
|
}
|
|
170
165
|
}
|
|
171
166
|
|
|
@@ -177,7 +172,8 @@ export class ParameterLookupTable {
|
|
|
177
172
|
const lowValue = data[low_offset + i];
|
|
178
173
|
const highValue = data[high_offset + i];
|
|
179
174
|
|
|
180
|
-
|
|
175
|
+
// inlined for speed: mix(low, high, fraction)
|
|
176
|
+
const value = lowValue * (1 - fraction) + highValue * fraction;
|
|
181
177
|
|
|
182
178
|
result[i] = value;
|
|
183
179
|
}
|
|
@@ -117,7 +117,7 @@ export class ShaderManager {
|
|
|
117
117
|
generateMipmaps: true,
|
|
118
118
|
minFilter: LinearMipMapLinearFilter,
|
|
119
119
|
magFilter: LinearFilter,
|
|
120
|
-
anisotropy: 0
|
|
120
|
+
anisotropy: 0 // sprites are always facing the screen, anisotropic filtering would be pointless
|
|
121
121
|
});
|
|
122
122
|
|
|
123
123
|
this.spriteTexture.name = 'Sprite sheet';
|
|
@@ -609,8 +609,8 @@ async function main(engine) {
|
|
|
609
609
|
|
|
610
610
|
engine.graphics.renderer.setClearColor('rgba(99,99,99,1)');
|
|
611
611
|
|
|
612
|
-
|
|
613
|
-
await sample_scene_0(engine);
|
|
612
|
+
await sample_scene_nam(engine);
|
|
613
|
+
// await sample_scene_0(engine);
|
|
614
614
|
}
|
|
615
615
|
|
|
616
616
|
/**
|
|
@@ -26,14 +26,16 @@ export class DepthLimitedBlur {
|
|
|
26
26
|
uniforms: UniformsUtils.clone(DepthLimitedBlurShader.uniforms),
|
|
27
27
|
defines: Object.assign({}, DepthLimitedBlurShader.defines),
|
|
28
28
|
vertexShader: DepthLimitedBlurShader.vertexShader,
|
|
29
|
-
fragmentShader: DepthLimitedBlurShader.fragmentShader
|
|
29
|
+
fragmentShader: DepthLimitedBlurShader.fragmentShader,
|
|
30
|
+
blending: NoBlending
|
|
30
31
|
});
|
|
31
32
|
|
|
32
33
|
this.__material_blur_y = new ShaderMaterial({
|
|
33
34
|
uniforms: UniformsUtils.clone(DepthLimitedBlurShader.uniforms),
|
|
34
35
|
defines: Object.assign({}, DepthLimitedBlurShader.defines),
|
|
35
36
|
vertexShader: DepthLimitedBlurShader.vertexShader,
|
|
36
|
-
fragmentShader: DepthLimitedBlurShader.fragmentShader
|
|
37
|
+
fragmentShader: DepthLimitedBlurShader.fragmentShader,
|
|
38
|
+
blending: NoBlending
|
|
37
39
|
});
|
|
38
40
|
|
|
39
41
|
|
|
@@ -97,7 +99,10 @@ export class DepthLimitedBlur {
|
|
|
97
99
|
*/
|
|
98
100
|
execute(renderer) {
|
|
99
101
|
// update intermediate buffer size based on input size
|
|
100
|
-
if (
|
|
102
|
+
if (
|
|
103
|
+
this.__intermediate.width !== this.__rt_output.width
|
|
104
|
+
|| this.__intermediate.height !== this.__rt_output.height
|
|
105
|
+
) {
|
|
101
106
|
this.__intermediate.setSize(this.__rt_output.width, this.__rt_output.height);
|
|
102
107
|
}
|
|
103
108
|
|
|
@@ -118,7 +123,7 @@ export class DepthLimitedBlur {
|
|
|
118
123
|
|
|
119
124
|
renderer.setRenderTarget(this.__rt_output);
|
|
120
125
|
renderer.clearColor();
|
|
121
|
-
|
|
126
|
+
|
|
122
127
|
renderScreenSpace(renderer, my);
|
|
123
128
|
|
|
124
129
|
// restore state
|
|
@@ -286,7 +286,13 @@ export class AmbientOcclusionPostProcessEffect extends EnginePlugin {
|
|
|
286
286
|
|
|
287
287
|
const size = graphics.viewport.size;
|
|
288
288
|
|
|
289
|
-
|
|
289
|
+
const target_resolution_x = Math.ceil(size.x * this.__resolution_scale);
|
|
290
|
+
const target_resolution_y = Math.ceil(size.y * this.__resolution_scale);
|
|
291
|
+
|
|
292
|
+
this.__render_target.setSize(
|
|
293
|
+
target_resolution_x,
|
|
294
|
+
target_resolution_y
|
|
295
|
+
);
|
|
290
296
|
}
|
|
291
297
|
|
|
292
298
|
async startup() {
|