Overview
Maquette turns a site outline into a 3D model you can import into your favourite editor or viewer.
Getting started
npm install @maquette/client @maquette/threeimport { Canvas } from '@react-three/fiber'
import { maquette } from '@maquette/client'
import { MaquetteLoader } from '@maquette/three'
const model = await maquette.build({
outline: [
[-71.2045, 46.8118],
[-71.2005, 46.8112],
[-71.1998, 46.8135],
[-71.2030, 46.8146],
[-71.2052, 46.8134],
],
})
const site = new MaquetteLoader().parse(model)
export default function App() {
return (
<Canvas>
<primitive object={site} />
</Canvas>
)
}Adding textures
Build with bare ground, then drape any imagery you have the right to display. Esri World Imagery needs no API key; show the credit it asks for.
// The document is georeferenced, so any imagery service can dress the ground.
const [minX, minY, , maxX, maxY] = model.metadata.geographicalExtent
const zone = model.metadata.referenceSystem.split('/').pop()
const texture = new TextureLoader().load(
'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/export' +
`?bbox=${minX},${minY},${maxX},${maxY}&bboxSR=${zone}&imageSR=${zone}` +
'&size=1024,1024&format=jpg&f=image',
)
texture.colorSpace = SRGBColorSpace
const width = maxX - minX
const depth = maxY - minY
site.traverse((child) => {
if (child.userData.type !== 'TINRelief') return
const position = child.geometry.getAttribute('position')
const uvs = new Float32Array(position.count * 2)
for (let i = 0; i < position.count; i++) {
uvs[i * 2] = (position.getX(i) + width / 2) / width
uvs[i * 2 + 1] = (position.getY(i) + depth / 2) / depth
}
child.geometry.setAttribute('uv', new BufferAttribute(uvs, 2))
child.material = new MeshStandardMaterial({ map: texture })
})