threeJs+vue 轻松切换几何体贴图
嗨,我是小路。今天主要和大家分享的主题是“threeJs+vue 轻松切换几何体贴图”。
想象一下,手头上正好有个在线3D家具商店,用户不仅可以看到产品的静态图片,还能实时更换沙发的颜色或材质,获得真实的购物体验。这就是我们今天分享的主题——通过简单的几行代码,您可以赋予任何3D几何体不同的外观,增强用户的参与感。

几何体贴图示例
一、示例介绍
设计一个几何体,并通过gui切换3d几何体上不同的图片。就像LOL切换皮肤,只是这个是最基础的。
1.加载图片
定义:通过纹理贴图加载器,将图片加载到几何体的材质里面。主要是放入.map属性里面。
//纹理贴图加载器TextureLoader
const texLoader = new THREE.TextureLoader();
2.图片偏移+动画
定义:将图片距离初始位置,平移一定的距离。
//纹理U方向偏移 将图片进行偏移
texture.offset.x += 0.5;
//渲染
const render = () => {
//贴图动画,每次渲染时,动画平移0.01texture?texture.offset.x += 0.01:null;renderer.render(scene, camera); //执行渲染操作meshObjx.bool ? mesh.rotateX(0.01) : null;//每次绕y轴旋转0.01弧度meshObjy.bool ? mesh.rotateY(0.01) : null;//每次绕y轴旋转0.01弧度meshObjz.bool ? mesh.rotateZ(0.01) : null;//每次绕y轴旋转0.01弧度//重复渲染requestAnimationFrame(render);//请求再次执行渲染函数render,渲染下一帧
}
3.图片显示面
定义:一般几何体默认有两个面,一个是正面,一个是背面。当图片切换成矩形平面时,这种效果更为明显。具体的效果,可看详情图。
child.material.side = THREE.SingleSide
二、实例代码
1、封装代码
const imgArr = reactive({ img: "" })
let texture = reactive("");
//更换模型图片
const setImg = () => {//.load()方法加载图像,返回一个纹理对象Textureconst girlTexture = texLoader.load('./girl.png');const goalTexture = texLoader.load('./goal.png');//切换模型上图片gui.add(imgArr, 'img', { '可爱': 1, '目标': 2 }).name('模型图片').onChange((value) => {//遍历mesh下所有的对象mesh.traverse((child) => {if (child instanceof THREE.Mesh) {if ([1, 2].includes(value)) {switch (value) {case 1:texture = girlTexturebreak;case 2:texture = goalTexturebreak;default:break;}//给模型进行贴图// 设置阵列模式texture.wrapS = THREE.RepeatWrapping;texture.wrapT = THREE.RepeatWrapping;// uv两个方向纹理重复数量 2*2 = 4个图片 自动将图片按照制定的数量平铺texture.repeat.set(2, 2);//注意选择合适的阵列数量//纹理U方向偏移 将图片进行偏移texture.offset.x += 0.5;child.material.map = texture;//THREE.SingleSide 单面,THREE.DoubleSide 双面 默认是双面贴图console.log(THREE.DoubleSide)child.material.side = THREE.SingleSide//开启透明child.material.transparent = false//更新模型child.material.needsUpdate = true;}}})})
}
2、整个示例代码
<template><div class="pageBox"><div class="leftBox" ref="leftRef"></div><div class="rightBox" ref="rightRef" :style="{ background: bgColor }"></div></div></template>
<script setup>
import { onMounted, reactive, ref } from 'vue';
import * as THREE from 'three';
// 引入轨道控制器扩展库OrbitControls.js
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// 设置相机控件轨道控制器OrbitControls// 引入dat.gui.js的一个类GUI
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
const bgColor = ref("")
// 实例化一个gui对象
const gui = new GUI();const leftRef = ref();
const rightRef = ref()
const meshObjx = reactive({ bool: false })
const meshObjy = reactive({ bool: false })
const meshObjz = reactive({ bool: false })
// 定义相机输出画布的尺寸(单位:像素px)
let width = 800; //宽度
let height = window.innerHeight; //高度
// 创建3D场景对象Scene
const scene = new THREE.Scene();// 实例化一个透视投影相机对象
const camera = new THREE.PerspectiveCamera(50, width / height, 2, 6000);//创建一个平面矩形对象Geometry
const geometry = new THREE.PlaneGeometry(150, 150, 150);//==============================================
//纹理贴图加载器TextureLoader
const texLoader = new THREE.TextureLoader();//创建一个材质对象Material
const material = new THREE.MeshBasicMaterial({color: 0xffffff,//0xff0000设置材质颜色为红色opacity: 0.5,
});
//将集合形体和材质融合
const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh// 创建渲染器对象
const renderer = new THREE.WebGLRenderer();onMounted(() => {initData()render();//添加相机空间const controls = new OrbitControls(camera, renderer.domElement);// 如果OrbitControls改变了相机参数,重新调用渲染器渲染三维场景controls.addEventListener('change', function () {renderer.render(scene, camera); //执行渲染操作});//监听鼠标、键盘事件//当窗口发生改变时,触发时间,重新渲染window.onresize = () => {height = window.innerHeight;width = window.innerWidth / 2;renderer.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)initData()}
})
const initData = () => {//设置网格模型在三维空间中的位置坐标,默认是坐标原点mesh.position.set(0, 10, 0);scene.add(mesh);//相机在Three.js三维坐标系中的位置// 根据需要设置相机位置具体值camera.position.set(200, 200, 200);camera.lookAt(mesh.position);//指向mesh对应的位置// AxesHelper:辅助观察的坐标系const axesHelper = new THREE.AxesHelper(150);scene.add(axesHelper);// 添加一个辅助网格地面// const gridHelper = new THREE.GridHelper(300, 25, 0x004444, 0x004444);// scene.add(gridHelper);setGui();renderer.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)//将innerHTML置空,避免append重复添加渲染leftRef.value.innerHTML = ''leftRef.value.append(renderer.domElement);
}//设置gui
const setGui = () => {//改变交互界面style属性gui.domElement.style.right = '0px';gui.domElement.style.width = '300px';//将gui和 几何体的位置绑定//将对应的属性x重命名gui.add(mesh.position, 'x', 0, 100).name('几何体x轴').onChange((value) => {console.log('x', value)//改变x时,进行其它的操作mesh.position.y = 50})//设置交互界面每次改变属性值间隔是多少gui.add(mesh.position, 'y', 0, 100).step(0.1)//设置交互界面 生成交互界面是下拉菜单,设置为数组// gui.add(mesh.position,'z',[-100,0,100]).name("Z轴")gui.add(mesh.position, 'z', { 'left': -100, 'center': 0, 'right': 100 }).name("Z轴")//设置交互页面 单选框 当变量的类型为布尔类型时,才会生成单选框gui.add(meshObjx, 'bool').name("是否开启x轴旋转")gui.add(meshObjy, 'bool').name("是否开启y轴旋转")gui.add(meshObjz, 'bool').name("是否开启z轴旋转")//改变颜色gui.addColor({ color: 0x00ffff }, 'color').onChange((value) => {//value是十进制,需要转换成十六进制bgColor.value = '#' + value.toString(16);mesh.material.color.set(value)})setImg();
}const imgArr = reactive({ img: "" })
let texture = reactive("");
//更换模型图片
const setImg = () => {//.load()方法加载图像,返回一个纹理对象Textureconst girlTexture = texLoader.load('./girl.png');const goalTexture = texLoader.load('./goal.png');//切换模型上图片gui.add(imgArr, 'img', { '可爱': 1, '目标': 2 }).name('模型图片').onChange((value) => {//遍历mesh下所有的对象mesh.traverse((child) => {if (child instanceof THREE.Mesh) {if ([1, 2].includes(value)) {switch (value) {case 1:texture = girlTexturebreak;case 2:texture = goalTexturebreak;default:break;}//给模型进行贴图// 设置阵列模式texture.wrapS = THREE.RepeatWrapping;texture.wrapT = THREE.RepeatWrapping;// uv两个方向纹理重复数量 2*2 = 4个图片 自动将图片按照制定的数量平铺texture.repeat.set(2, 2);//注意选择合适的阵列数量//纹理U方向偏移 将图片进行偏移texture.offset.x += 0.5;child.material.map = texture;//THREE.SingleSide 单面,THREE.DoubleSide 双面 默认是双面贴图console.log(THREE.DoubleSide)child.material.side = THREE.SingleSide//开启透明child.material.transparent = false//更新模型child.material.needsUpdate = true;}}})})
}
//渲染
const render = () => {texture?texture.offset.x += 0.01:null;renderer.render(scene, camera); //执行渲染操作meshObjx.bool ? mesh.rotateX(0.01) : null;//每次绕y轴旋转0.01弧度meshObjy.bool ? mesh.rotateY(0.01) : null;//每次绕y轴旋转0.01弧度meshObjz.bool ? mesh.rotateZ(0.01) : null;//每次绕y轴旋转0.01弧度//重复渲染requestAnimationFrame(render);//请求再次执行渲染函数render,渲染下一帧
}</script>
<style scoped lang="less">
.pageBox {width: 100%;height: 100vh;padding: 0;margin: 0;display: flex;justify-content: space-between;align-items: center;.rightBox {width: 100%;height: 100%;background: yellow;}
}
</style>
三、注意事项
1、在vue框架的基础上,一定要注意加载图片存放的路径。默认的当前文件夹是.public,不是src。
2、一定要设置模型的.needUpdate 为true,重新对3d几何体进行渲染;否则容易出现gui切换了图片,但是3d几何体上图片未做任何的切换的问题。
如果你认为该文章对你有帮助,伸出您的小手,帮忙【点赞】+【关注】+【收藏】。
相关文章:
threeJs+vue 轻松切换几何体贴图
嗨,我是小路。今天主要和大家分享的主题是“threeJsvue 轻松切换几何体贴图”。 想象一下,手头上正好有个在线3D家具商店,用户不仅可以看到产品的静态图片,还能实时更换沙发的颜色或材质,获得真实的购物体验。…...
【python】01_写在前面的话
又是爆肝干文的日子,继上次说要出一期Python新手入门教程系列文章后,就在不停地整理和码字,终于是把【基础入门】这一块给写出来了。 不积跬步无以至千里,不积小流无以成江海,一个一个板块的知识积累,早晚你…...
跨平台公式兼容性大模型提示词模板(飞书 + CSDN + Microsoft Word)
飞书云文档 CSDN MD编辑器 Microsoft Word 跨平台公式兼容方案: 一、背景痛点与解决方案 在技术文档创作中,数学公式的跨平台渲染一直存在三大痛点: 飞书云文档:原生KaTeX渲染与导出功能存在语法限制微软Word:Math…...
【Python爬虫(85)】联邦学习:爬虫数据协作的隐私保护新范式
【Python爬虫】专栏简介:本专栏是 Python 爬虫领域的集大成之作,共 100 章节。从 Python 基础语法、爬虫入门知识讲起,深入探讨反爬虫、多线程、分布式等进阶技术。以大量实例为支撑,覆盖网页、图片、音频等各类数据爬取ÿ…...
深入理解 并查集LRUCaChe
并查集&LRUCaChe 个人主页:顾漂亮 文章专栏:Java数据结构 1.并查集的原理 在一些应用问题中,需要将n个不同的元素划分成一些不相交的集合。开始时,每个元素自成一个单元素集合,然后根据一定规律将归于同一组元素的…...
最新版本SpringAI接入DeepSeek大模型,并集成Mybatis
当时集成这个环境依赖冲突,搞了好久,分享一下依赖配置 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instan…...
Effective Python:(17)
Effective Python提供90条python编程技巧和秘籍,对于我们养成良好的编程习惯,减少程序出错非常重要。 这条就是一条很好的建议,即尽量使用抛出异常来处理意外情况,尽量不要用none作为返回值进行判断。问题也比较显然,如…...
3-2 WPS JS宏 工作簿的打开与保存(模板批量另存为工作)学习笔记
************************************************************************************************************** 点击进入 -我要自学网-国内领先的专业视频教程学习网站 *******************************************************************************************…...
React + TypeScript 复杂布局开发实战
React TypeScript 复杂布局开发实战 一、项目架构设计(基于最新技术栈) 1.1 技术选型与工程创建 # 使用Vite 5.x React 19 TypeScript 5.4 npx create-vitelatest power-designer-ui --template react-ts cd power-designer-ui && npm inst…...
滑动验证组件-微信小程序
微信小程序-滑动验证组件,直接引用就可以了,效果如下: 组件参数: 1.enable-close:是否允许关闭,默认true 2.bind:onsuccess:验证后回调方法 引用方式: <verification wx:if&qu…...
Linux 命令大全完整版(12)
Linux 命令大全 5. 文件管理命令 ln(link) 功能说明:连接文件或目录。语 法:ln [-bdfinsv][-S <字尾备份字符串>][-V <备份方式>][--help][--version][源文件或目录][目标文件或目录] 或 ln [-bdfinsv][-S <字尾备份字符串>][-V…...
在VSCode中安装jupyter跑.ipynb格式文件
个人用vs用的较多,不习惯在浏览器单独打开jupyter,看着不舒服,直接上教程。 1、在你的环境中pip install ipykernel 2、在vscode的插件中安装jupyter扩展 3、安装扩展后,打开一个ipynb文件,并且在页面右上角配置内核 …...
IDEA配置JSP环境
首先下载IDEA2021.3,因为最新版本不能简单配置web开发环境。然后新建一个java开发项目: 然后右键创建的项目,添加web框架: 选择web appliciation 在web inf文件夹下创建classes和lib文件夹: 点击file ,选择…...
Idea 中 Project Structure简介
在 IntelliJ IDEA 中,Project Structure(项目结构)对话框是一个非常重要的配置界面,它允许你对项目的各个方面进行详细的设置和管理。下面将详细介绍 Project Structure 中各个主要部分的功能和用途。 1. Project(项…...
旁挂负载分担组网场景
旁挂负载分担组网场景(到路由策略) 1.拓扑 2.需求 使用传统三层架构中MSTPVRRP组网形式VLAN 2—>W3,SW4作为备份 VLAN 3—>SW4,SW3作为备份 MSTP设计—>SW3、4、5运行 实例1:VLAN 2 实例2:VLAN 3 3.配置 交换层 SW3配置 抢占延时ÿ…...
网络安全防御模型
目录 6.1 网络防御概述 一、网络防御的意义 二、被动防御技术和主动防御技术 三、网络安全 纵深防御体系 四、主要防御技术 6.2 防火墙基础 一、防火墙的基本概念 二、防火墙的位置 1.防火墙的物理位置 2.防火墙的逻辑位置 3. 防火墙的不足 三、防火墙技术类型 四…...
Qt 开源音视频框架模块之QtAV播放器实践
Qt 开源音视频框架模块QtAV播放器实践 1 摘要 QtAV是一个基于Qt的多媒体框架,旨在简化音视频播放和处理。它是一个跨平台的库,支持多种音视频格式,并提供了一个简单易用的API来集成音视频功能。QtAV的设计目标是为Qt应用程序提供强大的音视…...
MS SQL 2008 技术内幕:T-SQL 语言基础
《MS SQL 2008 技术内幕:T-SQL 语言基础》是一部全面介绍 Microsoft SQL Server 2008 中 T-SQL(Transact-SQL)语言的书籍。T-SQL 是 SQL Server 的扩展版本,增加了编程功能和数据库管理功能,使得开发者和数据库管理员能…...
【Pandas】pandas Series filter
Pandas2.2 Series Computations descriptive stats 方法描述Series.align(other[, join, axis, level, …])用于将两个 Series 对齐,使其具有相同的索引Series.case_when(caselist)用于根据条件列表对 Series 中的元素进行条件判断并返回相应的值Series.drop([lab…...
uake 网络安全 reverse网络安全
🍅 点击文末小卡片 ,免费获取网络安全全套资料,资料在手,涨薪更快 本文首发于“合天网安实验室” 首先从PEID的算法分析插件来介绍,要知道不管是在CTF竞赛的REVERSE题目中,还是在实际的商业产品中…...
vue实现根据点击或滑动展示对应高亮
页面需求: 点击左侧版本号,右侧展示对应版本内容并置于顶部右侧某一内容滚动到顶部时,左侧需要展示高亮 实现效果: 实现代码: <template><div><div class"historyBox pd-20 bg-white">…...
Magma:多模态 AI 智体的基础模型
25年2月来自微软研究、马里兰大学、Wisconsin大学、韩国 KAIST 和西雅图华盛顿大学的论文“Magma: A Foundation Model for Multimodal AI Agents”。 Magma 是一个基础模型,可在数字和物理世界中服务于多模态 AI 智体任务。Magma 是视觉-语言 (VL) 模型的重要扩展…...
浅显易懂HashMap的数据结构
HashMap 就像一个大仓库,里面有很多小柜子(数组),每个小柜子可以挂一串链条(链表),链条太长的时候会变成更高级的架子(红黑树)。下面用超简单的例子解释: 壹…...
怎么获取免费的 GPU 资源完成大语言模型(LLM)实验
怎么获取免费的 GPU 资源完成大语言模型(LLM)实验 目录 怎么获取免费的 GPU 资源完成大语言模型(LLM)实验在线平台类Google ColabKaggle NotebooksHugging Face Spaces百度飞桨 AI Studio在线平台类 Google Colab 特点:由 Google 提供的基于云端的 Jupyter 笔记本环境,提…...
Java SE与Java EE
Java SE(Java 平台标准版) Java SE 是 Java 平台的核心,提供了 Java 语言的基础功能。它包含了 Java 开发工具包(JDK),其中有 Java 编译器(javac)、Java 虚拟机(JVM&…...
02_linux系统命令
一、绝对路径与相对路径 1.以 ./ 开始的路径名是相对路径 2.以 / 开始的路径是绝对路径. 相对路径:会随着用户当前所在的目录发生改变. 绝对路径:不会根据用户所在的路径而改变. 3.gcc 编译器 编译器把高级语言(C语言/JAVA语言/C语言)生成二进制代码的一种工具.gcc 是专用…...
【leetcode hot 100 11】移动零
一、暴力解法:两个 for 循环,外层循环遍历所有可能的左边界,内层循环遍历所有可能的右边界 class Solution {public int maxArea(int[] height) {int max_area0;for(int i0; i<height.length; i){for(int ji1; j<height.length; j){in…...
AI绘画软件Stable Diffusion详解教程(2):Windows系统本地化部署操作方法(专业版)
一、事前准备 1、一台配置不错的电脑,英伟达显卡,20系列起步,建议显存6G起步,安装win10或以上版本,我的显卡是40系列,16G显存,所以跑大部分的模型都比较快; 2、科学上网࿰…...
轨迹控制--odrive的位置控制---负载设置
轨迹控制 此模式使您可以平滑地使电机旋转,从一个位置加速,匀速和减速到另一位置。 使用位置控制时,控制器只是试图尽可能快地到达设定点。 使用轨迹控制模式可以使您更灵活地调整反馈增益,以消除干扰,同时保持平稳的运…...
【安卓逆向】逆向APP界面UI修改再安装
1.背景 有一客户找到我,说能不能把APP首页的底部多余界面去掉。 逆向实战 想要去除安卓应用软件中的内容,需要对APP逆向进行修改再打包。 通过工具 MIT管理器工具 提取APK包,点击apk文件,点击查看反编译apk。 搜索关键字。这里关键…...
