点云数据切片及使用threejs加载

测试点云数数据大小 2.94G

cesium 加载:

数据处理:cesiumlab 点云切片->cesium 3Dtiles API 加载

threejs 加载

只支持 pcd 格式,故将 lsa 数据导入,在导出为了 pcd,在将数据直接转出 pcd 会直接闪退,不知是不是数据量的问题,还是电脑问题,然后试了下数据抽稀,在转化导出 200 多 M,然后直接加载,没有做 lod

Potree 加载 las

https://github.com/potree/potree
通过自带 Octree 优化加载性能

因为使用 Potree 加载的点云数据需要八叉树索引,而默认的 las 是没有构建有的(在软件上可视化时是会默认自动构建并可视化),所以需要对其进行转化为此库需要使用的相应的格式需要使用此库中自带的工具PotreeConverter 来转换
image.png
转换后的数据如上,原理类似于 3Dtiles 文件的组织

threejs+potree-core 切片加载

three.js 加载点云切片数据
在这里插入图片描述

实现原理是是先使用 potree 的八叉树索引构建工具将 las 数据转化为 octree 数据格式,然后使用网络 potree-core 库(potree 简化版),并实在 three 中通过八叉树索引加载点云动态加载,代码修改参考于 potree-core 的示例代码库。

<template>
  <canvas id="gl"></canvas>
</template>
<script setup>
import GUI from "lil-gui";
import {
  AmbientLight,
  AxesHelper,
  DirectionalLight,
  BoxGeometry,
  Clock,
  GridHelper,
  LoadingManager,
  SpotLight,
  SpotLightHelper,
  Mesh,
  MeshLambertMaterial,
  MeshStandardMaterial,
  PCFSoftShadowMap,
  PerspectiveCamera,
  PlaneGeometry,
  Vector3,
  MeshBasicMaterial,
  PointLight,
  PointLightHelper,
  Scene,
  WebGLRenderer
} from "three";
import {OrbitControls} from "three/examples/jsm/controls/OrbitControls";
import Stats from "three/examples/jsm/libs/stats.module";
import {PCDLoader} from "three/examples/jsm/loaders/PCDLoader.js"; // 注意是examples/jsm
import * as animations from "./utils/threeUtils/animations";
import {resizeRendererToDisplaySize} from "./utils/threeUtils/responsiveness";
import { PointCloudOctree, Potree } from 'potree-core'

import {onMounted, onUnmounted} from "vue";

const animation = {enabled: false, play: true};

let canvas;
let renderer;
let scene;
let loadingManager;
let ambientLight;
let pointLight;
let spotLight;
let directionalLight;
let cube;
let camera;
let cameraControls;
// let dragControls;
let axesHelper;
let pointLightHelper;
let spotLightHelper;
// let cameraHelper
let clock;
let stats;
let gui;
let points;
let pointClouds;
const potree = new Potree();

onMounted(() => {
  init();
  animate();
});

onUnmounted(() => {
  destroy();
  if (stats.dom && stats.dom.parentElement) {
    stats.dom.parentElement.removeChild(stats.dom);
  }
});

