@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
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
import { BinaryNode } from "../../../../core/bvh2/BinaryNode.js";
|
|
2
2
|
import { PointLightData } from "./PointLightData.js";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
ClampToEdgeWrapping,
|
|
5
|
+
DataTexture,
|
|
6
|
+
DataTexture3D,
|
|
7
|
+
Frustum,
|
|
8
|
+
LinearFilter,
|
|
9
|
+
LinearMipMapLinearFilter,
|
|
10
|
+
NearestFilter,
|
|
11
|
+
RGBAFormat,
|
|
12
|
+
RGBIntegerFormat,
|
|
13
|
+
UnsignedByteType,
|
|
14
|
+
UnsignedShortType
|
|
15
|
+
} from "three";
|
|
4
16
|
import { frustumFromCamera } from "../../ecs/camera/CameraSystem.js";
|
|
5
17
|
import Vector3 from "../../../../core/geom/Vector3.js";
|
|
6
18
|
import { query_bvh_frustum_from_objects } from "./query/query_bvh_frustum_from_objects.js";
|
|
@@ -23,9 +35,15 @@ import { read_frustum_corner } from "./read_frustum_corner.js";
|
|
|
23
35
|
import { BinaryUint32BVH } from "../../../../core/bvh2/binary/2/BinaryUint32BVH.js";
|
|
24
36
|
import { query_bvh_frustum_from_texture } from "./query/query_bvh_frustum_from_texture.js";
|
|
25
37
|
import { mat4 } from "gl-matrix";
|
|
26
|
-
import {
|
|
38
|
+
import { TextureAtlas } from "../../texture/atlas/TextureAtlas.js";
|
|
39
|
+
import { CachingTextureAtlas } from "../../texture/atlas/CachingTextureAtlas.js";
|
|
40
|
+
import { writeSample2DDataToDataTexture } from "../../texture/sampler/writeSampler2DDataToDataTexture.js";
|
|
41
|
+
import { Decal } from "./model/Decal.js";
|
|
42
|
+
import { ReferencedTextureAtlas } from "../../texture/atlas/ReferencedTextureAtlas.js";
|
|
43
|
+
import { v3_morton_encode_transformed } from "../../../../core/geom/3d/morton/v3_morton_encode_transformed.js";
|
|
44
|
+
import { v3_distance } from "../../../../core/geom/v3_distance.js";
|
|
27
45
|
|
|
28
|
-
const LOOKUP_CACHE_SIZE =
|
|
46
|
+
const LOOKUP_CACHE_SIZE = 1024; // must be power of two
|
|
29
47
|
|
|
30
48
|
/**
|
|
31
49
|
* Using continuous buffer for related attributes to get better cache utilization
|
|
@@ -65,6 +83,38 @@ const LOOKUP_CACHE = new Uint32Array(_scratch_array_buffer, (24 + 24) * 4, LOOKU
|
|
|
65
83
|
*/
|
|
66
84
|
const scratch_light_nodes = [];
|
|
67
85
|
|
|
86
|
+
/**
|
|
87
|
+
* How many bits are used to encode light type
|
|
88
|
+
* @type {number}
|
|
89
|
+
*/
|
|
90
|
+
const LIGHT_ENCODING_TYPE_BIT_COUNT = 2;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
*
|
|
94
|
+
* @param {AbstractLight|PointLight|Decal} light
|
|
95
|
+
* @returns {number}
|
|
96
|
+
*/
|
|
97
|
+
function encode_light_type(light) {
|
|
98
|
+
if (light.isPointLight === true) {
|
|
99
|
+
return 0;
|
|
100
|
+
} else if (light.isDecal === true) {
|
|
101
|
+
return 3;
|
|
102
|
+
} else {
|
|
103
|
+
throw new Error('Unsupported light type');
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
*
|
|
109
|
+
* @param {number} index
|
|
110
|
+
* @param {AbstractLight} light
|
|
111
|
+
* @returns {number}
|
|
112
|
+
*/
|
|
113
|
+
function encode_light_descriptor(index, light) {
|
|
114
|
+
const light_type = encode_light_type(light);
|
|
115
|
+
return light_type | (index << 2);
|
|
116
|
+
}
|
|
117
|
+
|
|
68
118
|
export class LightManager {
|
|
69
119
|
|
|
70
120
|
constructor() {
|
|
@@ -77,7 +127,7 @@ export class LightManager {
|
|
|
77
127
|
|
|
78
128
|
/**
|
|
79
129
|
*
|
|
80
|
-
* @type {Map<
|
|
130
|
+
* @type {Map<AbstractLight, PointLightData>}
|
|
81
131
|
* @private
|
|
82
132
|
*/
|
|
83
133
|
this.__light_point_data = new Map();
|
|
@@ -98,6 +148,7 @@ export class LightManager {
|
|
|
98
148
|
1,
|
|
99
149
|
);
|
|
100
150
|
|
|
151
|
+
this.__cluster_texture.flipY = false;
|
|
101
152
|
this.__cluster_texture.generateMipmaps = false;
|
|
102
153
|
|
|
103
154
|
this.__cluster_texture.magFilter = NearestFilter;
|
|
@@ -107,6 +158,12 @@ export class LightManager {
|
|
|
107
158
|
this.__cluster_texture.format = RGBIntegerFormat;
|
|
108
159
|
this.__cluster_texture.internalFormat = "RGB16UI";
|
|
109
160
|
|
|
161
|
+
/**
|
|
162
|
+
*
|
|
163
|
+
* @type {TextureBackedMemoryRegion}
|
|
164
|
+
* @readonly
|
|
165
|
+
* @private
|
|
166
|
+
*/
|
|
110
167
|
this.__lookup_data = new TextureBackedMemoryRegion();
|
|
111
168
|
this.__lookup_data.type = NumericType.Uint;
|
|
112
169
|
this.__lookup_data.channel_count = 1;
|
|
@@ -116,6 +173,7 @@ export class LightManager {
|
|
|
116
173
|
/**
|
|
117
174
|
*
|
|
118
175
|
* @type {TextureBackedMemoryRegion}
|
|
176
|
+
* @readonly
|
|
119
177
|
* @private
|
|
120
178
|
*/
|
|
121
179
|
this.__light_data = new TextureBackedMemoryRegion();
|
|
@@ -124,9 +182,49 @@ export class LightManager {
|
|
|
124
182
|
this.__light_data.channel_count = 4;
|
|
125
183
|
this.__light_data.resize(8);
|
|
126
184
|
|
|
185
|
+
/**
|
|
186
|
+
* @type {DataTexture}
|
|
187
|
+
* @readonly
|
|
188
|
+
* @private
|
|
189
|
+
*/
|
|
190
|
+
this.__decal_atlas_texture = new DataTexture(new Uint8Array(4), 1, 1, RGBAFormat);
|
|
191
|
+
this.__decal_atlas_texture.type = UnsignedByteType;
|
|
192
|
+
this.__decal_atlas_texture.flipY = false;
|
|
193
|
+
this.__decal_atlas_texture.wrapS = ClampToEdgeWrapping;
|
|
194
|
+
this.__decal_atlas_texture.wrapT = ClampToEdgeWrapping;
|
|
195
|
+
this.__decal_atlas_texture.minFilter = LinearMipMapLinearFilter;
|
|
196
|
+
this.__decal_atlas_texture.magFilter = LinearFilter;
|
|
197
|
+
this.__decal_atlas_texture.generateMipmaps = true;
|
|
198
|
+
this.__decal_atlas_texture.anisotropy = 4;
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
*
|
|
202
|
+
* @type {CachingTextureAtlas}
|
|
203
|
+
* @readonly
|
|
204
|
+
* @private
|
|
205
|
+
*/
|
|
206
|
+
this.__decal_atlas = new CachingTextureAtlas({
|
|
207
|
+
atlas: new TextureAtlas(16)
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
*
|
|
212
|
+
* @type {ReferencedTextureAtlas}
|
|
213
|
+
* @private
|
|
214
|
+
*/
|
|
215
|
+
this.__decal_patch_references = new ReferencedTextureAtlas(this.__decal_atlas);
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
*
|
|
219
|
+
* @type {Map<Decal, Reference>}
|
|
220
|
+
* @private
|
|
221
|
+
*/
|
|
222
|
+
this.__decal_references = new Map();
|
|
223
|
+
|
|
127
224
|
/**
|
|
128
225
|
*
|
|
129
226
|
* @type {IncrementalDeltaSet<PointLightData>}
|
|
227
|
+
* @readonly
|
|
130
228
|
* @private
|
|
131
229
|
*/
|
|
132
230
|
this.__visible_lights = new IncrementalDeltaSet();
|
|
@@ -174,25 +272,43 @@ export class LightManager {
|
|
|
174
272
|
*/
|
|
175
273
|
this.__cluster_frustum_points = new Float32Array(1);
|
|
176
274
|
|
|
177
|
-
|
|
178
275
|
this.setTileMapResolution(32, 16, 16);
|
|
179
276
|
|
|
180
|
-
|
|
181
277
|
this.__visible_lights.onAdded.add(this.__handle_visible_added, this);
|
|
182
278
|
this.__visible_lights.onRemoved.add(this.__handle_visible_removed, this);
|
|
183
279
|
|
|
280
|
+
/**
|
|
281
|
+
*
|
|
282
|
+
* @type {boolean}
|
|
283
|
+
* @private
|
|
284
|
+
*/
|
|
285
|
+
this.__light_data_needs_update = true;
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
*
|
|
289
|
+
* @type {boolean}
|
|
290
|
+
* @private
|
|
291
|
+
*/
|
|
184
292
|
this.__visible_bvh_needs_update = true;
|
|
293
|
+
|
|
294
|
+
this.__decal_atlas.atlas.on.painted.add(this.__update_decal_atlas_texture, this);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
__update_decal_atlas_texture() {
|
|
298
|
+
const sampler = this.__decal_atlas.atlas.sampler;
|
|
299
|
+
|
|
300
|
+
writeSample2DDataToDataTexture(sampler, this.__decal_atlas_texture);
|
|
185
301
|
}
|
|
186
302
|
|
|
187
303
|
/**
|
|
188
304
|
* Sometimes light lookup table can get quite large, to make sure we can store these addresses in the cluster texture,
|
|
189
305
|
* we may need to switch to a larger data type, such as Uint8->Uint16 or Uint16->Uint32
|
|
190
|
-
* @param {number}
|
|
306
|
+
* @param {number} bit_count How many bits should be addressable from the cluster content
|
|
191
307
|
* @returns {boolean} true if texture was rebuilt (underlying type change), false otherwise
|
|
192
308
|
* @private
|
|
193
309
|
*/
|
|
194
|
-
__set_cluster_addressable_bit_range(
|
|
195
|
-
const rounded_value = Math.ceil(
|
|
310
|
+
__set_cluster_addressable_bit_range(bit_count) {
|
|
311
|
+
const rounded_value = Math.ceil(bit_count);
|
|
196
312
|
|
|
197
313
|
this.__cluster_texture_precision = rounded_value;
|
|
198
314
|
const dataType = computeDataType(NumericType.Uint, rounded_value);
|
|
@@ -272,13 +388,23 @@ export class LightManager {
|
|
|
272
388
|
}
|
|
273
389
|
|
|
274
390
|
/**
|
|
275
|
-
*
|
|
276
391
|
* @returns {DataTexture3D}
|
|
277
392
|
*/
|
|
278
393
|
getTextureClusters() {
|
|
279
394
|
return this.__cluster_texture;
|
|
280
395
|
}
|
|
281
396
|
|
|
397
|
+
/**
|
|
398
|
+
* @returns {DataTexture}
|
|
399
|
+
*/
|
|
400
|
+
getDecalTexture() {
|
|
401
|
+
return this.__decal_atlas_texture;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* NOTE: do not modify the value
|
|
406
|
+
* @returns {Readonly<Vector3>}
|
|
407
|
+
*/
|
|
282
408
|
getResolution() {
|
|
283
409
|
return this.__tiles_resolution;
|
|
284
410
|
}
|
|
@@ -297,9 +423,17 @@ export class LightManager {
|
|
|
297
423
|
* @private
|
|
298
424
|
*/
|
|
299
425
|
__handle_visible_added(data) {
|
|
300
|
-
this.
|
|
426
|
+
this.__light_data_needs_update = true;
|
|
427
|
+
|
|
428
|
+
const light = data.light;
|
|
301
429
|
|
|
302
|
-
|
|
430
|
+
light.onDimensionChanged(this.__request_update_visible_bvh, this);
|
|
431
|
+
|
|
432
|
+
if (light instanceof Decal) {
|
|
433
|
+
const ref = this.__decal_patch_references.acquire(light.texture_diffuse);
|
|
434
|
+
|
|
435
|
+
this.__decal_references.set(light, ref);
|
|
436
|
+
}
|
|
303
437
|
}
|
|
304
438
|
|
|
305
439
|
/**
|
|
@@ -308,24 +442,77 @@ export class LightManager {
|
|
|
308
442
|
* @private
|
|
309
443
|
*/
|
|
310
444
|
__handle_visible_removed(data) {
|
|
311
|
-
this.
|
|
445
|
+
this.__light_data_needs_update = true;
|
|
446
|
+
|
|
447
|
+
const light = data.light;
|
|
448
|
+
light.offDimensionChanged(this.__request_update_visible_bvh, this);
|
|
312
449
|
|
|
313
|
-
|
|
450
|
+
if (light instanceof Decal) {
|
|
451
|
+
const ref = this.__decal_references.get(light);
|
|
314
452
|
|
|
315
|
-
|
|
453
|
+
ref.release();
|
|
454
|
+
|
|
455
|
+
this.__decal_references.delete(light);
|
|
456
|
+
}
|
|
316
457
|
}
|
|
317
458
|
|
|
318
459
|
/**
|
|
319
460
|
*
|
|
320
461
|
* @param {PointLightData} light
|
|
321
462
|
* @returns {number}
|
|
322
|
-
* @
|
|
463
|
+
* @protected
|
|
323
464
|
*/
|
|
324
465
|
__sort_visible_light_score(light) {
|
|
325
|
-
const
|
|
466
|
+
const center = scratch_corners;
|
|
467
|
+
|
|
468
|
+
light.light.getCenter(center)
|
|
469
|
+
|
|
470
|
+
const x = center[0];
|
|
471
|
+
const y = center[1];
|
|
472
|
+
const z = center[2];
|
|
326
473
|
|
|
327
|
-
|
|
328
|
-
|
|
474
|
+
return v3_morton_encode_transformed(x, y, z, this.__projection_matrix);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* DEBUG method
|
|
479
|
+
* @param {PointLightData} lights
|
|
480
|
+
* @param {number} count
|
|
481
|
+
* @returns {number} lower = better sorting score
|
|
482
|
+
* @private
|
|
483
|
+
*/
|
|
484
|
+
__assess_sorting_score(lights, count) {
|
|
485
|
+
|
|
486
|
+
let r = 0;
|
|
487
|
+
|
|
488
|
+
const center_a = [];
|
|
489
|
+
const center_b = [];
|
|
490
|
+
|
|
491
|
+
for (let i = 0; i < count; i++) {
|
|
492
|
+
const a = lights[i];
|
|
493
|
+
|
|
494
|
+
const score_a = this.__sort_visible_light_score(a);
|
|
495
|
+
a.light.getCenter(center_a);
|
|
496
|
+
|
|
497
|
+
for (let j = i + 1; j < count; j++) {
|
|
498
|
+
const b = lights[j];
|
|
499
|
+
|
|
500
|
+
const score_b = this.__sort_visible_light_score(b);
|
|
501
|
+
b.light.getCenter(center_b);
|
|
502
|
+
|
|
503
|
+
//
|
|
504
|
+
const score_distance = Math.abs(score_a - score_b);
|
|
505
|
+
const position_distance = v3_distance(
|
|
506
|
+
center_a[0], center_a[1], center_a[2],
|
|
507
|
+
center_b[0], center_b[1], center_b[2],
|
|
508
|
+
);
|
|
509
|
+
|
|
510
|
+
r += score_distance / position_distance;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
return r / (count * (count - 1) * 0.5);
|
|
329
516
|
}
|
|
330
517
|
|
|
331
518
|
/**
|
|
@@ -333,7 +520,10 @@ export class LightManager {
|
|
|
333
520
|
* @private
|
|
334
521
|
*/
|
|
335
522
|
__sort_visible_light() {
|
|
336
|
-
this.__visible_lights.sort(
|
|
523
|
+
this.__visible_lights.sort(
|
|
524
|
+
this.__sort_visible_light_score,
|
|
525
|
+
this
|
|
526
|
+
);
|
|
337
527
|
}
|
|
338
528
|
|
|
339
529
|
__update_visible_bvh() {
|
|
@@ -342,8 +532,6 @@ export class LightManager {
|
|
|
342
532
|
const lights = this.__visible_lights.elements;
|
|
343
533
|
const light_count = lights.length;
|
|
344
534
|
|
|
345
|
-
// sort light for better search and query locality
|
|
346
|
-
this.__sort_visible_light();
|
|
347
535
|
|
|
348
536
|
const vbvh = this.__visible_bvh;
|
|
349
537
|
|
|
@@ -360,8 +548,10 @@ export class LightManager {
|
|
|
360
548
|
|
|
361
549
|
const bb = datum.bvh_leaf_main;
|
|
362
550
|
|
|
551
|
+
const payload = encode_light_descriptor(datum.address, datum.light);
|
|
552
|
+
|
|
363
553
|
vbvh.setLeafData(
|
|
364
|
-
i,
|
|
554
|
+
i, payload,
|
|
365
555
|
bb.x0, bb.y0, bb.z0,
|
|
366
556
|
bb.x1, bb.y1, bb.z1
|
|
367
557
|
);
|
|
@@ -417,9 +607,6 @@ export class LightManager {
|
|
|
417
607
|
|
|
418
608
|
visible_lights.finalizeUpdate();
|
|
419
609
|
|
|
420
|
-
if (this.__visible_bvh_needs_update) {
|
|
421
|
-
this.__update_visible_bvh();
|
|
422
|
-
}
|
|
423
610
|
}
|
|
424
611
|
|
|
425
612
|
__write_light_data_texture() {
|
|
@@ -433,14 +620,33 @@ export class LightManager {
|
|
|
433
620
|
// write light data into texture
|
|
434
621
|
const visible_light_count = visible_lights.length;
|
|
435
622
|
|
|
436
|
-
|
|
623
|
+
// compute amount of space required for the lights
|
|
624
|
+
let address = 0;
|
|
625
|
+
for (let i = 0; i < visible_light_count; i++) {
|
|
626
|
+
const datum = visible_lights[i];
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
*
|
|
630
|
+
* @type {PointLight}
|
|
631
|
+
*/
|
|
632
|
+
const light = datum.light;
|
|
633
|
+
|
|
634
|
+
address += light.ENCODED_SLOT_COUNT;
|
|
635
|
+
}
|
|
636
|
+
|
|
437
637
|
|
|
438
|
-
this.__light_data
|
|
638
|
+
const light_data = this.__light_data;
|
|
639
|
+
light_data.resize(Math.ceil(address / 4));
|
|
640
|
+
|
|
641
|
+
light_data.update();
|
|
439
642
|
|
|
440
643
|
// update required lookup precision
|
|
441
|
-
this.__lookup_data.precision = Math.max(
|
|
644
|
+
this.__lookup_data.precision = Math.max(
|
|
645
|
+
0,
|
|
646
|
+
Math.ceil(Math.log2(light_data.size))
|
|
647
|
+
) + LIGHT_ENCODING_TYPE_BIT_COUNT;
|
|
442
648
|
|
|
443
|
-
const tx_light =
|
|
649
|
+
const tx_light = light_data.getTexture();
|
|
444
650
|
|
|
445
651
|
/**
|
|
446
652
|
*
|
|
@@ -448,13 +654,12 @@ export class LightManager {
|
|
|
448
654
|
*/
|
|
449
655
|
const tx_light_data = tx_light.image.data;
|
|
450
656
|
|
|
657
|
+
address = 0;
|
|
658
|
+
|
|
451
659
|
for (let i = 0; i < visible_light_count; i++) {
|
|
452
660
|
const datum = visible_lights[i];
|
|
453
661
|
|
|
454
|
-
|
|
455
|
-
const address = i * 8;
|
|
456
|
-
|
|
457
|
-
assert.lessThan(address, tx_light_data.length, "overflow")
|
|
662
|
+
assert.lessThan(address, tx_light_data.length, "overflow");
|
|
458
663
|
|
|
459
664
|
/**
|
|
460
665
|
*
|
|
@@ -462,10 +667,21 @@ export class LightManager {
|
|
|
462
667
|
*/
|
|
463
668
|
const light = datum.light;
|
|
464
669
|
|
|
465
|
-
|
|
670
|
+
datum.address = address >> 2;
|
|
671
|
+
|
|
672
|
+
const written_slots = light.toArray(tx_light_data, address);
|
|
673
|
+
|
|
674
|
+
address += written_slots;
|
|
675
|
+
|
|
676
|
+
// align address to 4 slot boundary
|
|
677
|
+
if ((address & 3) !== 0) {
|
|
678
|
+
address = ((address >> 2) + 1) << 2;
|
|
679
|
+
}
|
|
466
680
|
}
|
|
467
681
|
|
|
468
682
|
tx_light.needsUpdate = true;
|
|
683
|
+
|
|
684
|
+
this.__visible_bvh_needs_update = true;
|
|
469
685
|
}
|
|
470
686
|
|
|
471
687
|
__assign_lights_to_clusters() {
|
|
@@ -522,11 +738,15 @@ export class LightManager {
|
|
|
522
738
|
// clear cache
|
|
523
739
|
LOOKUP_CACHE.fill(0xFFFFFFFF);
|
|
524
740
|
|
|
741
|
+
// console.log('Assignment Start');
|
|
742
|
+
|
|
525
743
|
for (i_z_0 = 0; i_z_0 < tr_z; i_z_0++) {
|
|
526
744
|
const i_z_1 = i_z_0 + 1;
|
|
527
745
|
|
|
528
746
|
// construct z planes
|
|
529
747
|
|
|
748
|
+
const slice_offset = i_z_0 * tile_slice_size;
|
|
749
|
+
|
|
530
750
|
const z_plane_index_offset_0 = cluster_planes_z_offset + i_z_0 * 4;
|
|
531
751
|
|
|
532
752
|
read_plane_pair(cluster_planes, z_plane_index_offset_0, scratch_frustum_planes, 16);
|
|
@@ -553,25 +773,25 @@ export class LightManager {
|
|
|
553
773
|
const frustum_point_index_000 = i_z_0 * tr_xy_1 + i_y_0 * tr_x_1 + i_x_0;
|
|
554
774
|
read_frustum_corner(cluster_frustum_points, frustum_point_index_000, scratch_corners, 0);
|
|
555
775
|
|
|
556
|
-
const
|
|
557
|
-
|
|
776
|
+
const i_x_1 = i_x_0 + 1;
|
|
777
|
+
|
|
778
|
+
const frustum_point_index_100 = i_z_0 * tr_xy_1 + i_y_0 * tr_x_1 + i_x_1;
|
|
779
|
+
read_frustum_corner(cluster_frustum_points, frustum_point_index_100, scratch_corners, 12);
|
|
558
780
|
|
|
559
781
|
const frustum_point_index_010 = i_z_0 * tr_xy_1 + i_y_1 * tr_x_1 + i_x_0;
|
|
560
782
|
read_frustum_corner(cluster_frustum_points, frustum_point_index_010, scratch_corners, 6);
|
|
561
783
|
|
|
562
|
-
const
|
|
563
|
-
read_frustum_corner(cluster_frustum_points,
|
|
564
|
-
|
|
565
|
-
const i_x_1 = i_x_0 + 1;
|
|
784
|
+
const frustum_point_index_110 = i_z_0 * tr_xy_1 + i_y_1 * tr_x_1 + i_x_1;
|
|
785
|
+
read_frustum_corner(cluster_frustum_points, frustum_point_index_110, scratch_corners, 18);
|
|
566
786
|
|
|
567
|
-
const
|
|
568
|
-
read_frustum_corner(cluster_frustum_points,
|
|
787
|
+
const frustum_point_index_001 = i_z_1 * tr_xy_1 + i_y_0 * tr_x_1 + i_x_0;
|
|
788
|
+
read_frustum_corner(cluster_frustum_points, frustum_point_index_001, scratch_corners, 3);
|
|
569
789
|
|
|
570
790
|
const frustum_point_index_101 = i_z_1 * tr_xy_1 + i_y_0 * tr_x_1 + i_x_1;
|
|
571
791
|
read_frustum_corner(cluster_frustum_points, frustum_point_index_101, scratch_corners, 15);
|
|
572
792
|
|
|
573
|
-
const
|
|
574
|
-
read_frustum_corner(cluster_frustum_points,
|
|
793
|
+
const frustum_point_index_011 = i_z_1 * tr_xy_1 + i_y_1 * tr_x_1 + i_x_0;
|
|
794
|
+
read_frustum_corner(cluster_frustum_points, frustum_point_index_011, scratch_corners, 9);
|
|
575
795
|
|
|
576
796
|
const frustum_point_index_111 = i_z_1 * tr_xy_1 + i_y_1 * tr_x_1 + i_x_1;
|
|
577
797
|
read_frustum_corner(cluster_frustum_points, frustum_point_index_111, scratch_corners, 21);
|
|
@@ -587,7 +807,7 @@ export class LightManager {
|
|
|
587
807
|
scratch_corners
|
|
588
808
|
);
|
|
589
809
|
|
|
590
|
-
const tile_index =
|
|
810
|
+
const tile_index = slice_offset + (i_y_0 * tr_x) + i_x_0;
|
|
591
811
|
|
|
592
812
|
const tile_address = tile_index * 3;
|
|
593
813
|
|
|
@@ -607,7 +827,6 @@ export class LightManager {
|
|
|
607
827
|
Through experimentation, sorting was taking around 20% of the whole assignment time
|
|
608
828
|
while improving number of cache hits by around 40% (8000 without sorting -> 11000 with sorting)
|
|
609
829
|
*/
|
|
610
|
-
|
|
611
830
|
const cluster_data_hash = compute_light_data_hash_0(scratch_light_nodes, match_count) & (LOOKUP_CACHE_SIZE - 1);
|
|
612
831
|
|
|
613
832
|
const existing_lookup_address = LOOKUP_CACHE[cluster_data_hash];
|
|
@@ -641,12 +860,12 @@ export class LightManager {
|
|
|
641
860
|
for (i = 0; i < match_count; i++) {
|
|
642
861
|
/**
|
|
643
862
|
*
|
|
644
|
-
* @type {number
|
|
863
|
+
* @type {number}
|
|
645
864
|
*/
|
|
646
|
-
const
|
|
865
|
+
const light_descriptor = scratch_light_nodes[i];
|
|
647
866
|
|
|
648
867
|
// construct lookup table
|
|
649
|
-
light_lookup_texture_data[lookup_address_offset] =
|
|
868
|
+
light_lookup_texture_data[lookup_address_offset] = light_descriptor;
|
|
650
869
|
|
|
651
870
|
lookup_address_offset++;
|
|
652
871
|
}
|
|
@@ -818,11 +1037,22 @@ export class LightManager {
|
|
|
818
1037
|
this.__build_visible_light_list();
|
|
819
1038
|
// console.timeEnd('__build_visible_light_list');
|
|
820
1039
|
|
|
1040
|
+
// update decal atlas
|
|
1041
|
+
this.__decal_atlas.atlas.update();
|
|
821
1042
|
|
|
822
1043
|
// console.time('__write_light_data_texture');
|
|
823
|
-
this.
|
|
1044
|
+
if (this.__light_data_needs_update) {
|
|
1045
|
+
// sort light for better search and query locality
|
|
1046
|
+
this.__sort_visible_light();
|
|
1047
|
+
|
|
1048
|
+
this.__write_light_data_texture();
|
|
1049
|
+
}
|
|
824
1050
|
// console.timeEnd('__write_light_data_texture');
|
|
825
1051
|
|
|
1052
|
+
if (this.__visible_bvh_needs_update) {
|
|
1053
|
+
this.__update_visible_bvh();
|
|
1054
|
+
}
|
|
1055
|
+
|
|
826
1056
|
this.__build_cluster_frustum_points();
|
|
827
1057
|
// console.time('__build_cluster_frustum_planes');
|
|
828
1058
|
this.__build_cluster_frustum_planes();
|
|
@@ -848,6 +1078,11 @@ export class LightManager {
|
|
|
848
1078
|
setTileMapResolution(x, y, z) {
|
|
849
1079
|
const r = this.__tiles_resolution;
|
|
850
1080
|
|
|
1081
|
+
if (x === r.x && y === r.y && z === r.z) {
|
|
1082
|
+
// special case, no change
|
|
1083
|
+
return;
|
|
1084
|
+
}
|
|
1085
|
+
|
|
851
1086
|
r.set(x, y, z);
|
|
852
1087
|
|
|
853
1088
|
this.__cluster_texture_needs_rebuild = true;
|
|
@@ -868,6 +1103,10 @@ export class LightManager {
|
|
|
868
1103
|
);
|
|
869
1104
|
}
|
|
870
1105
|
|
|
1106
|
+
/**
|
|
1107
|
+
*
|
|
1108
|
+
* @param {AbstractLight} light
|
|
1109
|
+
*/
|
|
871
1110
|
addLight(light) {
|
|
872
1111
|
const lightData = new PointLightData(light);
|
|
873
1112
|
|
|
@@ -878,6 +1117,11 @@ export class LightManager {
|
|
|
878
1117
|
this.__light_point_data.set(light, lightData);
|
|
879
1118
|
}
|
|
880
1119
|
|
|
1120
|
+
/**
|
|
1121
|
+
*
|
|
1122
|
+
* @param {AbstractLight} light
|
|
1123
|
+
* @returns {boolean}
|
|
1124
|
+
*/
|
|
881
1125
|
removeLight(light) {
|
|
882
1126
|
|
|
883
1127
|
const data = this.__light_point_data.get(light);
|
|
@@ -3,35 +3,33 @@ import { LeafNode } from "../../../../core/bvh2/LeafNode.js";
|
|
|
3
3
|
export class PointLightData {
|
|
4
4
|
/**
|
|
5
5
|
*
|
|
6
|
-
* @param {
|
|
6
|
+
* @param {AbstractLight} light
|
|
7
7
|
*/
|
|
8
8
|
constructor(light) {
|
|
9
|
+
/**
|
|
10
|
+
*
|
|
11
|
+
* @type {AbstractLight}
|
|
12
|
+
*/
|
|
9
13
|
this.light = light;
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
this.bvh_leaf_main = new LeafNode(this, 0, 0, 0, 0, 0, 0);
|
|
13
|
-
|
|
14
|
-
this.bvh_leaf_visible = new LeafNode(this, 0, 0, 0, 0, 0, 0);
|
|
15
|
-
|
|
16
15
|
/**
|
|
17
|
-
*
|
|
16
|
+
*
|
|
18
17
|
* @type {number}
|
|
19
18
|
*/
|
|
20
|
-
this.
|
|
19
|
+
this.address = 0;
|
|
20
|
+
|
|
21
|
+
this.bvh_leaf_main = new LeafNode(this, 0, 0, 0, 0, 0, 0);
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
update() {
|
|
24
25
|
|
|
25
26
|
const leaf = this.bvh_leaf_main;
|
|
26
|
-
const leaf_2 = this.bvh_leaf_visible;
|
|
27
27
|
|
|
28
28
|
this.light.getAABB(leaf);
|
|
29
29
|
|
|
30
30
|
if (leaf.parentNode !== null) {
|
|
31
31
|
leaf.parentNode.bubbleRefit();
|
|
32
32
|
}
|
|
33
|
-
|
|
34
|
-
leaf_2.resize(leaf.x0, leaf.y0, leaf.z0, leaf.x1, leaf.y1, leaf.z1);
|
|
35
33
|
}
|
|
36
34
|
|
|
37
35
|
link() {
|
|
@@ -46,7 +44,5 @@ export class PointLightData {
|
|
|
46
44
|
|
|
47
45
|
// disconnect from bvh
|
|
48
46
|
this.bvh_leaf_main.disconnect();
|
|
49
|
-
|
|
50
|
-
this.bvh_leaf_visible.disconnect();
|
|
51
47
|
}
|
|
52
48
|
}
|
|
@@ -86,6 +86,10 @@ export class TextureBackedMemoryRegion {
|
|
|
86
86
|
this.__data_type = DataType.Uint8;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
get concrete_type(){
|
|
90
|
+
return this.__data_type;
|
|
91
|
+
}
|
|
92
|
+
|
|
89
93
|
/**
|
|
90
94
|
*
|
|
91
95
|
* @param {number} v
|
|
@@ -228,9 +232,14 @@ export class TextureBackedMemoryRegion {
|
|
|
228
232
|
* @param {number} size
|
|
229
233
|
*/
|
|
230
234
|
resize(size) {
|
|
235
|
+
assert.isNonNegativeInteger(size, 'size');
|
|
236
|
+
|
|
231
237
|
this.size = size;
|
|
232
238
|
|
|
233
|
-
const target_height = max2(
|
|
239
|
+
const target_height = max2(
|
|
240
|
+
Math.ceil(size / DATA_TEXTURE_WIDTH),
|
|
241
|
+
1
|
|
242
|
+
);
|
|
234
243
|
|
|
235
244
|
const current_height = this.__texture.image.height;
|
|
236
245
|
|