Threejs项目实战之一:汽车外观换肤效果三维展示

目录

  • 最终效果
  • 1 创建项目
  • 2 安装插件
  • 3 编写代码
    • 3.1 准备工作
    • 3.2 代码编写
      • 3.2.1 在template标签中构建html页面
      • 3.2.2 在style标签中构建页面样式文件
      • 3.2.3 在script标签中编写js代码

最终效果

先看下最终实现的效果
在这里插入图片描述
接下来,我们就从创建项目开始,一步一步实现这个效果

1 创建项目

  • D盘Project文件夹下新建一个文件夹vite-vue-bmw,鼠标右键点击新建的文件夹,使用vscode打开
  • 在vscode中使用快捷键Ctrl+Shift+~打开终端,在终端中使用vite构建工具创建项目,输入pnpm create vite bmw-app --template vue创建项目
  • 创建成功后,在终端中输入cd bmw-app进入文件夹
  • 输入pnpm i 安装依赖包
  • 安装完成后,输入pnpm run div 启动项目,打开浏览器,可以看到系统默认的页面,说明项目环境搭建成功
    在这里插入图片描述

2 安装插件

在控制终端中输入pnpm i three安装threejs插件,安装完成后,我们可以通过在App.vue中使用import引入threejs,然后通过控制台打印的方式验证threejs是否安装成功
引用代码如下:在script标签中添加如下代码

<script setup> 
import * as THREE from 'three'//导入three.js核心库
console.log(THREE) 
</script>

刷新浏览器,打开开发者工具,可以看到控制台已经输出了Module对象,说明threejs已经正确安装,可以在项目中使用了
在这里插入图片描述

3 编写代码

3.1 准备工作

  • 删除vite构建工具为我们自动创建的代码,清空App.vue中的style标签样式
  • 清空style.css中的样式,设置如下像素
    *{margin: 0;padding: 0;list-style: none;
    }
    
  • 删除vite构建工具为我们创建的components文件夹下的HelloWorld.vue文件

3.2 代码编写

3.2.1 在template标签中构建html页面

  • 在components文件夹下新建CarView.vue文件
  • 在CarView.vue文件的template标签中创建HTML标签,构建HTML页面
  • 在template标签中创建一个div,设置id为scene,作为threejs的容器
    <template>
    <div id="scene"></div>
    </template>
    
  • 创建5个div标签,作为车辆颜色选择的按钮使用,代码如下
    <template><div id="scene"></div><div class="car-color"><div class="color1"><div class="color-white" @click="setCarColor('#c0c0c0')"> </div><span>亮银色</span></div><div class="color1"><div class="color-blank" @click="setCarColor('#222')"> </div><span>星际黑</span></div><div class="color1"><div class="color-red" @click="setCarColor('#ff0000')"> </div><span>中国红</span></div><div class="color1"><div class="color-green" @click="setCarColor('#9dc209')"> </div><span>苹果绿</span></div><div class="color1"><div class="color-blue" @click="setCarColor('#2443e2')"> </div><span>雪邦蓝</span></div> </div>
    </template>
    

在template标签中定义了5中颜色,使用一个div设置外观样式为圆形显示,在其下方添加一个span标签,显示该颜色的名称,同时在圆形div上绑定click事件,调用setCarColor函数,并将该div的颜色代码作为参数传递给setCarColor函数。

3.2.2 在style标签中构建页面样式文件

这里不多说,不理解的小伙伴赶紧去补下CSS的相关知识,代码如下

<style scoped>
.car-color {/* 设置这个div居中显示 */margin: 0 auto;position:fixed; bottom: 50px;left: 30%;width: 40%;height: 100px;display: flex; justify-content:space-around;align-items: center;
}
.color1 { display: flex;flex-direction: column;justify-content: center;align-items: center;
}.color1 div {width: 80px;height: 80px;border-radius: 80px;cursor: pointer;box-shadow: 0px 10px 20px rgba(0, 0, 0, 0.3); 
}
.color-white { background-color: #c0c0c0; 
}
.color-blank { background-color: #222; 
}
.color-red { background-color: #FF0000; 
}
.color-green { background-color: #9dc209; 
}
.color-blue { background-color: #2443e2; 
}
span{margin-top: 5px;
}
</style>

