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 = false
    
      const 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.6
      scene.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 = true
      controls.dampingFactor = 0.25
      controls.enableZoom = true
      controls.maxDistance = 9
      controls.minDistance = 6
    
      controls.minPolarAngle = 0
      controls.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项目实战的第一个项目就实现了,小伙伴们有疑问的评论区留言,喜欢的小伙伴点赞关注+收藏哦!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ChatGPT/GPT4科研实践篇: AI绘图+论文写作+编程

1、熟练掌握ChatGPT提示词技巧及各种应用方法&#xff0c;并成为工作中的助手。 2、通过案例掌握ChatGPT撰写、修改论文及工作报告&#xff0c;提供写作能力及优化工作 3、熟练掌握ChatGPT融合相关插件的应用&#xff0c;完成数据分析、编程以及深度学习等相关科研项目。 4、…

【Windows本地端口占用脚本自动化】

本地启动多个Java微服务&#xff0c;因为停电或者内存回收原因&#xff0c;IDEA直接退出&#xff1b;再次启动各个服务会提示端口占用。 每次都cmd输入命令手动Kill比较繁琐&#xff0c;可以把此脚本放在桌面上作为一个小工具&#xff0c;运行即可。 代码(核心部分是chatGPT自…

k8s中的Pod网络;Service网络;网络插件Calico

Pod网络&#xff1b;Service网络&#xff1b;网络插件Calico Pod网络 在K8S集群里&#xff0c;多个节点上的Pod相互通信&#xff0c;要通过网络插件来完成&#xff0c;比如Calico网络插件。 使用kubeadm初始化K8S集群时&#xff0c;有指定一个参数–pod-network-cidr10.18.0…

【react】动态页面转换成html文件下载,解决样式问题

需求 今天遇到一个需求&#xff0c;挺恶心人的&#xff0c;将一个在线文档页面&#xff0c;可以导出成为html页面查看。 看到网上有使用fs模块&#xff0c;通过react的ReactDOMServer.renderToStaticMarkup将组件转成html字符串&#xff0c;输出文件了。 但是我尝试了&#x…

返回列表中满足指定条件的连续元素:只返回第一个不符合条件元素之前的各元素itertools.takewhile()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 返回列表中满足指定条件的连续元素&#xff1a; 只返回第一个不符合条件元素之前的各元素 itertools.takewhile() [太阳]选择题 请问以下代码输出的结果是&#xff1f; import itertools a …

在VSCode中运行Python脚本文件时如何传参

以下实验所处的操作系统环境说明&#xff1a; OS版本MacOSMonterey 12.1VSCodeOctober 2023 (version 1.84.2) 一、背景 在 VSCode 中写好 Python 脚本后&#xff0c;如果要运行起来&#xff0c;可以怎么做呢&#xff1f; 一般有以下几种方式&#xff1a; 1、直接在 VSCode…

【ARM Trace32(劳特巴赫) 使用介绍 11 -- Trace32 ARMv8/v9 系统寄存器读写】

文章目录 Trace32 ARMv8/v9 系统寄存器读写 Trace32 ARMv8/v9 系统寄存器读写 本文主要介绍如何使用trace32 来对 ARMv8 的系统寄存器及debug 寄存器进行配置&#xff0c;具体配置方法如下&#xff1a; 步骤1&#xff1a; 步骤2&#xff1a; 步骤3&#xff1a; 步骤4&#xf…

商务与经济统计案例分析:3-1Pelican 商店——python 实现

商务与经济统计案例分析:3-1Pelican 商店 要求Python实现 要求 1.净销售额的描述统计量和各种不同类型顾客的净销售额的描述统计量。 2.关于年龄与净销售额之间关系的描述统计量。 Python实现 0.相关分析&#xff1a;2-1案例 1.净销售额的描述统计量和各种不同类型顾客的净销…

【Docker二】docker网络模式、网络通信、数据管理

目录 一、docker网络模式&#xff1a; 1、概述 2、docker网络实现原理&#xff1a; 3、docker的网络模式&#xff1a; 3.1、bridge模式&#xff1a; 3.2、host模式&#xff1a; 3.3、container模式&#xff1a; 3.4、none模式&#xff1a; 3.5、自定义网络模式&#xf…