const init = () => {
  // renderer&&scene
  {
    canvas = document.querySelector("#gl");
    renderer = new WebGLRenderer({
      canvas, 
      antialias: true, 
      alpha: true,
      logarithmicDepthBuffer: false,//对数深度缓冲区
      precision: 'highp',//渲染精度
      premultipliedAlpha: true,//
      preserveDrawingBuffer: false,//是否保留绘图缓冲区
      powerPreference: 'high-performance'//电源偏好
    });
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
    // renderer.shadowMap.enabled = true; //开启阴影渲染
    // renderer.shadowMap.type = PCFSoftShadowMap; //阴影映射的类型
    scene = new Scene();
  }

 

  // LoadingManager
  {
    loadingManager = new LoadingManager();

    loadingManager.onStart = () => {
      console.log("loading started");
    };
    loadingManager.onProgress = (url, loaded, total) => {
      console.log("loading in progress:");
      console.log(`${url} -> ${loaded} / ${total}`);
    };
    loadingManager.onLoad = () => {
      console.log("loaded!");
    };
    loadingManager.onError = () => {
      console.log("❌ error while loading");
    };
  }

  // light
  {
    //环境光
    ambientLight = new AmbientLight("white", 0.4);

    //点光源
    pointLight = new PointLight("#ffdca8", 1.2, 100);
    pointLight.position.set(-2, 3, 3);
    pointLight.castShadow = true; //开启阴影投射
    pointLight.shadow.radius = 4; //设置软阴影的半径
    pointLight.shadow.camera.near = 0.5;
    pointLight.shadow.camera.far = 4000;
    //设置阴影贴图的大小,值越大阴影的质量越高,但同时也会更消耗性能。
    pointLight.shadow.mapSize.width = 2048;
    pointLight.shadow.mapSize.height = 2048;

    //聚光灯
    spotLight = new SpotLight(0xffffff, 1.0);
    spotLight.intensity = 1.0; //光照强度
    spotLight.angle = Math.PI / 6; //发散角度:光锥角度的二分之一
    spotLight.position.set(4, 5, 8);
    spotLight.castShadow = true;

    //平行光
    directionalLight = new DirectionalLight(0xffffff, 1);
    directionalLight.position.set(10, 10, 10);
    // directionalLight.position.set(100, 60, 50);
    directionalLight.castShadow = true;

    scene.add(spotLight);
    scene.add(ambientLight);
    scene.add(pointLight);
    scene.add(directionalLight);
  }

  //object
  {
    const sideLength = 1;
    const cubeGeometry = new BoxGeometry(sideLength, sideLength, sideLength);
    const cubeMaterial = new MeshStandardMaterial({
      color: "#f69f1f",
      metalness: 0.5,
      roughness: 0.7
    });
    cube = new Mesh(cubeGeometry, cubeMaterial);
    cube.castShadow = true;
    cube.position.y = 0.5;

    const planeGeometry = new PlaneGeometry(6, 6);
    const planeMaterial = new MeshLambertMaterial({
      color: "gray",
      emissive: "teal",
      emissiveIntensity: 0.2,
      side: 2,
      transparent: true,
      opacity: 0.4
    });
    const plane = new Mesh(planeGeometry, planeMaterial);
    plane.rotateX(Math.PI / 2);
    plane.receiveShadow = true;

    // console.log("cube", cube);

    scene.add(cube);
    scene.add(plane);
  }

   //potree 
   {
    points = new Potree();
    points.pointBudget = 1000000000
    pointClouds = [];
    points.loadPointCloud('metadata.json', (url) => {
        return `/test/${url}`
        }).then((pco) => {
          
          pco.material.size = 1.0
          pco.material.shape = 2
          pco.material.inputColorEncoding = 1
          pco.material.outputColorEncoding = 1

          console.log('PointCloud file loaded', pco)
          pco.position.set(0, 0, 0);
          console.log(pco)

          const box = pco.pcoGeometry.boundingBox
          const size = box.getSize(new Vector3())
          console.log(size)

          const geometry = new BoxGeometry(size.x, size.y, size.z)
          const material = new MeshBasicMaterial({ color: 0xFF0000, wireframe: true })
          const mesh = new Mesh(geometry, material)
          mesh.scale.set(0.001, 0.001, 0.001);
          console.log(mesh)
   
          mesh.raycast = () => false

          size.multiplyScalar(0.5)
  

          addPointCloud(pco)
        })

  }

  // camera
  {
    camera = new PerspectiveCamera(
      60,
      canvas.clientWidth / canvas.clientHeight,
      0.1,
      1000
    );
    camera.position.z = 30;
  }

  // controls
  {
    cameraControls = new OrbitControls(camera, canvas);
    cameraControls.target = cube.position.clone();
    cameraControls.enableDamping = true;
    // cameraControls.autoRotate = true;
    cameraControls.update();
  }

  // helpers
  {
    axesHelper = new AxesHelper(40);
    // axesHelper.visible = false;
    scene.add(axesHelper);

    pointLightHelper = new PointLightHelper(pointLight, undefined, "orange");
    pointLightHelper.visible = false;
    scene.add(pointLightHelper);

    spotLightHelper = new SpotLightHelper(spotLight, 0xffffff);
    spotLightHelper.visible = false;
    scene.add(spotLightHelper);

    //可视化平行光阴影对应的正投影相机对象
    // const cameraHelper = new CameraHelper(directionalLight.shadow.camera);
    // cameraHelper.visible = false
    // scene.add(cameraHelper);

    const gridHelper = new GridHelper(20, 20, "teal", "darkgray");
    gridHelper.position.y = -0.01;
    scene.add(gridHelper);
  }

  // STATS & CLOCK
  {
    clock = new Clock();
    stats = new Stats();
    // stats.dom.style.left = "200px";
    canvas.parentNode.appendChild(stats.dom);
  }

  //DEBUG GUI
  {
    gui = new GUI({title: "🐞 Debug GUI", width: 250});

    const lightsFolder = gui.addFolder("Lights");
    lightsFolder.add(pointLight, "visible").name("point light");
    lightsFolder.add(ambientLight, "visible").name("ambient light");
    lightsFolder.add(spotLight, "visible").name("spotLight light");
    lightsFolder.add(directionalLight, "visible").name("directional light");

    const helpersFolder = gui.addFolder("Helpers");
    helpersFolder.add(axesHelper, "visible").name("axes");
    helpersFolder.add(pointLightHelper, "visible").name("pointLightHelper");
    helpersFolder.add(spotLightHelper, "visible").name("spotLightHelper");
    // helpersFolder.add(cameraHelper, 'visible').name('directionalLightHelper')

    const cameraFolder = gui.addFolder("Camera");
    cameraFolder.add(cameraControls, "autoRotate");

    // reset GUI state button
    const resetGui = () => {
      localStorage.removeItem("guiState");
      gui.reset();
    };
    gui.add({resetGui}, "resetGui").name("RESET");

    // gui.close();
  }
};