3.2.3 在script标签中编写js代码

  • 在script标签中引入threejs
    import * as THREE from 'three'
  • 这里我们选择的车辆模型是gltf格式的文件,因此,我们需要引入threejs为我们提供的GLTFLoader加载器
    import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
  • 由于我们需要对车辆进行鼠标旋转缩放控制,因此我们需要引入threejs为我们提供的OrbitControls控制器
    import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
  • 引入vue的生命周期onMounted
    import { onMounted } from 'vue'
  • 创建一个init函数,用于初始化threejs设置
    const init = () => {}
  • 在init函数中创建场景,并设置场景的背景颜色
      // 初始化场景const scene = new THREE.Scene()// 设置场景背景色为白色scene.background = new THREE.Color(0xcccccc)  scene.environment = new THREE.Color(0xcccccc);
    
  • 在场景中添加地面
    // 在场景中添加地面const floorGeometry = new THREE.PlaneGeometry(20, 20)const material = new THREE.MeshPhysicalMaterial({side: THREE.DoubleSide,color: 0xffffff,metalness: 0,roughness: 0.1})// 设置地面透明material.transparent = falseconst floorMesh = new THREE.Mesh(floorGeometry, material)floorMesh.rotation.x = Math.PI / 2 floorMesh.position.setY(-0.385)scene.add(floorMesh) 
    
  • 创建相机,并设置相机位置
    const camera = new THREE.PerspectiveCamera(20,window.innerWidth / window.innerHeight,0.1,100)camera.position.set(9.5,0.5,0.5)  
    
  • 创建环境光、自然光、聚光灯等光照效果
    // 设置环境光scene.add(new THREE.AmbientLight(0xffffff, 0.5))	// 添加球光源const hesLight = new THREE.HemisphereLight(0xffffff,0x444444)hesLight.intensity = 0.6scene.add(hesLight)// 自然光const dirLight = new THREE.DirectionalLight()dirLight.position.set(0,0,15)scene.add(dirLight)const dirLight2 = new THREE.DirectionalLight()dirLight2.position.set(0,0,-15)scene.add(dirLight2)const dirLight3 = new THREE.DirectionalLight()dirLight3.position.set(15,0,0)scene.add(dirLight3)const dirLight4 = new THREE.DirectionalLight()dirLight4.position.set(-15,0,0)scene.add(dirLight4)const dirLight5 = new THREE.DirectionalLight()dirLight5.position.set(0,15,0)scene.add(dirLight5)const dirLight6 = new THREE.DirectionalLight()dirLight6.position.set(0,-15,0)scene.add(dirLight6)const dirLight7 = new THREE.DirectionalLight()dirLight7.position.set(5,15,5)scene.add(dirLight7)const dirLight8 = new THREE.DirectionalLight()dirLight8.position.set(-5,-15,-5)scene.add(dirLight8)// 聚光灯const sportLight = new THREE.SpotLight(0xffffff,0.8)sportLight.angle = Math.PI / 8; //散射角度,跟水平线的夹角sportLight.penumbra = 0.1;  // 聚光锥的半影衰减百分比sportLight.decay = 2; // 纵向:沿着光照距离的衰减量。sportLight.distance = 10;sportLight.shadow.radius = 10;// 阴影映射宽度,阴影映射高度 sportLight.shadow.mapSize.set(512, 512); sportLight.position.set(0, 15, 0);// 光照射的方向sportLight.target.position.set(0, 0, 0);sportLight.castShadow = true; scene.add(sportLight);
    
  • 使用GLTFLoader加载glb模型
    // 使用GLTFLoader加载glb模型const loader = new GLTFLoader() loader.load('/model/scene.gltf', //加载模型的url地址(gltf) => {let model = gltf.scene  model.traverse(obj => {if (obj.isMesh) {// console.log(obj) } if (obj.isMesh && obj.name.includes('glass')) {obj.material = glassMaterial} else if (obj.isMesh && obj.name.includes('carpaint') ) {obj.material = bodyMaterial} else if (obj.isMesh && obj.name.includes('rim')){// 更换轮毂obj.material = rimMaterial} else if (obj.isMesh && obj.name.includes('chrome')){} else if (obj.isMesh && obj.name.includes('tire')){// console.log(obj) } else if (obj.isMesh && obj.name.includes('Material')){// console.log(obj) } else if (obj.isMesh && obj.name.includes('brakedisk')){// 刹车盘// console.log(obj) }else if (obj.isMesh && obj.name.includes('black')){ // 车架// console.log(obj) }else if (obj.isMesh && obj.name.includes('mattemetal')){ // console.log(obj) }else if (obj.isMesh && obj.name.includes('mirror')){ // console.log(obj) }else if (obj.isMesh && obj.name.includes('interior')){ // 车辆内部// console.log(obj) }else if (obj.isMesh && obj.name.includes('white')){ // BMW车标白色// console.log(obj) }else if (obj.isMesh && obj.name.includes('blue')){ // BMW车标蓝色// console.log(obj) }else if (obj.isMesh && obj.name.includes('RootNode')){ // BMW车标蓝色// console.log(obj)  } else {// console.log(obj) }}) toSceneCenter(model) scene.add(model)},undefined,(error) => console.error(error))   // 设置物体的位置为坐标原点(0,0,0)function toSceneCenter(object) {object.position.set(0, -0.28, 0)}// 添加物体阴影scene.traverse(function (child) {if (child instanceof THREE.Mesh) child.castShadow = true;});
    
  • 创建渲染器
    // 创建渲染器const renderer = new THREE.WebGLRenderer({antialias:true})//设置抗锯齿 //设置屏幕像素比renderer.setPixelRatio(window.devicePixelRatio)//解决加载gltf格式模型纹理贴图和原图不一样问题renderer.outputColorSpace  = THREE.SRGBColorSpace renderer.setSize(window.innerWidth, window.innerHeight)document.getElementById('scene').appendChild(renderer.domElement)
    
  • 添加控制器
    // 添加控制器const controls = new OrbitControls(camera, renderer.domElement)controls.enableDamping = truecontrols.dampingFactor = 0.25controls.enableZoom = truecontrols.maxDistance = 9controls.minDistance = 6controls.minPolarAngle = 0controls.maxPolarAngle = 60 / 360 * 2 * Math.PI
    
  • 渲染循环
    // 渲染循环const animate = function () {controls.update()requestAnimationFrame(animate)renderer.render(scene, camera)}animate()
    
  • 要修改车辆外观颜色,我们需要先定义车辆材质,这里我们定义三个材质,分别是车辆的金属材质、玻璃材质和轮毂材质
  • 定义金属材质
    // 金属材质
    let bodyMaterial = new THREE.MeshPhysicalMaterial({color: "#c0c0c0", metalness: 1, roughness: 0.5, clearcoat: 1.0,  clearcoatRoughness: 0.03,   
    })
    
  • 定义玻璃材质
    // 玻璃材质
    let glassMaterial = new THREE.MeshPhysicalMaterial({color: "#ffffff",metalness: 0.25,roughness: 0,transparent: true,transmission: 1.0 
    });
    
  • 定义轮毂材质
    // 轮毂材质
    const rimMaterial = new THREE.MeshPhysicalMaterial({color: "#ffffff",metalness: 1,roughness: 0.5,clearcoat: 1.0, clearcoatRoughness: 0.03
    })
    
  • 设置鼠标点击事件
    const setCarColor = val => {bodyMaterial.color.set(val)
    }
    
  • 在App.vue中引入CarView.vue组件,并在template标签中调用CarView
    <template><CarView></CarView>
    </template>
    <script setup>
    import CarView from './components/CarView.vue';
    </script>
    <style scoped>
    </style>
    

