Three.js杂记(十四)———— 汽车展览·上

embedded/2024/12/23 6:56:39/

在学习了一些理论知识后,要做一下实战演练了,做一个简单的车辆展览来看看吧。

通过调整相机的位置,将导入的车辆模型分成三个视角展示。

  1. 车辆外部:可以观察车辆的整体外观以及轮廓结构
  2. 车辆内部:相机在汽车内部,可以改变相机焦点位置观察车辆内部情况

首先根据需求,先要有一辆汽车。我的素材是从爱给网上找到的,3D模型的类型是gltf格式,并且携带了3种动画效果。

在这里插入图片描述


创建场景和导入素材

场景的创建比较简单,具体可以参考上一篇文章 Three.js杂记(十三)—— 包围盒。里面对render渲染器、scene场景、camera相机等元素创建都有写过,并且对GLTFLoader3D模型导入也有过介绍,所以具体代码和流程就不再复述了。

为了界面更好区分,我将scene.background的颜色设置为了#ccc

scene.background = new THREE.Color("#ccc");

导入模型后:
在这里插入图片描述


设置光源和地面

当前模型是黑色的,因为我并没有设置环境贴图或者光线。

接下来设置光源,我使用了点光源PointLight,从5个不同方向对车辆进行照射。因为5个点光源,所以使用Group组的形式放到了一起。

// 添加灯光组
const lightGroup = new THREE.Group();
let lightDir = [[3, 0.5, 0],[-3, 0.5, 0],[0, 0.5, 3],[0, 0.5, -3],[0, 3, 0],
]
for(let i = 0; i < lightDir.length; i++) {let light1 = new THREE.PointLight(0xffffff, 10);light1.position.set(...lightDir[i]);lightGroup.add(light1);
}
scene.add(lightGroup);

当前拥有光源后效果:

在这里插入图片描述

为了更好的呈现,我在车辆下方添加了一块平面几何体PlaneGeometry,使用的材质是MeshStandardMaterial。对几何体进行绕x轴旋转。

// 制作地面
const floorGeometry = new THREE.PlaneGeometry(10, 10);
const floorMaterial = new THREE.MeshStandardMaterial({ color: '#fff' });
let floor = new THREE.Mesh(floorGeometry, floorMaterial);
floor.material.opacity = 0.5;
floor.rotateX(-Math.PI / 2);
floor.position.y = 0;
scene.add(floor);

当前车辆展示就看起来很有科技感了

在这里插入图片描述


内外切换面板

接下来准备一块面板,面板上添加外部和内部三种选项。

面板使用div元素制作,通过绝对定位放在界面右上角。

在这里插入图片描述

然后设置点击方法,对相机位置进行调整

这里我使用了Tween补间动画,然后在animtion中需要添加补间动画的update方法

import { update as TweenUpdate } from 'three/examples/jsm/libs/tween.module';
// ...
// 面板上数据
const cGUI = ref({cameraPos: [{ name: '车辆外部', pos: [-3, 3, 3] },{ name: '车辆内部', pos: [0, 0.8, 0] },]
})
// 切换相机视角方法
const changeCameraPos = (pos: number[]) => {// 创建补间对象const tween = new Tween(camera.position);tween.to({ x: pos[0],y: pos[1],z: pos[2]}, 1000).start();
}
// ...
function animate() {TweenUpdate(); //更新动画controls.update(); //鼠标控制render.render(scene, camera);window.requestAnimationFrame(animate);
}

这样一来,点击切换相机位置改变时,就可以比较流畅的看见过程。
以下是效果:

在这里插入图片描述


相机位置和视角

现在场景内已经使用了OrbitControls去用鼠标拖动改变相机位置。并且为了后续效果,我禁用了缩放功能

const controls = new OrbitControls(camera, render.domElement);  
controls.enableZoom = false;

但是,此功能在车辆内部就不适用了,改变相机位置会导致穿模。在车辆内部需要的是改变相机焦点lookAt ,保持相机的位置不动。

这里我是根据点击方法中相机位置,设置inOut属性判断内外。

