现在点云渲染出来了 就是视角切换有问题 机器每次给我点云数据的时候会把机器相对于一开始的位置和朝向的坐标给我 然后我用这两个字段设置相机的位置和lookAt 但是呈现出来的效果是不对的 是思路不对吗 three.js的相机把我搞懵了
<template>
<div class="warp">
<!-- 顶部 -->
<div class="top">
<img src="./assets/image/cha.svg" @click="showModel = true" />
<span>{{ name }}</span>
<div>
<img src="./assets/image/dl.svg" />
{{ dl }}%
</div>
<div>
<img src="./assets/image/nc.svg" />
{{ nc }}%
</div>
<img src="./assets/image/menu.svg" @click="postMessage(3)" />
</div>
<!-- 按钮 -->
<div class="btn" @click="postMessage(4)" v-if="btmShow">
<div>{{ lang != 2 ? '启动' : 'start-up' }}</div>
</div>
<!-- 底部 -->
<ul class="btm">
<li :class="{ 'active': type == 1 }" @click="type = 1">
<img src="./assets/image/2d.svg" />
2D
</li>
<li :class="{ 'active': type == 2 }" @click="type = 2">
<img src="./assets/image/3d.svg" />
3D
</li>
<li :class="{ 'active': type == 3 }" @click="type = 3">
<img src="./assets/image/hf.svg" />
{{ lang != 2 ? '数据回放' : 'Data playback' }}
</li>
<li @click="postMessage(2)">
<img src="./assets/image/ls.svg" />
{{ lang != 2 ? '历史记录' : 'History' }}
</li>
</ul>
<!-- 弹窗 -->
<transition>
<div class="model" v-if="showModel">
<h3>{{ lang != 2 ? '提示' : 'prompt' }}</h3>
<p>{{ lang != 2 ? '您确定要退出该界面吗?' : 'Are you sure you want to exit this interface?' }}</p>
<div class="btns">
<div class="btnn" @click="showModel = false">{{ lang != 2 ? '取消' : 'cancel' }}</div>
<div class="btnn" @click="esc">{{ lang != 2 ? '退出' : 'quit' }}</div>
</div>
</div>
</transition>
<!-- 进度 -->
<div id="jd" :style="{ 'right': (type != 3) ? '-5%' : '5%' }">
<c-progress class="c-progress" type="#FF9800" :percent="percent" @percentChange="onPercentChange"
:show-per-text="false" />
</div>
<!-- 底部状态灯 -->
<div class="btmm"></div>
<!-- 点云 -->
<div id="content"></div>
</div>
</template>
<script>
import CProgress from "./components/cop.vue";
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js';
import Stats from '@/utils/stats';
import { hslToRgb } from "@/utils";
import service from "./utils/service";
/* 场景/相机/渲染器/控件/性能监视/轨迹管道 */
let scene = null, camera = null, renderer = null, controls = null, stats = null, mesh = null;
/* 相机位置/朝向 */
let position = [0, -14, 15], lookAt = [0, 0, 0];
/* 窗口宽度 / 窗口高度 / 窗口宽高比 / 三维场景显示范围控制系数,系数越大,显示的范围越大 */
let width = window.innerWidth, height = window.innerHeight, k = width / height, s = 5;
let path = [];
export default {
components: { CProgress },
data() {
return {
lang: 1,
type: 2,
showModel: false,
percent: 100, // 进度控制
name: "zzcomm",
dl: 100,
nc: 100,
isCatmull: true,
btmShow: true,
}
},
async mounted() {
this.createWebGL();
// this.GuiInit(camera);
// this.createStats();
/* 使用本地点云 */
// const res = await service.getData2();
// let datas = res.data;
// let i = 0;
// let timer = setInterval(function () {
// if (!datas[i]?.pointcloud) {
// clearInterval(timer);
// timer = null;
// return;
// }
// let pointcloud = datas[i].pointcloud.map((item, index) => {
// return {
// x: item[0],
// y: item[1],
// z: item[2],
// i: item[3]
// }
// });
// let dsd = {
// data: pointcloud,
// position: {
// x: datas[i].position[0][0],
// y: datas[i].position[0][1],
// z: datas[i].position[0][2],
// },
// orientation: {
// x: datas[i].orientation[0][0],
// y: datas[i].orientation[0][1],
// z: datas[i].orientation[0][2],
// }
// }
// this.uniEvent(JSON.stringify(dsd));
// if (i >= 295) clearInterval(timer);
// timer = null;
// console.log(i, datas.length);
// i += 1;
// }, 200);
},
methods: {
/* 创建three三大件及控件对象 */
createWebGL() {
/* 创建场景 */
scene = new THREE.Scene();
/* 向场景中添加环境光 */
scene.add(new THREE.AmbientLight(0x444444));
// 创建相机
camera = new THREE.OrthographicCamera((-s * k), (s * k), s, -s, -2, 300);
// 设置相机位置
camera.position.set(...position);
// 设置相机朝向(指向的场景对象)
camera.lookAt(new THREE.Vector3(...lookAt));
// 添加坐标指示器
scene.add(new THREE.AxesHelper(10));
// const helper = new THREE.CameraHelper(camera);
// scene.add(helper);
/* 创建渲染器 */
renderer = new THREE.WebGLRenderer({ antialias: true });
// 设置渲染区域尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
// 设置背景颜色
renderer.setClearColor(0x000000, 1);
// DOM元素中插入渲染器
document.getElementById("content").appendChild(renderer.domElement);
/* 创建控件对象 */
controls = new OrbitControls(camera, renderer.domElement);
// 监听鼠标、键盘事件
let timer = null;
controls.addEventListener('change', () => {
this.isCatmull = false;
this.render();
if (timer != null) {
clearTimeout(timer);
timer = null;
}
timer = setTimeout(() => {
this.isCatmull = true;
clearTimeout(timer);
timer = null;
}, 10000);
});
},
/* 执行渲染操作 指定场景、相机作为参数 */
render() {
renderer.render(scene, camera);
// 更新性能插件
// stats.update();
},
/* 创建性能监视插件 */
createStats() {
stats = new Stats();
// 把stats对象生成的dom,添加到页面中(这样就能在页面中看到性能监视器了)
document.getElementById("content").appendChild(stats.dom);
},
/* 创建gui */
GuiInit(camera, material) {
const gui = new GUI({ title: document.title });
/* 相机位置 */
const position = { 'X': camera.position.x, 'Y': camera.position.y, 'Z': camera.position.z };
const POS = gui.addFolder('相机位置');
POS.add(position, 'X', -50, 50, 0.2).onChange((x) => {
camera.position.set(x, camera.position.y, camera.position.z);
this.render();
});
POS.add(position, 'Y', -50, 50, 0.2).onChange((y) => {
camera.position.set(camera.position.x, y, camera.position.z);
this.render();
});
POS.add(position, 'Z', -50, 50, 0.2).onChange((z) => {
camera.position.set(camera.position.x, camera.position.y, z);
this.render();
});
/* 相机朝向 */
const look = { 'X': 0, 'Y': 0, 'Z': 0 };
const LOK = gui.addFolder('相机朝向');
LOK.add(look, 'X', -50, 50, 0.2).onChange((x) => {
camera.lookAt(new THREE.Vector3(x, look['Y'], look['Z']));
this.render();
});
LOK.add(look, 'Y', -50, 50, 0.2).onChange((y) => {
camera.lookAt(new THREE.Vector3(look['X'], y, look['Z']));
this.render();
});
LOK.add(look, 'Z', -50, 50, 0.2).onChange((z) => {
camera.lookAt(new THREE.Vector3(look['X'], look['Y'], z));
this.render();
});
/* 材质对象 */
// const mater = { "顶点大小": material.size };
// const MAT = gui.addFolder('材质对象');
// MAT.add(mater, '顶点大小', 0.1, 2, 0.1).onChange((size) => {
// material.size = size;
// this.render();
// });
},
/* 创建几何图形对象 */
createBufferGeometry(data, colors) {
// 创建几何图形对象
let geometry = new THREE.BufferGeometry();
// 设置顶点数据 3个为一组,作为一个顶点的xyz坐标
geometry.attributes.position = new THREE.BufferAttribute(new Float32Array(data), 3);
geometry.attributes.color = new THREE.BufferAttribute(new Float32Array(colors), 3);
// 材质对象 模型颜色/模型大小
let material = new THREE.PointsMaterial({ vertexColors: true, size: 2 });
let model = new THREE.Points(geometry, material);
// 将图形对象配置到点模型对象上
scene.add(model);
this.render();
},
/* 创建曲线轨迹 利用管道模型 */
createCatmullRomCurve3(data) {
path.push(new THREE.Vector3(data.x, data.y, data.z));
if (path.length <= 1) return;
// 三维样条曲线
const curve3 = new THREE.CatmullRomCurve3([path[path.length - 2], path[path.length - 1]]);
// 路径/沿着轨迹细分数/管道半径/管道截面圆细分数
const geometry = new THREE.TubeGeometry(curve3, 10, 0.05, 10);
// 创建材质对象
const material = new THREE.MeshBasicMaterial({ color: 0x00FF00 });
// 创建网格模型
const mesh = new THREE.Mesh(geometry, material);
mesh.sxl = "sxl";
// 将图形对象配置到点模型对象上
scene.add(mesh);
},
/* 根据设备的位置和朝向信息设置视角 */
setCatmull(position, orientation) {
// 设置相机位置
camera.position.set(position.x, position.y, position.z);
// 设置相机朝向(指向的场景对象)
camera.lookAt(new THREE.Vector3(orientation.x, orientation.y, orientation.z));
},
/* 接受app的消息 */
uniEvent(data) {
this.btmShow = false;
let da = JSON.parse(data);
/* 设备名称/语言/内存/电量 */
if (da.name) {
this.name = da.name;
this.lang = da.lang;
this.nc = da.nc;
this.dl = da.dl;
};
/* 视角 */
if (da.orientation && da.position && this.isCatmull) this.setCatmull(da.position, da.orientation);
/* 轨迹 */
if (da.position != null && da.position != {}) {
da.position.x *= 1;
da.position.y *= 1;
da.position.z *= 1;
this.createCatmullRomCurve3(da.position);
}
/* 点云数据 */
if (da.data) {
let { sxl, colors } = this.setData(da.data);
this.createBufferGeometry(sxl, colors);
}
},
/* 格式化数据 */
setData(data) {
let sxl = [], colors = [];
data.forEach((item) => {
sxl.push(item.x);
sxl.push(item.y);
sxl.push(item.z);
/* 根据强度生成颜色 */
let rgb = hslToRgb((240 - item.i) / 330, 1, 0.5);
colors.push(rgb.r);
colors.push(rgb.g);
colors.push(rgb.b);
});
return { sxl, colors }
},
/* 向app传递消息 */
postMessage(type) {
uni.postMessage({ data: { type } });
},
/* 退出 */
esc() {
this.showModel = false;
this.postMessage(1);
},
/* 进度变化 */
onPercentChange(e) {
// this.isCatmull = false;
/* 当前画面上传存在的points */
let se = scene.children.filter((item) => item.type == "Points");
let asas = parseInt(se.length * (e / 100));
se.forEach((item, index) => item.visible = (index <= asas));
this.render();
},
},
created() {
let rem = (window.innerWidth / 390) * 100;
document.querySelector("html").style.fontSize = `${rem}px`;
window.uniEvent = this.uniEvent;
},
watch: {
type: function (val) {
if (val == 1) {
camera.position.set(0.03222047045112021, -0.020101109662445632, 20.518249384064756);
camera.lookAt(new THREE.Vector3(-0.0015703296445703431, 0.000979668141083902, -0.9999982871561036));
this.render();
}
if (val == 2) {
camera.position.set(0, -14, 15);
camera.lookAt(new THREE.Vector3(0, 0, 0));
this.render();
}
}
},
}
</script>
<style lang="less">
* {
margin: 0;
padding: 0;
}
body {
font-size: 14px;
width: 100vw;
height: 100vh;
overflow: hidden;
}
.warp {
background-color: black;
}
.top {
position: fixed;
width: 100vw;
left: 0;
top: 0.67rem;
padding: 0 0.2rem;
display: flex;
justify-content: space-between;
align-items: center;
color: #fff;
box-sizing: border-box;
}
.btm {
width: 100vw;
box-sizing: border-box;
display: flex;
justify-content: space-between;
color: #fff;
padding: 0 0.2rem;
position: fixed;
left: 0;
bottom: 5%;
li {
display: flex;
background-color: #323232;
border-radius: 0.08rem;
line-height: 0.4rem;
padding: 0 0.1rem;
white-space: nowrap;
img {
margin-right: 0.06rem;
}
&.active {
background-color: #FF9800;
}
}
}
/* 启动/关闭按钮 */
.btn {
position: fixed;
left: 50%;
bottom: 15%;
transform: translateX(-50%);
width: 0.94rem;
height: 0.94rem;
display: flex;
justify-content: center;
align-items: center;
background-color: rgba(164, 240, 189, 0.2);
border-radius: 50%;
div {
width: 0.78rem;
height: 0.78rem;
background: linear-gradient(180deg, #67D98D 0%, #41C63B 100%);
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
color: #fff;
font-size: 0.2rem;
}
}
/* 弹窗 */
.model {
position: fixed;
left: 50%;
top: 40%;
margin-left: -1.5rem;
background-color: #fff;
border-radius: 0.2rem;
width: 3rem;
padding: 0.2rem 0;
text-align: center;
h3 {
font-size: 0.2rem;
}
p {
padding: 0.16rem 0 0.35rem;
}
.btns {
display: flex;
justify-content: center;
.btnn {
border-radius: 0.08rem;
background-color: #E2E2E2;
line-height: 0.3rem;
width: 0.8rem;
&+.btnn {
background: linear-gradient(270deg, #FF9800 0%, #FEAB31 100%);
margin-left: 0.2rem;
color: #fff;
}
}
}
}
/* vue transition */
.v-enter-active,
.v-leave-active {
transition: opacity 0.5s ease, transform 0.5s ease;
}
.v-enter-from,
.v-leave-to {
opacity: 0;
transform: scale(0);
}
/* 步进器主体 */
#jd {
position: fixed;
top: 50%;
transform: translateY(-50%);
z-index: 999;
transition: all 0.3s;
}
/* btmm */
.btmm {
width: 100%;
height: 0.08rem;
background: linear-gradient(180deg, #67D98D 0%, #41C63B 100%);
position: fixed;
bottom: 0;
left: 0;
}
</style>