当前位置: 首页 > news >正文

Three 【3D车模换肤】

目录

  • 🌟前言
  • 🌟先看效果
  • 🌟实现代码
  • 🌟写在最后

🌟前言

哈喽小伙伴们,最近工作比较忙一直没有给大家更新,新的专栏 Three.js第三篇,记录一下博主学习Three.js的过程;一起来看下吧。

🌟先看效果

Three-3D车模换肤

🌟实现代码

<template><div><div ref="canvas" class="canvas" /><div class="car-color"><div class="color1"><div class="color-blue2" @click="setCarColor('#2e4e61')" /><span>天际蓝</span></div><div class="color1"><div class="color-white" @click="setCarColor('#c0c0c0')" /><span>亮银色</span></div><div class="color1"><div class="color-blank" @click="setCarColor('#222')" /><span>星际黑</span></div><div class="color1"><div class="color-red" @click="setCarColor('#ff0000')" /><span>中国红</span></div><div class="color1"><div class="color-green" @click="setCarColor('#9dc209')" /><span>苹果绿</span></div><div class="color1"><div class="color-blue" @click="setCarColor('#2443e2')" /><span>雪邦蓝</span></div></div></div></template><script>
import * as THREE from 'three'
import { dracoLoader } from './dracoLoader.js'
// 导入轨道控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
// 定义模型初始材质
const bodyMaterial = new THREE.MeshPhysicalMaterial({color: '#2e4e61',metalness: 1,roughness: 0.5,clearcoat: 1.0,clearcoatRoughness: 0.03
})
export default {data() {return {scene: null,camera: null,renderer: null,controls: null,animationMixer: null,clock: null}},computed: {},watch: {},mounted() {this.initThree()},methods: {initThree() {// 创建场景this.scene = new THREE.Scene()// 创建天空盒const path = '/skybox1/'const urls = [path + '6.png',path + '3.png',path + '2.png',path + '1.png',path + '5.png',path + '4.png']const textCube = new THREE.CubeTextureLoader().load(urls)// textCube.encoding = THREE.sRGBEncodingthis.scene.background = textCube// 创建相机  透视相机// fov:角度  aspect:宽高比  near:近端  far:远端this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 1000)// 设置相机位置this.camera.position.set(-20, 20, -44)this.scene.add(this.camera)// 创建地面const floorMat = new THREE.MeshStandardMaterial({color: 0xa9a9a9 // 材质的颜色})const floorGeometry = new THREE.BoxGeometry(300, 300, 0.01, 1, 1, 1)const floorMesh = new THREE.Mesh(floorGeometry, floorMat)floorMesh.receiveShadow = truefloorMesh.rotation.x = -Math.PI / 2.0this.scene.add(floorMesh)this.animationMixer = new THREE.AnimationMixer(this.scene) // 常见动画混合器// 时钟this.clock = new THREE.Clock()// 给场景增加环境光// 设置环境光this.scene.add(new THREE.AmbientLight(0xffffff, 0.5))// 添加球光源const hesLight = new THREE.HemisphereLight(0xffffff, 0x444444)hesLight.intensity = 0.6this.scene.add(hesLight)// 自然光// const dirLight = new THREE.DirectionalLight()// dirLight.position.set(0, 0, 15)// this.scene.add(dirLight)const dirLight2 = new THREE.DirectionalLight()dirLight2.position.set(0, 0, -15)this.scene.add(dirLight2)const dirLight3 = new THREE.DirectionalLight()dirLight3.position.set(15, 0, 0)this.scene.add(dirLight3)const dirLight4 = new THREE.DirectionalLight()dirLight4.position.set(-15, 0, 0)this.scene.add(dirLight4)const dirLight5 = new THREE.DirectionalLight()dirLight5.position.set(0, 15, 0)this.scene.add(dirLight5)const dirLight6 = new THREE.DirectionalLight()dirLight6.position.set(0, -15, 0)this.scene.add(dirLight6)const dirLight7 = new THREE.DirectionalLight()dirLight7.position.set(5, 15, 5)this.scene.add(dirLight7)const dirLight8 = new THREE.DirectionalLight()dirLight8.position.set(-5, -15, -5)this.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 = 10sportLight.shadow.radius = 10// 阴影映射宽度,阴影映射高度sportLight.shadow.mapSize.set(512, 512)sportLight.position.set(0, 15, 0)// 光照射的方向sportLight.target.position.set(0, 0, 0)sportLight.castShadow = truethis.scene.add(sportLight)// 加载模型const modelUrl = '/3DModel/911-transformed.glb' // 定义所使用模型路径路径dracoLoader(modelUrl).then((res) => {// console.log(res.scene)res.scene.name = '3dmodel'res.scene.traverse(function(child) {// console.log(child)if (child.isMesh) {child.frustumCulled = false// 模型阴影child.castShadow = true// 模型自发child.material.emissive = child.material.colorchild.material.emissiveMap = child.material.map}// 获取不同部位if (child.isMesh && child.name.indexOf('boot') !== -1 && child.name.indexOf('boot004') === -1) {child.material = bodyMaterial}})res.scene.scale.set(13, 13, 13)res.scene.rotateY(Math.PI)res.scene.rotation.z = Math.PIres.scene.position.set(0, 9, 0)this.scene.add(res.scene)}).catch((err) => {console.log(err)})// 初始化渲染器this.renderer = new THREE.WebGLRenderer()this.renderer.shadowMap.enabled = truethis.renderer.antialias = true// 设置渲染的尺寸大小this.renderer.setSize(window.innerWidth, window.innerHeight)this.renderer.setClearColor(0xffffff, 1.0)// 监听屏幕大小的改变,修改渲染器的宽高和相机的比例:window.addEventListener('resize', () => {this.renderer.setSize(window.innerWidth, window.innerHeight)this.camera.aspect = window.innerWidth / window.innerHeightthis.camera.updateProjectionMatrix()})// 将webgl渲染的canvas内容添加到body上this.$refs.canvas.appendChild(this.renderer.domElement)// 创建轨道控制器this.controls = new OrbitControls(this.camera, this.renderer.domElement)// 上下旋转范围this.controls.minPolarAngle = 0// 默认值0this.controls.maxPolarAngle = Math.PI / 2.1// 默认值Math.PIthis.controls.enableDamping = true // 开启阻尼this.controls.dampingFactor = 0.1this.controls.enableZoom = falsethis.controls.addEventListener('change', (event) => {console.log(event)})this.render()},render() {this.controls && this.controls.update()// 每一帧都需要更新this.animationMixer.update(this.clock.getDelta()) // 更新动画this.renderer.render(this.scene, this.camera)// 渲染下一帧的时候就会调用render函数requestAnimationFrame(this.render)},setCarColor(color) {console.log(color)// 通过点击不同的色块,给初始的模型材质赋值bodyMaterial.color.set(color)}}
}
</script><style scoped>
html, body {overflow-y: hidden !important;
}.canvas {overflow-y: hidden;overflow-x: hidden !important;
}.car-color {/* 设置这个div居中显示 */margin: 0 auto;position: fixed;top: 10%;right: -17%;width: 40%;height: auto;display: flex;flex-direction: column;justify-content: space-around;align-items: center;
}.color1 {display: flex;flex-direction: column;justify-content: center;align-items: center;
}.color1 div {width: 50px;height: 50px;border-radius: 80px;cursor: pointer;box-shadow: 0px 10px 20px rgba(0, 0, 0, 0.3);
}
.color1 span {color: #000;
}
.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;
}
.color-blue2 {background-color: #2e4e61;
}span {margin-top: 5px;
}</style>

🌟写在最后

更多Three知识以及API请大家持续关注,尽请期待。各位小伙伴让我们 let’s be prepared at all times!

✨原创不易,还希望各位大佬支持一下!
👍 点赞,你的认可是我创作的动力!
⭐️ 收藏,你的青睐是我努力的方向!
✏️ 评论,你的意见是我进步的财富!

http://www.lryc.cn/news/418208.html

相关文章:

  • 语言模型简介和Ngram模型(1)
  • MessageBox弹框替代系统自带的alert、confirm -- 高仿ElementUI MessageBox
  • 数据结构一排序算法
  • [Leetcode 215][Medium]-数组中的第K个最大元素-快排/小根堆/堆排序
  • 【栈和队列】常见面试题
  • 关于float浮点值二进制存储和运算精度损失的话题
  • python爬虫学习记录-请求模块urllib3
  • 谷粒商城实战笔记-133~135-城业务-商品上架-远程上架接口
  • 【React】详解 App.js 文件
  • 【ML】self-supervised Learning for speech and Image
  • 青岛实训day24(8/8)
  • *算法训练(leetcode)第四十五天 | 101. 孤岛的总面积、102. 沉没孤岛、103. 水流问题、104. 建造最大岛屿
  • 设计模式 由浅入深(待完结)
  • (第34天)645、最大二叉树
  • Python知识点:如何使用Paramiko进行SSH连接与操作
  • 代码随想录算法训练营第六天(一)|242.有效的字母异位词
  • 数据结构 | 考研代码题之顺序表 | 1 查找L中值为e的数据元素若找到则返回其下标,若找不到则返回-1
  • RLVF:避免过度泛化地从口头反馈中学习
  • 设计原则与思想-从项目实战中学习设计模式
  • python中的类属性、实例属性、类方法、实例方法和静态方法
  • A股继续底部震荡,探底是否能成功?
  • NPDP考前怎么复习?NPDP200问PDF版来啦~
  • ajax图书管理项目
  • 深入理解 Java SPI - 概念、原理、应用
  • JavaScript - 判断数组中是否包含某个的元素的几种方式
  • 如何用AI颠覆企业未来:从大企业到中小型企业的实战攻略
  • Linux磁盘管理_LVM逻辑卷_SWAP交换分区_Centos-LVM格式磁盘扩容
  • C++ 函数模板和类模板
  • 安卓Termux系统设备安装内网穿透工具实现远程使用SFTP传输文件
  • 文件属性获取