@woosh/meep-engine 2.75.2 → 2.75.4
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/meep.cjs +56 -60
- package/build/meep.min.js +1 -1
- package/build/meep.module.js +56 -60
- package/package.json +1 -1
- package/src/core/geom/3d/ray/ray_computeNearestPointToPoint.js +7 -1
- package/src/core/geom/3d/topology/simplify/compute_face_normal_change_dot_product.js +19 -39
- package/src/core/geom/3d/v3_compute_triangle_normal.js +1 -1
- package/src/core/geom/Quaternion.js +0 -59
- package/src/engine/asset/loaders/image/ImageRGBADataLoader.js +2 -1
- package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshHighlightSystem.js +7 -1
- package/src/engine/graphics/geometry/VertexDataSpec.d.ts +10 -0
- package/src/engine/graphics/geometry/VertexDataSpec.js +20 -21
- package/src/engine/graphics/render/visibility/hiz/buildCanvasViewFromTexture.js +41 -10
- package/src/engine/graphics/texture/formatToChannelCount.js +2 -1
- package/src/engine/graphics/texture/sampler/filter/sampler2d_scale_down_generic.js +2 -2
- package/src/engine/graphics/texture/sampler/prototypeSamplerFiltering.js +20 -19
- package/src/engine/graphics/texture/virtual/v2/NOTES.md +93 -1
- package/src/engine/graphics/texture/virtual/v2/VirtualTextureMaterial.js +193 -0
- package/src/engine/graphics/texture/virtual/v2/VirtualTextureMemoryMapping.js +203 -0
- package/src/engine/graphics/texture/virtual/v2/{PageTexture.js → VirtualTexturePage.js} +151 -22
- package/src/engine/graphics/texture/virtual/v2/VirtualTextureTileLoader.js +10 -1
- package/src/engine/graphics/texture/virtual/v2/VirtualTextureUsage.js +43 -10
- package/src/engine/graphics/texture/virtual/v2/VirtualTextureUsageShader.js +3 -3
- package/src/engine/graphics/texture/virtual/v2/VirtualTextureUsageUpdater.js +39 -11
- package/src/engine/graphics/texture/virtual/v2/debug/ResidencyDebugView.js +20 -5
- package/src/engine/graphics/texture/virtual/v2/prototype.js +148 -62
- package/src/engine/graphics/texture/virtual/v2/tile/VirtualTextureTile.js +4 -0
- package/src/core/bvh2/sah/surfaceAreaHeuristic.js +0 -15
- package/src/core/bvh2/sah/surfaceAreaHeuristicFull.js +0 -14
- package/src/core/geom/3d/aabb/computeBoundingBoxFromVertexData.js +0 -12
- package/src/core/geom/3d/frustum/array_normalize_plane.js +0 -25
- package/src/core/geom/3d/plane/lerp_planes_to_array.js +0 -53
- package/src/core/geom/3d/plane/planeRayIntersection.js +0 -14
- package/src/core/geom/3d/voxel/DenseBitVolume3D.js +0 -87
- package/src/core/geom/3d/voxel/buildVolumeFromProjectedGeometry.js +0 -23
- package/src/engine/graphics/texture/virtual/v2/ResidentTileTexture.js +0 -46
- /package/src/core/math/{bessel_i0.spec.js → bessel_j0.spec.js} +0 -0
|
@@ -24,4 +24,96 @@ Based on the `Usage` data, we populate our `Physical` texture of pages, and base
|
|
|
24
24
|
|
|
25
25
|
Most papers suggest introducing a border into each tile of ~4 pixels.
|
|
26
26
|
4 pixel border on a 128x128 pixel tile is going to take up 12.1% of space, which is quite a lot.
|
|
27
|
-
We can do filtering in software, that is - sample individual pixels and perform interpolation inside the shader.
|
|
27
|
+
We can do filtering in software, that is - sample individual pixels and perform interpolation inside the shader.
|
|
28
|
+
|
|
29
|
+
### Speeding up WebGL read-back
|
|
30
|
+
|
|
31
|
+
From [Babylon](https://github.com/BabylonJS/Babylon.js/blob/90dbafed8de9de752cdc399604f9c7c51116d630/src/Engines/engine.ts#L1772)
|
|
32
|
+
```ts
|
|
33
|
+
public _readPixelsAsync(x: number, y: number, w: number, h: number, format: number, type: number, outputBuffer: ArrayBufferView) {
|
|
34
|
+
if (this._webGLVersion < 2) {
|
|
35
|
+
throw new Error("_readPixelsAsync only work on WebGL2+");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let gl = <WebGL2RenderingContext>(this._gl as any);
|
|
39
|
+
const buf = gl.createBuffer();
|
|
40
|
+
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, buf);
|
|
41
|
+
gl.bufferData(gl.PIXEL_PACK_BUFFER, outputBuffer.byteLength, gl.STREAM_READ);
|
|
42
|
+
gl.readPixels(x, y, w, h, format, type, 0);
|
|
43
|
+
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);
|
|
44
|
+
|
|
45
|
+
const sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
|
|
46
|
+
if (!sync) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
gl.flush();
|
|
51
|
+
|
|
52
|
+
return this._clientWaitAsync(sync, 0, 10).then(() => {
|
|
53
|
+
gl.deleteSync(sync);
|
|
54
|
+
|
|
55
|
+
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, buf);
|
|
56
|
+
gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, outputBuffer);
|
|
57
|
+
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);
|
|
58
|
+
gl.deleteBuffer(buf);
|
|
59
|
+
|
|
60
|
+
return outputBuffer;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private _clientWaitAsync(sync: WebGLSync, flags = 0, intervalms = 10): Promise<void> {
|
|
65
|
+
const gl = <WebGL2RenderingContext>(this._gl as any);
|
|
66
|
+
return new Promise((resolve, reject) => {
|
|
67
|
+
const check = () => {
|
|
68
|
+
const res = gl.clientWaitSync(sync, flags, 0);
|
|
69
|
+
if (res == gl.WAIT_FAILED) {
|
|
70
|
+
reject();
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (res == gl.TIMEOUT_EXPIRED) {
|
|
74
|
+
setTimeout(check, intervalms);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
resolve();
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
check();
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
more links:
|
|
86
|
+
https://forum.babylonjs.com/t/speeding-up-readpixels/12739
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
## References
|
|
90
|
+
|
|
91
|
+
* https://studiopixl.com/2022-04-27/sparse-virtual-textures
|
|
92
|
+
* Anisotropic filtering in a shader: https://www.shadertoy.com/view/4lXfzn
|
|
93
|
+
|
|
94
|
+
## WebGL fails
|
|
95
|
+
|
|
96
|
+
WebGL doesn't seem to support mipmaps on integer textures
|
|
97
|
+
|
|
98
|
+
## Anisotropic filtering:
|
|
99
|
+
|
|
100
|
+
```glsl
|
|
101
|
+
// R is viewport resolution
|
|
102
|
+
// p is UV
|
|
103
|
+
vec4 textureAniso(sampler2D T, vec2 R, vec2 p) {
|
|
104
|
+
mat2 J = inverse(mat2(dFdx(p),dFdy(p))); // dFdxy: pixel footprint in texture space
|
|
105
|
+
J = transpose(J)*J; // quadratic form
|
|
106
|
+
float d = determinant(J), t = J[0][0]+J[1][1], // find ellipse: eigenvalues, max eigenvector
|
|
107
|
+
D = sqrt(abs(t*t-4.*d)), // abs() fix a bug: in weird view angles 0 can be slightly negative
|
|
108
|
+
V = (t-D)/2., v = (t+D)/2., // eigenvalues. ( ATTENTION: not sorted )
|
|
109
|
+
M = 1./sqrt(V), m = 1./sqrt(v), l =log2(m*R.y); // = 1./radii^2
|
|
110
|
+
|
|
111
|
+
//if (M/m>16.) l = log2(M/16.*R.y); // optional
|
|
112
|
+
|
|
113
|
+
vec2 A = M * normalize(vec2( -J[0][1] , J[0][0]-V )); // max eigenvector = main axis
|
|
114
|
+
vec4 O = vec4(0);
|
|
115
|
+
for (float i = -7.5; i<8.; i++) // sample x16 along main axis at LOD min-radius
|
|
116
|
+
O += textureLod(T, p+(i/16.)*A, l);
|
|
117
|
+
return O/16.;
|
|
118
|
+
}
|
|
119
|
+
```
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { DoubleSide, ShaderMaterial, Vector2 } from "three";
|
|
2
|
+
|
|
3
|
+
export class VirtualTextureMaterial extends ShaderMaterial {
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @param {VirtualTexturePage} page
|
|
7
|
+
* @param {VirtualTextureMemoryMapping} mapping
|
|
8
|
+
*/
|
|
9
|
+
constructor({
|
|
10
|
+
page,
|
|
11
|
+
mapping
|
|
12
|
+
}) {
|
|
13
|
+
super({
|
|
14
|
+
side: DoubleSide,
|
|
15
|
+
uniforms: {
|
|
16
|
+
u_page: { value: page.texture },
|
|
17
|
+
u_page_resolution: {
|
|
18
|
+
value: new Vector2(
|
|
19
|
+
page.page_texture_resolution_in_tiles[0],
|
|
20
|
+
page.page_texture_resolution_in_tiles[1]
|
|
21
|
+
)
|
|
22
|
+
},
|
|
23
|
+
u_tile_resolution: { value: page.tile_resolution },
|
|
24
|
+
u_tile_padding: { value: page.tile_margin },
|
|
25
|
+
u_mapping: { value: mapping.texture },
|
|
26
|
+
u_texture_resolution: { value: mapping.resolution * page.tile_resolution },
|
|
27
|
+
u_max_mip_level: { value: mapping.max_mip_level },
|
|
28
|
+
u_mapping_texture_width: { value: mapping.texture.image.width }
|
|
29
|
+
},
|
|
30
|
+
vertexShader: `
|
|
31
|
+
|
|
32
|
+
// uniform mat4 modelViewMatrix;
|
|
33
|
+
// uniform mat4 projectionMatrix;
|
|
34
|
+
|
|
35
|
+
// in vec2 uv;
|
|
36
|
+
// in vec3 position;
|
|
37
|
+
out vec2 vUv;
|
|
38
|
+
|
|
39
|
+
void main()
|
|
40
|
+
{
|
|
41
|
+
vUv = uv;
|
|
42
|
+
|
|
43
|
+
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
|
|
44
|
+
gl_Position = projectionMatrix * mvPosition;
|
|
45
|
+
}
|
|
46
|
+
`,
|
|
47
|
+
fragmentShader: `
|
|
48
|
+
|
|
49
|
+
precision highp usampler2D;
|
|
50
|
+
|
|
51
|
+
uniform sampler2D u_page;
|
|
52
|
+
uniform uvec2 u_page_resolution;
|
|
53
|
+
uniform usampler2D u_mapping;
|
|
54
|
+
|
|
55
|
+
uniform uint u_tile_resolution;
|
|
56
|
+
uniform uint u_tile_padding;
|
|
57
|
+
|
|
58
|
+
uniform uint u_texture_resolution;
|
|
59
|
+
uniform uint u_max_mip_level;
|
|
60
|
+
uniform uint u_mapping_texture_width;
|
|
61
|
+
|
|
62
|
+
in vec2 vUv;
|
|
63
|
+
|
|
64
|
+
float computeTextureLod(const in vec2 uv){
|
|
65
|
+
float scale_x = float(u_texture_resolution) ;
|
|
66
|
+
float scale_y = float(u_texture_resolution) ;
|
|
67
|
+
|
|
68
|
+
vec2 dx = dFdx( uv * scale_x ) ;
|
|
69
|
+
vec2 dy = dFdy( uv * scale_y ) ;
|
|
70
|
+
|
|
71
|
+
float d = max( dot( dx, dx ), dot( dy, dy ) );
|
|
72
|
+
|
|
73
|
+
return log2( d ) * 0.5;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
uint split_by_2(const in uint a) {
|
|
77
|
+
uint x = a;
|
|
78
|
+
x = (x | x << 16) & 0x0000FFFFu;
|
|
79
|
+
x = (x | x << 8) & 0x00FF00FFu;
|
|
80
|
+
x = (x | x << 4) & 0x0F0F0F0Fu;
|
|
81
|
+
x = (x | x << 2) & 0x33333333u;
|
|
82
|
+
x = (x | x << 1) & 0x55555555u;
|
|
83
|
+
return x;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
uint compose_tile_address(uint mip, uint x, uint y){
|
|
87
|
+
uint mip_resolution = 1u << mip;
|
|
88
|
+
|
|
89
|
+
uint mip_mask = mip_resolution - 1u;
|
|
90
|
+
uint index_offset = split_by_2(mip_mask);
|
|
91
|
+
|
|
92
|
+
return index_offset + x + y * mip_resolution;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
uvec2 PageTilePosition(
|
|
96
|
+
const in uint tile_lod,
|
|
97
|
+
const in uvec2 tile_coordinate,
|
|
98
|
+
out float f_mip_size
|
|
99
|
+
){
|
|
100
|
+
|
|
101
|
+
uint tile_address = compose_tile_address(tile_lod, tile_coordinate.x , tile_coordinate.y);
|
|
102
|
+
|
|
103
|
+
uint tile_mapping_x = tile_address % u_mapping_texture_width;
|
|
104
|
+
uint tile_mapping_y = tile_address / u_mapping_texture_width;
|
|
105
|
+
|
|
106
|
+
uint encoded_mapping = texelFetch(u_mapping, ivec2(tile_mapping_x, tile_mapping_y), 0 ).r;
|
|
107
|
+
|
|
108
|
+
// decode mapping
|
|
109
|
+
uint slot_index = encoded_mapping & 0x3FFFFFu;
|
|
110
|
+
uint mip_level = ( encoded_mapping >> 22) & 0x3FFu;
|
|
111
|
+
|
|
112
|
+
uint mip_size = 1u << mip_level;
|
|
113
|
+
|
|
114
|
+
f_mip_size = float(mip_size);
|
|
115
|
+
|
|
116
|
+
return uvec2(
|
|
117
|
+
slot_index % u_page_resolution.x,
|
|
118
|
+
slot_index / u_page_resolution.x
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
vec2 PageTileSoft(in vec2 uv , in uvec2 virtual_tile_position, uint tile_lod){
|
|
123
|
+
|
|
124
|
+
float f_mip_size;
|
|
125
|
+
|
|
126
|
+
uvec2 tp00 = PageTilePosition( tile_lod, virtual_tile_position, f_mip_size) ;
|
|
127
|
+
|
|
128
|
+
vec2 tile_uv = fract(uv * f_mip_size);
|
|
129
|
+
|
|
130
|
+
return vec2(tp00) + tile_uv;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
vec4 VirtualFetchLod(const in vec2 uv,const in uint texture_lod_0){
|
|
134
|
+
uint ui_texture_lod_0 = u_max_mip_level - texture_lod_0;
|
|
135
|
+
uint tile_mip_size = 1u << ui_texture_lod_0;
|
|
136
|
+
|
|
137
|
+
vec2 uvt = vec2(uv * float(tile_mip_size));
|
|
138
|
+
|
|
139
|
+
vec2 stuv = PageTileSoft(uv, uvec2(floor(uvt.x), floor(uvt.y)), ui_texture_lod_0);
|
|
140
|
+
|
|
141
|
+
vec2 tile_uv = fract(stuv);
|
|
142
|
+
vec2 tile_offset = stuv - tile_uv;
|
|
143
|
+
|
|
144
|
+
float f_tile_resolution = float(u_tile_resolution);
|
|
145
|
+
float slot_size = float(u_tile_resolution + u_tile_padding*2u);
|
|
146
|
+
|
|
147
|
+
ivec2 texture_size = textureSize(u_page,0);
|
|
148
|
+
|
|
149
|
+
vec2 texel = tile_offset * slot_size + float(u_tile_padding) + tile_uv*(f_tile_resolution) ;
|
|
150
|
+
// vec2 texel = tile_offset * slot_size + float(u_tile_padding) + tile_uv*(f_tile_resolution) - 0.5;
|
|
151
|
+
|
|
152
|
+
vec2 page_uv = texel / vec2(texture_size);
|
|
153
|
+
|
|
154
|
+
return textureLod(u_page, page_uv, 0.0);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
vec4 VirtualFetch(const in vec2 uv){
|
|
158
|
+
|
|
159
|
+
float texture_lod = computeTextureLod(uv);
|
|
160
|
+
|
|
161
|
+
float lod_fract = fract(texture_lod);
|
|
162
|
+
|
|
163
|
+
// return vec4(lod_fract, 1.0, 1.0, 1.0);
|
|
164
|
+
|
|
165
|
+
float texture_lod_0 = float(texture_lod);
|
|
166
|
+
float texture_lod_1 = ceil(texture_lod);
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
vec4 lod_0 = VirtualFetchLod(uv, uint(texture_lod_0));
|
|
170
|
+
vec4 lod_1 = VirtualFetchLod(uv, uint(texture_lod_1));
|
|
171
|
+
|
|
172
|
+
vec4 mip_blend = mix(
|
|
173
|
+
lod_0, lod_1, lod_fract
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
return mip_blend;
|
|
177
|
+
|
|
178
|
+
// return vec4(lod_fract, mip_blend.y, mip_blend.z, 1.0);
|
|
179
|
+
|
|
180
|
+
// return texelFetch( u_page, tuv, 0 );
|
|
181
|
+
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
void main(){
|
|
185
|
+
|
|
186
|
+
pc_fragColor = VirtualFetch(vUv);
|
|
187
|
+
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
`
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { ClampToEdgeWrapping, DataTexture, NearestFilter, RedIntegerFormat, UnsignedIntType } from "three";
|
|
2
|
+
import { assert } from "../../../../../core/assert.js";
|
|
3
|
+
import { UINT32_MAX } from "../../../../../core/binary/UINT32_MAX.js";
|
|
4
|
+
import { compose_tile_address } from "./tile/compose_tile_address.js";
|
|
5
|
+
import { decompose_finger_print } from "./tile/decompose_finger_print.js";
|
|
6
|
+
|
|
7
|
+
const EMPTY_TILE = UINT32_MAX;
|
|
8
|
+
|
|
9
|
+
/*
|
|
10
|
+
ENCODING:
|
|
11
|
+
22 bit : slot index
|
|
12
|
+
10 bit : tile mip
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Represents entire mip pyramid of tiles, where each tile slot points to an actual resident tile
|
|
17
|
+
*/
|
|
18
|
+
export class VirtualTextureMemoryMapping {
|
|
19
|
+
/**
|
|
20
|
+
* In tiles
|
|
21
|
+
* @type {number}
|
|
22
|
+
*/
|
|
23
|
+
#resolution = 0;
|
|
24
|
+
#max_mip_level = 0;
|
|
25
|
+
|
|
26
|
+
get max_mip_level(){
|
|
27
|
+
return this.#max_mip_level;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
#pyramid = new Uint32Array(0);
|
|
31
|
+
#texture = new DataTexture(
|
|
32
|
+
new Uint32Array(1),
|
|
33
|
+
1,
|
|
34
|
+
1,
|
|
35
|
+
RedIntegerFormat,
|
|
36
|
+
UnsignedIntType
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
get texture() {
|
|
40
|
+
return this.#texture;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
constructor() {
|
|
44
|
+
const texture = this.#texture;
|
|
45
|
+
|
|
46
|
+
texture.internalFormat = "R32UI";
|
|
47
|
+
texture.generateMipmaps = false;
|
|
48
|
+
|
|
49
|
+
texture.wrapS = ClampToEdgeWrapping;
|
|
50
|
+
texture.wrapT = ClampToEdgeWrapping;
|
|
51
|
+
|
|
52
|
+
texture.magFilter = NearestFilter;
|
|
53
|
+
texture.minFilter = NearestFilter;
|
|
54
|
+
// texture.minFilter = NearestMipMapNearestFilter;
|
|
55
|
+
// texture.magFilter = NearestMipMapNearestFilter;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
*
|
|
60
|
+
* @param {number} resolution in tiles
|
|
61
|
+
*/
|
|
62
|
+
set resolution(resolution) {
|
|
63
|
+
assert.isNonNegativeInteger(resolution, 'resolution');
|
|
64
|
+
|
|
65
|
+
if (this.#resolution === resolution) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
this.#resolution = resolution;
|
|
70
|
+
|
|
71
|
+
//max mip
|
|
72
|
+
const max_mip_level = Math.log2(resolution);
|
|
73
|
+
|
|
74
|
+
const desired_size = compose_tile_address(max_mip_level + 1, 0, 0);
|
|
75
|
+
|
|
76
|
+
const texture_dimension = Math.ceil(Math.sqrt(desired_size));
|
|
77
|
+
|
|
78
|
+
const size = texture_dimension*texture_dimension;
|
|
79
|
+
|
|
80
|
+
this.#max_mip_level = max_mip_level;
|
|
81
|
+
|
|
82
|
+
const arrayBuffer = new ArrayBuffer(size * 4);
|
|
83
|
+
|
|
84
|
+
this.#pyramid = new Uint32Array(arrayBuffer);
|
|
85
|
+
|
|
86
|
+
const texture = this.#texture;
|
|
87
|
+
texture.dispose();
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
texture.image.data = this.#pyramid;
|
|
91
|
+
texture.image.width = texture_dimension;
|
|
92
|
+
texture.image.height = texture_dimension;
|
|
93
|
+
|
|
94
|
+
// texture.mipmaps.splice(0, texture.mipmaps.length);
|
|
95
|
+
// let buffer_offset = 0;
|
|
96
|
+
// for (let mip_level = 0; mip_level <= max_mip_level; mip_level++) {
|
|
97
|
+
// const mip_resolution = 1 << mip_level;
|
|
98
|
+
//
|
|
99
|
+
// const texel_count = mip_resolution * mip_resolution;
|
|
100
|
+
// texture.mipmaps[mip_level] = {
|
|
101
|
+
// data: new Uint32Array(arrayBuffer, buffer_offset, texel_count),
|
|
102
|
+
// width: mip_resolution,
|
|
103
|
+
// height: mip_resolution
|
|
104
|
+
// };
|
|
105
|
+
//
|
|
106
|
+
// buffer_offset += texel_count * 4;
|
|
107
|
+
// }
|
|
108
|
+
//
|
|
109
|
+
// texture.mipmaps.reverse();
|
|
110
|
+
//
|
|
111
|
+
// const top_mip = texture.mipmaps[0];
|
|
112
|
+
// texture.image.data = top_mip.data;
|
|
113
|
+
// texture.image.width = top_mip.width;
|
|
114
|
+
// texture.image.height = top_mip.height;
|
|
115
|
+
|
|
116
|
+
texture.needsUpdate = true;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
get resolution() {
|
|
120
|
+
return this.#resolution;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
*
|
|
125
|
+
* @param {VirtualTexturePage} page
|
|
126
|
+
*/
|
|
127
|
+
set residency(page) {
|
|
128
|
+
|
|
129
|
+
const tiles = page.resident_tiles;
|
|
130
|
+
const tile_count = tiles.length;
|
|
131
|
+
|
|
132
|
+
// clear pyramid
|
|
133
|
+
|
|
134
|
+
const pyramid = this.#pyramid;
|
|
135
|
+
|
|
136
|
+
pyramid.fill(EMPTY_TILE);
|
|
137
|
+
|
|
138
|
+
// fill by residence
|
|
139
|
+
for (let i = 0; i < tile_count; i++) {
|
|
140
|
+
const tile = tiles[i];
|
|
141
|
+
|
|
142
|
+
const fingerPrint = tile.finder_print;
|
|
143
|
+
const { mip, x, y } = decompose_finger_print(fingerPrint);
|
|
144
|
+
const address = compose_tile_address(mip, x, y);
|
|
145
|
+
|
|
146
|
+
const encoded =
|
|
147
|
+
(tile.page_slot & 0x3FFFFF)
|
|
148
|
+
| ((mip & 0x3FF) << 22) //mip
|
|
149
|
+
;
|
|
150
|
+
|
|
151
|
+
pyramid[address] = encoded;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// back-fill empty slots
|
|
155
|
+
for (let mip = 1; mip <= this.#max_mip_level; mip++) {
|
|
156
|
+
|
|
157
|
+
const mip_resolution = 1 << mip;
|
|
158
|
+
|
|
159
|
+
for (let y = 0; y < mip_resolution; y++) {
|
|
160
|
+
for (let x = 0; x < mip_resolution; x++) {
|
|
161
|
+
|
|
162
|
+
const tile_address = compose_tile_address(mip, x, y);
|
|
163
|
+
|
|
164
|
+
if (pyramid[tile_address] !== EMPTY_TILE) {
|
|
165
|
+
// page is filled, all is good, move on
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const parent_mip = mip - 1;
|
|
170
|
+
const parent_x = x >>> 1;
|
|
171
|
+
const parent_y = y >>> 1;
|
|
172
|
+
|
|
173
|
+
const parent_tile_address = compose_tile_address(parent_mip, parent_x, parent_y);
|
|
174
|
+
|
|
175
|
+
const parent_encoded_tile = pyramid[parent_tile_address];
|
|
176
|
+
|
|
177
|
+
// decode parent tile
|
|
178
|
+
const tile_index = (parent_encoded_tile) & 0x3FFFFF
|
|
179
|
+
const tile_mip = (parent_encoded_tile >> 22) & 0x3FF
|
|
180
|
+
|
|
181
|
+
// swap in parent tile
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
const encoded_tile =
|
|
185
|
+
(tile_index)
|
|
186
|
+
| (tile_mip << 22)
|
|
187
|
+
;
|
|
188
|
+
|
|
189
|
+
pyramid[tile_address] = encoded_tile;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// request texture update
|
|
196
|
+
this.#texture.needsUpdate = true;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
dispose() {
|
|
201
|
+
this.#texture.dispose();
|
|
202
|
+
}
|
|
203
|
+
}
|