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

news/2024/7/10 3:14:05 标签: 汽车, javascript, Vue, 3d

目录

  • 最终效果
  • 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项目实战的第一个项目就实现了,小伙伴们有疑问的评论区留言,喜欢的小伙伴点赞关注+收藏哦!


http://www.niftyadmin.cn/n/5252877.html

相关文章

PTA:哈夫曼编码

题干 只有一行&#xff0c;是一个字符串&#xff0c;由长度不超过255个字符的小写英文字母组成。 输出格式: 有若干行&#xff0c;每行由两部分组成&#xff1a;一个字母和该字母出现的频率&#xff0c;中间用一个空格分隔&#xff0c;并按频率高低排列&#xff0c;频率相同时…

.[henderson@cock.li].mkp勒索病毒数据怎么处理|数据解密恢复

导言&#xff1a; 随着科技的迅猛发展&#xff0c;数字威胁也愈发猖獗&#xff0c;其中之一就是.[hendersoncock.li].mkp勒索病毒。这种威胁以其高效的数据加密和极端的勒索手段而著称。本文将深入介绍.[hendersoncock.li].mkp勒索病毒的特征&#xff0c;提供有效的数据恢复方…

使用Python代码识别股票价格图表模式

在股票市场交易的动态环境中&#xff0c;技术和金融的融合催生了分析市场趋势和预测未来价格走势的先进方法。本文将使用Python进行股票模式识别。 from collections import defaultdictimport numpy as npimport pandas as pdimport matplotlib.pyplot as pltfrom scipy.signa…

Linux下快速创建大文件的4种方法

1、使用 dd 命令创建大文件 dd 命令用于复制和转换文件&#xff0c;它最常见的用途是创建实时 Linux USB。dd 命令是实际写入硬盘&#xff0c;文件产生的速度取决于硬盘的读写速度&#xff0c;根据文件的大小&#xff0c;该命令将需要一些时间才能完成。 假设我们要创建一个名…

图的深度和广度优先遍历

题目描述 以邻接矩阵给出一张以整数编号为顶点的图&#xff0c;其中0表示不相连&#xff0c;1表示相连。按深度和广度优先进行遍历&#xff0c;输出全部结果。要求&#xff0c;遍历时优先较小的顶点。如&#xff0c;若顶点0与顶点2&#xff0c;顶点3&#xff0c;顶点4相连&…

排序算法之六:快速排序(递归)

快速排序的基本思想 快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法 其基本思想为&#xff1a; 任取待排序元素序列中的某元素作为基准值&#xff0c;按照该排序码将待排序集合分割成两子序列&#xff0c;左子序列中所有元素均小于基准值&#xff0c;右序列中所…

虚拟机VMware安装centos以及配置网络

目录 1、CentOS7的下载2、CentOS7的配置3、CentOS7的安装4、CentOS7的网络配置 4.1、自动获取IP4.2、固定获取IP 5、XShell连接CentO 准备工作&#xff1a;提前下载和安装好VMware。VMware的安装可以参考这一篇文章&#xff1a;VMware15的下载及安装教程。 1、CentOS7的下载 …

midwayjs从零开始创建项目,连接mikro-orm框架(必须有java的springboot基础)

前言&#xff1a; 我一直都是用java的springboot开发项目&#xff0c;然后进来新公司之后&#xff0c;公司的后端是用node.js&#xff0c;然后框架用的是 midwayjs &#xff0c;然后网上的资料比较少&#xff0c;在此特地记录一波 文档&#xff1a; 1.官方文档&#xff1a;介绍…