MeshDesc
MeshDesc is the base class for all mesh Descriptors. It provides common configuration properties, transform composition, and picking support. Every mesh Descriptor — both built-in and custom — inherits from this class, so the features described here are available on all mesh Descriptors.
Common Properties
Section titled “Common Properties”| Property | Type | Default | Description |
|---|---|---|---|
id | string | Auto-generated | Unique identifier for the object |
visible | boolean | true | Toggle visibility of the object |
position | { x: number, y: number, z: number } | - | Position (ECEF), or local offset when matrix/matrixWorld is set |
rotation | { x: number, y: number, z: number } | - | Rotation (Euler angles, radians), or local offset when matrix/matrixWorld is set |
scale | { x: number, y: number, z: number } | - | Scale, or local offset when matrix/matrixWorld is set |
matrix | Matrix4 | - | Local transform matrix. When set, position/rotation/scale become offsets within this frame |
matrixWorld | Matrix4 | - | World transform matrix. When set, position/rotation/scale become offsets within this frame |
pickable | boolean | false | Enable GPU-based click picking. Defined per Descriptor by picking-capable mesh Descriptors, not on the base config |
Transform Composition
Section titled “Transform Composition”MeshDesc supports three transform modes.
Standard Transforms
Section titled “Standard Transforms”When neither matrix nor matrixWorld is set, position, rotation, and scale are applied directly to the Three.js object in the ECEF coordinate system — the same way standard Three.js transforms work.
Local Frame with matrix
Section titled “Local Frame with matrix”When matrix is set, Three.js matrixAutoUpdate is disabled and the final local matrix is computed as:
effective = matrix · T(position) · R(rotation) · S(scale)This lets you supply a base frame and then express offsets within that frame.
World Frame with matrixWorld
Section titled “World Frame with matrixWorld”When matrixWorld is set, both matrixAutoUpdate and matrixWorldAutoUpdate are disabled, and the final world matrix is computed as:
effective = matrixWorld · T(position) · R(rotation) · S(scale)This is the most common mode for geographic placement. You supply a world-space reference frame (e.g., an ENU tangent frame from eastNorthUpToFixedFrame()) and express local offsets within that frame. This eliminates the need to manually compose frame matrices when positioning meshes on the globe.
Example: Placing Meshes in an ENU Frame
Section titled “Example: Placing Meshes in an ENU Frame”import ThreeView, { Color, geodeticToVector3, eastNorthUpToFixedFrame, degreeToRadian,} from "@navaramap/three";import { BoxMeshDesc } from "@navaramap/three_default_descs";
const view = new ThreeView();view.registerMesh("box", BoxMeshDesc);await view.init();
// Compute the ENU frame at a geographic originconst origin = geodeticToVector3({ lat: degreeToRadian(35.681236), lng: degreeToRadian(139.767125), height: 0,});const enuFrame = eastNorthUpToFixedFrame(origin);
// Place a box 200m east and 50m above the originconst box1 = view.addMesh<BoxMeshDesc>({ box: { width: 50, height: 100, depth: 50, color: new Color().setHex(0xff0000) }, matrixWorld: enuFrame, position: { x: 200, y: 50, z: 0 },});
// Place another box 100m northconst box2 = view.addMesh<BoxMeshDesc>({ box: { width: 50, height: 80, depth: 50, color: new Color().setHex(0x00ff00) }, matrixWorld: enuFrame, position: { x: 0, y: 40, z: 100 },});Picking
Section titled “Picking”Mesh Descriptors can opt into GPU-based click picking by setting pickable: true in the Descriptor config. The picking system renders pickable meshes into a dedicated single-pixel render target with each mesh’s batch ID encoded as an RGB color, reads back the pixel, and emits a "pick" event identifying which mesh was clicked.
Basic Usage
Section titled “Basic Usage”import ThreeView, { Color } from "@navaramap/three";import { BoxMeshDesc } from "@navaramap/three_default_descs";
const view = new ThreeView({ picking: true });view.registerMesh("box", BoxMeshDesc);await view.init();
const boxDesc = view.addMesh<BoxMeshDesc>({ box: { width: 100, height: 100, depth: 100, color: new Color().setHex(0xff0000), }, position: { x: 0, y: 0, z: 1000 }, pickable: true,});
view.on("pick", (info) => { if (info) { console.log("Picked layer:", info.layerId); console.log("Batch ID:", info.batchId); }});Batch ID
Section titled “Batch ID”The batch ID is a unique 24-bit integer assigned to each pickable mesh (or each instance in an instanced mesh Descriptor). You can read it from the Descriptor reference to determine which mesh was clicked:
// Single mesh Descriptorconst batchId = boxDesc.ref.batchId;
// Instanced mesh Descriptor — one batch ID per instanceconst batchIds = instancedDesc.ref.batchIds;Responding to Picks
Section titled “Responding to Picks”view.on("pick", (info) => { if (info && info.batchId === boxDesc.ref.batchId) { // Highlight the selected box boxDesc.update({ box: { color: new Color().setHex(0xffff00) } }); }});PickedFeature Type
Section titled “PickedFeature Type”type PickedFeature = { batchId: number; // 24-bit encoded ID properties?: Record<string, unknown>; // Feature properties (for GIS layers) layerId?: string; // Layer identifier};For implementing picking in custom Descriptors, see Custom Descriptor — Implementing Picking.
Coordinate Transformation
Section titled “Coordinate Transformation”The position property uses the ECEF (Earth-Centered, Earth-Fixed) coordinate system. To convert from latitude/longitude/altitude (geodetic coordinates) to ECEF, use the geodeticToVector3() function.
Basic Coordinate Transformation
Section titled “Basic Coordinate Transformation”import ThreeView, { Color, geodeticToVector3, degreeToRadian,} from "@navaramap/three";import { SphereMeshDesc } from "@navaramap/three_default_descs";
const view = new ThreeView();view.registerMesh("sphere", SphereMeshDesc);await view.init();
// Convert from latitude/longitude/altitude to ECEF coordinatesconst position = geodeticToVector3({ lat: degreeToRadian(35.681236), // Latitude (radians) lng: degreeToRadian(139.767125), // Longitude (radians) height: 200, // Altitude (meters)});
// Add a mesh Descriptor with the converted coordinatesconst sphereDesc = view.addMesh<SphereMeshDesc>({ sphere: { radius: 100, color: new Color().setHex(0x00aaff), }, position: { x: position.x, y: position.y, z: position.z, },});Using a Local Tangent Frame (ENU and others)
Section titled “Using a Local Tangent Frame (ENU and others)”The position property is Cartesian ECEF by default, so a bare position will not stand a mesh upright at a given longitude/latitude. For geographic placement, compute a local tangent frame at the origin and pass it as matrixWorld; position/rotation/scale are then interpreted as offsets within that frame.
Choose the frame function that matches the axis orientation your mesh expects. All take an ECEF origin (Vector3) and return a Matrix4, and all are exported from @navaramap/three:
| Function | Local axes (x, y, z) |
|---|---|
eastNorthUpToFixedFrame() | East, North, Up |
northEastDownToFixedFrame() | North, East, Down |
northUpEastToFixedFrame() | North, Up, East |
northWestUpToFixedFrame() | North, West, Up |
The most common choice is ENU (eastNorthUpToFixedFrame()):
import { geodeticToVector3, eastNorthUpToFixedFrame, degreeToRadian,} from "@navaramap/three";import { GLTFModelDesc } from "@navaramap/three_default_descs";
// GLTFModelDesc must be registered
// Compute positionconst origin = geodeticToVector3({ lat: degreeToRadian(35.681236), lng: degreeToRadian(139.767125), height: 0,});const enuFrame = eastNorthUpToFixedFrame(origin);
// Place the model along the Earth's surfaceconst modelDesc = view.addMesh<GLTFModelDesc>({ gltfModel: { url: "/models/building.gltf", }, matrixWorld: enuFrame,});Coordinate Transformation Functions
Section titled “Coordinate Transformation Functions”| Function | Description |
|---|---|
geodeticToVector3() | Converts geodetic coordinates (latitude/longitude/altitude) to ECEF coordinates (Vector3) |
vector3ToGeodetic() | Converts ECEF coordinates (Vector3) to geodetic coordinates |
degreeToRadian() | Converts degrees to radians |
radianToDegree() | Converts radians to degrees |
geodeticSurfaceNormal() | Gets the Earth’s surface normal vector at the specified position |
eastNorthUpToFixedFrame() | Gets the ENU (East-North-Up) tangent-frame matrix at the origin |
northEastDownToFixedFrame() | Gets the NED (North-East-Down) tangent-frame matrix at the origin |
northUpEastToFixedFrame() | Gets the NUE (North-Up-East) tangent-frame matrix at the origin |
northWestUpToFixedFrame() | Gets the NWU (North-West-Up) tangent-frame matrix at the origin |
For details, see navara_three_api.