//添加pointCloud
const addPointCloud =(pco) => {
scene.add(pco)
pointClouds.push(pco)
}

const animate = () => {
  requestAnimationFrame(animate);
  stats.update();
  if (animation.enabled && animation.play) {
    animations.rotate(cube, clock, Math.PI / 3);
    animations.bounce(cube, clock, 1, 0.5, 0.5);
  }

  if (resizeRendererToDisplaySize(renderer)) {
    const canvas = renderer.domElement;
    camera.aspect = canvas.clientWidth / canvas.clientHeight;
    camera.updateProjectionMatrix();
  }

  cameraControls.update();
  renderer.render(scene, camera);
  potree.updatePointClouds(pointClouds, camera, renderer)
};

const destroy = () => {
  if (gui) gui.destroy();

  scene.traverse(child => {
    if (child instanceof Mesh) {
      child.geometry.dispose();

      for (const key in child.material) {
        const value = child.material[key];

        if (value && typeof value.dispose === "function") {
          value.dispose();
        }
      }
    }
  });
};
</script>

<style>
#gl {
  width: 100vw;
  height: 100vh;
  display: block;
  background: rgb(25, 25, 25);
}

.lil-gui.root > .children > .lil-gui > .title {
  color: white;
  padding-right: 180px;
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/442561.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HUAWEI 华为交换机 配置 MAC 防漂移 防MAC伪造示例

组网需求 某企业网络中&#xff0c;用户需要访问企业的服务器。如果某些非法用户从其他接口假冒服务器的MAC 地址发送报文&#xff0c;则服务器的 MAC 地址将在其他接口学习到。这样用户发往服务器的报文就会发往非法用户&#xff0c;不仅会导致用户与服务器不能正常通信&…

FreeRTOS之消息队列的示例记录

前言 我的理解是 消息队列主要是用于任务之间存在主从关系的时候&#xff0c;比如说显示屏显示数据&#xff0c;显示屏的作用只是提供显示&#xff0c;数据来源应该是其他任务线程&#xff0c;所以就存在多个线程通信问题。 FreeRTOS中消息队列 这里我们以数组为例&#xff…

Pytorch学习 day07(神经网络基本骨架的搭建、2D卷积操作、2D卷积层)

神经网络基本骨架的搭建 Module&#xff1a;给所有的神经网络提供一个基本的骨架&#xff0c;所有神经网络都需要继承Module&#xff0c;并定义_ _ init _ _方法、 forward() 方法在_ _ init _ _方法中定义&#xff0c;卷积层的具体变换&#xff0c;在forward() 方法中定义&am…

Python 3 教程(1)

Python 3 教程 Python 的 3.0 版本&#xff0c;常被称为 Python 3000&#xff0c;或简称 Py3k。相对于 Python 的早期版本&#xff0c;这是一个较大的升级。为了不带入过多的累赘&#xff0c;Python 3.0 在设计的时候没有考虑向下兼容。 Python 介绍及安装教程我们在后期中有介…

【高效开发工具系列】Windows 系统下将 Windows 键盘的 ctrl 和 alt 互换

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

JVM——执行引擎

文章目录 1、概述2、计算机语言的发展史2.1、机器码2.2、汇编语言2.3、高级语言2.4、字节码 3、Java代码编译和执行过程4、解释器5、JIT编译器5.1、为什么HotSpot VM同时存在JIT编译器和解释器5.2、热点代码探测确定何时JIT5.3、设置执行模式5.4、C1编译器和C2编译器 6、AOT编译…

【蓝桥杯-单片机】LED和按键小练习:Led彩灯控制系统

文章目录 【蓝桥杯-单片机】LED和按键小练习&#xff1a;Led彩灯控制系统01 题目描述02 题目解答03 本题总结整体逻辑框架&#xff08;详细版&#xff09;整体逻辑框架&#xff08;缩略版&#xff09;按键读取模块按键消抖模块流水灯显示模式&#xff08;1&#xff09;从上向下…

USB PD快充充电器静电浪涌保护TVS

USB PD快充充电器已经成为生活中无处不在的必备物品&#xff0c;它能够为我们的各种电子设备提供快速而便捷的充电解决方案&#xff0c;比如智能手机和平板电脑&#xff0c;笔记本电脑&#xff0c;可穿戴设备&#xff0c;摄像机和摄像设备&#xff0c;汽车充电器&#xff0c;以…

图片二维码不限扫码次数怎么做?长期有效的图片二维码在线生成技巧

图片制作二维码能长期使用吗&#xff1f;在生活中很多地方都可以看到很多存有图片的二维码&#xff0c;通过扫码后查看图片内容&#xff0c;比如一些公共场所、产品介绍、景区等场所中都有图片转二维码的应用。那么怎么做出可以长期扫码展示图片二维码呢&#xff0c;其实方法很…

Awesome-Backbones-main——alexnet模型分析

AlexNet作为骨干网络相对较老&#xff0c;可能在复杂数据集上的表现不如一些最新的深度网络结构&#xff0c;如ResNet、EfficientNet等&#xff0c;学习率调整策略中采用了阶梯式学习率更新器&#xff0c;可能并不总是适合所有数据集和模型&#xff0c;需要根据具体情况调整学习…

【办公类-21-09】三级育婴师 视频转音频Python

背景需求&#xff1a; 用AI对话工具试试能否Python将MP4视频转成音频&#xff0c;再转成文字docx&#xff08;不用格式工厂转&#xff09; 结果&#xff1a; 视频MP4转音频wav 视频MP4转音频wav 作者&#xff1a;AI对话大师&#xff0c; 时间&#xff1a;2024年3月8日 impo…

开源的Java报表库JasperReports介绍

JasperReports 是一个流行的开源 Java 报表库&#xff0c;它允许开发人员创建丰富的、基于 Java 的报表&#xff0c;这些报表可以与多种数据源交互&#xff0c;并且可以很容易地集成到 Java 应用程序中。JasperReports 提供了丰富的功能&#xff0c;包括数据可视化、图表、子报…

【Vue+ElementUI】Table表格实现自定义表头展示+表头拖拽排序(附源码)

效果图 因项目采用的是Vue2&#xff0c;所以这个功能目前采用的是Vue2的写法。 Vue3请自行修改扩展代码&#xff1b;或收藏关注帖子&#xff0c;后续Vue3项目如有用到会在本帖子更新修改。 安装vuedraggable&#xff08;拖拽插件&#xff09; cnpm i vuedraggable先说用法&…

github Commits must have verified signatures

1.首先确认是否有权限&#xff0c;如有权限的情况下那就是配置有问题了 我的情况是&#xff0c;能拉取代码&#xff0c;提交的时候出现这种情况&#xff1a;Commits must have verified signatures 这里是生成证书&#xff0c;如果已经生成过的&#xff0c;就不用生成了 ssh…

GIS之深度学习08:安装GPU环境下的pytorch

环境&#xff1a; cuda&#xff1a;12.1.1 cudnn&#xff1a;12.x pytorch&#xff1a;2.2.0 torchvision&#xff1a;0.17.0 Python&#xff1a;3.8 操作系统&#xff1a;win &#xff08;本文安装一半才发现pytorch与cuda未对应&#xff0c;重新安装了cuda后才开始的&a…

超声波清洗机哪个品牌好?四款热度高超声波清洗机力荐

在当今社会&#xff0c;随着生活节奏的加快&#xff0c;年轻人越来越多地依赖眼镜来纠正视力或保护眼睛。无论是为了时尚搭配&#xff0c;还是因为长时间面对电脑和手机屏幕导致的视力问题&#xff0c;眼镜已经成为许多年轻人日常生活中不可或缺的配件。然而&#xff0c;就在我…

SSH安全协议介绍

知识改变命运&#xff0c;技术就是要分享&#xff0c;有问题随时联系&#xff0c;免费答疑&#xff0c;欢迎联系&#xff01; SSH&#xff08;Secure Shell&#xff0c;安全外壳&#xff09;是一种网络安全协议&#xff0c;通过加密和认证机制实现安全的访问和文件传输等业…

植物病虫害:YOLO水稻虫害识别数据集(6类,五千余张图像,标注完整)

YOLO水稻虫害识别数据集&#xff0c;包含褐飞虱&#xff0c;绿叶蝉&#xff0c;正常叶片&#xff0c;稻虫&#xff0c;二化螟&#xff0c;蝇蛆6个类别&#xff0c;共五千余张图像&#xff0c;yolo标注完整。 适用于CV项目&#xff0c;毕设&#xff0c;科研&#xff0c;实验等 …

uniapp微信小程序获取当前位置

uni-app微信小程序uni.getLocation获取位置&#xff1b;authorize scope.userLocation需要在app.json中声明permission&#xff1b;小程序用户拒绝授权后重新授权-CSDN博客

AIOPS:Zabbix结合讯飞星火做自动化告警+邮件通知并基于人工智能提供解决方案

目前Zabbix官方已经提供Zabbix+ChatGPT的解决方案 ChatGPT一周年,你充分利用了吗?Zabbix+ChatGPT,轻松化解告警! 但是由于需要魔法等其他因素,比较不稳定,遂决定使用国内模型,这里我挑选的是讯飞星火,基于我之前的文档,在此基础上通过Zabbix的告警脚本实现调用AI模型…