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家具商店,用户不仅可以看到产品的静态图片,还能实时更换沙发的颜色或材质,获得真实的购物体验。…...
Android ObjectBox数据库使用与集成指南
ObjectBox其核心特点ObjectBox与 SQLite 和 Realm 的对比Android集成ObjectBox创建ObjectBox实体对象创建ObjectBox操作管理类OBManager在Application初始化ObjectBox插入或更新数据查询数据统计数据分页数据查询删除数据总结今天分享一套Android另一个数据库ObjectBox。Object…...
【HarmonyOS Next】地图使用详解(一)
背景 这系列文章主要讲解鸿蒙地图的使用,当前可以免费使用,并提供了丰富的SDK给开发者去自定义控件开发。目前可以实现个性化显示地图、位置搜索和路径规划等功能,轻松完成地图构建工作。需要注意的是,现在测试只能使用实体手机去…...
seacmsv9注入管理员账号密码+orderby+limi
1:mysql默认存储引擎innoDB携带的表 1,mysql.innodb_table_stats 2,mysql.innodb_index_stats SELECT table_name FROM mysql.innodb_table_stats WHERE database_name DATABASE(); 2: 关键字做处理 HEX编码:0x696E666F726D6174696F6E5F7…...
C#与AI的交互(以DeepSeek为例)
C#与ai的交互 与AI的交互使用的Http请求的方式,通过发送请求,服务器响应ai生成的文本 下面是完整的代码,我这里使用的是Ollama本地部署的deepseek,在联网调用api时,则url会有不同 public class OllamaRequester {[Se…...
面试八股文--数据库基础知识总结(2) MySQL
本文介绍关于MySQL的相关面试知识 一、关系型数据库 1、定义 关系型数据库(Relational Database)是一种基于关系模型的数据库管理系统(DBMS),它将数据存储在表格(表)中,并通过表格…...
Failed to start The PHP FastCGI Process Manager.
报错如下: Job for php-fpm.service failed because the control process exited with error code. See "systemctl status php-fpm.service" and "journalctl -xe" for details. 2月 25 21:49:00 nginx systemd[1]: Starting The PHP FastC…...
软件供应链安全工具链研究系列——RASP自适应威胁免疫平台(上篇)
1.1 基本能力 RASP是一种安全防护技术,运行在程序执行期间,使程序能够自我监控和识别有害的输入和行为。也就是说一个程序如果注入或者引入了RASP技术,那么RASP就和这个程序融为一体,使应用程序具备了自我防护的能力,…...
Spring Boot集成MyBatis访问MySQL:从项目搭建到基础数据库查询(基础入门)
Spring Boot集成MyBatis访问MySQL 一、引言 在当今企业级应用开发中,Spring Boot、MyBatis与MySQL的组合凭借其高效性和灵活性,成为构建数据驱动型应用的首选方案。本文将带你从零开始搭建项目,掌握Spring Boot集成MyBatis的基础入门内容。…...
一周学会Flask3 Python Web开发-Jinja2模板继承和include标签使用
锋哥原创的Flask3 Python Web开发 Flask3视频教程: 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 不管是开发网站还是后台管理系统,我们页面里多多少少有公共的模块。比如博客网站,就有公共的头部&…...
【2025.2.25更新】wordpress免费AI插件,文章内容、图片自动生成、视频自动生成、网站AI客服、批量采集文章,内置deepseek联网满血版
wordpress免费AI插件,文章内容、文章图片、长尾关键词、视频自动生成、网站AI客服、批量采集文章,插件已接入腾讯云大模型知识引擎xDeepSeek,基于腾讯云大模型知识引擎xDeepSeek可联网满血版,插件可实现文章生成、长尾关键词生成、…...
待解决 leetcode71 简化路径 栈的应用
用多种ifelse很不好很复杂容易丢情况 class Solution { public:string simplifyPath(string path) {stack<char> st;string result;int n path.size();while(n > 1 && (path[n-1] / || path[n-1] .)){if(n > 2 && path[n-2] . && pat…...
数据安全_笔记系列09_人工智能(AI)与机器学习(ML)在数据安全中的深度应用
数据安全_笔记系列09_人工智能(AI)与机器学习(ML)在数据安全中的深度应用 人工智能与机器学习技术通过自动化、智能化的数据分析,显著提升了数据分类、威胁检测的精度与效率,尤其在处理非结构化数据、复杂…...
RocketMQ 可观测性最佳实践
RocketMQ 概述 Apache RocketMQ 是一个开源的分布式消息传递和流处理平台,由阿里巴巴团队最初开发并捐赠给 Apache 软件基金会。它主要用于处理大规模消息的发送和接收,支持高吞吐量、可扩展性强且具有高可用性的消息服务。 RocketMQ 的优势有以下几点…...
P9420 [蓝桥杯 2023 国 B] 子 2023
P9420 [蓝桥杯 2023 国 B] 子 2023 题目 分析代码 题目 分析 刚拿到这道题,我大脑简单算了一下,这个值太大了,直观感觉就很难!! 但是,你仔仔细细的一看,先从最简单的第一步入手,再…...
OpenAI开放Deep Research权限,AI智能体大战升级,DeepSeek与Claude迎来新对决
每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…...
学习笔记04——JMM内存模型
一、Java内存模型(JMM)是什么? Java内存模型(Java Memory Model, JMM)是Java多线程编程中共享内存的访问规则,定义了线程如何与主内存(Main Memory)和工作内存(Work Mem…...
将VsCode变得顺手好用(1
目录 设置中文 配置调试功能 提效和增强相关插件 主题和图标相关插件 创建js文件 设置中文 打开【拓展】 输入【Chinese】 下载完成后重启Vs即可变为中文 配置调试功能 在随便一个位置新建一个文件夹,用于放置调试文件以及你未来写的代码,随便命名但…...
Fisher信息矩阵(Fisher Information Matrix,简称FIM)
Fisher信息矩阵简介 Fisher信息矩阵(Fisher Information Matrix,简称FIM)是统计学和信息理论中的一个重要概念,广泛应用于参数估计、统计推断和机器学习领域。它以统计学家罗纳德费希尔(Ronald Fisher)的名…...
Vue2+Three.js加载并展示一个三维模型(提供Gitee源码)
目录 一、案例截图 二、安装Three.js 三、代码实现 四、Gitee源码 一、案例截图 二、安装Three.js npm install three 三、代码实现 模型资源我是放在public文件夹下面的: 完整代码: <template><div><div ref"container&qu…...
多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...
深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...
【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...
【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...
CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...
令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...
UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...
