Feature: Add path segment rendering and point outlines
This commit is contained in:
@@ -7454,6 +7454,104 @@ export class ViewportHost {
|
|||||||
return new BufferGeometry().setFromPoints(points);
|
return new BufferGeometry().setFromPoints(points);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private createPathPointVectors(path: ScenePath): Vector3[] {
|
||||||
|
const points = path.points.map(
|
||||||
|
(point) =>
|
||||||
|
new Vector3(point.position.x, point.position.y, point.position.z)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (path.loop && points.length > 1) {
|
||||||
|
points.push(points[0].clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
private createPathSegmentMesh(
|
||||||
|
start: Vector3,
|
||||||
|
end: Vector3,
|
||||||
|
radius: number,
|
||||||
|
material: MeshBasicMaterial,
|
||||||
|
pathId: string
|
||||||
|
): Mesh<CylinderGeometry, MeshBasicMaterial> | null {
|
||||||
|
const delta = end.clone().sub(start);
|
||||||
|
const length = delta.length();
|
||||||
|
|
||||||
|
if (length < 0.0001) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const mesh = new Mesh(
|
||||||
|
new CylinderGeometry(radius, radius, length, 10, 1),
|
||||||
|
material
|
||||||
|
);
|
||||||
|
const direction = delta.normalize();
|
||||||
|
|
||||||
|
mesh.position.copy(start).add(end).multiplyScalar(0.5);
|
||||||
|
mesh.quaternion.setFromUnitVectors(new Vector3(0, 1, 0), direction);
|
||||||
|
mesh.renderOrder = PATH_RENDER_ORDER;
|
||||||
|
mesh.userData.pathId = pathId;
|
||||||
|
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
private createPathSegmentMeshes(path: ScenePath): PathRenderObjects["segments"] {
|
||||||
|
const points = this.createPathPointVectors(path);
|
||||||
|
const segments: PathRenderObjects["segments"] = [];
|
||||||
|
|
||||||
|
for (let index = 0; index < points.length - 1; index += 1) {
|
||||||
|
const outlineMesh = this.createPathSegmentMesh(
|
||||||
|
points[index],
|
||||||
|
points[index + 1],
|
||||||
|
PATH_SEGMENT_OUTLINE_RADIUS,
|
||||||
|
new MeshBasicMaterial({
|
||||||
|
color: PATH_OUTLINE_COLOR,
|
||||||
|
depthTest: false,
|
||||||
|
depthWrite: false
|
||||||
|
}),
|
||||||
|
path.id
|
||||||
|
);
|
||||||
|
const mesh = this.createPathSegmentMesh(
|
||||||
|
points[index],
|
||||||
|
points[index + 1],
|
||||||
|
PATH_SEGMENT_RADIUS,
|
||||||
|
new MeshBasicMaterial({
|
||||||
|
color: PATH_COLOR,
|
||||||
|
depthTest: false,
|
||||||
|
depthWrite: false
|
||||||
|
}),
|
||||||
|
path.id
|
||||||
|
);
|
||||||
|
|
||||||
|
if (outlineMesh !== null && mesh !== null) {
|
||||||
|
segments.push({
|
||||||
|
outlineMesh,
|
||||||
|
mesh
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return segments;
|
||||||
|
}
|
||||||
|
|
||||||
|
private addPathSegmentMeshes(segments: PathRenderObjects["segments"]) {
|
||||||
|
for (const segment of segments) {
|
||||||
|
this.pathGroup.add(segment.outlineMesh);
|
||||||
|
this.pathGroup.add(segment.mesh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private disposePathSegmentMeshes(segments: PathRenderObjects["segments"]) {
|
||||||
|
for (const segment of segments) {
|
||||||
|
this.pathGroup.remove(segment.outlineMesh);
|
||||||
|
this.pathGroup.remove(segment.mesh);
|
||||||
|
segment.outlineMesh.geometry.dispose();
|
||||||
|
segment.outlineMesh.material.dispose();
|
||||||
|
segment.mesh.geometry.dispose();
|
||||||
|
segment.mesh.material.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private rebuildPaths(document: SceneDocument, selection: EditorSelection) {
|
private rebuildPaths(document: SceneDocument, selection: EditorSelection) {
|
||||||
this.clearPaths();
|
this.clearPaths();
|
||||||
|
|
||||||
@@ -7467,7 +7565,9 @@ export class ViewportHost {
|
|||||||
|
|
||||||
const renderObjects = this.createPathRenderObjects(path, selection);
|
const renderObjects = this.createPathRenderObjects(path, selection);
|
||||||
this.pathGroup.add(renderObjects.line);
|
this.pathGroup.add(renderObjects.line);
|
||||||
|
this.addPathSegmentMeshes(renderObjects.segments);
|
||||||
for (const pointMesh of renderObjects.pointMeshes) {
|
for (const pointMesh of renderObjects.pointMeshes) {
|
||||||
|
this.pathGroup.add(pointMesh.outlineMesh);
|
||||||
this.pathGroup.add(pointMesh.mesh);
|
this.pathGroup.add(pointMesh.mesh);
|
||||||
}
|
}
|
||||||
this.pathRenderObjects.set(path.id, renderObjects);
|
this.pathRenderObjects.set(path.id, renderObjects);
|
||||||
@@ -7486,33 +7586,59 @@ export class ViewportHost {
|
|||||||
new LineBasicMaterial({
|
new LineBasicMaterial({
|
||||||
color: isPathSelected(selection, path.id)
|
color: isPathSelected(selection, path.id)
|
||||||
? PATH_SELECTED_COLOR
|
? PATH_SELECTED_COLOR
|
||||||
: PATH_COLOR
|
: PATH_COLOR,
|
||||||
|
depthTest: false,
|
||||||
|
depthWrite: false,
|
||||||
|
linewidth: PATH_LINE_WIDTH
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
line.renderOrder = PATH_RENDER_ORDER + 1;
|
||||||
line.userData.pathId = path.id;
|
line.userData.pathId = path.id;
|
||||||
|
|
||||||
|
const segments = this.createPathSegmentMeshes(path);
|
||||||
const pointMeshes = path.points.map((point) => {
|
const pointMeshes = path.points.map((point) => {
|
||||||
|
const outlineMesh = new Mesh(
|
||||||
|
new SphereGeometry(PATH_POINT_OUTLINE_RADIUS, 16, 12),
|
||||||
|
new MeshBasicMaterial({
|
||||||
|
color: PATH_OUTLINE_COLOR,
|
||||||
|
depthTest: false,
|
||||||
|
depthWrite: false
|
||||||
|
})
|
||||||
|
);
|
||||||
const mesh = new Mesh(
|
const mesh = new Mesh(
|
||||||
new SphereGeometry(PATH_POINT_RADIUS, 12, 12),
|
new SphereGeometry(PATH_POINT_RADIUS, 16, 12),
|
||||||
new MeshBasicMaterial({
|
new MeshBasicMaterial({
|
||||||
color: isPathSelected(selection, path.id)
|
color: isPathSelected(selection, path.id)
|
||||||
? PATH_POINT_SELECTED_COLOR
|
? PATH_POINT_SELECTED_COLOR
|
||||||
: PATH_POINT_COLOR
|
: PATH_POINT_COLOR,
|
||||||
|
depthTest: false,
|
||||||
|
depthWrite: false
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
outlineMesh.position.set(
|
||||||
|
point.position.x,
|
||||||
|
point.position.y,
|
||||||
|
point.position.z
|
||||||
|
);
|
||||||
mesh.position.set(point.position.x, point.position.y, point.position.z);
|
mesh.position.set(point.position.x, point.position.y, point.position.z);
|
||||||
|
outlineMesh.renderOrder = PATH_RENDER_ORDER + 2;
|
||||||
|
mesh.renderOrder = PATH_RENDER_ORDER + 3;
|
||||||
|
outlineMesh.userData.pathId = path.id;
|
||||||
|
outlineMesh.userData.pathPointId = point.id;
|
||||||
mesh.userData.pathId = path.id;
|
mesh.userData.pathId = path.id;
|
||||||
mesh.userData.pathPointId = point.id;
|
mesh.userData.pathPointId = point.id;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
pointId: point.id,
|
pointId: point.id,
|
||||||
|
outlineMesh,
|
||||||
mesh
|
mesh
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
line,
|
line,
|
||||||
|
segments,
|
||||||
pointMeshes
|
pointMeshes
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -7521,9 +7647,13 @@ export class ViewportHost {
|
|||||||
this.pathGroup.remove(renderObjects.line);
|
this.pathGroup.remove(renderObjects.line);
|
||||||
renderObjects.line.geometry.dispose();
|
renderObjects.line.geometry.dispose();
|
||||||
renderObjects.line.material.dispose();
|
renderObjects.line.material.dispose();
|
||||||
|
this.disposePathSegmentMeshes(renderObjects.segments);
|
||||||
|
|
||||||
for (const pointMesh of renderObjects.pointMeshes) {
|
for (const pointMesh of renderObjects.pointMeshes) {
|
||||||
|
this.pathGroup.remove(pointMesh.outlineMesh);
|
||||||
this.pathGroup.remove(pointMesh.mesh);
|
this.pathGroup.remove(pointMesh.mesh);
|
||||||
|
pointMesh.outlineMesh.geometry.dispose();
|
||||||
|
pointMesh.outlineMesh.material.dispose();
|
||||||
pointMesh.mesh.geometry.dispose();
|
pointMesh.mesh.geometry.dispose();
|
||||||
pointMesh.mesh.material.dispose();
|
pointMesh.mesh.material.dispose();
|
||||||
}
|
}
|
||||||
@@ -7555,7 +7685,9 @@ export class ViewportHost {
|
|||||||
this.currentSelection
|
this.currentSelection
|
||||||
);
|
);
|
||||||
this.pathGroup.add(renderObjects.line);
|
this.pathGroup.add(renderObjects.line);
|
||||||
|
this.addPathSegmentMeshes(renderObjects.segments);
|
||||||
for (const pointMesh of renderObjects.pointMeshes) {
|
for (const pointMesh of renderObjects.pointMeshes) {
|
||||||
|
this.pathGroup.add(pointMesh.outlineMesh);
|
||||||
this.pathGroup.add(pointMesh.mesh);
|
this.pathGroup.add(pointMesh.mesh);
|
||||||
}
|
}
|
||||||
this.pathRenderObjects.set(pathId, renderObjects);
|
this.pathRenderObjects.set(pathId, renderObjects);
|
||||||
@@ -7577,6 +7709,9 @@ export class ViewportHost {
|
|||||||
|
|
||||||
renderObjects.line.geometry.dispose();
|
renderObjects.line.geometry.dispose();
|
||||||
renderObjects.line.geometry = this.createPathLineGeometry(path);
|
renderObjects.line.geometry = this.createPathLineGeometry(path);
|
||||||
|
this.disposePathSegmentMeshes(renderObjects.segments);
|
||||||
|
renderObjects.segments = this.createPathSegmentMeshes(path);
|
||||||
|
this.addPathSegmentMeshes(renderObjects.segments);
|
||||||
|
|
||||||
for (const pointMesh of renderObjects.pointMeshes) {
|
for (const pointMesh of renderObjects.pointMeshes) {
|
||||||
const point = path.points.find(
|
const point = path.points.find(
|
||||||
@@ -7587,6 +7722,11 @@ export class ViewportHost {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pointMesh.outlineMesh.position.set(
|
||||||
|
point.position.x,
|
||||||
|
point.position.y,
|
||||||
|
point.position.z
|
||||||
|
);
|
||||||
pointMesh.mesh.position.set(
|
pointMesh.mesh.position.set(
|
||||||
point.position.x,
|
point.position.x,
|
||||||
point.position.y,
|
point.position.y,
|
||||||
|
|||||||
Reference in New Issue
Block a user