diff --git a/app/components/Form.tsx b/app/components/Form.tsx
index 00862fc..ab47784 100644
--- a/app/components/Form.tsx
+++ b/app/components/Form.tsx
@@ -258,43 +258,47 @@ export function Form() {
>
{
- {sceneView?.model.children.map((child) => {
- const key = `toggle-visibility-${child.name}`;
- let color = "transparent";
- if ((child as Mesh).material instanceof MeshStandardMaterial) {
- color = `#${(
- (child as Mesh).material as MeshStandardMaterial
- ).color.getHexString()}`;
- }
- const visible = (child as Mesh).visible;
+ {sceneView?.model.children
+ .filter((c) => c.name !== "Topography")
+ .map((child) => {
+ const key = `toggle-visibility-${child.name}`;
+ let color = "transparent";
+ if (
+ (child as Mesh).material instanceof MeshStandardMaterial
+ ) {
+ color = `#${(
+ (child as Mesh).material as MeshStandardMaterial
+ ).color.getHexString()}`;
+ }
+ const visible = (child as Mesh).visible;
- return (
-
-
- handleCheckboxChange(child.name)}
- className="hover:cursor-pointer"
- defaultChecked={visible ? true : false}
- />
-
-
- );
- })}
+
+
handleCheckboxChange(child.name)}
+ className="hover:cursor-pointer"
+ defaultChecked={visible ? true : false}
+ />
+
+
+ );
+ })}
}
diff --git a/app/three/CustomMapHeightNodeShader.ts b/app/three/CustomMapHeightNodeShader.ts
deleted file mode 100644
index 240c62e..0000000
--- a/app/three/CustomMapHeightNodeShader.ts
+++ /dev/null
@@ -1,237 +0,0 @@
-import {
- BufferGeometry,
- Intersection,
- Material,
- MeshPhongMaterial,
- NearestFilter,
- Raycaster,
- RGBAFormat,
- Texture,
- Vector3,
-} from "three";
-
-import {
- MapHeightNode,
- MapNodeGeometry,
- MapPlaneNode,
- UnitsUtils,
- MapNode,
- QuadTreePosition,
- TextureUtils,
- MapView,
-} from "geo-three";
-
-/**
- * Map height node that uses GPU height calculation to generate the deformed plane mesh.
- *
- * This solution is faster if no mesh interaction is required since all trasnformations are done in the GPU the transformed mesh cannot be accessed for CPU operations (e.g. raycasting).
- *
- * @param parentNode - The parent node of this node.
- * @param mapView - Map view object where this node is placed.
- * @param location - Position in the node tree relative to the parent.
- * @param level - Zoom level in the tile tree of the node.
- * @param x - X position of the node in the tile tree.
- * @param y - Y position of the node in the tile tree.
- */
-export class CustomMapHeightNodeShader extends MapHeightNode {
- /**
- * Default height texture applied when tile load fails.
- *
- * This tile sets the height to sea level where it is common for the data sources to be missing height data.
- */
- public static defaultHeightTexture =
- TextureUtils.createFillTexture("#0186C0");
-
- /**
- * Size of the grid of the geometry displayed on the scene for each tile.
- */
- public static geometrySize: number = 256;
-
- /**
- * Map node plane geometry.
- */
- public static geometry: BufferGeometry = new MapNodeGeometry(
- 1.0,
- 1.0,
- CustomMapHeightNodeShader.geometrySize,
- CustomMapHeightNodeShader.geometrySize,
- true
- );
-
- /**
- * Base geometry of the map node.
- */
- public static baseGeometry: BufferGeometry = MapPlaneNode.geometry;
-
- /**
- * Base scale of the map node.
- */
- public static baseScale: Vector3 = new Vector3(
- UnitsUtils.EARTH_PERIMETER,
- 1,
- UnitsUtils.EARTH_PERIMETER
- );
-
- public constructor(
- parentNode: MapHeightNode | undefined,
- mapView: MapView,
- location: number = QuadTreePosition.root,
- level: number = 0,
- x: number = 0,
- y: number = 0
- ) {
- const material: Material = CustomMapHeightNodeShader.prepareMaterial(
- new MeshPhongMaterial({
- map: MapNode.defaultTexture,
- color: 0xffffff,
- })
- );
-
- super(
- parentNode,
- mapView,
- location,
- level,
- x,
- y,
- CustomMapHeightNodeShader.geometry,
- material
- );
-
- this.frustumCulled = true;
- }
-
- /**
- * Prepare the three.js material to be used in the map tile.
- *
- * @param material - Material to be transformed.
- */
- public static prepareMaterial(material: Material): Material {
- material.userData = {
- heightMap: { value: CustomMapHeightNodeShader.defaultHeightTexture },
- };
-
- material.onBeforeCompile = (shader) => {
- // Pass uniforms from userData
- for (const i in material.userData) {
- shader.uniforms[i] = material.userData[i];
- }
-
- // Vertex variables
- shader.vertexShader =
- `
- uniform sampler2D heightMap;
- ` + shader.vertexShader;
-
- // Vertex depth logic
- // elevation = -10000 + ((R * 256 * 256 + G * 256 + B) * 0.1)
- // heightMap stores normalized values in the range [0, 1]
- // multiply by 255.0 to obtain values in the range [0, 255]
- shader.vertexShader = shader.vertexShader.replace(
- "#include ",
- `
- #include
-
- // Calculate height of the tile
- vec4 _theight = texture(heightMap, vMapUv);
- float _height = ((_theight.r * 255.0 * 65536.0 + _theight.g * 255.0 * 256.0 + _theight.b * 255.0) * 0.1) - 10000.0;
-
- // Apply height displacement
- vec3 _transformed = position + _height * normal;
-
-
- gl_Position = projectionMatrix * modelViewMatrix * vec4(_transformed, 1.0);
- `
- );
- };
-
- return material;
- }
-
- public async loadData(): Promise {
- await super.loadData();
-
- this.textureLoaded = true;
- }
-
- public async loadHeightGeometry(): Promise {
- if (this.mapView.heightProvider === null) {
- throw new Error("GeoThree: MapView.heightProvider provider is null.");
- }
-
- if (
- this.level < this.mapView.heightProvider.minZoom ||
- this.level > this.mapView.heightProvider.maxZoom
- ) {
- console.warn("Geo-Three: Loading tile outside of provider range: ", this);
-
- (this.material as MeshPhongMaterial).map =
- CustomMapHeightNodeShader.defaultTexture;
- (this.material as MeshPhongMaterial).needsUpdate = true;
- return;
- }
-
- try {
- const image = await this.mapView.heightProvider.fetchTile(
- this.level,
- this.x,
- this.y
- );
-
- if (this.disposed) {
- return;
- }
-
- const texture = new Texture(image as HTMLImageElement);
- texture.generateMipmaps = false;
- texture.format = RGBAFormat;
- texture.magFilter = NearestFilter;
- texture.minFilter = NearestFilter;
- texture.needsUpdate = true;
-
- (this.material as Material).userData.heightMap.value = texture;
- } catch (e) {
- console.warn("Could not fetch tile: ", e);
- if (this.disposed) {
- return;
- }
-
- console.warn("Geo-Three: Failed to load height data: ", this);
-
- // Water level texture (assume that missing texture will be water level)
- (this.material as Material).userData.heightMap.value =
- CustomMapHeightNodeShader.defaultHeightTexture;
- }
-
- (this.material as Material).needsUpdate = true;
-
- this.heightLoaded = true;
- }
-
- /**
- * Overrides normal raycasting, to avoid raycasting when isMesh is set to false.
- *
- * Switches the geometry for a simpler one for faster raycasting.
- */
- public raycast(raycaster: Raycaster, intersects: Intersection[]): void {
- if (this.isMesh === true) {
- this.geometry = MapPlaneNode.geometry;
-
- super.raycast(raycaster, intersects);
-
- this.geometry = CustomMapHeightNodeShader.geometry;
- }
- }
-
- public dispose(): void {
- super.dispose();
-
- if (
- (this.material as Material).userData.heightMap.value &&
- (this.material as Material).userData.heightMap.value !==
- CustomMapHeightNodeShader.defaultHeightTexture
- ) {
- (this.material as Material).userData.heightMap.value.dispose();
- }
- }
-}
diff --git a/app/three/SceneView.ts b/app/three/SceneView.ts
index a642b2c..02de088 100644
--- a/app/three/SceneView.ts
+++ b/app/three/SceneView.ts
@@ -172,10 +172,8 @@ export class SceneView extends EventTarget {
}
toggleTopography() {
- const osmTopo = this._scene.getObjectByName("osm-topography");
const topo = this._scene.getObjectByName("Topography");
- if (osmTopo && topo) {
- // osmTopo.visible = !osmTopo.visible;
+ if (topo) {
topo.visible = !topo.visible;
}
}
@@ -468,14 +466,7 @@ async function init(container: HTMLElement, modelId = MODEL_ID) {
// Build the 3D model
const meshes = await buildMeshes(mappedFeatures);
const model = new Group();
- for (const mesh of meshes) {
- if (mesh.name !== "Topography") {
- model.add(mesh);
- } else {
- // Add the topography as a separate layer
- scene.add(mesh);
- }
- }
+ model.add(...meshes);
model.name = "geologic-model";
scene.add(model);
@@ -498,8 +489,8 @@ async function init(container: HTMLElement, modelId = MODEL_ID) {
// Create the map view for OSM topography
const lod = new LODFrustum();
- lod.simplifyDistance = 200;
- lod.subdivideDistance = 120;
+ lod.simplifyDistance = 225;
+ lod.subdivideDistance = 80;
const map = new MapView(MapView.PLANAR, provider);
map.lod = lod;
diff --git a/app/three/ShaderMaterial.ts b/app/three/ShaderMaterial.ts
index deeef9f..11f61ca 100644
--- a/app/three/ShaderMaterial.ts
+++ b/app/three/ShaderMaterial.ts
@@ -1,4 +1,5 @@
import {
+ Color,
DataArrayTexture,
LinearFilter,
RGBAFormat,
@@ -45,10 +46,12 @@ dataArrayTexture.needsUpdate = true;
// Create shader material
export const shaderMaterial = new ShaderMaterial({
+ clipping: true,
uniforms: {
tileBounds: { value: tileBounds },
tileCount: { value: maxTiles },
tiles: { value: dataArrayTexture },
+ color: { value: new Color(1, 1, 1) },
},
vertexShader:
ShaderChunk.common +
@@ -58,10 +61,16 @@ export const shaderMaterial = new ShaderMaterial({
varying vec3 vWorldPosition;
varying float fragDepth;
+ #include
+
void main() {
+ #include
vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
fragDepth = (gl_Position.z / gl_Position.w + 1.0) * 0.5;
+
+ #include
+ #include
` +
ShaderChunk.logdepthbuf_vertex +
@@ -77,7 +86,11 @@ export const shaderMaterial = new ShaderMaterial({
varying vec3 vWorldPosition;
varying float fragDepth;
+ #include
+
void main() {
+ #include
+
vec4 color = vec4(191.0/255.0, 209.0/255.0, 229.0/255.0, 1.0); // Default color
for (int i = 0; i < ${maxTiles}; i++) {
diff --git a/app/three/utils/build-clipping-planes.ts b/app/three/utils/build-clipping-planes.ts
index cc823e2..4c93d9f 100644
--- a/app/three/utils/build-clipping-planes.ts
+++ b/app/three/utils/build-clipping-planes.ts
@@ -1,6 +1,7 @@
import {
BufferAttribute,
BufferGeometry,
+ Color,
DoubleSide,
EdgesGeometry,
Group,
@@ -649,8 +650,13 @@ function generateCapMeshes(
? 1
: -1;
+ const color =
+ mesh.material instanceof MeshStandardMaterial
+ ? mesh.material.color
+ : new Color(1, 1, 1);
+
const material = new MeshStandardMaterial({
- color: (mesh.material as MeshStandardMaterial).color,
+ color,
side: DoubleSide,
metalness: 0.0,
roughness: 1.0,
diff --git a/app/three/utils/build-scene.ts b/app/three/utils/build-scene.ts
index 805ea9b..063eee1 100644
--- a/app/three/utils/build-scene.ts
+++ b/app/three/utils/build-scene.ts
@@ -37,8 +37,8 @@ let overlayCamera: OrthographicCamera;
let overlayScene: Scene;
let maxSize = 0;
const compass = new Group();
-const UI_WIDTH = 200;
-const UI_HEIGHT = 200;
+const UI_WIDTH = 150;
+const UI_HEIGHT = 150;
export function buildScene(container: HTMLElement, extent: Extent) {
maxSize = getMaxSize(extent);
@@ -152,11 +152,8 @@ function renderOverlay() {
);
// Render the overlay scene to the screen (position it in the bottom left)
- renderer.setScissorTest(true);
- renderer.setScissor(10, 10, UI_WIDTH, UI_HEIGHT);
renderer.setViewport(10, 10, UI_WIDTH, UI_HEIGHT);
renderer.render(overlayScene, overlayCamera);
- renderer.setScissorTest(false); // Disable scissor testing for the rest of the scene
renderer.setViewport(
0,
0,