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!
✨原创不易,还希望各位大佬支持一下!
👍 点赞,你的认可是我创作的动力!
⭐️ 收藏,你的青睐是我努力的方向!
✏️ 评论,你的意见是我进步的财富!
相关文章:
Three 【3D车模换肤】
目录 🌟前言🌟先看效果🌟实现代码🌟写在最后 🌟前言 哈喽小伙伴们,最近工作比较忙一直没有给大家更新,新的专栏 Three.js第三篇,记录一下博主学习Three.js的过程;一起来…...

语言模型简介和Ngram模型(1)
语言模型介绍一 语言模型语言模型概念语言模型应用-语音识别声纹特征提取语言模型挑选成句 语言模型应用-手写识别语言模型应用-输入法语言模型分类语言模型评价指标-困惑度PPL N-gram语言模型马尔科夫假设平滑问题平滑问题解决一平滑问题解决二 插值优化语言模型应用-文本纠错…...

MessageBox弹框替代系统自带的alert、confirm -- 高仿ElementUI MessageBox
MessageBox 弹框 MessageBox 的作用是替代系统自带的 alert、confirm ,仅适合展示较为简单的内容。如果需要弹出较为复杂的内容,请使用定制的弹窗。基本仿照ElementUI的同名组件。 原生,无依赖项,自适应布局,双端通用&…...
数据结构一排序算法
排序算法总结 冒泡排序 冒泡排序(Bubble Sort)也是一种简单直观的排序算法。假设长度为n的数组arr,要按照从小到大排序。则冒泡排序的具体过程可以描述为:首先从数组的第一个元素开始到数组最后一个元素为止,对数组中…...

[Leetcode 215][Medium]-数组中的第K个最大元素-快排/小根堆/堆排序
一、题目描述 原题地址 二、整体思路 (1)快排 对于SELECT K问题,可以通过三路快排解决,快排可以把一个元素放至按升序排序的数组正确的位置,左边为小于该元素的元素集合,右边为大于该元素的元素集合。 三…...