设置完成后,刷新浏览器,看效果如下:
在这里插入图片描述
点选下方圆形的颜色div,可以看到车辆颜色跟着进行改变,鼠标左键点选车辆并上下左右移动可以旋转车辆。通过鼠标滚轮可以放大缩小车辆。
最终实现的效果如下
在这里插入图片描述
至此,我们给车辆换肤的效果已经完成了,由于是项目实战,涉及到vue和threejs中基础的知识就不过细讲解了,不了解的小伙伴可以看我之前的博客,里面涉及的内容之前都有讲到过。
ok,我们threejs项目实战的第一个项目就实现了,小伙伴们有疑问的评论区留言,喜欢的小伙伴点赞关注+收藏哦!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

自主并不等于智能

自主不等于智能&#xff0c;也不是自动化的简单升级。自主性和智能性是两个不同的概念。自主性指物体或系统具有独立决策和行动的能力&#xff0c;不需要人为干预。而智能性指物体或系统具有类似人类的智慧、学习和适应能力。 虽然自主性通常与智能性相关&#xff0c;但并非所有…

李宏毅bert记录

一、自监督学习&#xff08;Self-supervised Learning&#xff09; 在监督学习中&#xff0c;模型的输入为x&#xff0c;若期望输出是y&#xff0c;则在训练的时候需要给模型的期望输出y以判断其误差——有输入和输出标签才能训练监督学习的模型。 自监督学习在没有标注的训练…