stateflow——如何查看状态机中参数变化及状态机断点调试

法一&#xff1a;使用Data Inspector 点击“符号图窗”和“属性”&#xff0c;如图&#xff1b;在选择变量n并右键点击inspector&#xff0c;最后在logging&#xff0c;如图 法二&#xff1a;log active state 和法一类似使用data inspector查看&#xff0c;类似的查看方法和…

《机器学习实战》MNIST 数据集的导入方法

1、在网上下载数据集 mnister 数据集有两个类型&#xff0c; &#xff08;1&#xff09;一个是手写的阿拉伯数字图片&#xff1a;MNIST 下载地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1dd-I-laysPbT8wxbyvxTvg 提取码&#xff1a;1234 &#xff08;2…

【Flink系列五】Checkpoint及Barrier原理

本章内容 一致性检查点从检查点恢复状态检查点实现算法-barrier保存点Savepoint状态后端&#xff08;state backend&#xff09; 本文先设置一个前提&#xff0c;流处理的数据都是可回放的&#xff08;可以理解成消费的kafka的数据&#xff09; 一致性检查点&#xff08;che…

基于ssm少儿编程管理系统源码和论文

idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 环境&#xff1a; jdk8 tomcat8.5 开发技术 ssm 基于ssm少儿编程管理系统源码和论文744 摘要 网络的广泛应用给生活带来了十分的便利。所以把少儿编程管理系统与现在网络相结合&#xff0c;利用java技术建设…

安装python第三方库后,在pycharm中不能正常导入

python小白学习opencv&#xff0c;使用pip安装完opencv库后import cv2报错&#xff0c;按照如下设置解决&#xff1a; 需要正确设置python解释器路径

VC++使用GetProcessTimes获取进程创建时间、销毁时间、用户态时间、内核态时间

一、GetProcessTimes函数简介&#xff08;微软MSDN&#xff09; 微软提供了一个非常有用的API函数GetProcessTimes用来获取进程创建时间、销毁时间、用户态时间、内核态时间&#xff0c;msdn连接为&#xff1a;GetProcessTimes 函数 (processthreadsapi.h) 其函数原型为&#…

<Linux>(极简关键、省时省力)《Linux操作系统原理分析之Linux文件管理(3)》(27)

《Linux操作系统原理分析之Linux文件管理&#xff08;3&#xff09;》&#xff08;27&#xff09; 8 Linux文件管理8.6 文件管理和操作8.6.1 系统对文件的管理8.6.2 进程对文件的管理 8 Linux文件管理 8.6 文件管理和操作 8.6.1 系统对文件的管理 Linux 系统把所有打开的活动…

智能优化算法应用:基于北方苍鹰算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于北方苍鹰算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于北方苍鹰算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.北方苍鹰算法4.实验参数设定5.算法结果6.参考…

12.07

#include "mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent) {//窗口设置//去掉表头this->setWindowFlags(Qt::FramelessWindowHint);//重新设置大小this->resize(800,420);//设置背景颜色this->setStyleSheet("background-color:whi…

mfc140.dll丢失的解决方法,以及解决方法的优缺点

如果你在使用电脑时遇到了“mfc140.dll丢失”的错误提示&#xff0c;这可能会阻止你运行特定的应用程序或游戏。这篇文章将向你介绍导致此错误出现的原因以及mfc140.dll丢失的解决方法&#xff0c;让你的电脑系统恢复正常运行。 一.mfc140.dll丢失的解决方法以及优缺点 方法 1…

Hadoop3.x完全分布式环境搭建Zookeeper和Hbase

先在主节点上进行安装和配置&#xff0c;随后分发到各个从节点上。 1. 安装zookeeper 1.1 解压zookeeper并添加环境变量 1&#xff09;解压zookeeper到/usr/local文件夹下 tar -zxvf /usr/local2&#xff09;进入/usr/local文件夹将apache-zookeeper-3.8.0-bin改名为zookeep…