【栈和队列】常见面试题
文章目录 1.[有效的括号](https://leetcode.cn/problems/valid-parentheses/description/)1.1 题目要求1.2 利用栈解决 2. [用队列实现栈](https://leetcode.cn/problems/implement-stack-using-queues/description/)2.1 题目要求2.2 用队列实现栈 3.[用栈实现队列](https://le…...

关于float浮点值二进制存储和运算精度损失的话题
1.前言 浮点值的存储、运算都可能会带来精度损失,了解精度损失背后的机制原因方便我们更好的了解什么情况下会发生精度损失、什么情况下精度损失较大,以及思考怎么避免或减少精度损失。 2.知识点 (1)IEEE 754标准 EEE 754标准…...

python爬虫学习记录-请求模块urllib3
(文章内容仅作学习交流使用) urllib3是一个功能强大、条理清晰,用于HTTP客户端的第三方模块 urllib3-发送网络请求 使用urllib3发送网络请求时,需要先创建PoolManager对象,并使用该对象的request方法发送请求&#…...

谷粒商城实战笔记-133~135-城业务-商品上架-远程上架接口
文章目录 一,谷粒商城实战笔记-133-城业务-商品上架-远程上架接口1,开发目标2,详细设计2.1,提前建立索引2.2,构造批量操作请求参数2.3,使用HighLevelClient调用bulk请求保存数据 二,134-商城业务…...

【React】详解 App.js 文件
文章目录 一、App.js文件的基本结构1. 引入必要的模块2. 定义根组件3. 导出根组件 二、App.js文件的详细解析1. 函数组件与类组件函数组件类组件 2. 使用CSS模块3. 组织子组件4. 管理组件状态使用useState钩子使用state对象 三、App.js文件的最佳实践1. 保持组件的简洁和模块化…...

【ML】self-supervised Learning for speech and Image
【ML】self-supervised Learning for speech and Image 1. self-supervised Learning for speech and Image1.1 自监督学习在语音处理领域的方法及其特点1.2 自监督学习在图像处理领域的方法及其特点 2. Predictive Approach2.1 特点2.2 适用场景 3. contrastive Learning4. 语…...
青岛实训day24(8/8)
一.Python环境准备 1.查看有没有python3 yum list installed |grep python yum list |grep python3 最新安装3.12可以使用源码安装 2.下载安装python3 yum -y install python3 3.查看版本 [rootpython ~]# python3 --version Python 3.6.8 4.进入编辑 [r…...
*算法训练(leetcode)第四十五天 | 101. 孤岛的总面积、102. 沉没孤岛、103. 水流问题、104. 建造最大岛屿
刷题记录 101. 孤岛的总面积DFSBFS 102. 沉没孤岛DFSBFS *103. 水流问题*104. 建造最大岛屿 101. 孤岛的总面积 题目地址 本题要求不与矩阵边缘相连的孤岛的总面积。先将与四个边缘相连的岛屿变为海洋,再统计剩余的孤岛的总面积。无需再标识访问过的结点ÿ…...
设计模式 由浅入深(待完结)
一、设计模式是什么? 设计模式是指在软件开发中,经过验证的,用于解决在特定环境下,重复出现的,特定问题的解决方案。 二、设计模式有哪些? 1. 观察者模式 定义对象间的一种一对多(变化&#x…...
(第34天)645、最大二叉树
目录 645、最大二叉树题目描述思路代码 645、最大二叉树 题目描述 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点,其值为 nums 中的最大值。 递归地在最大值 左边 的 子数组前缀上 构建左子树。 递归地在最大…...
Python知识点:如何使用Paramiko进行SSH连接与操作
使用Paramiko进行SSH连接与操作可以分为以下几个步骤: 安装Paramiko: 首先需要安装Paramiko库,可以使用pip进行安装: pip install paramiko建立SSH连接: 使用Paramiko连接远程服务器,需要提供服务器的地址、…...

代码随想录算法训练营第六天(一)|242.有效的字母异位词
LeetCode 242 有效的字母异位词 题目: 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。 注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。 示例 1: 输入: s "anagram&q…...
数据结构 | 考研代码题之顺序表 | 1 查找L中值为e的数据元素若找到则返回其下标,若找不到则返回-1
文章目录 1 题目2 题解 1 题目 假设有一个顺序表 L,其存储的所有数据元素均为不重复的正数,查找L中值为e的数据元素,若找到则返回其下标,若找不到则返回-1。 2 题解 C语言代码: /*假设有一个顺序表 L,其…...

RLVF:避免过度泛化地从口头反馈中学习
人工智能咨询培训老师叶梓 转载标明出处 大模型在不同行业和个人中的广泛应用要求模型能够根据具体的用户反馈进行调整或定制,以满足细微的要求和偏好。虽然通过高层次的口头反馈来指定模型调整非常方便,例如“在给老板起草电子邮件时不要使用表情符号”…...
设计原则与思想-从项目实战中学习设计模式
文章目录 开源项目通过剖析Java JDK源码学习灵活应用设计模式1. 单例模式(Singleton Pattern)示例:`java.lang.Runtime`2. 工厂模式(Factory Pattern)示例:`java.util.Date`3. 观察者模式(Observer Pattern)示例:`java.util.Observable` 和 `java.util.Observer`4. 适…...

基于安卓的线上考试APP源码数据库文档
摘 要 21世纪的今天,随着社会的不断发展与进步,人们对于信息科学化的认识,已由低层次向高层次发展,由原来的感性认识向理性认识提高,管理工作的重要性已逐渐被人们所认识,科学化的管理,使信息存…...

论文MR-SVD
每个像素 7 个 FLOPs意思: FLOPs(浮点运算次数):衡量算法计算复杂度的指标,数值越小表示运算越高效。含义:对图像中每个像素进行处理时,仅需执行7 次浮点运算(如加减乘除等…...
一个完整的时间序列异常检测系统,使用Flask作为后端框架,实现了AE(自编码器)、TimesNet和LSTM三种模型,并提供可视化展示
时间序列异常检测系统 下面是一个完整的时间序列异常检测系统,使用Flask作为后端框架,实现了AE(自编码器)、TimesNet和LSTM三种模型,并提供可视化展示。 系统概述 这个系统能够: 从多种来源加载时间序列数据使用三种先进算法进行异常检测可视化展示原始数据、重建数据和…...

STM标准库-TIM旋转编码器
文章目录 一、编码器接口1.1简介1.2正交编码器1.3编码器接口基本结构**1. 模块与 STM32 配置的映射关系****2. 设计实现步骤(核心流程)****① 硬件规划****② 时钟使能****③ GPIO 配置(对应架构图 “GPIO” 模块)****④ 时基单元…...

网络爬虫一课一得
网页爬虫(Web Crawler)是一种自动化程序,通过模拟人类浏览行为,从互联网上抓取、解析和存储网页数据。其核心作用是高效获取并结构化网络信息,为后续分析和应用提供数据基础。以下是其详细作用和用途方向: …...
分布式爬虫代理IP使用技巧
最近我们讨论的是分布式爬虫如何使用代理IP。在我们日常的分布式爬虫系统中,多个爬虫节点同时工作,每个节点都需要使用代理IP来避免被目标网站封禁。怎么解决代理IP问题显得尤为重要。 我们知道在分布式爬虫中使用代理IP是解决IP封禁、提高并发能力和实…...
AI Agent 架构设计:ReAct 与 Self-Ask 模式对比与分析
一、引言 (一) AI Agent 技术发展背景 🚀 AI Agent 的演进是一场从“遵循指令”到“自主决策”的深刻变革。早期,以规则引擎为核心的系统(如关键词匹配的客服机器人)只能在预设的流程上运行。然而,大语言模型的崛起为…...
【学习记录】如何使用 Python 提取 PDF 文件中的内容
如何使用 Python 提取 PDF 文件中的内容 在文档自动化处理、数据提取和信息分析等任务中,从 PDF 文件中提取文本是一项常见需求。PDF 文件通常分为两种类型:基于文本的 PDF 和 包含扫描图像的 PDF。 本文将介绍如何使用 Python 分别提取这两种类型的 P…...
Riverpod与GetX的优缺点对比
Riverpod 与 GetX 的优缺点对比 在 Flutter 开发领域,Riverpod 和 GetX 都是备受关注的状态管理与依赖注入框架,它们各有优劣,适用于不同的开发场景。以下从多个维度详细对比二者的优缺点。 一、Riverpod 的优缺点 (一)优点 架构清晰,数据流向明确:基于 Provider 模…...

如何使用Jmeter进行压力测试?
🍅 点击文末小卡片,免费获取软件测试全套资料,资料在手,涨薪更快 一、什么是压力测试 软件测试中:压力测试(Stress Test),也称为强度测试、负载测试。压力测试是模拟实际应用的软硬…...