【后端】JVM 远程调试

前言 再好的代码,也还是有瑕疵的,不是代码不给力,是线上问题太牛逼太玄幻。这不刚部署就出现了问题,幸好还是测试的时候,早点发现早点解决,不给任何人带来不必要的损失,是我做人的原则,只要钱到位,任何问题都不是问题。 JVM 远程调试 不得不说 IDEA 和 宝塔配合是真…

工厂方法设计模式项目实践

前言 以采集数据处理逻辑为例&#xff0c;数据采集分为不同种类如&#xff1a;MQTT、MODBUS、HTTP等&#xff0c;不同的采集数据有不同的解析处理逻辑。但总体解析处理步骤是固定的。可以使用工厂方法设计模式简化代码&#xff0c;让代码变得更加优雅。 代码实战 抽象类 总体…

gpt3、gpt2与gpt1区别

参考&#xff1a;深度学习&#xff1a;GPT1、GPT2、GPT-3_HanZee的博客-CSDN博客 Zero-shot Learning / One-shot Learning-CSDN博客 Zero-shot&#xff08;零次学习&#xff09;简介-CSDN博客 GPT-2 模型由多层单向transformer的解码器部分构成&#xff0c;本质上是自回归模型…

10_企业架构NOSQL数据库之MongoDB

企业架构NOSQL数据库之MongoDB 学习目标和内容 1、能够简单描述MongoDB的使用特点 2、能够安装配置启动MongoDB 3、能够使用命令行客户端简单操作MongoDB 4、能够实现基本的数据操作 5、能够实现MongoDB基本安全设置 6、能够操作安装php的MongoDB扩展 一、背景描述及其方案设计…

springcloud alibaba-Sentinel

文章目录 一.前置知识1.雪崩问题2.服务保护技术对比 二.Sentinel三.微服务整合Sentinel1.限流规则1.流控模式2.流控效果热点参数限流(更细粒度的限流方式) 2.隔离和降级Feign整合Sentinel1.线程隔离2.熔断降级 3.授权规则4.规则持久化 一.前置知识 1.雪崩问题 设想一下以下场…

【C语言】用户空间使用非缓存内存

在用户空间使用非缓存内存通常不是标准做法&#xff0c;因为非缓存内存的操作与硬件平台紧密相关&#xff0c;并且通常被保留给内核模块或设备驱动程序使用。 一、方法 用户空间程序一般不直接处理非缓存内存问题&#xff0c;因为它们依赖于操作系统来管理内存缓存一致性。尽…

C++使用策略模式,减少使用switch...case...

目录 原理函数类模板函数使用switch...case...不使用switch...case... 知识点decltypestd::remove_reference 原理 函数 #include <iostream> #include <functional> #include <map>void fun1(int a, int b) {std::cout << "fun1 : a "<…

鸿蒙Harmony ArkUI十大开源项目

一 OH哔哩 https://gitee.com/ohos_port/ohbili 项目简介 【OH哔哩】是一款基于OpenHarmony系统ArkUI框架开发的哔哩哔哩动画第三方客户端 用到的三方库 bilibili-API-collect 哔哩哔哩-API收集整理ohos_ijkplayer 基于FFmpeg的视频播放器PullToRefresh 下拉刷新、上拉加载组件…

