Remove height provider from geo-three
This commit is contained in:
parent
233216c284
commit
b544c315b0
5 changed files with 152 additions and 11 deletions
|
@ -259,9 +259,9 @@ export function Form() {
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
{sceneView?.model.children.map((child) => {
|
{sceneView?.model.children.map((child) => {
|
||||||
const key = `toggle-visibility-${child.name}`;
|
const key = `toggle-visibility-${child.name}`;
|
||||||
const color = `#${(
|
//const color = `#${(
|
||||||
(child as Mesh).material as MeshStandardMaterial
|
// (child as Mesh).material as MeshStandardMaterial
|
||||||
).color.getHexString()}`;
|
//).color.getHexString()}`;
|
||||||
const visible = (child as Mesh).visible;
|
const visible = (child as Mesh).visible;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -272,7 +272,7 @@ export function Form() {
|
||||||
<span
|
<span
|
||||||
className="inline-block w-5 h-5 flex-none rounded"
|
className="inline-block w-5 h-5 flex-none rounded"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: color,
|
backgroundColor: "white",
|
||||||
}}
|
}}
|
||||||
></span>
|
></span>
|
||||||
<input
|
<input
|
||||||
|
|
|
@ -112,7 +112,7 @@ export class CustomMapHeightNodeShader extends MapHeightNode {
|
||||||
};
|
};
|
||||||
|
|
||||||
material.onBeforeCompile = (shader) => {
|
material.onBeforeCompile = (shader) => {
|
||||||
// Pass uniforms from userData to the
|
// Pass uniforms from userData
|
||||||
for (const i in material.userData) {
|
for (const i in material.userData) {
|
||||||
shader.uniforms[i] = material.userData[i];
|
shader.uniforms[i] = material.userData[i];
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,9 @@ import {
|
||||||
Material,
|
Material,
|
||||||
Mesh,
|
Mesh,
|
||||||
MeshBasicMaterial,
|
MeshBasicMaterial,
|
||||||
|
MeshPhongMaterial,
|
||||||
MeshStandardMaterial,
|
MeshStandardMaterial,
|
||||||
|
Object3D,
|
||||||
PerspectiveCamera,
|
PerspectiveCamera,
|
||||||
Plane,
|
Plane,
|
||||||
Raycaster,
|
Raycaster,
|
||||||
|
@ -32,12 +34,16 @@ import {
|
||||||
} from "three/examples/jsm/Addons.js";
|
} from "three/examples/jsm/Addons.js";
|
||||||
import {
|
import {
|
||||||
LODFrustum,
|
LODFrustum,
|
||||||
|
LODRaycast,
|
||||||
|
MapPlaneNode,
|
||||||
MapTilerProvider,
|
MapTilerProvider,
|
||||||
MapView,
|
MapView,
|
||||||
OpenStreetMapsProvider,
|
OpenStreetMapsProvider,
|
||||||
|
UnitsUtils,
|
||||||
} from "geo-three";
|
} from "geo-three";
|
||||||
import { CustomMapHeightNodeShader } from "./CustomMapHeightNodeShader";
|
import { CustomMapHeightNodeShader } from "./CustomMapHeightNodeShader";
|
||||||
import { Data, createSVG } from "./utils/create-borehole-svg";
|
import { Data, createSVG } from "./utils/create-borehole-svg";
|
||||||
|
import { TileData, updateTiles } from "./ShaderMaterial";
|
||||||
|
|
||||||
export type CustomEvent = CustomEventInit<{
|
export type CustomEvent = CustomEventInit<{
|
||||||
element: SVGSVGElement | null;
|
element: SVGSVGElement | null;
|
||||||
|
@ -489,18 +495,55 @@ async function init(container: HTMLElement, modelId = MODEL_ID) {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create the map view for OSM topography
|
// Create the map view for OSM topography
|
||||||
const lod = new LODFrustum();
|
const lod = new LODRaycast();
|
||||||
|
|
||||||
// @ts-expect-error Type definition for MapView is incorrect - missing parameter for lod
|
const map = new MapView(MapView.PLANAR, provider);
|
||||||
const map = new MapView(MapView.PLANAR, provider, heightProvider, lod);
|
map.lod = lod;
|
||||||
const customNode = new CustomMapHeightNodeShader(undefined, map);
|
// const customNode = new CustomMapHeightNodeShader(undefined, map);
|
||||||
map.setRoot(customNode);
|
// map.setRoot(customNode);
|
||||||
map.rotateX(Math.PI / 2);
|
map.rotateX(Math.PI / 2);
|
||||||
|
|
||||||
map.name = "topography";
|
map.name = "topography";
|
||||||
map.visible = false;
|
map.visible = false;
|
||||||
scene.add(map);
|
scene.add(map);
|
||||||
|
|
||||||
|
controls.addEventListener("change", () => {
|
||||||
|
const tiles: TileData[] = [];
|
||||||
|
function traverse(node: MapPlaneNode) {
|
||||||
|
if (node.isMesh) {
|
||||||
|
const bounds = UnitsUtils.tileBounds(node.level, node.x, node.y);
|
||||||
|
|
||||||
|
const xmin = bounds[0];
|
||||||
|
const ymin = bounds[2];
|
||||||
|
const xmax = xmin + bounds[1];
|
||||||
|
const ymax = ymin + bounds[3];
|
||||||
|
|
||||||
|
if (
|
||||||
|
(extent.xmax >= xmin && extent.ymax >= ymin) ||
|
||||||
|
(extent.xmin <= xmax && extent.ymax >= ymin) ||
|
||||||
|
(extent.xmin <= xmax && extent.ymin <= ymax) ||
|
||||||
|
(extent.xmax >= xmin && extent.ymin <= ymax)
|
||||||
|
) {
|
||||||
|
tiles.push({
|
||||||
|
xmin,
|
||||||
|
ymin,
|
||||||
|
xmax,
|
||||||
|
ymax,
|
||||||
|
texture: (node.material as MeshPhongMaterial).map,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const c of node.children) {
|
||||||
|
traverse(c as MapPlaneNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
map.lod.updateLOD(map, camera, renderer, scene);
|
||||||
|
traverse(map.root);
|
||||||
|
|
||||||
|
updateTiles(tiles.reverse());
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
scene,
|
scene,
|
||||||
model,
|
model,
|
||||||
|
|
98
app/three/ShaderMaterial.ts
Normal file
98
app/three/ShaderMaterial.ts
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
import { ShaderMaterial, Texture, Vector4 } from "three";
|
||||||
|
|
||||||
|
export interface TileData {
|
||||||
|
xmin: number;
|
||||||
|
ymin: number;
|
||||||
|
xmax: number;
|
||||||
|
ymax: number;
|
||||||
|
texture: Texture | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxTiles = 16;
|
||||||
|
|
||||||
|
// Initialize empty texture slots
|
||||||
|
const dummyTexture = new Texture();
|
||||||
|
dummyTexture.image = document.createElement("canvas");
|
||||||
|
dummyTexture.needsUpdate = true;
|
||||||
|
|
||||||
|
// Create shader material
|
||||||
|
export const shaderMaterial = new ShaderMaterial({
|
||||||
|
uniforms: {
|
||||||
|
tileTextures: { value: Array(maxTiles).fill(dummyTexture) },
|
||||||
|
tileBounds: { value: Array(maxTiles).fill(new Vector4(0, 0, 0, 0)) },
|
||||||
|
tileCount: { value: 0 },
|
||||||
|
},
|
||||||
|
vertexShader: `
|
||||||
|
varying vec3 vWorldPosition;
|
||||||
|
void main() {
|
||||||
|
vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;
|
||||||
|
gl_Position = projectionMatrix * viewMatrix * vec4(vWorldPosition, 1.0);
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
fragmentShader: `
|
||||||
|
uniform sampler2D tileTextures[${maxTiles}];
|
||||||
|
uniform vec4 tileBounds[${maxTiles}];
|
||||||
|
uniform int tileCount;
|
||||||
|
varying vec3 vWorldPosition;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 color = vec4(1.0, 1.0, 1.0, 1.0); // Default color
|
||||||
|
|
||||||
|
for (int i = 0; i < ${maxTiles}; i++) {
|
||||||
|
if (i >= tileCount) break; // Only process available tiles
|
||||||
|
|
||||||
|
vec4 bounds = tileBounds[i];
|
||||||
|
|
||||||
|
if (vWorldPosition.x >= bounds.x && vWorldPosition.x <= bounds.y &&
|
||||||
|
vWorldPosition.y >= bounds.z && vWorldPosition.y <= bounds.w) {
|
||||||
|
|
||||||
|
vec2 uv = (vWorldPosition.xy - bounds.xz) / (bounds.yw - bounds.xz);
|
||||||
|
switch (i) {
|
||||||
|
case 0: color = texture2D(tileTextures[0], uv); break;
|
||||||
|
case 1: color = texture2D(tileTextures[1], uv); break;
|
||||||
|
case 2: color = texture2D(tileTextures[2], uv); break;
|
||||||
|
case 3: color = texture2D(tileTextures[3], uv); break;
|
||||||
|
case 4: color = texture2D(tileTextures[4], uv); break;
|
||||||
|
case 5: color = texture2D(tileTextures[5], uv); break;
|
||||||
|
case 6: color = texture2D(tileTextures[6], uv); break;
|
||||||
|
case 7: color = texture2D(tileTextures[7], uv); break;
|
||||||
|
case 8: color = texture2D(tileTextures[8], uv); break;
|
||||||
|
case 9: color = texture2D(tileTextures[9], uv); break;
|
||||||
|
case 10: color = texture2D(tileTextures[10], uv); break;
|
||||||
|
case 11: color = texture2D(tileTextures[11], uv); break;
|
||||||
|
case 12: color = texture2D(tileTextures[12], uv); break;
|
||||||
|
case 13: color = texture2D(tileTextures[13], uv); break;
|
||||||
|
case 14: color = texture2D(tileTextures[14], uv); break;
|
||||||
|
case 15: color = texture2D(tileTextures[15], uv); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break; // Stop checking once we find the correct tile
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gl_FragColor = color;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
|
||||||
|
export function updateTiles(newTiles: TileData[]) {
|
||||||
|
if (newTiles.length > maxTiles) {
|
||||||
|
newTiles = newTiles.slice(0, maxTiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
const textures = newTiles.map((t) => t.texture);
|
||||||
|
const bounds = newTiles.map(
|
||||||
|
(t) => new Vector4(t.xmin, t.xmax, t.ymin, t.ymax)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Fill remaining slots with dummy data to maintain uniform array size
|
||||||
|
while (textures.length < maxTiles) {
|
||||||
|
textures.push(dummyTexture);
|
||||||
|
bounds.push(new Vector4(0, 0, 0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update shader uniforms
|
||||||
|
shaderMaterial.uniforms.tileTextures.value = textures;
|
||||||
|
shaderMaterial.uniforms.tileBounds.value = bounds;
|
||||||
|
shaderMaterial.uniforms.tileCount.value = newTiles.length;
|
||||||
|
}
|
|
@ -61,7 +61,7 @@ async function buildMesh(layerData: MappedFeature) {
|
||||||
const material = new MeshStandardMaterial({
|
const material = new MeshStandardMaterial({
|
||||||
color: color,
|
color: color,
|
||||||
metalness: 0.0,
|
metalness: 0.0,
|
||||||
roughness: 1.0,
|
roughness: 5.0,
|
||||||
flatShading: true,
|
flatShading: true,
|
||||||
side: DoubleSide,
|
side: DoubleSide,
|
||||||
wireframe: false,
|
wireframe: false,
|
||||||
|
|
Loading…
Add table
editor.link_modal.header
Reference in a new issue