// 切换相机视角方法
const changeCameraPos = (pos: number[]) => {if (Math.abs(pos[0]) < 1){inOut = true;  // 在车辆内部controls.enableRotate =false; // 禁止旋转} else {inOut = false;  // 在车辆外部controls.enableRotate = true; // 允许旋转}// ......
}

此时,在animation动画中,也需要进行判断处理:

function animate() {// ...if (!inOut) {controls.update(); //鼠标控制}// ...
}

将这些设置完成后,车辆外部能正常观察汽车,但是内部移动不动,此时就需要绑定鼠标按下移动释放等事件了。

通过这些事件中鼠标的位置,去设置camera相机的焦点位置。此处我参考了:three.js笔记5–添加鼠标移动视角 | Here. There. (godbasin.github.io)

原理也很明了:相当于以相机固定不动位置作为顶点,然后用焦点画一个圆环

在这里插入图片描述

代码:

// 定义角度
var theta = 0;
// 初始化鼠标X方向移动值
var mouseX = 0;
var r = 1000 / (2* Math.PI); // 用于角度计算: 鼠标移动1000px时,角度改变2PI
var far = 100; // 用于照相机焦点设置(焦点距离,越大越精确)
var move = 0.1; // 用于步长(照相机移动距离)
var mousedownFlag = false; // 鼠标是否按下
var inOut = false;
// 添加鼠标移动时事件
document.addEventListener('mousemove', handleMousemove, false);
// 添加鼠标页面点击释放
document.addEventListener('mousedown', initMousePosition, false);
document.addEventListener('mouseup', ()=>{ mousedownFlag = false; }, false);
// 初始化鼠标移动值
function initMousePosition(e:any) {if (!inOut) return ;mousedownFlag = inOut;mouseX = getMousePos(e || window.event).x;
}
// 获取鼠标坐标,传入事件event
function getMousePos(event: any) {var e = event || window.event;var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;var scrollY = document.documentElement.scrollTop || document.body.scrollTop;var x = e.pageX || e.clientX + scrollX;var y = e.pageY || e.clientY + scrollY;return { 'x': x, 'y': y };
}// 处理鼠标移动
function handleMousemove(e: any) {if (!mousedownFlag) return ;var e = e || window.event;// 获取鼠标x坐标var newMouseX = getMousePos(e).x;// 若值无效,更新坐标然后返回if (Number.isNaN((newMouseX - mouseX) / r)) { mouseX = newMouseX; return; }// 更新视角以及坐标位置theta += (newMouseX - mouseX) / r;mouseX = newMouseX;// 更新照相机焦点renderCameraLookat();
}
// 更新照相机焦点
function renderCameraLookat() {camera.lookAt(new THREE.Vector3(camera.position.x + far * Math.sin(theta), 1, camera.position.z + far * Math.cos(theta)));
}

因为上述代码已经在mousemove的过程中修改了相机的焦点位置,所以不需要在animation方法中再去添加。

当前切换到汽车内部,可以拖动旋转相机,对车内情况进行观察了

在这里插入图片描述


后续

PS: 这里对于ThreeJs的性能消耗还是要提一下的,主要是使用GPU进行处理图形,但是这次突然是我的CPU爆炸,排查原因可能是浏览器设置导致,然后我通过Edgeedge://flags/设置GPU。
![[t10.png]]
并且我的笔记本有GPU0和GPU1,是双显。去Nvidia中进行了设置,具体可参考:Win10笔记本双显卡怎么切换 在哪里设置独立显卡-百度经验 (baidu.com)

后续此汽车模型还有3种动画效果,之后再进行播放和切换了。

未完待续…

在这里插入图片描述


http://www.ppmy.cn/embedded/25469.html

相关文章

DataV的轮播表后端返回的数据处理

由于官网上DataV的轮播表的接收data格式为: export default {data: [[行1列1, 行1列2, 行1列3],[行2列1, 行2列2, 行2列3],[行3列1, 行3列2, 行3列3],[行4列1, 行4列2, 行4列3],[行5列1, 行5列2, 行5列3],[行6列1, 行6列2, 行6列3],[行7列1, 行7列2, 行7列3],[行8列1, 行8列2,…

现代机器学习(ML)技术在医疗成像领域的新应用

现代机器学习(ML)技术在医疗成像领域的新应用主要包括以下几个方面: 一、自动病变检测 使用深度学习算法,尤其是卷积神经网络(CNN),自动识别和分类医学影像中的病变,如肿瘤、炎症等。自动病变检测是现代机器学习技术在医疗成像领域应用的一个重要方向。它主要通过以下…

使用 Docker 自建一款怀旧游戏之 - 扫雷

1&#xff09;扫雷 简介 扫雷 是一种经典的单人电脑游戏&#xff0c;最初由微软公司在 1990 年代开发并内置在 Windows 操作系统中。游戏的目标是在一个由方块组成的网格上揭开所有非地雷的方块&#xff0c;而不触发地雷。每个方块上都标有数字&#xff0c;表示周围 8 个方块中…

Python urllib 爬虫入门(1)

本文主要为Python urllib类库函数和属性介绍及一些简单示例。 目录 urllib爬取网页 简单示例 写入文件 其他读取方法 readline函数 readlines函数 response属性 当前环境信息 返回状态码 返回url地址 对url进行编码与解码 写入文件 总结 urllib爬取网页 通过pyth…

混合A* 中基于 Voronoi 势场的路径代价和 Voronoi 势场的实现测试

参考 Practical Search Techniques in Path Planning for Autonomous Driving 混合 A* 论文 Sensor-Based Exploration: The Hierarchical Generalized Voronoi Graph Voronoi 图论文 认识 Voronoi &#xff0c;泰森多边形 voronoi 介绍和应用 Voronoi Field 和 Voronoi Dia…

【数据结构】顺序表专题

前言 本篇文章我们来进行有关顺序表的专题训练&#xff0c;让我们一起来看一下有关顺序表的算法题 &#x1f493; 个人主页&#xff1a;小张同学zkf ⏩ 文章专栏&#xff1a;数据结构 &#x1f4dd;若有问题 评论区见 &#x1f389;欢迎大家点赞&#x1f44d;收藏⭐文章 1.移除…

修改后门ctime | Linux 后门系列

0x00 前情提要 在 alias 后门 &#xff5c; Linux 后门系列一文中&#xff0c;我们为了让后门完美一些&#xff0c;修改了后门文件的 atime、mtime&#xff0c;但是 ctime 一直没有办法修改&#xff0c;今天我们来把这一块补齐&#xff0c;让后门更加完美 atime -> access t…

golang反射

go反射 反射基本介绍应用场景基本使用结构体注意练习最佳实践遍历结构体的方法&#xff0c;调用接头体的方法&#xff0c;获取结构体的标签 反射 基本介绍 反射可以在运行时动态获取变量的各种信息&#xff0c;比如变量的类型(type)、类别(kind)如果是结构体变量&#xff0c;…