Change to WebGPU
This commit is contained in:
parent
523cf0945a
commit
4dadaf470c
6 changed files with 170 additions and 160 deletions
|
@ -8,7 +8,6 @@ import {
|
|||
LineBasicMaterial,
|
||||
LineSegments,
|
||||
Mesh,
|
||||
MeshBasicMaterial,
|
||||
MeshStandardMaterial,
|
||||
Object3DEventMap,
|
||||
PerspectiveCamera,
|
||||
|
@ -17,11 +16,17 @@ import {
|
|||
Scene,
|
||||
Vector2,
|
||||
Vector3,
|
||||
WebGLRenderer,
|
||||
} from "three";
|
||||
import { DragControls, OrbitControls } from "three/examples/jsm/Addons.js";
|
||||
import { Extent } from "./build-scene";
|
||||
import earcut from "earcut";
|
||||
import {
|
||||
ClippingGroup,
|
||||
MeshBasicNodeMaterial,
|
||||
MeshStandardNodeMaterial,
|
||||
WebGPURenderer,
|
||||
} from "three/webgpu";
|
||||
import { Fn, uniform, vec4 } from "three/tsl";
|
||||
|
||||
export enum Orientation {
|
||||
X = "X",
|
||||
|
@ -32,7 +37,7 @@ export enum Orientation {
|
|||
NZ = "NZ",
|
||||
}
|
||||
|
||||
type PlaneMesh = Mesh<PlaneGeometry, MeshBasicMaterial, Object3DEventMap>;
|
||||
type PlaneMesh = Mesh<PlaneGeometry, MeshBasicNodeMaterial, Object3DEventMap>;
|
||||
type EdgeMesh = LineSegments<
|
||||
EdgesGeometry<PlaneGeometry>,
|
||||
LineBasicMaterial,
|
||||
|
@ -49,7 +54,7 @@ let currentExtent: Extent;
|
|||
const BUFFER = 500;
|
||||
|
||||
export function buildClippingplanes(
|
||||
renderer: WebGLRenderer,
|
||||
renderer: WebGPURenderer,
|
||||
camera: PerspectiveCamera,
|
||||
orbitControls: OrbitControls,
|
||||
extent: Extent,
|
||||
|
@ -148,7 +153,7 @@ export function buildClippingplanes(
|
|||
const planeGeometry = new PlaneGeometry(width, height);
|
||||
const planeMesh = new Mesh(
|
||||
planeGeometry,
|
||||
new MeshBasicMaterial({
|
||||
new MeshBasicNodeMaterial({
|
||||
visible: true,
|
||||
color: 0xa92a4e,
|
||||
transparent: true,
|
||||
|
@ -190,6 +195,19 @@ export function buildClippingplanes(
|
|||
edgeMeshMap[p.orientation] = edges;
|
||||
}
|
||||
|
||||
for (const o in Orientation) {
|
||||
const capMeshGroupName = `cap-mesh-group-${o}`;
|
||||
let capMeshGroup = scene.getObjectByName(capMeshGroupName) as ClippingGroup;
|
||||
if (capMeshGroup) {
|
||||
capMeshGroup.clear();
|
||||
} else {
|
||||
capMeshGroup = new ClippingGroup();
|
||||
capMeshGroup.name = capMeshGroupName;
|
||||
capMeshGroup.clippingPlanes = planes;
|
||||
scene.add(capMeshGroup);
|
||||
}
|
||||
}
|
||||
|
||||
// Add meshes to the scene
|
||||
const planeMeshGroup = new Group();
|
||||
planeMeshGroup.name = "clipping-planes";
|
||||
|
@ -388,29 +406,21 @@ export function buildClippingplanes(
|
|||
}
|
||||
|
||||
// Remove existing cap meshes
|
||||
const capMeshGroupName = `cap-mesh-group-${object.name}`;
|
||||
let capMeshGroup = scene.getObjectByName(capMeshGroupName);
|
||||
while (capMeshGroup) {
|
||||
scene.remove(capMeshGroup);
|
||||
capMeshGroup = scene.getObjectByName(capMeshGroupName);
|
||||
}
|
||||
const capMeshGroupName = `cap-mesh-group-${orientation}`;
|
||||
const capMeshGroup = scene.getObjectByName(
|
||||
capMeshGroupName
|
||||
) as ClippingGroup;
|
||||
if (capMeshGroup) {
|
||||
capMeshGroup.clear();
|
||||
|
||||
// Generate new cap meshes
|
||||
const capMeshes = generateCapMeshes(
|
||||
meshes,
|
||||
plane.clone(),
|
||||
planes,
|
||||
orientation,
|
||||
scene
|
||||
);
|
||||
|
||||
// Add new cap meshes
|
||||
if (capMeshes.length > 0) {
|
||||
const newCapMeshGroup = new Group();
|
||||
|
||||
newCapMeshGroup.add(...capMeshes);
|
||||
newCapMeshGroup.name = capMeshGroupName;
|
||||
scene.add(newCapMeshGroup);
|
||||
// Generate new cap meshes
|
||||
generateCapMeshes(
|
||||
meshes,
|
||||
plane.clone(),
|
||||
orientation,
|
||||
scene,
|
||||
capMeshGroup
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -576,12 +586,10 @@ function resizeClippingPlane(
|
|||
function generateCapMeshes(
|
||||
meshes: Mesh[],
|
||||
plane: Plane,
|
||||
planes: Plane[],
|
||||
orientation: Orientation,
|
||||
scene: Scene
|
||||
scene: Scene,
|
||||
capMeshGroup: ClippingGroup
|
||||
) {
|
||||
const capMeshes: Mesh[] = [];
|
||||
|
||||
// Rescale to local coordinates
|
||||
if (orientation === Orientation.Z || orientation === Orientation.NZ)
|
||||
plane.constant /= scene.scale.z;
|
||||
|
@ -640,9 +648,6 @@ function generateCapMeshes(
|
|||
// Intersection surface can be a multipolygon consisting of disconnected polygons
|
||||
const polygons: Vector3[][] = buildPolygons(edges);
|
||||
|
||||
// Clip cap surfaces with clipping planes
|
||||
const clippingPlanes = planes.filter((p) => !p.normal.equals(plane.normal));
|
||||
|
||||
const offset =
|
||||
orientation === Orientation.NX ||
|
||||
orientation === Orientation.NY ||
|
||||
|
@ -651,24 +656,30 @@ function generateCapMeshes(
|
|||
: -1;
|
||||
|
||||
const color =
|
||||
mesh.material instanceof MeshStandardMaterial
|
||||
mesh.material instanceof MeshStandardNodeMaterial
|
||||
? mesh.material.color
|
||||
: new Color(1, 1, 1);
|
||||
|
||||
const material = new MeshStandardMaterial({
|
||||
const material = new MeshStandardNodeMaterial({
|
||||
color,
|
||||
side: DoubleSide,
|
||||
metalness: 0.0,
|
||||
roughness: 1.0,
|
||||
metalness: 0.1,
|
||||
roughness: 0.5,
|
||||
flatShading: true,
|
||||
polygonOffset: true,
|
||||
polygonOffsetFactor: offset,
|
||||
polygonOffsetUnits: offset,
|
||||
clippingPlanes,
|
||||
wireframe: scene.userData.wireframe,
|
||||
alphaToCoverage: true,
|
||||
});
|
||||
|
||||
const localMeshes = polygons.map((polygon) => {
|
||||
const tColor = uniform(new Color(color));
|
||||
const fragmentShader = Fn(() => {
|
||||
return vec4(tColor.r, tColor.g, tColor.b, 1.0);
|
||||
});
|
||||
material.fragmentNode = fragmentShader();
|
||||
|
||||
polygons.forEach((polygon) => {
|
||||
const geometry = triangulatePolygon(polygon, plane);
|
||||
|
||||
const capMesh = new Mesh(geometry, material);
|
||||
|
@ -687,13 +698,11 @@ function generateCapMeshes(
|
|||
}
|
||||
positionAttr.needsUpdate = true;
|
||||
|
||||
return capMesh;
|
||||
if (capMesh) {
|
||||
capMeshGroup.add(capMesh);
|
||||
}
|
||||
});
|
||||
|
||||
capMeshes.push(...localMeshes);
|
||||
}
|
||||
|
||||
return capMeshes;
|
||||
}
|
||||
|
||||
// Build polygons by grouping connected intersection edges
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
import {
|
||||
BufferAttribute,
|
||||
BufferGeometry,
|
||||
Color,
|
||||
DoubleSide,
|
||||
Mesh,
|
||||
MeshStandardMaterial,
|
||||
} from "three";
|
||||
|
||||
import { fetchVertices, fetchTriangleIndices, transform } from "./utils";
|
||||
import { TRIANGLE_INDICES_URL, VERTICES_URL } from "../config";
|
||||
import { shaderMaterial } from "../ShaderMaterial";
|
||||
import { topoNodeMaterial } from "../ShaderMaterial";
|
||||
import { MeshStandardNodeMaterial } from "three/webgpu";
|
||||
import { Fn, uniform, vec3, vec4 } from "three/tsl";
|
||||
|
||||
interface MappedFeature {
|
||||
featuregeom_id: number;
|
||||
|
@ -24,6 +26,8 @@ export async function buildMeshes(mappedFeatures: MappedFeature[]) {
|
|||
const mesh = await buildMesh(layerData);
|
||||
if (layerData.name === "Topography") {
|
||||
mesh.visible = false;
|
||||
} else {
|
||||
mesh.visible = true;
|
||||
}
|
||||
meshes.push(mesh);
|
||||
}
|
||||
|
@ -58,19 +62,26 @@ async function buildMesh(layerData: MappedFeature) {
|
|||
const indices = new BufferAttribute(indexArray, 1);
|
||||
|
||||
geometry.setIndex(indices);
|
||||
geometry.computeVertexNormals();
|
||||
|
||||
const material = new MeshStandardMaterial({
|
||||
const material = new MeshStandardNodeMaterial({
|
||||
color: color,
|
||||
metalness: 0.1,
|
||||
roughness: 0.5,
|
||||
flatShading: true,
|
||||
side: DoubleSide,
|
||||
wireframe: false,
|
||||
alphaToCoverage: true,
|
||||
});
|
||||
|
||||
const tColor = uniform(new Color(color));
|
||||
const fragmentShader = Fn(() => {
|
||||
return vec4(tColor.r, tColor.g, tColor.b, 1.0);
|
||||
});
|
||||
material.colorNode = fragmentShader();
|
||||
|
||||
const mesh = new Mesh(
|
||||
geometry,
|
||||
name === "Topography" ? shaderMaterial : material
|
||||
name === "Topography" ? topoNodeMaterial : material
|
||||
);
|
||||
mesh.name = name;
|
||||
mesh.userData.layerId = geomId;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import {
|
||||
PerspectiveCamera,
|
||||
Scene,
|
||||
WebGLRenderer,
|
||||
AmbientLight,
|
||||
DirectionalLight,
|
||||
Group,
|
||||
|
@ -19,6 +18,7 @@ import {
|
|||
|
||||
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
|
||||
import { getCenter3D, getMaxSize } from "./utils";
|
||||
import { WebGPURenderer } from "three/webgpu";
|
||||
|
||||
export interface Extent {
|
||||
xmin: number;
|
||||
|
@ -30,7 +30,7 @@ export interface Extent {
|
|||
}
|
||||
|
||||
let controls: OrbitControls;
|
||||
let renderer: WebGLRenderer;
|
||||
let renderer: WebGPURenderer;
|
||||
let camera: PerspectiveCamera;
|
||||
let scene: Scene;
|
||||
let overlayCamera: OrthographicCamera;
|
||||
|
@ -54,15 +54,15 @@ export function buildScene(container: HTMLElement, extent: Extent) {
|
|||
camera.lookAt(center);
|
||||
|
||||
// Initialize the renderer
|
||||
renderer = new WebGLRenderer({
|
||||
renderer = new WebGPURenderer({
|
||||
logarithmicDepthBuffer: true,
|
||||
antialias: true,
|
||||
});
|
||||
|
||||
renderer.setPixelRatio(window.devicePixelRatio);
|
||||
renderer.setSize(width, height);
|
||||
renderer.localClippingEnabled = true;
|
||||
renderer.autoClear = false;
|
||||
// renderer.setAnimationLoop(animate);
|
||||
|
||||
// Handle window resize event to adapt the aspect ratio
|
||||
window.addEventListener("resize", () => onWindowResize(container));
|
||||
|
@ -117,7 +117,7 @@ function onWindowResize(container: HTMLElement) {
|
|||
camera.updateProjectionMatrix();
|
||||
renderer.setSize(container.clientWidth, container.clientHeight);
|
||||
|
||||
// required if controls.enableDamping or controls.autoRotate are set to true
|
||||
// Required if controls.enableDamping or controls.autoRotate are set to true
|
||||
controls.update();
|
||||
}
|
||||
|
||||
|
@ -152,7 +152,12 @@ function renderOverlay() {
|
|||
);
|
||||
|
||||
// Render the overlay scene to the screen (position it in the bottom left)
|
||||
renderer.setViewport(10, 10, UI_WIDTH, UI_HEIGHT);
|
||||
renderer.setViewport(
|
||||
10,
|
||||
renderer.domElement.height - UI_HEIGHT - 10,
|
||||
UI_WIDTH,
|
||||
UI_HEIGHT
|
||||
);
|
||||
renderer.render(overlayScene, overlayCamera);
|
||||
renderer.setViewport(
|
||||
0,
|
||||
|
@ -179,7 +184,7 @@ function buildDefaultLights(scene: Scene, extent: Extent) {
|
|||
lights.push(ambient);
|
||||
|
||||
// Directional lights
|
||||
const directionalLight = new DirectionalLight(0xffffff, 1.5);
|
||||
const directionalLight = new DirectionalLight(0xffffff, 2);
|
||||
directionalLight.position.set(
|
||||
lightPosition.x,
|
||||
lightPosition.y,
|
||||
|
|
Loading…
Add table
editor.link_modal.header
Reference in a new issue