Skip to content

Commit

Permalink
fix: apply some of the suggested changes
Browse files Browse the repository at this point in the history
  • Loading branch information
HoloTheDrunk committed Nov 27, 2024
1 parent 55a01e7 commit 7e84c08
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 51 deletions.
2 changes: 1 addition & 1 deletion src/Core/Prefab/Globe/GlobeLayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class GlobeLayer extends TiledGeometryLayer {
CRS.tms_3857,
];
const uvCount = config.tileMatrixSets.length;
const builder = new GlobeTileBuilder({ crs: 'EPSG:4978', uvCount });
const builder = new GlobeTileBuilder({ uvCount });

super(id, object3d || new THREE.Group(), schemeTile, builder, config);

Expand Down
71 changes: 37 additions & 34 deletions src/Core/Prefab/Globe/GlobeTileBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,35 +16,56 @@ const quatToAlignLongitude = new THREE.Quaternion();
const quatToAlignLatitude = new THREE.Quaternion();
const quatNormalToZ = new THREE.Quaternion();

function WGS84ToOneSubY(latitude: number) {
/** Transforms a WGS84 latitude into a usable texture offset. */
function WGS84ToOneSubY(latitude: number): number {
return 1.0 - (0.5 - Math.log(Math.tan(
PI_OV_FOUR + THREE.MathUtils.degToRad(latitude) * 0.5,
)) * INV_TWO_PI);
}

type Transform = {
/** Buffers for 2-part coordinate mapping operations. */
coords: [Coordinates, Coordinates];
position: THREE.Vector3;
dimension: THREE.Vector2;
};

/** Specialized parameters for the [GlobeTileBuilder]. */
export interface GlobeTileBuilderParams extends TileBuilderParams {
/** Number of rows of tiles, essentially the resolution of the globe. */
nbRow: number;
/** Offset of the second texture set. */
deltaUV1: number;
/** Transformation to align a tile's normal to the Z axis. */
quatNormalToZ: THREE.Quaternion;
}

/**
* TileBuilder implementation for the purpose of generating globe (or more
* precisely ellipsoidal) tile arrangements.
*/
export class GlobeTileBuilder
implements TileBuilder<GlobeTileBuilderParams> {
private _crs: string;
private _transform: {
coords: Coordinates[];
position: THREE.Vector3;
dimension: THREE.Vector2;
};
private static _crs: string = 'EPSG:4978';
private static _computeExtraOffset(params: GlobeTileBuilderParams): number {
const t = WGS84ToOneSubY(params.projected.latitude) * params.nbRow;
return (!isFinite(t) ? 0 : t) - params.deltaUV1;
}

/**
* Buffer holding information about the tile/vertex currently being
* processed.
*/
private _transform: Transform;

public computeExtraOffset?: (params: GlobeTileBuilderParams) => number;

public get crs(): string {
return this._crs;
return GlobeTileBuilder._crs;
}

public constructor(options: {
crs: string,
/** Number of unaligned texture sets. */
uvCount: number,
}) {
this._transform = {
Expand All @@ -56,9 +77,6 @@ implements TileBuilder<GlobeTileBuilderParams> {
dimension: new THREE.Vector2(),
};

this._crs = options.crs;
// Order crs projection on tiles

// UV: Normalized coordinates (from degree) on the entire tile
// EPSG:4326
// Offset: Float row coordinate from Pseudo mercator coordinates
Expand All @@ -68,13 +86,6 @@ implements TileBuilder<GlobeTileBuilderParams> {
}
}

private static _computeExtraOffset(params: GlobeTileBuilderParams): number {
const t = WGS84ToOneSubY(params.projected.latitude) * params.nbRow;
return (!isFinite(t) ? 0 : t) - params.deltaUV1;
}

// prepare params
// init projected object -> params.projected
public prepare(params: TileBuilderParams): GlobeTileBuilderParams {
const nbRow = 2 ** (params.level + 1.0);
let st1 = WGS84ToOneSubY(params.extent.south);
Expand Down Expand Up @@ -103,54 +114,46 @@ implements TileBuilder<GlobeTileBuilderParams> {
return { ...params, ...newParams };
}

// get center tile in cartesian 3D
public center(extent: Extent) {
return extent.center(this._transform.coords[0])
.as(this.crs, this._transform.coords[1])
.toVector3();
}

// get position 3D cartesian
public vertexPosition(position: THREE.Vector2): THREE.Vector3 {
return this._transform.coords[0]
.setFromValues(position.x, position.y)
.as(this.crs, this._transform.coords[1])
.toVector3(this._transform.position);
}

// get normal for last vertex
public vertexNormal() {
return this._transform.coords[1].geodesicNormal;
}

// coord u tile to projected
public uProject(u: number, extent: Extent): number {
return extent.west + u * this._transform.dimension.x;
}

// coord v tile to projected
public vProject(v: number, extent: Extent): number {
return extent.south + v * this._transform.dimension.y;
}

public computeShareableExtent(extent: Extent): ShareableExtent {
// Compute shareable extent to pool the geometries
// the geometry in common extent is identical to the existing input
// with a transformation (translation, rotation)

// TODO: It should be possible to use equatorial plan symetrie,
// but we should be reverse UV on tile
// Common geometry is looking for only on longitude
// NOTE: It should be possible to take advantage of equatorial plane
// symmetry, for which we'd have to reverse the tile's UVs.
// This would halve the memory requirement when viewing a full globe,
// but that case is not that relevant for iTowns' usual use cases and
// the globe mesh memory usage is already inconsequential.
const sizeLongitude = Math.abs(extent.west - extent.east) / 2;
const shareableExtent = new Extent(
extent.crs,
-sizeLongitude, sizeLongitude,
extent.south, extent.north,
);

// compute rotation to transform tile to position on ellipsoid
// this transformation takes into account the transformation of the
// parents
// Compute rotation to transform the tile to position on the ellispoid.
// This transformation takes the parents' transformation into account.
const rotLon = THREE.MathUtils.degToRad(
extent.west - shareableExtent.west,
);
Expand Down
7 changes: 6 additions & 1 deletion src/Core/Prefab/Planar/PlanarTileBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,17 @@ type Transform = {
normal: THREE.Vector3,
};

/** Specialized parameters for the [PlanarTileBuilder]. */
export interface PlanarTileBuilderParams extends TileBuilderParams {
crs: string;
uvCount?: number;
nbRow: number;
}

/**
* TileBuilder implementation for the purpose of generating planar
* tile arrangements.
*/
export class PlanarTileBuilder implements TileBuilder<PlanarTileBuilderParams> {
private _uvCount: number;
private _transform: Transform;
Expand Down Expand Up @@ -62,7 +67,7 @@ export class PlanarTileBuilder implements TileBuilder<PlanarTileBuilderParams> {
// init projected object -> params.projected
public prepare(params: TileBuilderParams): PlanarTileBuilderParams {
const newParams = params as PlanarTileBuilderParams;
newParams.nbRow = 2 ** (params.zoom + 1.0);
newParams.nbRow = 2 ** (params.level + 1.0);
newParams.projected = new Projected();
return newParams;
}
Expand Down
27 changes: 23 additions & 4 deletions src/Core/Prefab/TileBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@ export type GpuBufferAttributes = {
uvs: THREE.BufferAttribute[];
};

/**
* Reference to a tile's extent with rigid transformations.
* Enables reuse of geometry, saving a bit of memory.
*/
export type ShareableExtent = {
shareableExtent: Extent;
quaternion: THREE.Quaternion;
position: THREE.Vector3;
};

// TODO: Check if this order is right
// Ideally we split this into Vec2 and a simpler LatLon type
// Somewhat equivalent to a light Coordinates class
export class Projected extends THREE.Vector2 {
Expand All @@ -47,14 +50,18 @@ export interface TileBuilderParams {
disableSkirt: boolean;
/** Whether to render the skirt. */
hideSkirt: boolean;
/**
* Cache-related.
* Tells the function whether to build or skip the index and uv buffers.
*/
buildIndexAndUv_0: boolean;
/** Number of segments (edge loops) inside tiles. */
segments: number;
// TODO: Move this out of the interface
/** Buffer for projected points. */
projected: Projected;
extent: Extent;
level: number;
zoom: number;
center: THREE.Vector3;
}

Expand All @@ -63,13 +70,26 @@ export interface TileBuilder<SpecializedParams extends TileBuilderParams> {

/** Convert builder-agnostic params to specialized ones. */
prepare(params: TileBuilderParams): SpecializedParams;
/**
* Computes final offset of the second texture set.
* Only relevant in the case of more than one texture sets.
*/
computeExtraOffset?: (params: SpecializedParams) => number;
/** Get the center of the tile in 3D cartesian coordinates. */
/** Get the center of the current tile as a 3D vector. */
center(extent: Extent): THREE.Vector3;
/** Converts an x/y tile-space position to its equivalent in 3D space. */
vertexPosition(position: THREE.Vector2): THREE.Vector3;
/** Gets the geodesic normal of the last processed vertex. */
vertexNormal(): THREE.Vector3;
/** Project horizontal texture coordinate to world space. */
uProject(u: number, extent: Extent): number;
/** Project vertical texture coordinate to world space. */
vProject(v: number, extent: Extent): number;
/**
* Compute shareable extent to pool geometries together.
* The geometry of tiles on the same latitude is the same with an added
* rigid transform.
*/
computeShareableExtent(extent: Extent): ShareableExtent;
}

Expand All @@ -86,7 +106,6 @@ export function newTileGeometry(
`${builder.crs}_${params.disableSkirt ? 0 : 1}_${params.segments}`;

let promiseGeometry = cacheTile.get(south, params.level, bufferKey);
// let promiseGeometry;

// build geometry if doesn't exist
if (!promiseGeometry) {
Expand Down
14 changes: 8 additions & 6 deletions src/Core/Prefab/computeBufferTileGeometry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ export type Buffers = {
uvs: [Option<Float32Array>, Option<Float32Array>],
};

type TmpBuffers = Buffers & {
type BuffersAndSkirt = Buffers & {
skirt: IndexArray,
};

function pickUintArraySize(
function getUintArrayConstructor(
highestValue: number,
): Uint8ArrayConstructor | Uint16ArrayConstructor | Uint32ArrayConstructor {
let picked = null;
Expand Down Expand Up @@ -50,7 +50,7 @@ function allocateIndexBuffer(
}

const indexBufferSize = getBufferIndexSize(nSeg, params.disableSkirt);
const indexConstructor = pickUintArraySize(nVertex);
const indexConstructor = getUintArrayConstructor(nVertex);

const tileLen = indexBufferSize;
const skirtLen = 4 * nSeg;
Expand All @@ -77,7 +77,7 @@ function allocateBuffers(
nSeg: number,
builder: TileBuilder<TileBuilderParams>,
params: TileBuilderParams,
): TmpBuffers {
): BuffersAndSkirt {
const {
index,
skirt,
Expand Down Expand Up @@ -127,11 +127,12 @@ function initComputeUv1(value: number): (uv: Float32Array, id: number) => void {
type ComputeUvs =
[typeof computeUv0 | (() => void), ReturnType<typeof initComputeUv1>?];

/** Compute buffers describing a tile according to a builder and its params. */
// TODO: Split this even further into subfunctions
export function computeBuffers(
builder: TileBuilder<TileBuilderParams>,
params: TileBuilderParams,
) {
): Buffers {
// n seg, n+1 vert + <- skirt, n verts per side
// <---------------> / |
// +---+---+---+---+ |
Expand All @@ -154,7 +155,7 @@ export function computeBuffers(
throw new Error('Tile segments count is too big');
}

const outBuffers: TmpBuffers = allocateBuffers(
const outBuffers: BuffersAndSkirt = allocateBuffers(
nTotalVertex, nSeg,
builder, params,
);
Expand Down Expand Up @@ -243,6 +244,7 @@ export function computeBuffers(
}
}

/** Copy passed indices at the desired index of the output index buffer. */
function bufferizeTri(id: number, va: number, vb: number, vc: number) {
outBuffers.index![id + 0] = va;
outBuffers.index![id + 1] = vb;
Expand Down
5 changes: 2 additions & 3 deletions src/Core/TileGeometry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Cache from 'Core/Scheduler/Cache';
import OBB from 'Renderer/OBB';

type PartialTileBuilderParams =
Pick<TileBuilderParams, 'extent' | 'level' | 'zoom'>
Pick<TileBuilderParams, 'extent' | 'level'>
& Partial<TileBuilderParams>;

function defaultBuffers(
Expand Down Expand Up @@ -96,8 +96,7 @@ export class TileGeometry extends THREE.BufferGeometry {
}

/**
* Initialize reference count for this geometry.
* Idempotent operation.
* Initialize reference count for this geometry if it is currently null.
*
* @param cacheTile - The [Cache] used to store this geometry.
* @param keys - The [south, level, epsg] key of this geometry.
Expand Down
2 changes: 1 addition & 1 deletion src/Renderer/OBB.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Coordinates from 'Core/Geographic/Coordinates';
import CRS from 'Core/Geographic/Crs';

// get oriented bounding box of tile
const builder = new GlobeTileBuilder({ crs: 'EPSG:4978', uvCount: 1 });
const builder = new GlobeTileBuilder({ uvCount: 1 });
const size = new THREE.Vector3();
const dimension = new THREE.Vector2();
const center = new THREE.Vector3();
Expand Down
2 changes: 1 addition & 1 deletion test/unit/obb.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ describe('Planar tiles OBB computation', function () {
});
});
describe('Ellipsoid tiles OBB computation', function () {
const builder = new GlobeTileBuilder({ crs: 'EPSG:4978', uvCount: 1 });
const builder = new GlobeTileBuilder({ uvCount: 1 });

it('should compute globe-level 0 OBB correctly', function (done) {
const extent = new Extent('EPSG:4326', -180, 0, -90, 90);
Expand Down

0 comments on commit 7e84c08

Please sign in to comment.