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

news2024/12/25 10:34:35

目录

  • 最终效果
  • 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.coloradmin.cn/o/1305483.html

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

相关文章

三天精通Selenium Web 自动化 - 测试框架(一)

1 框架结构雏形 返回 新建的一个java project&#xff0c;项目名为autotest,创建如下结构 图1 框架结构雏形 base&#xff1a;里面有个基类 &#xff08;BaseParpare.java&#xff09;&#xff0c;这个类的主要作用是启动&#xff08;启动浏览器使用了TetsNG的BeforeClass&am…

P4 Qt基础控件——工具按钮toolButton(上)

前言 &#x1f3ac; 个人主页&#xff1a;ChenPi &#x1f43b;推荐专栏1: 《C_ChenPi的博客-CSDN博客》✨✨✨ &#x1f525; 推荐专栏2: 《Linux C应用编程&#xff08;概念类&#xff09;_ChenPi的博客-CSDN博客》✨✨✨ &#x1f33a;本篇简介 &#xff1a;这一章我们学一…

披荆斩棘的「矿区无人驾驶」,能否真正打开千亿级市场?

随着2022年备受瞩目的台泥句容矿无人驾驶运输项目硬核落地&#xff0c;以及相关科技公司开放该矿24小时无人矿卡生产运营直播以证明其项目并非在演示&#xff0c;2023年全国开启了大规模矿区无人驾驶商业化落地&#xff0c;堪称矿区无人驾驶元年。虽然我国矿区无人驾驶市场渗透…

【C语言】数据结构——小堆实例探究

&#x1f497;个人主页&#x1f497; ⭐个人专栏——数据结构学习⭐ &#x1f4ab;点击关注&#x1f929;一起学习C语言&#x1f4af;&#x1f4ab; 导读&#xff1a; 我们在前面学习了单链表和顺序表&#xff0c;以及栈和队列。 今天我们来学习小堆。 关注博主或是订阅专栏&a…

ArkUI组件

目录 一、概述 声明式UI 应用模型 二、常用组件 1、Image&#xff1a;图片展示组件 示例 配置控制授权申请 2、Text&#xff1a;文本显示组件 示例 3、TextInput&#xff1a;文本输入组件 示例 4、Button&#xff1a;按钮组件 5、Slider&#xff1a;滑动条组件 …

【日志技术】附Logback入门教程

文章目录 日志概论日志的体系Logback快速入门日志配置文件配置日志级别 日志概论 什么是日志&#xff1f;其实可以通过下面几个问题来了解的。 系统系统能记住某些数据被谁操作&#xff0c;比如被谁删除了&#xff1f;想分析用户浏览系统的具体情况&#xff0c;比如挖掘用户的…

常州经开区大学生音乐节——常州首届校园乐队比赛

2023年12月9日下午&#xff0c;由江苏省文化馆指导、常州经开区社会事业局主办、常州柒号文化传播有限公司承办、百吉琴行协办的青春制“燥”大学生音乐节——常州首届校园乐队比赛&#xff0c;在常州经开区文化活动中心顺利举办。 常州经开区社会事业局副局长 方姣 为本次比赛…

CPU、内存与硬盘及IO操作

目录 1、概念简介 1.1 CPU&#xff08;Central Processing Unit&#xff0c;中央处理器&#xff09; 1.2 硬盘&#xff08;Hard Disk Drive&#xff09; 1.3 内存&#xff08;Memory&#xff09; 2、计算机程序在进行io读写操作时&#xff0c;这三者的功能和实现原理 1、概…

使用Gson完成java对象的序列化和反序列化

一、前言&#xff1a;json是什么&#xff1f;&#xff0c;Gson是什么&#xff1f; 1.JSON&#xff08;javaScript Object Notation&#xff09; 是一种轻量级的数据交换格式。易于人阅读和编写&#xff0c;同时也易于机器解析和生成。 2.Gson 是Google提供的用来在java对象…

手持式心电图机|12道便携式心电图机主板方案定制

心电图机被广泛应用于心脏状况的监测&#xff0c;可以从多个角度观察心脏情况&#xff0c;及时反映患者的病情&#xff0c;以便医生和患者了解。触摸屏使得控制和信息录入变得轻松。心电图报告提供多种语言选择&#xff0c;便于上传信息&#xff0c;实现无纸化报告。同时&#…

