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

2024-04-29 16:20

本文主要是介绍Three.js杂记(十四)———— 汽车展览·上,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

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

  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种动画效果,之后再进行播放和切换了。

未完待续…

在这里插入图片描述

这篇关于Three.js杂记(十四)———— 汽车展览·上的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/946576

相关文章

Node.js 中 http 模块的深度剖析与实战应用小结

《Node.js中http模块的深度剖析与实战应用小结》本文详细介绍了Node.js中的http模块,从创建HTTP服务器、处理请求与响应,到获取请求参数,每个环节都通过代码示例进行解析,旨在帮... 目录Node.js 中 http 模块的深度剖析与实战应用一、引言二、创建 HTTP 服务器:基石搭建(一

使用Vue.js报错:ReferenceError: “Vue is not defined“ 的原因与解决方案

《使用Vue.js报错:ReferenceError:“Vueisnotdefined“的原因与解决方案》在前端开发中,ReferenceError:Vueisnotdefined是一个常见... 目录一、错误描述二、错误成因分析三、解决方案1. 检查 vue.js 的引入方式2. 验证 npm 安装3.

JS常用组件收集

收集了一些平时遇到的前端比较优秀的组件,方便以后开发的时候查找!!! 函数工具: Lodash 页面固定: stickUp、jQuery.Pin 轮播: unslider、swiper 开关: switch 复选框: icheck 气泡: grumble 隐藏元素: Headroom

【专题】2024飞行汽车技术全景报告合集PDF分享(附原数据表)

原文链接: https://tecdat.cn/?p=37628 6月16日,小鹏汇天旅航者X2在北京大兴国际机场临空经济区完成首飞,这也是小鹏汇天的产品在京津冀地区进行的首次飞行。小鹏汇天方面还表示,公司准备量产,并计划今年四季度开启预售小鹏汇天分体式飞行汽车,探索分体式飞行汽车城际通勤。阅读原文,获取专题报告合集全文,解锁文末271份飞行汽车相关行业研究报告。 据悉,业内人士对飞行汽车行业

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)

Node.js学习记录(二)

目录 一、express 1、初识express 2、安装express 3、创建并启动web服务器 4、监听 GET&POST 请求、响应内容给客户端 5、获取URL中携带的查询参数 6、获取URL中动态参数 7、静态资源托管 二、工具nodemon 三、express路由 1、express中路由 2、路由的匹配 3、路由模块化 4、路由模块添加前缀 四、中间件

EasyPlayer.js网页H5 Web js播放器能力合集

最近遇到一个需求,要求做一款播放器,发现能力上跟EasyPlayer.js基本一致,满足要求: 需求 功性能 分类 需求描述 功能 预览 分屏模式 单分屏(单屏/全屏) 多分屏(2*2) 多分屏(3*3) 多分屏(4*4) 播放控制 播放(单个或全部) 暂停(暂停时展示最后一帧画面) 停止(单个或全部) 声音控制(开关/音量调节) 主辅码流切换 辅助功能 屏

使用JS/Jquery获得父窗口的几个方法(笔记)

<pre name="code" class="javascript">取父窗口的元素方法:$(selector, window.parent.document);那么你取父窗口的父窗口的元素就可以用:$(selector, window.parent.parent.document);如题: $(selector, window.top.document);//获得顶级窗口里面的元素 $(

js异步提交form表单的解决方案

1.定义异步提交表单的方法 (通用方法) /*** 异步提交form表单* @param options {form:form表单元素,success:执行成功后处理函数}* <span style="color:#ff0000;"><strong>@注意 后台接收参数要解码否则中文会导致乱码 如:URLDecoder.decode(param,"UTF-8")</strong></span>

js react 笔记 2

起因, 目的: 记录一些 js, react, css 1. 生成一个随机的 uuid // 需要先安装 crypto 模块const { randomUUID } = require('crypto');const uuid = randomUUID();console.log(uuid); // 输出类似 '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'