@ortho-earth/voxel 0.0.0-stage → 0.4.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/LICENSE +29 -0
- package/README.md +85 -2
- package/dist/grid.d.ts +160 -0
- package/dist/grid.js +455 -0
- package/dist/index.d.ts +114 -0
- package/dist/index.js +289 -0
- package/dist/voxel-draw.d.ts +16 -0
- package/dist/voxel-draw.js +77 -0
- package/dist/voxel-gl.d.ts +184 -0
- package/dist/voxel-gl.js +629 -0
- package/dist/voxel-gpu.d.ts +22 -0
- package/dist/voxel-gpu.js +674 -0
- package/dist/voxel-reader.d.ts +16 -0
- package/dist/voxel-reader.js +16 -0
- package/package.json +42 -5
package/LICENSE
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
GNU GENERAL PUBLIC LICENSE
|
|
2
|
+
Version 3, 29 June 2007
|
|
3
|
+
|
|
4
|
+
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
|
5
|
+
Everyone is permitted to copy and distribute verbatim copies
|
|
6
|
+
of this license document, but changing it is not allowed.
|
|
7
|
+
|
|
8
|
+
Preamble
|
|
9
|
+
|
|
10
|
+
The GNU General Public License is a free, copyleft license for
|
|
11
|
+
software and other kinds of works.
|
|
12
|
+
|
|
13
|
+
For the conditions of distribution and use, see the full text at
|
|
14
|
+
<https://www.gnu.org/licenses/gpl-3.0.txt>.
|
|
15
|
+
|
|
16
|
+
Copyright (c) 2026 Kenji Yoshida
|
|
17
|
+
|
|
18
|
+
This program is free software: you can redistribute it and/or modify
|
|
19
|
+
it under the terms of the GNU General Public License as published by
|
|
20
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
21
|
+
(at your option) any later version.
|
|
22
|
+
|
|
23
|
+
This program is distributed in the hope that it will be useful,
|
|
24
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
25
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
26
|
+
GNU General Public License for more details.
|
|
27
|
+
|
|
28
|
+
You should have received a copy of the GNU General Public License
|
|
29
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
package/README.md
CHANGED
|
@@ -1,3 +1,86 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @ortho-earth/voxel
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Voxel grids for [`@ortho-earth/globe`](../../packages/globe). The plugin fills the reserved `map.addData` kind `"voxel"`. The globe already checks the contract (`VoxelData` in `src/voxel.ts`); this package draws it.
|
|
4
|
+
|
|
5
|
+
- **Drawing** is a same-frame overlay with the globe's camera: the grid's bounding box (or the curved shell of a `region` grid) is rasterised and the fragment shader **marches a ray through the cells**. `render: "blocks"` stops at the first solid cell (DDA, one step per cell) and shades it by its face, like a block world. `render: "volume"` takes fixed steps, samples the grid trilinearly and composites the colormap's colour and alpha front to back, like a weather or density field. `render: "iso"` finds where the value crosses `threshold` (bisection) and shades that surface by the field's gradient. All three come from the **same `VoxelData`**; only the option differs.
|
|
6
|
+
- **WebGPU first**: when the globe draws with WebGPU the overlay shares its `GPUDevice` and reads the scene depth texture directly (no copy); otherwise it draws with WebGL2 (every device, including Android where the globe itself is WebGL2). Same shader logic in WGSL and GLSL, same pixels.
|
|
7
|
+
- Grids are **hidden by terrain and buildings** through the scene depth: the ray stops where the scene is.
|
|
8
|
+
- `clip` keeps a sub-box of the grid (a thin range is a **slice**); it changes without re-uploading the grid, as do `render`, `opacity`, `step`, `threshold`, `colormap`, `alphaRamp`, `depthTest` and `properties`.
|
|
9
|
+
- They are **picked** by the unified picking: `handle.pick(x, y)`, `map.on("click", id, …)` and `queryRenderedFeatures({ layers: [id] })`. A hit carries the cell `index`, its `[i, j, k]` `cell`, the cell's `value` (scalar grids, via `handle.pick`) and your `properties`. Picking marches only the pixels under the cursor (scissor), so it stays cheap.
|
|
10
|
+
- **Preparation** runs in a worker (`voxel-reader.ts`): values are quantised to 8 bits (`R8`, or `RGBA8` for `components: 4`), the colormap is baked, the box is placed or the region shell is tessellated; the main thread only forwards the buffers.
|
|
11
|
+
- **Large grids** are split into **bricks**: a grid with an axis beyond 256 cells (the 3D texture size every WebGL2 device guarantees) becomes bricks of 126 cells per axis, one texture each with a 1-cell apron so trilinear sampling and iso gradients run across the seams. Bricks are drawn far to near, a brick whose cells are all below `threshold` (or empty) is skipped, and `clip`, `threshold`, picking (`index` / `cell` of the whole grid) and every style change work across them. `handle.bricks` says how many.
|
|
12
|
+
- **Time**: `times` (ms, ascending) makes `values` a run of frames, one per time. The layer follows `map.clock` by default (the last frame at or before the clock's time; scrub or play the clock and the frame changes without re-uploading), or `time: <ms>` pins one frame. One `range` covers every frame so colours compare across time.
|
|
13
|
+
- Stages 1–4 are done (box and region grids, blocks / volume / iso, clipping, WebGPU and WebGL2, 3D Tiles `EXT_primitive_voxels`); stage 5 has bricks and time, while level of detail and file readers (NetCDF, Zarr) follow. See [PLAN.md](./PLAN.md).
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
import { createGlobe } from "@ortho-earth/globe";
|
|
17
|
+
import { voxelPlugin } from "@ortho-earth/voxel";
|
|
18
|
+
|
|
19
|
+
const map = await createGlobe({ target: "#map", plugins: [voxelPlugin()] }); // or map.use(voxelPlugin({ backend: "auto" | "webgpu" | "webgl2" }))
|
|
20
|
+
map.supports("data.voxel"); // true ("plugin", via "voxel")
|
|
21
|
+
|
|
22
|
+
// a 64 × 64 × 32 density field, 2 km × 2 km × 1 km, its origin corner at Tokyo station
|
|
23
|
+
const field = map.addData({
|
|
24
|
+
dims: [64, 64, 32],
|
|
25
|
+
box: { origin: [139.7671, 35.6812, 0], size: [2000, 2000, 1000] },
|
|
26
|
+
values: new Float32Array(64 * 64 * 32), // x fastest: values[i + 64 * (j + 64 * k)]
|
|
27
|
+
noData: 0,
|
|
28
|
+
}, { kind: "voxel", id: "field", render: "volume", colormap: "turbo", opacity: 0.3 });
|
|
29
|
+
|
|
30
|
+
// the same grid as opaque blocks, cells below 0.5 empty; then as the 0.5 surface; then sliced
|
|
31
|
+
const blocks = map.addData(sameData, { kind: "voxel", id: "blocks", render: "blocks", threshold: 0.5, colormap: ["#3a6", "#fd4"] });
|
|
32
|
+
blocks.setProps({ render: "iso" }); // no re-upload
|
|
33
|
+
blocks.setProps({ clip: [0, 1, 0, 1, 0.45, 0.55] }); // a horizontal slice
|
|
34
|
+
|
|
35
|
+
// a weather field on a longitude × latitude × height grid (west, south, east, north in degrees; heights in meters)
|
|
36
|
+
const wx = map.addData({ dims: [120, 80, 20], region: [128, 30, 146, 46, 0, 12000], values: temperature }, { kind: "voxel", id: "wx", colormap: "magma", opacity: 0.4 });
|
|
37
|
+
|
|
38
|
+
await field.ready;
|
|
39
|
+
field.backend; // "webgpu" | "webgl2" (null until the overlay has chosen)
|
|
40
|
+
map.on("click", "field", e => console.log(e.features[0].properties.cell));
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## VoxelData
|
|
44
|
+
|
|
45
|
+
| field | meaning |
|
|
46
|
+
|---|---|
|
|
47
|
+
| `dims` | `[nx, ny, nz]` cells; `values[i + nx * (j + ny * k)]` |
|
|
48
|
+
| `box` | `{ origin: [lng, lat, alt], size: [m, m, m], orientation?: [heading, pitch, roll] }` — the grid's x, y, z axes point east, north, up from the origin corner (heading rotates them clockwise from north); or `{ transform }`, a column-major 4×4 that takes the **unit cube `[0, 1]³`** to ECEF meters (the column lengths are the edges; the way a 3D Tiles tile transform × a glTF node matrix places a voxel primitive). A transform box is placed at its absolute height |
|
|
49
|
+
| `region` | `[west, south, east, north, h0, h1]` degrees and meters: cell x follows longitude, y latitude, z height. `east < west` crosses the antimeridian. Placed at its absolute height |
|
|
50
|
+
| `values` | `Float32Array`, `Uint16Array` or `Uint8Array`, `nx·ny·nz·components` long (× the number of `times`) |
|
|
51
|
+
| `components` | `1` (scalar, coloured by the colormap; default) or `4` (RGBA, drawn as is; alpha 0 = empty) |
|
|
52
|
+
| `noData` | cells with this value are empty |
|
|
53
|
+
| `range` | values mapped to the colormap's 0..1 (default the data's min / max over every frame) |
|
|
54
|
+
| `times` | frame times in ms, strictly ascending; `values` holds the frames one after another (globe 2.2.0+) |
|
|
55
|
+
|
|
56
|
+
## Options
|
|
57
|
+
|
|
58
|
+
| option | meaning |
|
|
59
|
+
|---|---|
|
|
60
|
+
| `id` | layer id for picking and `map.on` |
|
|
61
|
+
| `render` | `"volume"` (default), `"blocks"` or `"iso"` |
|
|
62
|
+
| `colormap` | a name (`viridis` `magma` `inferno` `plasma` `turbo` `grey` `heat` `cool` `blues` `reds`), a list of colours spread evenly, or `[t, colour]` stops. Colours `"#rrggbb"`, `"#rrggbbaa"` or `[r, g, b, a?]` |
|
|
63
|
+
| `range` | overrides the data's `range` |
|
|
64
|
+
| `threshold` | blocks / volume: cells below this value (data units) are empty; iso: the value of the surface |
|
|
65
|
+
| `clip` | `[x0, x1, y0, y1, z0, z1]` fractions 0..1 of each axis to keep (default everything) |
|
|
66
|
+
| `alphaRamp` | volume: alpha over the colormap's 0..1 when the colours carry none (default `[0, 1]`) |
|
|
67
|
+
| `step` | volume / iso: distance between samples in cells (default 0.5; smaller is finer and slower). Region blocks sample every quarter cell |
|
|
68
|
+
| `opacity` | multiplies every cell's opacity (default 1) |
|
|
69
|
+
| `altitude` | `"relative"` (the origin's alt is above the ground, default for origin boxes) or `"absolute"` (above the ellipsoid; default for transform boxes and regions) |
|
|
70
|
+
| `depthTest` | hidden by terrain and buildings (default true) |
|
|
71
|
+
| `above` | draw above the labels (default false) |
|
|
72
|
+
| `properties` | merged into every pick hit's `properties` |
|
|
73
|
+
| `time` | grids with `times`: `"clock"` (follow `map.clock`, default) or a time in ms (show the frame at or before it) |
|
|
74
|
+
|
|
75
|
+
## Handle
|
|
76
|
+
|
|
77
|
+
`id`, `kind`, `shape`, `dims`, `n` (cells), `bricks` (0 = one texture), `times` (null without frames), `frame` (the frame shown), `anchor`, `range`, `backend` (`"webgpu"` | `"webgl2"`, null until the overlay has chosen), `reader` (`"worker"` | `"main"`), `error` (the renderer refused the layer, e.g. a grid beyond the 3D texture limit), `ready`, `setData(data)`, `setProps(opts)` (style-only changes do not re-upload the grid), `setVisible(on)`, `pick(x, y, r?)` (the value of the frame shown), `remove()`.
|
|
78
|
+
|
|
79
|
+
## Notes
|
|
80
|
+
|
|
81
|
+
- Scalar values are quantised to 8 bits for the GPU (`range` → 1..255, 0 = empty). The colormap resolves 256 steps and an iso threshold lands on one of them; `handle.pick` reports the original value from the data kept on the main thread.
|
|
82
|
+
- A grid with every axis within 256 cells is one texture; a larger one is split into bricks (above). The bricks are kept in GPU memory as a whole (1 byte per cell, 4 for RGBA): a 1024 × 1024 × 128 grid needs 128 MB, so very large grids need level of detail (still to come) on phones.
|
|
83
|
+
- Region grids are marched in meters along a straight ray and each sample is converted back to longitude / latitude / height, so cell borders are the true meridians, parallels and height surfaces. Their blocks mode samples the nearest cell every quarter cell instead of a DDA (slightly soft edges). The shell is built on a sphere; under the ellipsoid display (`?ell=1`) a country-sized region can sit a few km off, which stage 3 will tighten. Very large regions (thousands of km) shade with the anchor's east / north / up.
|
|
84
|
+
- All grids of one map share one overlay canvas (the render worker's WebGL contexts are limited); the overlay goes away a moment (`OVERLAY_LINGER_MS`, 250 ms) after the last handle is removed, so `remove()` followed at once by `addData()` (switching scenes) keeps the same overlay instead of tearing it down and racing a new one with the same name.
|
|
85
|
+
- **3D Tiles**: a tileset whose glTF content carries `EXT_primitive_voxels` (with `KHR_implicit_shapes` boxes or `EXT_implicit_ellipsoid_region` regions), or whose `root.content` declares `3DTILES_content_voxels` (the grid fills the tile's bounding volume), becomes one layer per tile through `map.add3DTiles(url, { voxel: { render, colormap, threshold, property, … } })`; `property` picks the attribute (a class property name works too). Cylinders are not drawn yet; without this plugin the globe skips the grids and warns once.
|
|
86
|
+
- A live example: [`/globe/voxel`](https://www.ortho-earth.com/globe/voxel) (`apps/voxel/voxel.ts`): a noise cloud, a torus, Mt. Fuji as blocks from `map.sampleTerrain` and the USGS catalog as a region density volume.
|
package/dist/grid.d.ts
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import type { VoxelData } from "@ortho-earth/globe";
|
|
2
|
+
export type Hpr = [heading: number, pitch: number, roll: number];
|
|
3
|
+
export type RenderMode = "blocks" | "volume" | "iso";
|
|
4
|
+
/** 断面=各軸の残す範囲(0〜1 の割合)[x0, x1, y0, y1, z0, z1] */
|
|
5
|
+
export type Clip = [number, number, number, number, number, number];
|
|
6
|
+
/** 色表の指定=名前か、色の並び(等間隔)か、[位置 0〜1, 色] の並び。色="#rrggbb"/"#rrggbbaa"/[r, g, b, a?](0〜255) */
|
|
7
|
+
export type ColorStop = string | [number, number, number] | [number, number, number, number];
|
|
8
|
+
export type ColormapSpec = string | ColorStop[] | Array<[number, ColorStop]>;
|
|
9
|
+
export interface PrepareOptions {
|
|
10
|
+
colormap?: ColormapSpec;
|
|
11
|
+
/** 色表に写す値の幅(省略=data.range か、値の min/max) */
|
|
12
|
+
range?: [number, number] | null;
|
|
13
|
+
/** 体積の α(色表に α が無い時)=値 0〜1 に対する [a0, a1](既定 [0, 1]) */
|
|
14
|
+
alphaRamp?: [number, number] | null;
|
|
15
|
+
/** これ未満の値のセルは空(データの単位・既定=無し) */
|
|
16
|
+
threshold?: number | null;
|
|
17
|
+
/** 楕円体表示の b/a(region の殻を本体と同じ形で作る・既定 1=球) */
|
|
18
|
+
rAx?: number;
|
|
19
|
+
}
|
|
20
|
+
/** region(経緯度×高さの格子)の描き手向けの欄 */
|
|
21
|
+
export interface GeoGrid {
|
|
22
|
+
/** 西・南(度)・経度の幅・緯度の幅(度・正) */ west: number;
|
|
23
|
+
south: number;
|
|
24
|
+
spanLon: number;
|
|
25
|
+
spanLat: number;
|
|
26
|
+
/** 高さの範囲(m) */ h0: number;
|
|
27
|
+
h1: number;
|
|
28
|
+
/** 殻(6 面を分割した三角形・錨からの東北上 m・外向き CCW)=裏面を描く箱の代わり */ shell: Float32Array;
|
|
29
|
+
/** 殻を包む球(東北上 m・中心 xyz と半径)=光線の入口の目安 */ bs: [number, number, number, number];
|
|
30
|
+
/** セルの大きさ(m・東・北・上)=刻みと法線の尺 */ cellM: [number, number, number];
|
|
31
|
+
}
|
|
32
|
+
export interface Prepared {
|
|
33
|
+
shape: "box" | "region";
|
|
34
|
+
dims: [number, number, number];
|
|
35
|
+
comps: 1 | 4;
|
|
36
|
+
n: number;
|
|
37
|
+
tex: Uint8Array;
|
|
38
|
+
cmap: Uint8Array;
|
|
39
|
+
anchor: [number, number, number]; /** セルの座標(0〜dims)→ 錨からの東北上 m(行優先 3×3・region は対角=セルの大きさ) */
|
|
40
|
+
A: Float64Array; /** 錨から格子の最遠点まで(m) */
|
|
41
|
+
radius: number;
|
|
42
|
+
range: [number, number]; /** 空の判定の閾(R8 の 0〜1) */
|
|
43
|
+
thr: number; /** transform で置いた=絶対高さ */
|
|
44
|
+
placed: boolean;
|
|
45
|
+
geo: GeoGrid | null;
|
|
46
|
+
/** 時間の次元(data.times)=こまの時刻(ms)と、こまごとのテクスチャ(frames[0] は tex と同じ物)。こまが無ければ null */
|
|
47
|
+
times: number[] | null;
|
|
48
|
+
frames: Uint8Array[] | null;
|
|
49
|
+
}
|
|
50
|
+
export type Mat3 = number[];
|
|
51
|
+
/** 名前のある色表(matplotlib/turbo の要約=9 点を等間隔に。厳密な表ではない) */
|
|
52
|
+
export declare const COLORMAPS: Readonly<Record<string, readonly string[]>>;
|
|
53
|
+
export declare const COLORMAP_NAMES: readonly string[];
|
|
54
|
+
export declare function parseColor(c: ColorStop): [number, number, number, number | null];
|
|
55
|
+
/** 色表の指定 → [位置, 色] の並び(位置は昇順・0 と 1 を含む) */
|
|
56
|
+
export declare function colorStops(spec: ColormapSpec | undefined): Array<[number, [number, number, number, number | null]]>;
|
|
57
|
+
/** 色表=256 段の RGBA8(値 0〜1 → 色・α は stop に無ければ alphaRamp=[a0, a1] の線形) */
|
|
58
|
+
export declare function buildColormap(spec: ColormapSpec | undefined, alphaRamp?: [number, number] | null): Uint8Array;
|
|
59
|
+
/** 値の min/max(noData を除く・1 成分) */
|
|
60
|
+
export declare function valueRange(values: ArrayLike<number>, noData: number | undefined): [number, number];
|
|
61
|
+
/** 1 成分の値 → R8(0=空・1〜255=range を [0,1] に写した物。range の外は端に寄せる・threshold 未満は空) */
|
|
62
|
+
export declare function quantize(values: ArrayLike<number>, range: [number, number], noData: number | undefined, threshold: number | null | undefined): Uint8Array;
|
|
63
|
+
/** 4 成分(RGBA)→ RGBA8(Uint8 はそのまま・Uint16 は 1/257・Float32 は 0〜1 を 255 倍。noData は α 0) */
|
|
64
|
+
export declare function toRgba8(values: Float32Array | Uint16Array | Uint8Array, noData: number | undefined): Uint8Array;
|
|
65
|
+
export interface EnuBasis {
|
|
66
|
+
E: number[];
|
|
67
|
+
N: number[];
|
|
68
|
+
U: number[];
|
|
69
|
+
u: number[];
|
|
70
|
+
}
|
|
71
|
+
/** 錨の東北上 m → 単位球(列=東・北・上×1/R)=本体の単位球(y が極)。splat の splat-gl.ts と同じ */
|
|
72
|
+
export declare function enuBasis(lon: number, lat: number, rAx?: number): EnuBasis;
|
|
73
|
+
/** ECEF(WGS84・z が極)→ 経緯度・楕円体高 */
|
|
74
|
+
export declare function ecefToLngLat(x: number, y: number, z: number): [number, number, number];
|
|
75
|
+
/** ECEF の東北上の基底(行=東・北・上の単位ベクトル・ECEF m → ENU m は行優先 3×3) */
|
|
76
|
+
export declare function ecefEnuRows(lon: number, lat: number): Mat3;
|
|
77
|
+
export declare const mul3: (A: ArrayLike<number>, B: ArrayLike<number>) => Mat3;
|
|
78
|
+
/** 行優先 3×3 の逆行列(特異なら投げる) */
|
|
79
|
+
export declare function inv3(m: ArrayLike<number>): Mat3;
|
|
80
|
+
/** heading(北から時計回り)・pitch・roll(度)=東北上の中の向き(行優先 3×3・splat の placeMat と同じ約束) */
|
|
81
|
+
export declare function hprMat([hd, pt, rl]?: Hpr | []): Mat3;
|
|
82
|
+
export interface Placement {
|
|
83
|
+
anchor: [number, number, number];
|
|
84
|
+
A: Float64Array;
|
|
85
|
+
radius: number;
|
|
86
|
+
placed: boolean;
|
|
87
|
+
}
|
|
88
|
+
/** VoxelData の box → 錨+A(セル → 東北上 m)。transform=局所の単位立方体 [0,1]³ → ECEF m */
|
|
89
|
+
export declare function placeBox(box: NonNullable<VoxelData["box"]>, dims: [number, number, number]): Placement;
|
|
90
|
+
/** 経緯度・高さ → 単位球(本体の単位球=y が極・rAx=楕円体の b/a で測地緯度を更成緯度に) */
|
|
91
|
+
export declare const unitAt: (lon: number, lat: number, h: number, rAx?: number) => number[];
|
|
92
|
+
export declare const SHELL_N = 16;
|
|
93
|
+
/** VoxelData の region → 錨(中心の経緯度・h0)+殻+セルの大きさ。region=[w, s, e, n(度), h0, h1(m)]・e < w は日付変更線を跨ぐ */
|
|
94
|
+
export declare function placeRegion(region: ArrayLike<number>, dims: [number, number, number], rAx?: number): Placement & {
|
|
95
|
+
geo: GeoGrid;
|
|
96
|
+
};
|
|
97
|
+
/** 断面の指定を検める(各軸 [lo, hi]・0〜1・lo < hi) */
|
|
98
|
+
export declare function checkClip(c: unknown): Clip | null;
|
|
99
|
+
type NormVoxel = VoxelData & {
|
|
100
|
+
shape: "box" | "region";
|
|
101
|
+
dims: [number, number, number];
|
|
102
|
+
components: 1 | 4;
|
|
103
|
+
};
|
|
104
|
+
export declare function checkVoxelData(d: unknown): NormVoxel;
|
|
105
|
+
/** こま t の値(times が無ければ全部)=values の部分(写さない) */
|
|
106
|
+
export declare function frameValues<T extends Float32Array | Uint16Array | Uint8Array>(values: T, n: number, comps: number, t: number): T;
|
|
107
|
+
/** 時刻 ms → 見せるこま=その時刻までで最後のこま(最初のこまより前は 0・最後より後は最後) */
|
|
108
|
+
export declare function frameAt(times: ArrayLike<number>, ms: number): number;
|
|
109
|
+
/** 閾(データの単位)→ R8 の 0〜1 */
|
|
110
|
+
export declare const thrOf: (threshold: number | null | undefined, range: [number, number]) => number;
|
|
111
|
+
/** VoxelData → 描き手へ渡す物(worker で。配列は transfer できる物)。値は閾で切らない(閾は描き手が見る=等値面は場の全体が要る) */
|
|
112
|
+
export declare function prepare(data: unknown, o?: PrepareOptions): Prepared;
|
|
113
|
+
export declare const transferables: (p: Prepared | PreparedGrid) => ArrayBuffer[];
|
|
114
|
+
/** 一枚のテクスチャで描く格子の上限(各軸) */
|
|
115
|
+
export declare const BRICK_LIMIT = 256;
|
|
116
|
+
/** ブリックの持ち分(各軸のセル数)=テクスチャは糊代を足して最大 BRICK + 2 */
|
|
117
|
+
export declare const BRICK = 126;
|
|
118
|
+
export interface Brick {
|
|
119
|
+
/** テクスチャの 0 番のセルの親の格子での位置 */ off: [number, number, number];
|
|
120
|
+
/** 描く範囲(テクスチャのセル座標)[x0, y0, z0, x1, y1, z1] */ own: [number, number, number, number, number, number];
|
|
121
|
+
dims: [number, number, number];
|
|
122
|
+
n: number;
|
|
123
|
+
tex: Uint8Array; /** こまごとのテクスチャ(frames[0]=tex)・こまが無ければ null */
|
|
124
|
+
frames: Uint8Array[] | null; /** 最大値(R8 の 0〜255・RGBA は α・こまを通して) */
|
|
125
|
+
vmax: number;
|
|
126
|
+
anchor: [number, number, number];
|
|
127
|
+
A: Float64Array;
|
|
128
|
+
radius: number;
|
|
129
|
+
geo: GeoGrid | null;
|
|
130
|
+
}
|
|
131
|
+
export interface PreparedGrid extends Prepared {
|
|
132
|
+
vmax: number; /** 分けた時のブリック(tex は空) */
|
|
133
|
+
bricks: Brick[] | null;
|
|
134
|
+
}
|
|
135
|
+
/** 詰めた値の最大(R8 はそのまま・RGBA は α) */
|
|
136
|
+
export declare function maxOf(tex: Uint8Array, comps: 1 | 4): number;
|
|
137
|
+
/** 分けるか(一軸でも上限を越える) */
|
|
138
|
+
export declare const needsBricks: (dims: ArrayLike<number>, limit?: number) => boolean;
|
|
139
|
+
/** 各軸の持ち分の区切り([始め, 終わり) の並び) */
|
|
140
|
+
export declare function brickSpans(n: number, brick?: number): Array<[number, number]>;
|
|
141
|
+
/** 格子の部分(off から bd セル角)を写す(x が最速・成分は comps 個ずつ) */
|
|
142
|
+
export declare function extract<T extends Float32Array | Uint16Array | Uint8Array>(values: T, dims: [number, number, number], comps: number, off: [number, number, number], bd: [number, number, number]): T;
|
|
143
|
+
/** ブリックの番号(テクスチャの中)→ 親の格子の番号 */
|
|
144
|
+
export declare function parentIndex(index: number, dims: ArrayLike<number>, off: ArrayLike<number>, full: ArrayLike<number>): {
|
|
145
|
+
index: number;
|
|
146
|
+
cell: [number, number, number];
|
|
147
|
+
};
|
|
148
|
+
/** prepare の大きな格子版=上限を越えればブリックに分ける(越えなければ prepare と同じ+vmax) */
|
|
149
|
+
export declare function prepareGrid(data: unknown, o?: PrepareOptions, brick?: number, limit?: number): PreparedGrid;
|
|
150
|
+
export interface RayHit {
|
|
151
|
+
cell: [number, number, number];
|
|
152
|
+
t: number;
|
|
153
|
+
axis: 0 | 1 | 2 | -1;
|
|
154
|
+
steps: number;
|
|
155
|
+
}
|
|
156
|
+
/** 光線と箱 [0, dims] の交わり(t0, t1)。無ければ null */
|
|
157
|
+
export declare function rayBox(ro: ArrayLike<number>, rd: ArrayLike<number>, dims: ArrayLike<number>): [number, number, number] | null;
|
|
158
|
+
/** ブロックの DDA:値(R8・0=空)が thr 以上の最初のセル。tMax=ここまで(シーンの深度)。cell 空間の光線 */
|
|
159
|
+
export declare function marchBlocks(tex: Uint8Array, dims: [number, number, number], ro: ArrayLike<number>, rd: ArrayLike<number>, thr?: number, tMax?: number, comps?: 1 | 4): RayHit | null;
|
|
160
|
+
export {};
|