现代雷达车载应用——第2章 汽车雷达系统原理 2.2节

经典著作&#xff0c;值得一读&#xff0c;英文原版下载链接【免费】ModernRadarforAutomotiveApplications资源-CSDN文库。 2.2 汽车雷达架构 从顶层来看&#xff0c;基本的汽车雷达由发射器&#xff0c;接收器和天线组成。图2.2给出了一种简化的单通道连续波雷达结构[2]。这…

三天搞定jmeter入门到入职全套教程之使用Jmeter录制脚本

相对于LoadRunner跟SilkPerformer来说&#xff0c;Jmeter确实有差距&#xff0c;但毕竟前两者太贵&#xff0c;Jmeter胜在免费开源。 先看下LoadRunner录制的脚本如下&#xff0c;美如画&#xff0c;结构清晰&#xff0c;易于修改编辑&#xff0c;比如做关联等。当然目前LoadR…

CSS Grid布局入门:从零开始创建一个网格系统

CSS Grid布局入门&#xff1a;从零开始创建一个网格系统 引言 在响应式设计日益重要的今天&#xff0c;CSS Grid布局系统是前端开发中的一次革新。它使得创建复杂、灵活的布局变得简单而直观。本教程将通过分步骤的方式&#xff0c;让你从零开始掌握CSS Grid&#xff0c;并在…

[湖湘杯 2021 final]MultistaeAgency

文章目录 题目是给了源码&#xff0c;我们先来看web的main.go package mainimport ("bytes""crypto/md5""encoding/json""fmt""io""io/ioutil""log""math/rand""net/http""o…

实验7:索引和视图定义

【实验目的】 1、了解索引和视图的含义 2、熟悉索引和视图的创建规则 3、掌握索引和视图的创建和管理 【实验设备及器材】 1、硬件&#xff1a;PC机&#xff1b; 2、软件&#xff1a;(1)Windows7; (2)Microsoft SQL Server 2012。 【主要内容】 索引的创建、删除、重建…

web如何实现录制音频,满满干货(下篇)

上篇中讲了&#xff0c;web如何实现录制音频&#xff0c;这一篇中&#xff0c;介绍如何播放录制好的音频&#xff0c;以及如何下载和上传音频。 播放 播放&#xff0c;其实就有很多种方法了&#xff0c;可以先上传到云服务器&#xff0c;然后生成链接&#xff0c;使用audio标…

AMC8历年真题在线练习、解析全新按年份独立,更便捷练习和巩固

告诉大家一个好消息&#xff01; 根据家长朋友们的反馈&#xff0c;六分成长独家制作的AMC8美国数学竞赛的历年真题在练已全新架构和上线&#xff0c;改为了按年份独立一套试卷&#xff0c;这样在线练习加载更快&#xff0c;随需练习也更方便。 先来一睹为快&#xff0c;练习的…

什么是 AWS IAM?如何使用 IAM 数据库身份验证连接到 Amazon RDS(上)

驾驭云服务的安全环境可能很复杂&#xff0c;但 AWS IAM 为安全访问管理提供了强大的框架。在本文中&#xff0c;我们将探讨什么是 AWS Identity and Access Management (IAM) 以及它如何增强安全性。我们还将提供有关使用 IAM 连接到 Amazon Relational Database Service (RDS…

【Week P1】 MNIST手写数字识别

文章目录 一、环境配置1.1 安装环境1.2 设置环境&#xff0c;开始本文内容 二、准备数据三、搭建网络结构四、开始训练五、查看训练结果六、总结2.1 ⭐ torchvision.datasets.MNIST详解(Line4 & Line9)2.2 ⭐ torch.utils.data.DataLoader详解(Line4 & Line9)2.3 ⭐ sq…

《天天爱科学》期刊国家级知网投稿

《天天爱科学》国家级期刊知网收录&#xff0c;投稿方向&#xff1a;幼儿教育、基础教育文章&#xff0c;不收案例分析、教学设计、图表讲解、例题分析。 刊名&#xff1a;天天爱科学 主管单位&#xff1a;中国出版传媒股份有限公司 主办单位&#xff1a;人民文学出版社有限…