@woosh/meep-engine 2.71.0 → 2.73.0
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-terrain.js +1 -1
- package/build/meep.cjs +36 -187
- package/build/meep.min.js +1 -1
- package/build/meep.module.js +36 -187
- package/package.json +3 -2
- package/src/core/collection/array/array_get_index_in_range.js +1 -1
- package/src/core/collection/array/array_swap.js +2 -2
- package/src/core/geom/3d/v3_compute_triangle_normal.js +7 -1
- package/src/core/geom/vec3/v3_normalize_array.js +27 -0
- package/src/engine/ecs/terrain/BufferedGeometryArraysBuilder.js +2 -2
- package/src/engine/graphics/ecs/camera/FrustumProjector.js +31 -182
- package/src/engine/graphics/geometry/buffered/ComputeNormals.js +11 -26
- package/src/engine/graphics/texture/virtual/v2/NOTES.md +27 -0
- package/src/engine/graphics/texture/virtual/v2/ShaderUsage.js +51 -26
- package/src/engine/graphics/texture/virtual/v2/SparseTexture.js +182 -0
- package/src/engine/graphics/texture/virtual/v2/TextureTile.js +31 -0
- package/src/engine/graphics/texture/virtual/v2/TileLoader.js +215 -0
- package/src/engine/graphics/texture/virtual/v2/UsageDebugView.js +64 -0
- package/src/engine/graphics/texture/virtual/v2/UsageMetadata.js +153 -0
- package/src/engine/graphics/texture/virtual/v2/UsagePyramidDebugView.js +252 -0
- package/src/engine/graphics/texture/virtual/v2/VirtualTextureManager.js +257 -0
- package/src/engine/graphics/texture/virtual/v2/compose_finger_print.js +13 -0
- package/src/engine/graphics/texture/virtual/v2/finger_print_to_tile_index.js +37 -0
- package/src/engine/graphics/texture/virtual/v2/prototype.js +122 -31
- package/src/engine/graphics/texture/virtual/v2/tile_index_to_finger_print.js +31 -0
- package/src/core/geom/2d/quad-tree/PointQuadTree.js +0 -478
- package/src/core/math/random/makeRangedRandom.js +0 -19
- package/src/engine/ecs/terrain/TerrainGeometryBuilder.js +0 -152
- package/src/engine/ecs/terrain/ecs/PromiseSamplerHeight.js +0 -66
- package/src/engine/ecs/terrain/ecs/TerrainClassifier.js +0 -125
- package/src/engine/graphics/clouds/MaterialTransformer.js +0 -0
- package/src/engine/graphics/clouds/TerrainCloudsPlugin.js +0 -0
- package/src/engine/graphics/clouds/cs_build_fragment_shader.js +0 -0
- package/src/engine/graphics/clouds/cs_build_vertex_shader.js +0 -0
- package/src/engine/graphics/ecs/camera/TiltCameraController.js +0 -69
- package/src/engine/graphics/ecs/camera/is_valid_distance_value.js +0 -11
- package/src/engine/graphics/texture/sampler/SampleTraverser.js +0 -165
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { compose_finger_print } from "./compose_finger_print.js";
|
|
2
|
+
import { finger_print_to_tile_index } from "./finger_print_to_tile_index.js";
|
|
3
|
+
|
|
4
|
+
export class UsageMetadata {
|
|
5
|
+
|
|
6
|
+
#counts_intrinsic = new Uint32Array(0);
|
|
7
|
+
|
|
8
|
+
get counts() {
|
|
9
|
+
return this.#counts_intrinsic;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
#max_mip_level = 0;
|
|
13
|
+
|
|
14
|
+
set max_mip_level(v) {
|
|
15
|
+
this.#max_mip_level = v;
|
|
16
|
+
|
|
17
|
+
this.#ensureCapacity();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
get max_mip_level() {
|
|
21
|
+
return this.#max_mip_level;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
*
|
|
26
|
+
*/
|
|
27
|
+
#ensureCapacity() {
|
|
28
|
+
|
|
29
|
+
const finger_print = compose_finger_print(this.#max_mip_level + 1, 0, 0);
|
|
30
|
+
|
|
31
|
+
const size = finger_print_to_tile_index(finger_print);
|
|
32
|
+
|
|
33
|
+
if (this.#counts_intrinsic.length >= size) {
|
|
34
|
+
// already large enough
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
this.#counts_intrinsic = new Uint32Array(size);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
#getIndexBy(mip, x, y) {
|
|
42
|
+
const finger_print = compose_finger_print(mip, x, y);
|
|
43
|
+
|
|
44
|
+
return finger_print_to_tile_index(finger_print);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
*
|
|
49
|
+
* @param {number} fingerprint
|
|
50
|
+
* @returns {number}
|
|
51
|
+
*/
|
|
52
|
+
getCountByFingerprint(fingerprint) {
|
|
53
|
+
const index = finger_print_to_tile_index(fingerprint);
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
return this.#counts_intrinsic[index];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
*
|
|
61
|
+
* @param {number} mip
|
|
62
|
+
* @param {number} x
|
|
63
|
+
* @param {number} y
|
|
64
|
+
* @returns {number}
|
|
65
|
+
*/
|
|
66
|
+
getCountBy(mip, x, y) {
|
|
67
|
+
const finger_print = compose_finger_print(mip, x, y);
|
|
68
|
+
|
|
69
|
+
return this.getCountByFingerprint(finger_print);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
clear() {
|
|
73
|
+
this.#counts_intrinsic.fill(0);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Given existing usage, award same usage to all tiles up the chain all the way to the root
|
|
78
|
+
* This helps avoid popping and ensures that when there's not enough space - at least the higher level LOD tiles are available
|
|
79
|
+
* @param {number} bias added to the ancestor tiles to make them more likely to be loaded
|
|
80
|
+
*/
|
|
81
|
+
promoteAncestors(bias = 1) {
|
|
82
|
+
|
|
83
|
+
// traverse mip pyramid in reverse, so we can push counts to parents one level at a time
|
|
84
|
+
for (let mip = this.#max_mip_level - 1; mip > 0; mip--) {
|
|
85
|
+
|
|
86
|
+
const mip_resolution = 1 << mip;
|
|
87
|
+
|
|
88
|
+
for (let y = 0; y < mip_resolution; y++) {
|
|
89
|
+
for (let x = 0; x < mip_resolution; x++) {
|
|
90
|
+
|
|
91
|
+
const count = this.getCountBy(mip, x, y);
|
|
92
|
+
|
|
93
|
+
if (count <= 0) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// get higher-level lod
|
|
98
|
+
const parent_level = mip - 1;
|
|
99
|
+
const parent_x = x >>> 1;
|
|
100
|
+
const parent_y = y >>> 1;
|
|
101
|
+
|
|
102
|
+
const parent_index = this.#getIndexBy(parent_level, parent_x, parent_y);
|
|
103
|
+
|
|
104
|
+
const parent_count = this.#counts_intrinsic[parent_index];
|
|
105
|
+
|
|
106
|
+
const expected_count = count + bias;
|
|
107
|
+
|
|
108
|
+
if (parent_count < expected_count) {
|
|
109
|
+
this.#counts_intrinsic[parent_index] = expected_count;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
*
|
|
121
|
+
* @param {Uint8Array} data usage texture data
|
|
122
|
+
*/
|
|
123
|
+
fromTexture(data) {
|
|
124
|
+
this.clear();
|
|
125
|
+
|
|
126
|
+
const data_size = data.length;
|
|
127
|
+
|
|
128
|
+
this.#ensureCapacity(data_size >> 2);
|
|
129
|
+
|
|
130
|
+
for (let offset = 0; offset < data_size; offset += 4) {
|
|
131
|
+
|
|
132
|
+
if (data[offset + 3] === 0) {
|
|
133
|
+
// no data
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const mip_level = data[offset];
|
|
138
|
+
|
|
139
|
+
// we create a mask to make sure we don't end up with invalid tile position values
|
|
140
|
+
const max_tile_value = (1 << mip_level) - 1;
|
|
141
|
+
|
|
142
|
+
const tile_x = data[offset + 1] & max_tile_value;
|
|
143
|
+
const tile_y = data[offset + 2] & max_tile_value;
|
|
144
|
+
|
|
145
|
+
const finger_print = compose_finger_print(mip_level, tile_x, tile_y);
|
|
146
|
+
|
|
147
|
+
const index0 = finger_print_to_tile_index(finger_print);
|
|
148
|
+
|
|
149
|
+
this.#counts_intrinsic[index0]++;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
}
|
|
153
|
+
}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { assert } from "../../../../../core/assert.js";
|
|
2
|
+
import LabelView from "../../../../../view/common/LabelView.js";
|
|
3
|
+
import EmptyView from "../../../../../view/elements/EmptyView.js";
|
|
4
|
+
|
|
5
|
+
const ABSOLUTE_CSS = {
|
|
6
|
+
position: "absolute",
|
|
7
|
+
top: 0,
|
|
8
|
+
left: 0
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
class TextureLODView extends EmptyView {
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
*
|
|
15
|
+
* @type {View[]}
|
|
16
|
+
*/
|
|
17
|
+
#tiles = [];
|
|
18
|
+
|
|
19
|
+
#resolution = [1, 1];
|
|
20
|
+
|
|
21
|
+
constructor({
|
|
22
|
+
resolution = [1, 1],
|
|
23
|
+
tile_size = 8
|
|
24
|
+
}) {
|
|
25
|
+
super({ css: ABSOLUTE_CSS });
|
|
26
|
+
|
|
27
|
+
this.css({
|
|
28
|
+
background: "rgba(255,255,255,0.05)"
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
this.#resolution = resolution;
|
|
32
|
+
|
|
33
|
+
const width = resolution[0];
|
|
34
|
+
const height = resolution[1];
|
|
35
|
+
|
|
36
|
+
assert.isNonNegativeInteger(width, 'width');
|
|
37
|
+
assert.isNonNegativeInteger(height, 'height');
|
|
38
|
+
|
|
39
|
+
for (let j = 0; j < height; j++) {
|
|
40
|
+
for (let i = 0; i < width; i++) {
|
|
41
|
+
const tileView = new EmptyView({ css: ABSOLUTE_CSS });
|
|
42
|
+
|
|
43
|
+
// const flipped_y = height - j - 1;
|
|
44
|
+
tileView.position.set(i * tile_size, j * tile_size);
|
|
45
|
+
tileView.size.set(tile_size, tile_size);
|
|
46
|
+
|
|
47
|
+
this.clearTile(tileView);
|
|
48
|
+
|
|
49
|
+
this.#tiles.push(tileView)
|
|
50
|
+
|
|
51
|
+
this.addChild(tileView);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
this.size.set(width * tile_size, height * tile_size);
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
const label = new LabelView(`${width} x ${height}`, {
|
|
59
|
+
css: {
|
|
60
|
+
...ABSOLUTE_CSS,
|
|
61
|
+
color: '#FFFFFF',
|
|
62
|
+
textShadow: '0 0 2px black',
|
|
63
|
+
whiteSpace: "pre"
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
label.position.set(this.size.x + 4, (this.size.y - 20) * 0.5);
|
|
68
|
+
|
|
69
|
+
this.addChild(label);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
clear() {
|
|
73
|
+
const resolution = this.#resolution;
|
|
74
|
+
const count = resolution[0] * resolution[1];
|
|
75
|
+
for (let i = 0; i < count; i++) {
|
|
76
|
+
|
|
77
|
+
const view = this.#tiles[i];
|
|
78
|
+
|
|
79
|
+
this.clearTile(view);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
*
|
|
85
|
+
* @param {View} view
|
|
86
|
+
*/
|
|
87
|
+
clearTile(view) {
|
|
88
|
+
|
|
89
|
+
view.css({
|
|
90
|
+
background: "none"
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
view.visible = false;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
getTile(x, y) {
|
|
97
|
+
assert.isNonNegativeInteger(x, 'x');
|
|
98
|
+
assert.isNonNegativeInteger(y, 'y');
|
|
99
|
+
|
|
100
|
+
const resolution = this.#resolution;
|
|
101
|
+
|
|
102
|
+
// assert.lessThan(x, resolution[0]);
|
|
103
|
+
// assert.lessThan(y, resolution[1]);
|
|
104
|
+
|
|
105
|
+
const width = resolution[0];
|
|
106
|
+
|
|
107
|
+
const view = this.#tiles[x + width * y];
|
|
108
|
+
|
|
109
|
+
if (view === undefined) {
|
|
110
|
+
debugger
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return view;
|
|
114
|
+
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export class UsagePyramidDebugView extends EmptyView {
|
|
120
|
+
#levels = [];
|
|
121
|
+
#resolution = [1, 1];
|
|
122
|
+
#tile_size = 0;
|
|
123
|
+
|
|
124
|
+
#used_set = [];
|
|
125
|
+
#used_set_size = 0;
|
|
126
|
+
|
|
127
|
+
#image_url = null
|
|
128
|
+
|
|
129
|
+
setImageURL(url) {
|
|
130
|
+
this.#image_url = url;
|
|
131
|
+
|
|
132
|
+
this.#applyImageURL();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
#applyImageURL() {
|
|
136
|
+
|
|
137
|
+
const background = {
|
|
138
|
+
backgroundImage: this.#image_url === null ? "none" : `url(${this.#image_url})`,
|
|
139
|
+
backgroundSize: "contain"
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
this.#levels.forEach(l => {
|
|
143
|
+
|
|
144
|
+
l.css(background);
|
|
145
|
+
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
setTextureParameters(resolution, tile_size) {
|
|
150
|
+
if (this.#resolution[0] === resolution && this.#resolution[1] === resolution && this.#tile_size === tile_size) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
this.#tile_size = tile_size;
|
|
155
|
+
this.#resolution = [resolution, resolution];
|
|
156
|
+
|
|
157
|
+
this.#levels.splice(0, this.#levels.length);
|
|
158
|
+
this.removeAllChildren();
|
|
159
|
+
|
|
160
|
+
let size = resolution / tile_size;
|
|
161
|
+
|
|
162
|
+
assert.isNonNegativeInteger(size, 'size');
|
|
163
|
+
|
|
164
|
+
while (size > 0) {
|
|
165
|
+
const lod = new TextureLODView({
|
|
166
|
+
resolution: [size, size],
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
lod.css({
|
|
170
|
+
border: "1px solid rgba(0,0,0,0.7)"
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
this.#levels.push(lod);
|
|
174
|
+
|
|
175
|
+
this.addChild(lod);
|
|
176
|
+
|
|
177
|
+
size >>>= 1;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
this.#levels.reverse();
|
|
181
|
+
|
|
182
|
+
let y = 0;
|
|
183
|
+
for (let i = 0; i < this.#levels.length; i++) {
|
|
184
|
+
const level = this.#levels[i];
|
|
185
|
+
|
|
186
|
+
level.position.set(2, y);
|
|
187
|
+
|
|
188
|
+
y += level.size.y + 4;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
this.#applyImageURL();
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
*
|
|
196
|
+
* @param {UsageMetadata} usage
|
|
197
|
+
*/
|
|
198
|
+
set usage(usage) {
|
|
199
|
+
|
|
200
|
+
for (let i = 0; i < this.#used_set_size; i++) {
|
|
201
|
+
const finger_print = this.#used_set[i];
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
const mip = (finger_print >> 24) & 0xFF;
|
|
205
|
+
const x = (finger_print >> 16) & 0xFF;
|
|
206
|
+
const y = (finger_print >> 8) & 0xFF;
|
|
207
|
+
|
|
208
|
+
const mipView = this.#levels[mip];
|
|
209
|
+
|
|
210
|
+
const tile = mipView.getTile(x, y);
|
|
211
|
+
|
|
212
|
+
mipView.clearTile(tile);
|
|
213
|
+
}
|
|
214
|
+
this.#used_set_size = 0;
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
const mip_count = this.#levels.length;
|
|
218
|
+
|
|
219
|
+
for (let mip = 0; mip < mip_count; mip++) {
|
|
220
|
+
const size = 1 << mip;
|
|
221
|
+
|
|
222
|
+
for (let y = 0; y < size; y++) {
|
|
223
|
+
for (let x = 0; x < size; x++) {
|
|
224
|
+
const count = usage.getCountBy(mip,x,y);
|
|
225
|
+
|
|
226
|
+
if(count === 0){
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const mipView = this.#levels[mip];
|
|
231
|
+
|
|
232
|
+
const tile = mipView.getTile(x, y);
|
|
233
|
+
|
|
234
|
+
tile.css({
|
|
235
|
+
background: "rgba(255,0,0,0.8)"
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
tile.visible = true;
|
|
239
|
+
|
|
240
|
+
const finger_print = (mip << 24)
|
|
241
|
+
| (x << 16)
|
|
242
|
+
| (y << 8)
|
|
243
|
+
;
|
|
244
|
+
|
|
245
|
+
this.#used_set[this.#used_set_size] = finger_print;
|
|
246
|
+
this.#used_set_size++;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
}
|
|
252
|
+
}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ClampToEdgeWrapping,
|
|
3
|
+
GLSL3,
|
|
4
|
+
Matrix4,
|
|
5
|
+
NearestFilter,
|
|
6
|
+
NoBlending,
|
|
7
|
+
RawShaderMaterial,
|
|
8
|
+
RGBAIntegerFormat,
|
|
9
|
+
UnsignedByteType,
|
|
10
|
+
Vector2,
|
|
11
|
+
Vector4,
|
|
12
|
+
WebGLRenderTarget
|
|
13
|
+
} from "three";
|
|
14
|
+
import { assert } from "../../../../../core/assert.js";
|
|
15
|
+
import { clamp } from "../../../../../core/math/clamp.js";
|
|
16
|
+
import { max2 } from "../../../../../core/math/max2.js";
|
|
17
|
+
import { renderScreenSpace } from "../../../render/utils/renderScreenSpace.js";
|
|
18
|
+
import { Sampler2D } from "../../sampler/Sampler2D.js";
|
|
19
|
+
import { fragment, vertex } from "./ShaderUsage.js";
|
|
20
|
+
import { UsageMetadata } from "./UsageMetadata.js";
|
|
21
|
+
|
|
22
|
+
const usage_material_uniforms = {
|
|
23
|
+
"u_mt_params": { value: new Vector2(0.1, 1) },
|
|
24
|
+
/**
|
|
25
|
+
* Format: VT_WIDTH, VT_HEIGHT, VT_TILE_SIZE, VT_ID
|
|
26
|
+
* - VT_WIDTH : width of the virtual texture
|
|
27
|
+
* - VT_HEIGHT : height of the virtual texture
|
|
28
|
+
* - VT_TILE_SIZE : resolution of a single tile
|
|
29
|
+
* - VT_ID : multiple different virtual textures may be used, this identifies current texture
|
|
30
|
+
*/
|
|
31
|
+
"u_mt_tex": { value: new Vector4(1, 1, 1, 3) },
|
|
32
|
+
"u_mt_viewport_size": { value: new Vector2(1, 1) },
|
|
33
|
+
"modelViewMatrix": { value: new Matrix4() },
|
|
34
|
+
"projectionMatrix": { value: new Matrix4() }
|
|
35
|
+
};
|
|
36
|
+
const usage_material = new RawShaderMaterial({
|
|
37
|
+
|
|
38
|
+
uniforms: usage_material_uniforms,
|
|
39
|
+
vertexShader: vertex(),
|
|
40
|
+
fragmentShader: fragment(),
|
|
41
|
+
glslVersion: GLSL3
|
|
42
|
+
|
|
43
|
+
});
|
|
44
|
+
usage_material.blending = NoBlending;
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
const clear_usage_material = new RawShaderMaterial({
|
|
48
|
+
vertexShader: `
|
|
49
|
+
precision mediump float;
|
|
50
|
+
in vec2 uv;
|
|
51
|
+
void main() {
|
|
52
|
+
|
|
53
|
+
gl_Position = vec4( (uv - 0.5)*2.0, 0.0, 1.0 );
|
|
54
|
+
|
|
55
|
+
}`,
|
|
56
|
+
fragmentShader: `
|
|
57
|
+
|
|
58
|
+
precision mediump int;
|
|
59
|
+
out uvec4 out_decoded;
|
|
60
|
+
|
|
61
|
+
void main(){
|
|
62
|
+
out_decoded = uvec4(0u);
|
|
63
|
+
}
|
|
64
|
+
`,
|
|
65
|
+
glslVersion: GLSL3
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
export class VirtualTextureManager {
|
|
69
|
+
|
|
70
|
+
#usage_buffer = new WebGLRenderTarget(1, 1, {
|
|
71
|
+
wrapT: ClampToEdgeWrapping,
|
|
72
|
+
wrapS: ClampToEdgeWrapping,
|
|
73
|
+
generateMipmaps: false,
|
|
74
|
+
minFilter: NearestFilter,
|
|
75
|
+
magFilter: NearestFilter,
|
|
76
|
+
format: RGBAIntegerFormat,
|
|
77
|
+
depthBuffer: true,
|
|
78
|
+
stencilBuffer: false,
|
|
79
|
+
type: UnsignedByteType,
|
|
80
|
+
internalFormat: "RGBA8UI"
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
#usage_pixel_data = Sampler2D.uint8(4, 1, 1);
|
|
84
|
+
|
|
85
|
+
#viewport_resolution = [1, 1];
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
*
|
|
89
|
+
* @type {number}
|
|
90
|
+
*/
|
|
91
|
+
#usage_resolution_scale = 32;
|
|
92
|
+
|
|
93
|
+
#usage_metadata = new UsageMetadata();
|
|
94
|
+
|
|
95
|
+
#texture_id = 3;
|
|
96
|
+
#texture_resolution = 65536;
|
|
97
|
+
#tile_resolution = 256;
|
|
98
|
+
#max_mip_level = 0;
|
|
99
|
+
|
|
100
|
+
get texture_resolution() {
|
|
101
|
+
return this.#texture_resolution;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
get tile_resolution() {
|
|
105
|
+
return this.#tile_resolution;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
get max_mip_level() {
|
|
109
|
+
return this.#max_mip_level;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Used to fetch higher resolution tiles
|
|
114
|
+
* @type {number}
|
|
115
|
+
*/
|
|
116
|
+
#usage_texture_bias = 0.1;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
*
|
|
120
|
+
* @param {number} resolution
|
|
121
|
+
* @param {number} tile_size
|
|
122
|
+
* @param {number} texture_id
|
|
123
|
+
*/
|
|
124
|
+
setTextureParameters(
|
|
125
|
+
resolution,
|
|
126
|
+
tile_size,
|
|
127
|
+
texture_id
|
|
128
|
+
) {
|
|
129
|
+
this.#texture_id = texture_id;
|
|
130
|
+
this.#texture_resolution = resolution;
|
|
131
|
+
this.#tile_resolution = tile_size;
|
|
132
|
+
this.#max_mip_level = Math.log2(this.#texture_resolution / this.#tile_resolution);
|
|
133
|
+
|
|
134
|
+
if (!Number.isInteger(this.#max_mip_level)) {
|
|
135
|
+
throw new Error(`texture resolution must be a power-of-two multiple of tile resolution`);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
this.#initialize_usage_uniforms();
|
|
139
|
+
|
|
140
|
+
this.#usage_metadata.max_mip_level = this.#max_mip_level;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
get usage_metadata() {
|
|
144
|
+
return this.#usage_metadata;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
get usage_data() {
|
|
148
|
+
return this.#usage_pixel_data;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
constructor() {
|
|
152
|
+
this.#initialize_usage_uniforms();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
#initialize_usage_uniforms() {
|
|
156
|
+
|
|
157
|
+
const uniforms = usage_material.uniforms;
|
|
158
|
+
|
|
159
|
+
const max_mip_level = this.#max_mip_level;
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
uniforms.u_mt_params.value.set(
|
|
163
|
+
this.#usage_texture_bias,
|
|
164
|
+
max_mip_level
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
uniforms.u_mt_tex.value.set(
|
|
168
|
+
this.#texture_resolution,
|
|
169
|
+
this.#texture_resolution,
|
|
170
|
+
this.#tile_resolution,
|
|
171
|
+
this.#texture_id
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
*
|
|
177
|
+
* @param {number} x
|
|
178
|
+
* @param {number} y
|
|
179
|
+
*/
|
|
180
|
+
setViewportResolution(x, y) {
|
|
181
|
+
assert.isNumber(x, 'x');
|
|
182
|
+
assert.isNumber(y, 'y');
|
|
183
|
+
|
|
184
|
+
assert.notNaN(x, 'x');
|
|
185
|
+
assert.notNaN(y, 'y');
|
|
186
|
+
|
|
187
|
+
const _x = max2(1, Math.floor(x));
|
|
188
|
+
const _y = max2(1, Math.floor(y));
|
|
189
|
+
|
|
190
|
+
const viewport = this.#viewport_resolution;
|
|
191
|
+
|
|
192
|
+
if (_x === viewport[0] && _y === viewport[1]) {
|
|
193
|
+
// no change, do nothing
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
viewport[0] = _x;
|
|
198
|
+
viewport[1] = _y;
|
|
199
|
+
|
|
200
|
+
const usage_resolution_x = clamp(Math.floor(_x / this.#usage_resolution_scale), 1, _x);
|
|
201
|
+
const usage_resolution_y = clamp(Math.floor(_y / this.#usage_resolution_scale), 1, _y);
|
|
202
|
+
|
|
203
|
+
this.#usage_buffer.setSize(usage_resolution_x, usage_resolution_y);
|
|
204
|
+
this.#usage_pixel_data.resize(usage_resolution_x, usage_resolution_y, true);
|
|
205
|
+
|
|
206
|
+
const usage_material_uniforms = usage_material.uniforms;
|
|
207
|
+
usage_material_uniforms.u_mt_viewport_size.value.set(_x / usage_resolution_x, _y / usage_resolution_y);
|
|
208
|
+
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
*
|
|
213
|
+
* @param {WebGLRenderer} renderer
|
|
214
|
+
* @param {Scene} scene
|
|
215
|
+
* @param {Camera} camera
|
|
216
|
+
*/
|
|
217
|
+
updateUsage(renderer, scene, camera) {
|
|
218
|
+
|
|
219
|
+
const usage_buffer = this.#usage_buffer;
|
|
220
|
+
|
|
221
|
+
const uniforms = usage_material.uniforms;
|
|
222
|
+
|
|
223
|
+
uniforms.modelViewMatrix.value.multiplyMatrices(camera.matrixWorldInverse, camera.matrixWorld);
|
|
224
|
+
uniforms.projectionMatrix.value.copy(camera.projectionMatrix);
|
|
225
|
+
|
|
226
|
+
// remember existing state
|
|
227
|
+
const _old_render_target = renderer.getRenderTarget();
|
|
228
|
+
const _auto_clear = renderer.autoClear;
|
|
229
|
+
|
|
230
|
+
const _old_material = scene.overrideMaterial;
|
|
231
|
+
|
|
232
|
+
renderer.autoClear = false;
|
|
233
|
+
renderer.setRenderTarget(usage_buffer);
|
|
234
|
+
scene.overrideMaterial = usage_material;
|
|
235
|
+
|
|
236
|
+
// clear out usage texture
|
|
237
|
+
renderScreenSpace(renderer, clear_usage_material);
|
|
238
|
+
|
|
239
|
+
renderer.clearDepth();
|
|
240
|
+
|
|
241
|
+
renderer.render(scene, camera);
|
|
242
|
+
|
|
243
|
+
scene.overrideMaterial = _old_material;
|
|
244
|
+
|
|
245
|
+
renderer.readRenderTargetPixels(usage_buffer, 0, 0, usage_buffer.width, usage_buffer.height, this.#usage_pixel_data.data);
|
|
246
|
+
|
|
247
|
+
renderer.setRenderTarget(_old_render_target);
|
|
248
|
+
renderer.autoClear = _auto_clear;
|
|
249
|
+
|
|
250
|
+
this.#usage_metadata.fromTexture(this.#usage_pixel_data.data);
|
|
251
|
+
this.#usage_metadata.promoteAncestors(1);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
dispose() {
|
|
255
|
+
this.#usage_buffer.dispose();
|
|
256
|
+
}
|
|
257
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { split_by_2 } from "../../../../../core/geom/3d/morton/split_by_2.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @param {number} finger_print
|
|
6
|
+
* @returns {{mip: number, x: number, y: number}}
|
|
7
|
+
*/
|
|
8
|
+
export function decompose_finger_print(finger_print) {
|
|
9
|
+
const mip = (finger_print >> 24) & 0xFF;
|
|
10
|
+
const x = (finger_print >> 16) & 0xFF;
|
|
11
|
+
const y = (finger_print >> 8) & 0xFF;
|
|
12
|
+
|
|
13
|
+
return { mip, x, y };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
*
|
|
18
|
+
* @param {number} finger_print
|
|
19
|
+
* @returns {number}
|
|
20
|
+
*/
|
|
21
|
+
export function finger_print_to_tile_index(finger_print) {
|
|
22
|
+
// decode fingerprint
|
|
23
|
+
const mip = (finger_print >> 24) & 0xFF;
|
|
24
|
+
const x = (finger_print >> 16) & 0xFF;
|
|
25
|
+
const y = (finger_print >> 8) & 0xFF;
|
|
26
|
+
|
|
27
|
+
// figure out resolution of this mip level
|
|
28
|
+
const mip_resolution = 1 << mip;
|
|
29
|
+
|
|
30
|
+
// this is basically converting something like 0100 to 0011;
|
|
31
|
+
const mip_mask = mip_resolution - 1;
|
|
32
|
+
|
|
33
|
+
// where data for this mip starts
|
|
34
|
+
const index_offset = split_by_2(mip_mask);
|
|
35
|
+
|
|
36
|
+
return index_offset + x + y * mip_resolution;
|
|
37
|
+
}
|