【FPGA图像处理实战】- 图像处理前景如何?就业前景如何?

图像处理是FPGA应用的主要领域之一&#xff0c;图像处理数据量特别大且对实时性处理要求高的场景&#xff0c;这恰好能发挥FPGA流水线可实时处理的优势。 那么FPGA图像处理的前景如何&#xff1f; 一、FPGA开发&#xff08;图像处理&#xff09;招聘就业情况 看FPGA图像处理…

ELK 日志解决方案

ELK 是目前最流行的集中式日志解决方案&#xff0c;提供了对日志收集、存储、展示等一站式的解决方案。 ELK 分别指 Elasticsearch、Logstash、Kibana。 Elasticsearch&#xff1a;分布式数据搜索引擎&#xff0c;基于 Apache Lucene 实现&#xff0c;可集群&#xff0c;提供…

B 站基于 StarRocks 构建大数据元仓

作者&#xff1a;bilibili 大数据高级开发工程师 杨洋 B站大数据元仓是一款用来观测大数据引擎运行情况、推动大作业治理的系统诊断产品。经过调研和性能测试&#xff0c;大数据元仓最终以 StarRocks 为技术底座&#xff0c;从实际的应用效果来看&#xff0c;大部分查询都能在几…

Stm32_串口的帧(不定长)数据接收

目录标题 前言1、串口中断接收固定帧头帧尾数据1.1、任务需求1.2、实现思路1.3、程序源码&#xff1a; 2、串口中断接收用定时器来判断帧结束3、串口中断接收数据空闲中断3.1、串口的空闲中断3.2、实现思路3.3、程序源码 4、串口的空闲中断DMA转运4.1、DMA简介4.2、DMA模式4.3、…

AHB 与 DMA

AHB&#xff08;先进高性能总线&#xff09; 随着深亚微米工艺技术日益成熟&#xff0c;集成电路芯片的规模越来越大。数字IC从基于时序驱动的设计方法&#xff0c;发展到基于IP核复用的设计方法&#xff0c;并在SOC设计中得到了广泛应用。在基于IP核复用的SoC&#xff08;Syst…

【BME2112】w11 notes

下周做老鼠实验 group analysis SPM group analysis 数据地址resting state 可以分析&#xff1a;correlation 计算两个脑区的相关性 静息态实验简单functional 成功的实验能看到激活区不成功的实验&#xff1a;比如被试头动太大&#xff0c;不是健康的被试 Spontaneous brain…

ALPHA开发板烧录工具MfgTool烧写方法

一. 简介 MfgTool 工具是 NXP 提供的专门用于给 I.MX 系列 CPU 烧写系统的软件&#xff0c;可以在 NXP 官网下载到。运行在windows下。可以烧写uboot.imx、zImage、dtb&#xff0c;rootfs。通过 USB口进行烧写。 上一篇文章简单了解了 ALPHA开发板烧录工具MfgTool。文章地址…

数据结构之交换排序

目录 交换排序 冒泡排序 冒泡排序的时间复杂度 快速排序 快速排序单趟排序的时间复杂度 快速排序的时间复杂度 交换排序 在日常生活中交换排序的使用场景是很多的&#xff0c;比如在学校做早操&#xff0c;老师通常会让学生按大小个排队&#xff0c;如果此时来了一个新学…

MySQL系列(一):索引篇

为什么是B树&#xff1f; 我们推导下&#xff0c;首先看下用哈希表做索引&#xff0c;是否可以满足需求。如果我们用哈希建了索引&#xff0c;那么对于如下这种SQL&#xff0c;通过哈希&#xff0c;可以快速检索出数据&#xff1a; select * from t_user_info where id1;但是这…

ThreadX开源助力Microsoft扩大应用范围:对比亚马逊AWS的策略差异

全球超过120亿台设备正在运行ThreadX&#xff0c;这是一款专为资源受限环境设计的实时操作系统。该操作系统在微控制器和小型处理器上表现出色&#xff0c;以极高的可靠性和精确的时间控制处理任务而闻名。 ThreadX曾是英特尔芯片管理引擎的引擎&#xff0c;并且是控制Raspber…