@woosh/meep-engine 2.72.0 → 2.74.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-image-decoder.js +1 -1
- package/build/meep.cjs +38 -189
- package/build/meep.min.js +1 -1
- package/build/meep.module.js +38 -189
- package/package.json +3 -2
- package/src/engine/asset/loaders/image/codec/NativeImageDecoder.js +2 -1
- package/src/engine/asset/loaders/image/codec/ThreadedImageDecoder.js +4 -5
- package/src/engine/asset/loaders/image/png/PNGReader.js +23 -19
- package/src/engine/graphics/ecs/camera/FrustumProjector.js +31 -182
- package/src/engine/graphics/generate_halton_jitter.js +21 -0
- package/src/engine/graphics/render/buffer/simple-fx/taa/TemporalSupersamplingRenderPlugin.js +3 -20
- package/src/engine/graphics/texture/virtual/v2/NOTES.md +11 -1
- package/src/engine/graphics/texture/virtual/v2/ShaderUsage.js +7 -5
- package/src/engine/graphics/texture/virtual/v2/SparseTexture.js +291 -0
- package/src/engine/graphics/texture/virtual/v2/TileLoader.js +232 -0
- package/src/engine/graphics/texture/virtual/v2/UsageMetadata.js +118 -134
- package/src/engine/graphics/texture/virtual/v2/VirtualTextureManager.js +73 -9
- package/src/engine/graphics/texture/virtual/v2/debug/ResidencyDebugView.js +58 -0
- package/src/engine/graphics/texture/virtual/v2/debug/UsageDebugView.js +63 -0
- package/src/engine/graphics/texture/virtual/v2/{UsagePyramidDebugView.js → debug/UsagePyramidDebugView.js} +27 -23
- package/src/engine/graphics/texture/virtual/v2/prototype.js +62 -19
- package/src/engine/graphics/texture/virtual/v2/tile/TextureTile.js +31 -0
- package/src/engine/graphics/texture/virtual/v2/tile/compose_finger_print.js +23 -0
- package/src/engine/graphics/texture/virtual/v2/tile/compose_tile_address.js +22 -0
- package/src/engine/graphics/texture/virtual/v2/tile/decompose_finger_print.js +12 -0
- package/src/engine/graphics/texture/virtual/v2/tile/finger_print_to_tile_address.js +16 -0
- package/src/engine/graphics/texture/virtual/v2/tile/tile_address_to_finger_print.js +35 -0
- package/src/view/CSS_ABSOLUTE_POSITIONING.js +5 -0
- 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/virtual/v2/UsageDebugView.js +0 -51
|
@@ -12,8 +12,10 @@ import {
|
|
|
12
12
|
WebGLRenderTarget
|
|
13
13
|
} from "three";
|
|
14
14
|
import { assert } from "../../../../../core/assert.js";
|
|
15
|
+
import { array_copy } from "../../../../../core/collection/array/array_copy.js";
|
|
15
16
|
import { clamp } from "../../../../../core/math/clamp.js";
|
|
16
17
|
import { max2 } from "../../../../../core/math/max2.js";
|
|
18
|
+
import { generate_halton_jitter } from "../../../generate_halton_jitter.js";
|
|
17
19
|
import { renderScreenSpace } from "../../../render/utils/renderScreenSpace.js";
|
|
18
20
|
import { Sampler2D } from "../../sampler/Sampler2D.js";
|
|
19
21
|
import { fragment, vertex } from "./ShaderUsage.js";
|
|
@@ -65,8 +67,25 @@ const clear_usage_material = new RawShaderMaterial({
|
|
|
65
67
|
glslVersion: GLSL3
|
|
66
68
|
});
|
|
67
69
|
|
|
70
|
+
const scratch_matrix = new Float32Array(16);
|
|
71
|
+
|
|
68
72
|
export class VirtualTextureManager {
|
|
69
73
|
|
|
74
|
+
#frame_index = 0;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* In order to avoid aliasing due to the fact that we render at a lower resolution, we move the camera slightly each frame to sweep across texels in-between
|
|
78
|
+
* @type {Float32Array}
|
|
79
|
+
*/
|
|
80
|
+
#frame_jitter_offsets = new Float32Array([0, 0]);
|
|
81
|
+
#frame_jitter_samples = 1;
|
|
82
|
+
#frame_jitter_enabled = true;
|
|
83
|
+
|
|
84
|
+
#initialize_frame_jitter() {
|
|
85
|
+
this.#frame_jitter_samples = this.#usage_resolution_scale;
|
|
86
|
+
this.#frame_jitter_offsets = generate_halton_jitter(this.#frame_jitter_samples);
|
|
87
|
+
}
|
|
88
|
+
|
|
70
89
|
#usage_buffer = new WebGLRenderTarget(1, 1, {
|
|
71
90
|
wrapT: ClampToEdgeWrapping,
|
|
72
91
|
wrapS: ClampToEdgeWrapping,
|
|
@@ -95,6 +114,7 @@ export class VirtualTextureManager {
|
|
|
95
114
|
#texture_id = 3;
|
|
96
115
|
#texture_resolution = 65536;
|
|
97
116
|
#tile_resolution = 256;
|
|
117
|
+
#max_mip_level = 0;
|
|
98
118
|
|
|
99
119
|
get texture_resolution() {
|
|
100
120
|
return this.#texture_resolution;
|
|
@@ -104,12 +124,17 @@ export class VirtualTextureManager {
|
|
|
104
124
|
return this.#tile_resolution;
|
|
105
125
|
}
|
|
106
126
|
|
|
127
|
+
get max_mip_level() {
|
|
128
|
+
return this.#max_mip_level;
|
|
129
|
+
}
|
|
130
|
+
|
|
107
131
|
/**
|
|
108
132
|
* Used to fetch higher resolution tiles
|
|
109
133
|
* @type {number}
|
|
110
134
|
*/
|
|
111
135
|
#usage_texture_bias = 0.1;
|
|
112
136
|
|
|
137
|
+
|
|
113
138
|
/**
|
|
114
139
|
*
|
|
115
140
|
* @param {number} resolution
|
|
@@ -124,8 +149,15 @@ export class VirtualTextureManager {
|
|
|
124
149
|
this.#texture_id = texture_id;
|
|
125
150
|
this.#texture_resolution = resolution;
|
|
126
151
|
this.#tile_resolution = tile_size;
|
|
152
|
+
this.#max_mip_level = Math.log2(this.#texture_resolution / this.#tile_resolution);
|
|
153
|
+
|
|
154
|
+
if (!Number.isInteger(this.#max_mip_level)) {
|
|
155
|
+
throw new Error(`texture resolution must be a power-of-two multiple of tile resolution`);
|
|
156
|
+
}
|
|
127
157
|
|
|
128
158
|
this.#initialize_usage_uniforms();
|
|
159
|
+
|
|
160
|
+
this.#usage_metadata.max_mip_level = this.#max_mip_level;
|
|
129
161
|
}
|
|
130
162
|
|
|
131
163
|
get usage_metadata() {
|
|
@@ -138,17 +170,15 @@ export class VirtualTextureManager {
|
|
|
138
170
|
|
|
139
171
|
constructor() {
|
|
140
172
|
this.#initialize_usage_uniforms();
|
|
173
|
+
this.#initialize_frame_jitter();
|
|
141
174
|
}
|
|
142
175
|
|
|
143
176
|
#initialize_usage_uniforms() {
|
|
144
177
|
|
|
145
178
|
const uniforms = usage_material.uniforms;
|
|
146
179
|
|
|
147
|
-
const max_mip_level =
|
|
180
|
+
const max_mip_level = this.#max_mip_level;
|
|
148
181
|
|
|
149
|
-
if (!Number.isInteger(max_mip_level)) {
|
|
150
|
-
throw new Error(`texture resolution must be a power-of-two multiple of tile resolution`);
|
|
151
|
-
}
|
|
152
182
|
|
|
153
183
|
uniforms.u_mt_params.value.set(
|
|
154
184
|
this.#usage_texture_bias,
|
|
@@ -199,6 +229,28 @@ export class VirtualTextureManager {
|
|
|
199
229
|
|
|
200
230
|
}
|
|
201
231
|
|
|
232
|
+
#prepareUsageUniforms(camera) {
|
|
233
|
+
|
|
234
|
+
const uniforms = usage_material.uniforms;
|
|
235
|
+
const usage_buffer = this.#usage_buffer;
|
|
236
|
+
const camera_projection_matrix = camera.projectionMatrix.elements;
|
|
237
|
+
|
|
238
|
+
if (this.#frame_jitter_enabled) {
|
|
239
|
+
// apply jitter to projection matrix
|
|
240
|
+
const jitter_index = this.#frame_index % this.#frame_jitter_samples;
|
|
241
|
+
|
|
242
|
+
const jitter_offset_x = this.#frame_jitter_offsets[jitter_index * 2];
|
|
243
|
+
const jitter_offset_y = this.#frame_jitter_offsets[jitter_index * 2 + 1];
|
|
244
|
+
|
|
245
|
+
camera_projection_matrix[8] = jitter_offset_x / usage_buffer.width;
|
|
246
|
+
camera_projection_matrix[9] = jitter_offset_y / usage_buffer.height;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
uniforms.modelViewMatrix.value.multiplyMatrices(camera.matrixWorldInverse, camera.matrixWorld);
|
|
251
|
+
uniforms.projectionMatrix.value.copy(camera.projectionMatrix);
|
|
252
|
+
}
|
|
253
|
+
|
|
202
254
|
/**
|
|
203
255
|
*
|
|
204
256
|
* @param {WebGLRenderer} renderer
|
|
@@ -209,37 +261,49 @@ export class VirtualTextureManager {
|
|
|
209
261
|
|
|
210
262
|
const usage_buffer = this.#usage_buffer;
|
|
211
263
|
|
|
212
|
-
const uniforms = usage_material.uniforms;
|
|
213
264
|
|
|
214
|
-
|
|
215
|
-
uniforms.projectionMatrix.value.copy(camera.projectionMatrix);
|
|
265
|
+
const camera_projection_matrix = camera.projectionMatrix.elements;
|
|
216
266
|
|
|
217
267
|
// remember existing state
|
|
218
268
|
const _old_render_target = renderer.getRenderTarget();
|
|
219
269
|
const _auto_clear = renderer.autoClear;
|
|
220
|
-
|
|
270
|
+
array_copy(camera_projection_matrix, 0, scratch_matrix, 0, 16);
|
|
221
271
|
const _old_material = scene.overrideMaterial;
|
|
272
|
+
const _old_camera_matrix_update = camera.matrixAutoUpdate;
|
|
273
|
+
|
|
274
|
+
camera.matrixAutoUpdate = false;
|
|
222
275
|
|
|
223
276
|
renderer.autoClear = false;
|
|
224
277
|
renderer.setRenderTarget(usage_buffer);
|
|
225
|
-
scene.overrideMaterial = usage_material;
|
|
226
278
|
|
|
227
279
|
// clear out usage texture
|
|
228
280
|
renderScreenSpace(renderer, clear_usage_material);
|
|
229
281
|
|
|
230
282
|
renderer.clearDepth();
|
|
231
283
|
|
|
284
|
+
scene.overrideMaterial = usage_material;
|
|
285
|
+
|
|
286
|
+
this.#prepareUsageUniforms(camera);
|
|
287
|
+
|
|
232
288
|
renderer.render(scene, camera);
|
|
233
289
|
|
|
234
290
|
scene.overrideMaterial = _old_material;
|
|
235
291
|
|
|
236
292
|
renderer.readRenderTargetPixels(usage_buffer, 0, 0, usage_buffer.width, usage_buffer.height, this.#usage_pixel_data.data);
|
|
237
293
|
|
|
294
|
+
// restore state
|
|
238
295
|
renderer.setRenderTarget(_old_render_target);
|
|
239
296
|
renderer.autoClear = _auto_clear;
|
|
297
|
+
array_copy(scratch_matrix, 0, camera_projection_matrix, 0, 16);
|
|
240
298
|
|
|
299
|
+
camera.matrixAutoUpdate = _old_camera_matrix_update;
|
|
300
|
+
|
|
301
|
+
//
|
|
241
302
|
this.#usage_metadata.fromTexture(this.#usage_pixel_data.data);
|
|
242
303
|
this.#usage_metadata.promoteAncestors(1);
|
|
304
|
+
this.#usage_metadata.sortOccupancy();
|
|
305
|
+
|
|
306
|
+
this.#frame_index++;
|
|
243
307
|
}
|
|
244
308
|
|
|
245
309
|
dispose() {
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { CSS_ABSOLUTE_POSITIONING } from "../../../../../../view/CSS_ABSOLUTE_POSITIONING.js";
|
|
2
|
+
import { CanvasView } from "../../../../../../view/elements/CanvasView.js";
|
|
3
|
+
import EmptyView from "../../../../../../view/elements/EmptyView.js";
|
|
4
|
+
import { sampler2d_write_to_canvas_raw } from "../../../sampler/sampler2d_write_to_canvas_raw.js";
|
|
5
|
+
|
|
6
|
+
export class ResidencyDebugView extends EmptyView {
|
|
7
|
+
/**
|
|
8
|
+
*
|
|
9
|
+
* @type {SparseTexture|null}
|
|
10
|
+
*/
|
|
11
|
+
texture = null;
|
|
12
|
+
|
|
13
|
+
#canvas = new CanvasView();
|
|
14
|
+
|
|
15
|
+
constructor() {
|
|
16
|
+
super({
|
|
17
|
+
css: {
|
|
18
|
+
position: "absolute"
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
this.#canvas.css(CSS_ABSOLUTE_POSITIONING);
|
|
23
|
+
|
|
24
|
+
this.addChild(this.#canvas);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
update() {
|
|
28
|
+
|
|
29
|
+
const t = this.texture;
|
|
30
|
+
if (t === null) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const canvas = this.#canvas;
|
|
35
|
+
canvas.size.readFromArray(t.page_texture_resolution);
|
|
36
|
+
|
|
37
|
+
this.size.copy(canvas.size);
|
|
38
|
+
|
|
39
|
+
const residentTiles = t.resident_tiles;
|
|
40
|
+
|
|
41
|
+
const temp = new CanvasView();
|
|
42
|
+
const tile_resolution = t.tile_resolution;
|
|
43
|
+
temp.size.setScalar(tile_resolution);
|
|
44
|
+
|
|
45
|
+
const tile_columns = t.page_texture_resolution[0] / tile_resolution;
|
|
46
|
+
|
|
47
|
+
for (let i = 0; i < residentTiles.length; i++) {
|
|
48
|
+
const tile = residentTiles[i];
|
|
49
|
+
|
|
50
|
+
sampler2d_write_to_canvas_raw(tile.data, temp.el);
|
|
51
|
+
|
|
52
|
+
const column = tile.page_slot % tile_columns;
|
|
53
|
+
const row = (tile.page_slot / tile_columns) | 0;
|
|
54
|
+
|
|
55
|
+
canvas.context2d.drawImage(temp.el, 0, 0, tile_resolution, tile_resolution, tile_resolution * column, tile_resolution * row, tile_resolution, tile_resolution);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import LabelView from "../../../../../../view/common/LabelView.js";
|
|
2
|
+
import EmptyView from "../../../../../../view/elements/EmptyView.js";
|
|
3
|
+
import { decompose_finger_print } from "../tile/decompose_finger_print.js";
|
|
4
|
+
import { tile_address_to_finger_print } from "../tile/tile_address_to_finger_print.js";
|
|
5
|
+
|
|
6
|
+
export class UsageDebugView extends EmptyView {
|
|
7
|
+
#tileCount = new LabelView("")
|
|
8
|
+
#tiles = new EmptyView();
|
|
9
|
+
#mip_levels = 0;
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
constructor(opt) {
|
|
13
|
+
super(opt);
|
|
14
|
+
|
|
15
|
+
this.addChild(this.#tileCount);
|
|
16
|
+
this.addChild(this.#tiles);
|
|
17
|
+
|
|
18
|
+
this.css({
|
|
19
|
+
position: "absolute",
|
|
20
|
+
left: "0",
|
|
21
|
+
top: "0",
|
|
22
|
+
background: "rgba(255,255,255,0.5)",
|
|
23
|
+
fontFamily: "monospace",
|
|
24
|
+
fontSize: "10px"
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
set mip_levels(v) {
|
|
29
|
+
this.#mip_levels = v;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
*
|
|
34
|
+
* @param {UsageMetadata} usage
|
|
35
|
+
*/
|
|
36
|
+
set usage(usage) {
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
this.#tiles.removeAllChildren();
|
|
40
|
+
|
|
41
|
+
const occupancy = usage.occupancy;
|
|
42
|
+
const occupancyCount = usage.occupancy_count;
|
|
43
|
+
|
|
44
|
+
for (let i = 0; i < occupancyCount; i++) {
|
|
45
|
+
const occupancy_index = occupancy[i];
|
|
46
|
+
const fingerPrint = tile_address_to_finger_print(occupancy_index);
|
|
47
|
+
|
|
48
|
+
const count = usage.getCountByFingerprint(fingerPrint);
|
|
49
|
+
|
|
50
|
+
if (count <= 0) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const { mip, x, y } = decompose_finger_print(fingerPrint);
|
|
55
|
+
|
|
56
|
+
this.#tiles.addChild(new LabelView(`ID: ${0} Level: ${mip} X: ${x} Y: ${y} USAGE: ${count}`));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
this.#tileCount.updateText(`Tile Count: ${occupancyCount}`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
}
|
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
import { assert } from "
|
|
2
|
-
import LabelView from "
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
top: 0,
|
|
8
|
-
left: 0
|
|
9
|
-
};
|
|
1
|
+
import { assert } from "../../../../../../core/assert.js";
|
|
2
|
+
import LabelView from "../../../../../../view/common/LabelView.js";
|
|
3
|
+
import { CSS_ABSOLUTE_POSITIONING } from "../../../../../../view/CSS_ABSOLUTE_POSITIONING.js";
|
|
4
|
+
import EmptyView from "../../../../../../view/elements/EmptyView.js";
|
|
5
|
+
import { decompose_finger_print } from "../tile/decompose_finger_print.js";
|
|
6
|
+
import { tile_address_to_finger_print } from "../tile/tile_address_to_finger_print.js";
|
|
10
7
|
|
|
11
8
|
class TextureLODView extends EmptyView {
|
|
12
9
|
|
|
@@ -22,7 +19,7 @@ class TextureLODView extends EmptyView {
|
|
|
22
19
|
resolution = [1, 1],
|
|
23
20
|
tile_size = 8
|
|
24
21
|
}) {
|
|
25
|
-
super({ css:
|
|
22
|
+
super({ css: CSS_ABSOLUTE_POSITIONING });
|
|
26
23
|
|
|
27
24
|
this.css({
|
|
28
25
|
background: "rgba(255,255,255,0.05)"
|
|
@@ -38,10 +35,11 @@ class TextureLODView extends EmptyView {
|
|
|
38
35
|
|
|
39
36
|
for (let j = 0; j < height; j++) {
|
|
40
37
|
for (let i = 0; i < width; i++) {
|
|
41
|
-
const tileView = new EmptyView({ css:
|
|
38
|
+
const tileView = new EmptyView({ css: CSS_ABSOLUTE_POSITIONING });
|
|
42
39
|
|
|
43
40
|
// const flipped_y = height - j - 1;
|
|
44
41
|
tileView.position.set(i * tile_size, j * tile_size);
|
|
42
|
+
// tileView.position.set(i * tile_size, flipped_y * tile_size);
|
|
45
43
|
tileView.size.set(tile_size, tile_size);
|
|
46
44
|
|
|
47
45
|
this.clearTile(tileView);
|
|
@@ -57,7 +55,7 @@ class TextureLODView extends EmptyView {
|
|
|
57
55
|
|
|
58
56
|
const label = new LabelView(`${width} x ${height}`, {
|
|
59
57
|
css: {
|
|
60
|
-
...
|
|
58
|
+
...CSS_ABSOLUTE_POSITIONING,
|
|
61
59
|
color: '#FFFFFF',
|
|
62
60
|
textShadow: '0 0 2px black',
|
|
63
61
|
whiteSpace: "pre"
|
|
@@ -200,10 +198,7 @@ export class UsagePyramidDebugView extends EmptyView {
|
|
|
200
198
|
for (let i = 0; i < this.#used_set_size; i++) {
|
|
201
199
|
const finger_print = this.#used_set[i];
|
|
202
200
|
|
|
203
|
-
|
|
204
|
-
const mip = (finger_print >> 24) & 0xFF;
|
|
205
|
-
const x = (finger_print >> 16) & 0xFF;
|
|
206
|
-
const y = (finger_print >> 8) & 0xFF;
|
|
201
|
+
const { mip, x, y } = decompose_finger_print(finger_print);
|
|
207
202
|
|
|
208
203
|
const mipView = this.#levels[mip];
|
|
209
204
|
|
|
@@ -213,14 +208,22 @@ export class UsagePyramidDebugView extends EmptyView {
|
|
|
213
208
|
}
|
|
214
209
|
this.#used_set_size = 0;
|
|
215
210
|
|
|
216
|
-
const tile_count = usage.tile_count;
|
|
217
211
|
|
|
218
|
-
|
|
219
|
-
|
|
212
|
+
const occupancy = usage.occupancy;
|
|
213
|
+
const occupancyCount = usage.occupancy_count;
|
|
214
|
+
|
|
215
|
+
for (let i = 0; i < occupancyCount; i++) {
|
|
216
|
+
const occupancy_index = occupancy[i];
|
|
217
|
+
const fingerPrint = tile_address_to_finger_print(occupancy_index);
|
|
218
|
+
|
|
219
|
+
const count = usage.getCountByFingerprint(fingerPrint);
|
|
220
|
+
|
|
221
|
+
if (count <= 0) {
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const { mip, x, y } = decompose_finger_print(fingerPrint);
|
|
220
226
|
|
|
221
|
-
const mip = (finger_print >> 24) & 0xFF;
|
|
222
|
-
const x = (finger_print >> 16) & 0xFF;
|
|
223
|
-
const y = (finger_print >> 8) & 0xFF;
|
|
224
227
|
|
|
225
228
|
const mipView = this.#levels[mip];
|
|
226
229
|
|
|
@@ -232,8 +235,9 @@ export class UsagePyramidDebugView extends EmptyView {
|
|
|
232
235
|
|
|
233
236
|
tile.visible = true;
|
|
234
237
|
|
|
235
|
-
this.#used_set[this.#used_set_size] =
|
|
238
|
+
this.#used_set[this.#used_set_size] = fingerPrint;
|
|
236
239
|
this.#used_set_size++;
|
|
237
240
|
}
|
|
241
|
+
|
|
238
242
|
}
|
|
239
243
|
}
|
|
@@ -15,7 +15,13 @@ import {
|
|
|
15
15
|
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
|
|
16
16
|
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
17
17
|
import EmptyView from "../../../../../view/elements/EmptyView.js";
|
|
18
|
-
import {
|
|
18
|
+
import { AssetManager } from "../../../../asset/AssetManager.js";
|
|
19
|
+
import { GameAssetType } from "../../../../asset/GameAssetType.js";
|
|
20
|
+
import { ImageRGBADataLoader } from "../../../../asset/loaders/image/ImageRGBADataLoader.js";
|
|
21
|
+
import { ResidencyDebugView } from "./debug/ResidencyDebugView.js";
|
|
22
|
+
import { UsageDebugView } from "./debug/UsageDebugView.js";
|
|
23
|
+
import { UsagePyramidDebugView } from "./debug/UsagePyramidDebugView.js";
|
|
24
|
+
import { SparseTexture } from "./SparseTexture.js";
|
|
19
25
|
import { VirtualTextureManager } from "./VirtualTextureManager.js";
|
|
20
26
|
|
|
21
27
|
let camera,
|
|
@@ -31,30 +37,52 @@ let camera,
|
|
|
31
37
|
|
|
32
38
|
let mesh;
|
|
33
39
|
|
|
40
|
+
const am = new AssetManager();
|
|
41
|
+
am.registerLoader(GameAssetType.Image, new ImageRGBADataLoader());
|
|
42
|
+
am.startup();
|
|
43
|
+
|
|
34
44
|
const virtualTextureManager = new VirtualTextureManager();
|
|
35
45
|
virtualTextureManager.setTextureParameters(
|
|
36
|
-
|
|
37
|
-
16384,
|
|
38
|
-
|
|
46
|
+
4096,
|
|
47
|
+
// 16384,
|
|
48
|
+
32,
|
|
39
49
|
3
|
|
40
50
|
);
|
|
41
51
|
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
52
|
+
const sparseTexture = new SparseTexture();
|
|
53
|
+
sparseTexture.path = "data/textures/utility/vt/TexelDensity1";
|
|
54
|
+
sparseTexture.page_texture_size = [512, 512];
|
|
55
|
+
sparseTexture.tile_resolution = virtualTextureManager.tile_resolution;
|
|
56
|
+
sparseTexture.asset_manager = am;
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
console.log(sparseTexture);
|
|
46
60
|
|
|
47
61
|
// const TEXTURE_URL = "data/textures/utility/uv_map_reference.png";
|
|
48
|
-
|
|
62
|
+
const TEXTURE_URL = "data/textures/utility/4096x4096TexelDensityTexture1.png";
|
|
49
63
|
// const TEXTURE_URL = "data/textures/utility/Lenna.png";
|
|
50
64
|
// const TEXTURE_URL = "data/textures/utility/TESTIMAGES/SAMPLING/8BIT/RGB/2448x2448/SRC/img_2448x2448_3x8bit_SRC_RGB_cards_a.png";
|
|
51
|
-
const TEXTURE_URL = "data/models/LowPolyTownshipSet/Town_Hall//diffuse_2048.png";
|
|
65
|
+
// const TEXTURE_URL = "data/models/LowPolyTownshipSet/Town_Hall//diffuse_2048.png";
|
|
66
|
+
|
|
67
|
+
const container_view = new EmptyView();
|
|
68
|
+
//
|
|
69
|
+
const usageDebugView = new UsageDebugView();
|
|
70
|
+
usageDebugView.mip_levels = virtualTextureManager.max_mip_level;
|
|
71
|
+
// container_view.addChild(usageDebugView);
|
|
72
|
+
|
|
52
73
|
|
|
53
74
|
const usagePyramidDebugView = new UsagePyramidDebugView();
|
|
54
75
|
usagePyramidDebugView.setImageURL(TEXTURE_URL);
|
|
55
|
-
|
|
56
76
|
container_view.addChild(usagePyramidDebugView);
|
|
57
77
|
|
|
78
|
+
const residencyDebugView = new ResidencyDebugView();
|
|
79
|
+
residencyDebugView.texture = sparseTexture;
|
|
80
|
+
residencyDebugView.css({
|
|
81
|
+
bottom: 0,
|
|
82
|
+
right: 0
|
|
83
|
+
});
|
|
84
|
+
container_view.addChild(residencyDebugView);
|
|
85
|
+
|
|
58
86
|
const options = {
|
|
59
87
|
spin: true
|
|
60
88
|
};
|
|
@@ -65,11 +93,27 @@ animate();
|
|
|
65
93
|
|
|
66
94
|
function makeTorus() {
|
|
67
95
|
const size = 0.65;
|
|
96
|
+
|
|
97
|
+
const map = new TextureLoader().load(TEXTURE_URL);
|
|
98
|
+
map.flipY = false;
|
|
99
|
+
|
|
68
100
|
mesh = new Mesh(new TorusGeometry(size, 0.3, 30, 30), new MeshStandardMaterial({
|
|
69
101
|
roughness: 0.4,
|
|
70
|
-
map
|
|
102
|
+
map
|
|
71
103
|
}));
|
|
72
104
|
mesh.rotation.x = 0.3;
|
|
105
|
+
|
|
106
|
+
scene.add(mesh);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function makeGLTF(path) {
|
|
110
|
+
|
|
111
|
+
new GLTFLoader().load(path, (gltf) => {
|
|
112
|
+
|
|
113
|
+
mesh = gltf.scene;
|
|
114
|
+
scene.add(mesh);
|
|
115
|
+
|
|
116
|
+
});
|
|
73
117
|
}
|
|
74
118
|
|
|
75
119
|
function init() {
|
|
@@ -88,13 +132,9 @@ function init() {
|
|
|
88
132
|
|
|
89
133
|
clock = new Clock();
|
|
90
134
|
|
|
135
|
+
makeTorus();
|
|
91
136
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
mesh = gltf.scene;
|
|
95
|
-
scene.add(mesh);
|
|
96
|
-
|
|
97
|
-
});
|
|
137
|
+
// makeGLTF("data/models/LowPolyTownshipSet/Town_Hall/model.gltf");
|
|
98
138
|
|
|
99
139
|
scene.add(new DirectionalLight(0xFFFFFF, 0.7));
|
|
100
140
|
scene.add(new AmbientLight(0xFFFFFF, 0.2));
|
|
@@ -163,12 +203,15 @@ function render() {
|
|
|
163
203
|
|
|
164
204
|
virtualTextureManager.setViewportResolution(view_port_size.x, view_port_size.y);
|
|
165
205
|
virtualTextureManager.updateUsage(renderer, scene, camera);
|
|
206
|
+
sparseTexture.update_usage(virtualTextureManager.usage_metadata);
|
|
166
207
|
|
|
167
208
|
renderer.clear();
|
|
168
209
|
renderer.render(scene, camera)
|
|
169
210
|
|
|
170
|
-
|
|
211
|
+
usageDebugView.usage = virtualTextureManager.usage_metadata;
|
|
171
212
|
|
|
172
213
|
usagePyramidDebugView.setTextureParameters(virtualTextureManager.texture_resolution, virtualTextureManager.tile_resolution);
|
|
173
214
|
usagePyramidDebugView.usage = virtualTextureManager.usage_metadata;
|
|
215
|
+
|
|
216
|
+
residencyDebugView.update();
|
|
174
217
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export class TextureTile {
|
|
2
|
+
|
|
3
|
+
finder_print = 0;
|
|
4
|
+
|
|
5
|
+
last_used_time = 0;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Currently occupied page slot, only valid when page is resident
|
|
9
|
+
* @type {number}
|
|
10
|
+
*/
|
|
11
|
+
page_slot = -1;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
*
|
|
15
|
+
* @type {Sampler2D|null}
|
|
16
|
+
*/
|
|
17
|
+
data = null;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
*
|
|
21
|
+
* @param {TextureTile} other
|
|
22
|
+
* @returns {boolean}
|
|
23
|
+
*/
|
|
24
|
+
equals(other) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
hash() {
|
|
29
|
+
return 0;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { assert } from "../../../../../../core/assert.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @param {number} mip
|
|
6
|
+
* @param {number} x
|
|
7
|
+
* @param {number} y
|
|
8
|
+
* @returns {number}
|
|
9
|
+
*/
|
|
10
|
+
export function compose_finger_print(mip, x, y) {
|
|
11
|
+
// validate
|
|
12
|
+
assert.isNonNegativeInteger(x, 'x');
|
|
13
|
+
assert.isNonNegativeInteger(y, 'y');
|
|
14
|
+
assert.isNonNegativeInteger(mip, 'mip');
|
|
15
|
+
|
|
16
|
+
assert.lessThan(x, (1 << mip), 'x');
|
|
17
|
+
assert.lessThan(y, (1 << mip), 'y');
|
|
18
|
+
|
|
19
|
+
return (mip << 24)
|
|
20
|
+
| (x << 16)
|
|
21
|
+
| (y << 8)
|
|
22
|
+
;
|
|
23
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { split_by_2 } from "../../../../../../core/geom/3d/morton/split_by_2.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @param {number} mip
|
|
6
|
+
* @param {number} x
|
|
7
|
+
* @param {number} y
|
|
8
|
+
* @returns {number}
|
|
9
|
+
*/
|
|
10
|
+
export function compose_tile_address(mip, x, y) {
|
|
11
|
+
|
|
12
|
+
// figure out resolution of this mip level
|
|
13
|
+
const mip_resolution = 1 << mip;
|
|
14
|
+
|
|
15
|
+
// this is basically converting something like 0100 to 0011;
|
|
16
|
+
const mip_mask = mip_resolution - 1;
|
|
17
|
+
|
|
18
|
+
// where data for this mip starts
|
|
19
|
+
const index_offset = split_by_2(mip_mask);
|
|
20
|
+
|
|
21
|
+
return index_offset + x + y * mip_resolution;
|
|
22
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* @param {number} finger_print
|
|
4
|
+
* @returns {{mip: number, x: number, y: number}}
|
|
5
|
+
*/
|
|
6
|
+
export function decompose_finger_print(finger_print) {
|
|
7
|
+
const mip = (finger_print >> 24) & 0xFF;
|
|
8
|
+
const x = (finger_print >> 16) & 0xFF;
|
|
9
|
+
const y = (finger_print >> 8) & 0xFF;
|
|
10
|
+
|
|
11
|
+
return { mip, x, y };
|
|
12
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { compose_tile_address } from "./compose_tile_address.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @param {number} finger_print
|
|
6
|
+
* @returns {number}
|
|
7
|
+
*/
|
|
8
|
+
export function finger_print_to_tile_address(finger_print) {
|
|
9
|
+
// decode fingerprint
|
|
10
|
+
const mip = (finger_print >> 24) & 0xFF;
|
|
11
|
+
const x = (finger_print >> 16) & 0xFF;
|
|
12
|
+
const y = (finger_print >> 8) & 0xFF;
|
|
13
|
+
|
|
14
|
+
return compose_tile_address(mip, x, y);
|
|
15
|
+
}
|
|
16
|
+
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { split_by_2 } from "../../../../../../core/geom/3d/morton/split_by_2.js";
|
|
2
|
+
import { compose_finger_print } from "./compose_finger_print.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @param {number} index
|
|
7
|
+
* @returns {number}
|
|
8
|
+
*/
|
|
9
|
+
export function tile_address_to_finger_print(index) {
|
|
10
|
+
for (let mip = 0; mip < 99; mip++) {
|
|
11
|
+
const resolution = 1 << mip;
|
|
12
|
+
|
|
13
|
+
const mip_mask = resolution - 1;
|
|
14
|
+
|
|
15
|
+
const index_offset = split_by_2(mip_mask);
|
|
16
|
+
|
|
17
|
+
const next_mip_mask = mip_mask << 1 | 0x1;
|
|
18
|
+
|
|
19
|
+
const index_offset_next = split_by_2(next_mip_mask);
|
|
20
|
+
|
|
21
|
+
if (index >= index_offset_next) {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const local_index = index - index_offset;
|
|
26
|
+
|
|
27
|
+
const y = (local_index / resolution) | 0;
|
|
28
|
+
const x = local_index % resolution;
|
|
29
|
+
|
|
30
|
+
return compose_finger_print(mip, x, y,);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// not found
|
|
34
|
+
return -1;
|
|
35
|
+
}
|