@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.
Files changed (35) hide show
  1. package/build/bundle-worker-image-decoder.js +1 -1
  2. package/build/meep.cjs +38 -189
  3. package/build/meep.min.js +1 -1
  4. package/build/meep.module.js +38 -189
  5. package/package.json +3 -2
  6. package/src/engine/asset/loaders/image/codec/NativeImageDecoder.js +2 -1
  7. package/src/engine/asset/loaders/image/codec/ThreadedImageDecoder.js +4 -5
  8. package/src/engine/asset/loaders/image/png/PNGReader.js +23 -19
  9. package/src/engine/graphics/ecs/camera/FrustumProjector.js +31 -182
  10. package/src/engine/graphics/generate_halton_jitter.js +21 -0
  11. package/src/engine/graphics/render/buffer/simple-fx/taa/TemporalSupersamplingRenderPlugin.js +3 -20
  12. package/src/engine/graphics/texture/virtual/v2/NOTES.md +11 -1
  13. package/src/engine/graphics/texture/virtual/v2/ShaderUsage.js +7 -5
  14. package/src/engine/graphics/texture/virtual/v2/SparseTexture.js +291 -0
  15. package/src/engine/graphics/texture/virtual/v2/TileLoader.js +232 -0
  16. package/src/engine/graphics/texture/virtual/v2/UsageMetadata.js +118 -134
  17. package/src/engine/graphics/texture/virtual/v2/VirtualTextureManager.js +73 -9
  18. package/src/engine/graphics/texture/virtual/v2/debug/ResidencyDebugView.js +58 -0
  19. package/src/engine/graphics/texture/virtual/v2/debug/UsageDebugView.js +63 -0
  20. package/src/engine/graphics/texture/virtual/v2/{UsagePyramidDebugView.js → debug/UsagePyramidDebugView.js} +27 -23
  21. package/src/engine/graphics/texture/virtual/v2/prototype.js +62 -19
  22. package/src/engine/graphics/texture/virtual/v2/tile/TextureTile.js +31 -0
  23. package/src/engine/graphics/texture/virtual/v2/tile/compose_finger_print.js +23 -0
  24. package/src/engine/graphics/texture/virtual/v2/tile/compose_tile_address.js +22 -0
  25. package/src/engine/graphics/texture/virtual/v2/tile/decompose_finger_print.js +12 -0
  26. package/src/engine/graphics/texture/virtual/v2/tile/finger_print_to_tile_address.js +16 -0
  27. package/src/engine/graphics/texture/virtual/v2/tile/tile_address_to_finger_print.js +35 -0
  28. package/src/view/CSS_ABSOLUTE_POSITIONING.js +5 -0
  29. package/src/engine/graphics/clouds/MaterialTransformer.js +0 -0
  30. package/src/engine/graphics/clouds/TerrainCloudsPlugin.js +0 -0
  31. package/src/engine/graphics/clouds/cs_build_fragment_shader.js +0 -0
  32. package/src/engine/graphics/clouds/cs_build_vertex_shader.js +0 -0
  33. package/src/engine/graphics/ecs/camera/TiltCameraController.js +0 -69
  34. package/src/engine/graphics/ecs/camera/is_valid_distance_value.js +0 -11
  35. 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 = Math.log2(this.#texture_resolution / this.#tile_resolution);
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
- uniforms.modelViewMatrix.value.multiplyMatrices(camera.matrixWorldInverse, camera.matrixWorld);
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 "../../../../../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
- };
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: ABSOLUTE_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: ABSOLUTE_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
- ...ABSOLUTE_CSS,
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
- for (let i = 0; i < tile_count; i++) {
219
- const finger_print = usage.getTile(i);
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] = finger_print;
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 { UsagePyramidDebugView } from "./UsagePyramidDebugView.js";
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
- // 2048,
37
- 16384,
38
- 128,
46
+ 4096,
47
+ // 16384,
48
+ 32,
39
49
  3
40
50
  );
41
51
 
42
- const container_view = new EmptyView();
43
- //
44
- // const usageDebugView = new UsageDebugView();
45
- // container_view.addChild(usageDebugView);
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
- // const TEXTURE_URL = "data/textures/utility/4096x4096TexelDensityTexture1.png";
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: new TextureLoader().load(TEXTURE_URL)
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
- new GLTFLoader().load("data/models/LowPolyTownshipSet/Town_Hall/model.gltf", (gltf) => {
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
- // usageDebugView.usage = virtualTextureManager.usage_metadata;
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
+ }