potree 官网示例
前置条件:
potree 无法直接加载 LAS,LCD,PLY等格式的点云文件,
需要通过 PotreeConverte 转换为 octree 数据格式,前端渲染中加载转换后的 json 格式
格式转换方向
.las ---- potreeConverter ----> .json
结合 vue3 使用
1、模板 html 引入 potree 官网示例中的所有 js 依赖
potree 示例中的 js 依赖如下:
确保能在 vue 项目中,window
中有 potree
2、创建渲染视图区域组件
组件挂载后初始化 viewer
// 全局常量
const Potree = window.Potree;
const THREE = window.THREE;
const i18next = window.i18next;
const TWEEN = window.TWEEN;
const viewer: Ref = ref(null); // viewer 容器
// 初始化视图容器
const initViewer = () => {
if (!Potree || viewer.value) return;
let viewerArgs = {
noDragAndDrop: true,
};
viewer.value = new Potree.Viewer(
document.getElementById(`potree_render_area${areaIdIndex}`),
viewerArgs,
);
// 创建原始引用
const Viewer = toRaw(viewer.value)
// 设置裁剪属性
Viewer.setClipTask(Potree.ClipTask.SHOW_INSIDE);
Viewer.loadGUI();
// 禁用 edl
Viewer.setEDLEnabled(false);
// 设置视场角
Viewer.setFOV(60);
// viewer最大可视点云数量固定
Viewer.setPointBudget(50 * 1000 * 1000);
Viewer.loadSettingsFromURL();
// 设置天背景
Viewer.setBackground('black');
Viewer.setDescription('');
Viewer.setMinNodeSize(0);
Viewer.setControls(Viewer.earthControls);
// 官方 自带 GUi
// this.viewer.loadGUI(() => {
// this.viewer.setLanguage('zh');
// window.$('#menu_tools').next().show();
// window.$('#menu_clipping').next().show();
// this.viewer.toggleSidebar();
// });
// 注册 Sidebar
sidebar = new Sidebar(Viewer)
sidebar.init()
console.log('viewer initialized');
};
onMounted(() => {
nextTick(() => {
// 挂载后初始化视图
initViewer();
});
});
3、加载点云数据
Potree.loadPointCloud(path).then((e: any) => {
// PointCloudOctree实例
// 该实例有唯一的uuid,可以保存起来方便后续对该实例进行操作
let pointcloud = e.pointcloud;
// console.log(pointcloud)
appStore.setOriginFileUuid(fileId, pointcloud.uuid)
// 材质
let material = pointcloud.material;
// name赋值
// pointcloud.name = 'fileName';
// 检查是否有彩色信息
let hasRGBA =
pointcloud.getAttributes().attributes.find((a: any) => a.name === 'rgba') !== undefined;
if (hasRGBA) {
material.activeAttributeName = 'rgba';
} else {
material.activeAttributeName = 'color';
}
// 点云点大小
material.size = 1;
material.minSize = 1;
material.maxSize = 16;
material.pointSizeType = Potree.PointSizeType.FIXED;
// 设置高程渐变方案
material.gradient = Potree.Gradients.TURBO;
// 将点云数据添加到场景
viewer.value.scene.addPointCloud(pointcloud);
viewer.value.setBackground('black');
// 设置相机
viewer.value.zoomTo(e.pointcloud);
// 设置控制器
// viewer.value.setControls(viewer.value.earthControls);
// 设置视场角
viewer.value.setFOV(60);
// 设置最小节点大小,值越小越清晰
viewer.value.setMinNodeSize(0);
// 打开高质量渲染
viewer.value.useHQ = false;
// 点云数量
fetch(path)
.then((response) => response.json())
.then((jsonData) => {
// name赋值
pointcloud.name = jsonData.name;
// 点云数量
// 根据导入的点云数据来设置对应的点云数量
// viewer.value.setPointBudget(jsonData.points);
// 设置点云数量
pointcloud.pointBudget = jsonData.points;
// 设置初始视角
viewer.value.scene.view.setView(new THREE.Vector3(6.44, -6.70, 5.52), new THREE.Vector3(-0.53, 0.55, -0.63));
viewer.value.scene.view.lookAt(-0.53, 0.55, -0.63);
});
})
4、结合官网提供的 工具栏代码,进行其他深入操作
export class Sidebar {
viewer: any
measuringTool: any
profileTool: any
volumeTool: any
constructor(viewer: any) {
this.viewer = viewer;
this.measuringTool = viewer.measuringTool;
this.profileTool = viewer.profileTool;
this.volumeTool = viewer.volumeTool;
}
initScene() {
// 监听点云追加
let onPointCloudAdded = (e: any) => {
let pointcloud: any = e.pointcloud;
console.log('initScene--pointcloud------>')
console.log(pointcloud)
SceneObj.pointclouds.push(pointcloud)
// let cloudIcon = `${Potree.resourcePath}/icons/cloud.svg`;
// let node = createNode(pcID, pointcloud.name, cloudIcon, pointcloud);
pointcloud.addEventListener("visibility_changed", () => {
console.log(pointcloud.visible)
if (pointcloud.visible) {
// tree.jstree('check_node', node);
} else {
// tree.jstree('uncheck_node', node);
}
});
};
// 监听测量对象
let onMeasurementAdded = (e: any) => {
let measurement = e.measurement;
console.log('添加测量对象')
// console.log(measurement);
nextTick(() => {
setTimeout(() => {
const meItem = {
checked: true,
label: measurement.name,
id: measurement.uuid,
}
console.log(e.scene.measurements);
// 追加测量对象数
appStore.addMeasurementsTreeData(meItem, measurement.uuid)
// let icon = Utils.getMeasurementIcon(measurement);
// createNode(measurementID, measurement.name, icon, measurement);
}, 0);
})
};
// 监听体积增加
let onVolumeAdded = (e: any) => {
let volume = e.volume;
// let icon = Utils.getMeasurementIcon(volume);
// let node = createNode(measurementID, volume.name, icon, volume);
volume.addEventListener("visibility_changed", () => {
console.log(volume)
if (volume.visible) {
// tree.jstree('check_node', node);
} else {
// tree.jstree('uncheck_node', node);
}
});
};
// 监听高度坡面增加
let onProfileAdded = (e: any) => {
let profile = e.profile;
// let icon = Utils.getMeasurementIcon(profile);
// createNode(measurementID, profile.name, icon, profile);
};
// 监听标注事件
let onAnnotationAdded = (e: any) => {
let annotation = e.annotation;
// let annotationIcon = `${Potree.resourcePath}/icons/annotation.svg`;
// let parentID = this.annotationMapping.get(annotation.parent);
// let annotationID = createNode(parentID, annotation.title, annotationIcon, annotation);
// this.annotationMapping.set(annotation, annotationID);
// annotation.addEventListener("annotation_changed", (e) => {
// let annotationsRoot = $("#jstree_scene").jstree().get_json("annotations");
// let jsonNode = annotationsRoot.children.find(child => child.data.uuid === annotation.uuid);
// $.jstree.reference(jsonNode.id).rename_node(jsonNode.id, annotation.title);
// });
};
// 相机动作
let onCameraAnimationAdded = (e: any) => {
const animation = e.animation;
// const animationIcon = `${Potree.resourcePath}/icons/camera_animation.svg`;
// createNode(otherID, "animation", animationIcon, animation);
};
// 向导图
let onOrientedImagesAdded = (e: any) => {
const images = e.images;
// const imagesIcon = `${Potree.resourcePath}/icons/picture.svg`;
// const node = createNode(imagesID, "images", imagesIcon, images);
images.addEventListener("visibility_changed", () => {
console.log('images.visible', images.visible)
if (images.visible) {
// tree.jstree('check_node', node);
} else {
// tree.jstree('uncheck_node', node);
}
});
};
// img 360
let onImages360Added = (e: any) => {
const images = e.images;
// const imagesIcon = `${Potree.resourcePath}/icons/picture.svg`;
// const node = createNode(imagesID, "360° images", imagesIcon, images);
images.addEventListener("visibility_changed", () => {
console.log('360images.visible', images.visible)
if (images.visible) {
// tree.jstree('check_node', node);
} else {
// tree.jstree('uncheck_node', node);
}
});
};
// 地质
const onGeopackageAdded = (e: any) => {
const geopackage = e.geopackage;
// const geopackageIcon = `${Potree.resourcePath}/icons/triangle.svg`;
// const tree = $(`#jstree_scene`);
// const parentNode = "vectors";
// for (const layer of geopackage.node.children) {
// const name = layer.name;
// let shpPointsID = tree.jstree('create_node', parentNode, {
// "text": name,
// "icon": geopackageIcon,
// "object": layer,
// "data": layer,
// },
// "last", false, false);
// tree.jstree(layer.visible ? "check_node" : "uncheck_node", shpPointsID);
// }
};
this.viewer.scene.addEventListener("pointcloud_added", onPointCloudAdded);
this.viewer.scene.addEventListener("measurement_added", onMeasurementAdded);
this.viewer.scene.addEventListener("profile_added", onProfileAdded);
this.viewer.scene.addEventListener("volume_added", onVolumeAdded);
this.viewer.scene.addEventListener("camera_animation_added", onCameraAnimationAdded);
this.viewer.scene.addEventListener("oriented_images_added", onOrientedImagesAdded);
this.viewer.scene.addEventListener("360_images_added", onImages360Added);
this.viewer.scene.addEventListener("geopackage_added", onGeopackageAdded);
this.viewer.scene.addEventListener("polygon_clip_volume_added", onVolumeAdded);
this.viewer.scene.annotations.addEventListener("annotation_added", onAnnotationAdded);
/**
* 删除操作
*/
// let onMeasurementRemoved = (e) => {
// let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");
// let jsonNode = measurementsRoot.children.find(child => child.data.uuid === e.measurement.uuid);
// tree.jstree("delete_node", jsonNode.id);
// };
// let onVolumeRemoved = (e) => {
// let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");
// let jsonNode = measurementsRoot.children.find(child => child.data.uuid === e.volume.uuid);
// tree.jstree("delete_node", jsonNode.id);
// };
// let onPolygonClipVolumeRemoved = (e) => {
// let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");
// let jsonNode = measurementsRoot.children.find(child => child.data.uuid === e.volume.uuid);
// tree.jstree("delete_node", jsonNode.id);
// };
// let onProfileRemoved = (e) => {
// let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");
// let jsonNode = measurementsRoot.children.find(child => child.data.uuid === e.profile.uuid);
// tree.jstree("delete_node", jsonNode.id);
// };
// this.viewer.scene.addEventListener("measurement_removed", onMeasurementRemoved);
// this.viewer.scene.addEventListener("volume_removed", onVolumeRemoved);
// this.viewer.scene.addEventListener("polygon_clip_volume_removed", onPolygonClipVolumeRemoved);
// this.viewer.scene.addEventListener("profile_removed", onProfileRemoved);
// {
// let annotationIcon = `${Potree.resourcePath}/icons/annotation.svg`;
// this.annotationMapping = new Map();
// this.annotationMapping.set(this.viewer.scene.annotations, annotationsID);
// this.viewer.scene.annotations.traverseDescendants(annotation => {
// let parentID = this.annotationMapping.get(annotation.parent);
// let annotationID = createNode(parentID, annotation.title, annotationIcon, annotation);
// this.annotationMapping.set(annotation, annotationID);
// });
// }
const scene = this.viewer.scene;
for (let pointcloud of scene.pointclouds) {
onPointCloudAdded({ pointcloud: pointcloud });
}
for (let measurement of scene.measurements) {
onMeasurementAdded({ measurement: measurement });
}
for (let volume of [...scene.volumes, ...scene.polygonClipVolumes]) {
onVolumeAdded({ volume: volume });
}
for (let animation of scene.cameraAnimations) {
onCameraAnimationAdded({ animation: animation });
}
for (let images of scene.orientedImages) {
onOrientedImagesAdded({ images: images });
}
for (let images of scene.images360) {
onImages360Added({ images: images });
}
for (const geopackage of scene.geopackages) {
onGeopackageAdded({ geopackage: geopackage });
}
for (let profile of scene.profiles) {
onProfileAdded({ profile: profile });
}
// {
// createNode(otherID, "Camera", null, new Camera());
// }
this.viewer.addEventListener("scene_changed", (e: any) => {
// propertiesPanel.setScene(e.scene);
e.oldScene.removeEventListener("pointcloud_added", onPointCloudAdded);
e.oldScene.removeEventListener("measurement_added", onMeasurementAdded);
e.oldScene.removeEventListener("profile_added", onProfileAdded);
e.oldScene.removeEventListener("volume_added", onVolumeAdded);
e.oldScene.removeEventListener("polygon_clip_volume_added", onVolumeAdded);
// e.oldScene.removeEventListener("measurement_removed", onMeasurementRemoved);
e.scene.addEventListener("pointcloud_added", onPointCloudAdded);
e.scene.addEventListener("measurement_added", onMeasurementAdded);
e.scene.addEventListener("profile_added", onProfileAdded);
e.scene.addEventListener("volume_added", onVolumeAdded);
e.scene.addEventListener("polygon_clip_volume_added", onVolumeAdded);
// e.scene.addEventListener("measurement_removed", onMeasurementRemoved);
});
}
init() {
this.initScene();
}
}
参考学习:potree 使用手册
鸣谢作者;