【Three.js】vue2导入pcd文件 PCDLoader

文章讲述了在使用Vue.js结合three.js加载PCD点云文件时遇到的两个主要问题:资源404错误和BufferGeometry计算错误。作者通过检查路径和源码调试,发现是路径配置和数据异常导致的问题。解决方案包括去掉URL中的public前缀和修改three.js源码中的Math.max处理方式,以及确保PCD文件不含NaN值。最后,文章提供了修复后的代码片段。
摘要由CSDN通过智能技术生成

一、最终效果图

二、遇到的问题解决办法

1.资源加载不出

a.TypeError: Cannot read properties of null (reading '1')
    at parseHeader (PCDLoader.js?edd4:119:1)
    at PCDLoader.parse (PCDLoader.js?edd4:226:1)
    at Object.eval [as onLoad] (PCDLoader.js?edd4:34:1)
    at XMLHttpRequest.eval (three.module.js?5a89:34770:1)

b.GET http://localhost:8080/public/Zaghetto 404 (Not Found)

两者本质同个问题,都是没有获取到pcd文件资源,第一个由于设置了vue-router,使他没有获取到后返回来index.html (官方文档https://router.vuejs.org/zh/guide/essentials/history-mode.html#html5-%E6%A8%A1%E5%BC%8F)

文件位置
文件位置

404,我先检查了路径名称发现没拼写错误,后来尝试 public下其他常见类型文件可以,只有这个pcd文件不行,然后我就看了他们的请求网站,发现pcd文件的请求网址多了个‘/public',导致请求路径错误。

解决办法:

url直接不写public/直接从第二级开始写

2.bufferGeometry报错

three.module.js?5a89:10091 THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values. 

字面意思是 'radius'和'position'现在值为非数字

从threejs源码中找到 computeBoundingSphere(),通过断点,可以看出是由于这个maxRadiusSq值为NaN,然后这个值又是由于center.distanceToSquared(_vector$8)为NaN, 导致Math.max为NaN。这个值是由于 _vector$8.fromBufferAttribute(position, i)为NaN,顺藤摸瓜发现最终是因为position里有的值为NaN,position从哪里来?是导入的pcd文件。

解决办法:

a. Math.max(a,b)a,b中有一个NaN就返回NaN,所以可以将threejs源码中Math.max()替换成其它比大小方法

//maxRadiusSq = Math.max(maxRadiusSq, center.distanceToSquared(_vector$8));
//替换成
maxRadiusSq = center.distanceToSquared(_vector$8) > maxRadiusSq ? center.distanceToSquared(_vector$8) : maxRadiusSq

 b.pcd文件不要含NaN

三、最终代码

<template>
  <div
    v-loading="loading"
    element-loading-background="rgba(0, 0, 0, 0.8)"
    id="pcdcontainer"
    ref="pcdcontainer"
  ></div>
<!-- v-loding 是element Ui的 -->
</template>

<script>
import * as THREE from "three";
import { PCDLoader } from "three/examples/jsm/loaders/PCDLoader.js";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"; 
export default {
  created () {
  },
  data () {
    return {
      elem: null,
      scene: null,
      camera: null, 
      renderer: null, 
      loader: null,
      controls: null,
      clock: new THREE.Clock(),
      loading: true,
      pointcloud: null,
    }
  },
  beforeMount () {

  },
  mounted () {
    this.init()
  },
  methods: {
    init () {
      this.elem = document.getElementById('pcdContainer');//获取要渲染的Dom
      // 相机
      this.camera = new THREE.PerspectiveCamera(
        30, // 视野
        this.elem.clientWidth / this.elem.clientHeight, // 纵横比
        0.1, // 近平面
        1000 // 远平面
      );
      // 渲染器
      this.renderer = new THREE.WebGLRenderer({
        antialias: true,
        alpha: true
      });
      this.renderer.setClearColor(new THREE.Color(0x303030)); // 背景色
      this.renderer.setSize(this.elem.clientWidth, this.elem.clientHeight);
      this.elem.appendChild(this.renderer.domElement);
      this.scene = new THREE.Scene(); // 场景
      this.loader = new PCDLoader(); //PCD加载器
      const THIS = this
        //加载PCD文件
        THIS.loader.load(
         'Zaghetto.pcd',
          function (points) {
            points.geometry.rotateX(0.5 * Math.PI);//旋转模型,可调
            points.material.color = new THREE.Color(0x00ffff); // 模型颜色
            THIS.scene.add(points);
            var middle = new THREE.Vector3();
            console.log(points.geometry);
            points.geometry.computeBoundingBox();
            points.geometry.boundingBox.getCenter(middle);
            points.applyMatrix4(
              new THREE.Matrix4().makeTranslation(
                -middle.x,
                -middle.y,
                -middle.z
              )
            );
            // 比例
            var largestDimension = Math.max(
              points.geometry.boundingBox.max.x,
              points.geometry.boundingBox.max.y,
              points.geometry.boundingBox.max.z
            );
            THIS.camera.position.y = largestDimension * 3;//相机位置,可调
            THIS.animate();
            //轨道控制器 旋转、平移、缩放
            THIS.controls = new OrbitControls(
              THIS.camera,
              THIS.renderer.domElement
            );
            THIS.controls.enableDamping = true;//旋转、平移开启阻尼
            THIS.controls.addEventListener("change", THIS.render); // 监听鼠标、键盘事件  
             放大缩小等

          },
            function (xhr) {
            let load = xhr.loaded / xhr.total
            if (load == 1) {
              THIS.loading = false
            }
          },
          function (error) {
            console.log(error);
          }
        );
    },
    render () {
      this.renderer.render(this.scene, this.camera);
    },
    animate () {
      let delta = this.clock.getDelta();
      if (this.controls) {
        this.controls.update(delta);
      }
      requestAnimationFrame(this.animate)
      this.render();
    },
  },
  computed: {},
  watch: {},
  filters: {},
  components: {}
}
</script>
<style scoped lang='scss'>
#pcdcontainer {
  width: 1920px;
  height: 1080px;
}
</style>

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值