@loaders.gl/terrain
Version:
Framework-independent loader for terrain raster formats
74 lines (73 loc) • 3.05 kB
JavaScript
// loaders.gl
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors
import { getMeshBoundingBox } from '@loaders.gl/schema';
import decode, { DECODING_STEPS } from "./decode-quantized-mesh.js";
import { addSkirt } from "./helpers/skirt.js";
export function parseQuantizedMesh(arrayBuffer, options = {}) {
const { bounds } = options;
// Don't parse edge indices or format extensions
const { header, vertexData, triangleIndices: originalTriangleIndices, westIndices, northIndices, eastIndices, southIndices } = decode(arrayBuffer, DECODING_STEPS.triangleIndices);
let triangleIndices = originalTriangleIndices;
let attributes = getMeshAttributes(vertexData, header, bounds);
// Compute bounding box before adding skirt so that z values are not skewed
// TODO: Find bounding box from header, instead of doing extra pass over
// vertices.
const boundingBox = getMeshBoundingBox(attributes);
if (options?.skirtHeight) {
const { attributes: newAttributes, triangles: newTriangles } = addSkirt(attributes, triangleIndices, options.skirtHeight, {
westIndices,
northIndices,
eastIndices,
southIndices
});
attributes = newAttributes;
triangleIndices = newTriangles;
}
return {
// Data return by this loader implementation
loaderData: {
header: {}
},
header: {
// @ts-ignore
vertexCount: triangleIndices.length,
boundingBox
},
// TODO
schema: undefined,
topology: 'triangle-list',
mode: 4, // TRIANGLES
indices: { value: triangleIndices, size: 1 },
attributes
};
}
function getMeshAttributes(vertexData, header, bounds) {
const { minHeight, maxHeight } = header;
const [minX, minY, maxX, maxY] = bounds || [0, 0, 1, 1];
const xScale = maxX - minX;
const yScale = maxY - minY;
const zScale = maxHeight - minHeight;
const nCoords = vertexData.length / 3;
// vec3. x, y defined by bounds, z in meters
const positions = new Float32Array(nCoords * 3);
// vec2. 1 to 1 relationship with position. represents the uv on the texture image. 0,0 to 1,1.
const texCoords = new Float32Array(nCoords * 2);
// Data is not interleaved; all u, then all v, then all heights
for (let i = 0; i < nCoords; i++) {
const x = vertexData[i] / 32767;
const y = vertexData[i + nCoords] / 32767;
const z = vertexData[i + nCoords * 2] / 32767;
positions[3 * i + 0] = x * xScale + minX;
positions[3 * i + 1] = y * yScale + minY;
positions[3 * i + 2] = z * zScale + minHeight;
texCoords[2 * i + 0] = x;
texCoords[2 * i + 1] = y;
}
return {
POSITION: { value: positions, size: 3 },
TEXCOORD_0: { value: texCoords, size: 2 }
// TODO: Parse normals if they exist in the file
// NORMAL: {}, - optional, but creates the high poly look with lighting
};
}