react项目中使用threejs加载glb文件

news/2024/11/18 10:03:00/文章来源:https://www.cnblogs.com/ZerlinM/p/18551791

安装threejs

yarn add three

首先创建 renderModel.js文件

import * as THREE from 'three'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import * as TWEEN from 'three/examples/jsm/libs/tween.module';const modeLoader = {gltf: () => {return new GLTFLoader()},glb: () => {return new GLTFLoader()}
}let canvasContainer = null
let camera = null
let scene = null
let renderer = null
let controls = null
let model = nullconst initEvents = {raycaster: new THREE.Raycaster(),pickedObject: null,pickedObjectSavedColor: 0,pickPosition: new THREE.Vector2(), //创建二维平面
}export const renderInit = (container) => {return new Promise((resolve, reject) => {canvasContainer = container.currentclearModel()init()setLight()resolve()})
}const init = () => {camera = new THREE.PerspectiveCamera(45,canvasContainer.clientWidth / canvasContainer.clientHeight,0.1,1000)camera.position.set(0, 0, 150)camera.up.x = 0;camera.up.y = 1;camera.up.z = 0;camera.updateProjectionMatrix()scene = new THREE.Scene()scene.background = new THREE.Color(0xf8f8f8);renderer = new THREE.WebGLRenderer({antialias: true,alpha: true})renderer.setSize(canvasContainer.clientWidth, canvasContainer.clientHeight)renderer.gammaFactor = 2.2console.log('THREE', THREE)renderer.setPixelRatio(window.devicePixelRatio) // 设置设备像素比canvasContainer.appendChild(renderer.domElement)controls = new OrbitControls(camera, renderer.domElement)controls.enableDamping = trueanimate()
}const animate = () => {requestAnimationFrame(() => animate())renderer.render(scene, camera)controls.update()// TWEEN.update()
}const setLight = () => {const light1 = new THREE.DirectionalLight(0xffffff, 2)light1.position.set(0, 50, 0)scene.add(light1)const light2 = new THREE.DirectionalLight(0xffffff, 2)light2.position.set(0, 50, 100)scene.add(light2)const light3 = new THREE.DirectionalLight(0xffffff, 2)light3.position.set(0, 50, -100)scene.add(light3)const ambientLight = new THREE.AmbientLight(0xffffff, 2)scene.add(ambientLight)
}// 设置模型大小
const initSize = (obj) => {let group = objgroup.updateMatrixWorld()const box = new THREE.Box3().setFromObject(group)const size = box.getSize(new THREE.Vector3())const center = box.getCenter(new THREE.Vector3())const maxSize = Math.max(size.x, size.y, size.z)const targetSize = 1 // 目标大小const scale = targetSize / (maxSize > 1 ? maxSize : 0.5)group.scale.set(scale, scale, scale)controls.maxDistance = size.length() * 10camera.lookAt(center)camera.updateProjectionMatrix()
}const getDracoLoader = () => {const dracoloader = new DRACOLoader()dracoloader.setDecoderPath('3d/draco/')dracoloader.setDecoderConfig({ type: 'js' })dracoloader.preload()return dracoloader
}export const loadModel = (config) => {return new Promise((resolve, reject) => {const { type, url } = configconst loader = modeLoader[type]()if (['gltf', 'glb'].includes(type)) {const dracoloader = getDracoLoader()loader.setDRACOLoader(dracoloader)}loader.load(url, (object) => {const obj = object.scenemodel = obj.children[0]scene.add(obj)// 添加世界坐标辅助器const axesHelper = new THREE.AxesHelper(5);scene.add(axesHelper);initSize(obj)resolve(true)}, () => {}, err => {console.log(err)reject()})})
}// 模型切换清除上个模型
const clearModel = () => {// 必须要清空当前div下的canvas不然canvas会继续叠加if (canvasContainer) {canvasContainer.firstChild && canvasContainer.removeChild(canvasContainer.firstChild)}
}export const tween3D = (Position) => {  //传递任意目标位置,从当前位置运动到目标位置camera.lookAt(new THREE.Vector3(0, 0, 0));// var p1 = { //定义相机位置是目标位置到中心点距离的2.2倍//   x: camera.position.x / 2.2,//   y: camera.position.y - 15,//   z: camera.position.z / 2.2// }var p1 = { //定义相机位置是目标位置到中心点距离的2.2倍x: camera.position.x,y: camera.position.y,z: camera.position.z}var p2 = {x: Position.x,y: Position.y,z: Position.z,}var update = function (object) {// camera.position.set(object.x * 2.2, object.y + 15, object.z * 2.2);camera.position.set(object.x, object.y, object.z);// controls.target.set(object.x, object.y, object.z);camera.lookAt(0, 0, 0); //保证动画执行时,相机焦距在中心点controls.enabled = false;controls.update();};var tween = new TWEEN.Tween(p1).to(p2, 1200)//第一段动画.onUpdate(update)// 动画完成后的执行函数.onComplete(() => {controls.enabled = true; //执行完成后开启控制}).easing(TWEEN.Easing.Quadratic.InOut).start();// 放大动画var targetScale = { x: 2, y: 2, z: 2 }; // 目标缩放比例const tweenScale = new TWEEN.Tween(model.scale) // 缩放对象.to(targetScale, 1000) // 动画时间.onComplete(() => {// Tween动画完成后重新绑定事件监听器// window.addEventListener('wheel', onMouseWheel, false);}).easing(TWEEN.Easing.Quadratic.InOut) // 缓动函数.start(); // 开始动画
}// 组合模型加载(以obj和mtl 为例)
// const loadGroupModel = () => {
//   const { type, url } = config
//   const typeList = type.split(',')
//   let t1 = typeList[0]
//   let t2 = typeList[1]
//   const loader1 = modeLoader[t1]()
//   const loader2 = modeLoader[t2]()
//   loader1.load(url[0], (materials) => {
//     materials.preload()
//     loader2.setMaterials(materials)
//     loader2.load(url[1], (object) => {
//       scene.add(object)
//       initSize(object)
//     })
//   })
// }

DRACOLoader需要将 node_modules/three/examples/jsm/libs下的draco文件夹复制到 public 文件下

需要安装 copy-webpack-plugin 打包时将public文件夹复制出来

yarn add copy-webpack-plugin

webpack.config.js中

const copyWebpackPlugin = require('copy-webpack-plugin');module.exports = {...plugins: [...new copyWebpackPlugin([{ from: "public" }]),],
}

使用

import React, { useState, useEffect, useRef } from 'react';
import { renderInit, loadModel } from './renderModel'
import s from './ThreeModel.less'import model from './images/3d/pump3d.glb';export default function ThreeModel(props) {const container = useRef()const config = {type: 'glb',url: model,}useEffect(() => {if (container.current && props.show?.pool3D) {loadObj(config)}}, [container, props.show?.pool3D])const loadObj = async (params) => {await renderInit(container)const load = await loadModel(params)// load =true 表示加载完成console.log('load', load)}return (<div className={s.modelCon}><div className={s.modelBox} style={{ width: '100%', height: '100%' }} ref={container}></div></div>)
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/836033.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络性能评估工具Iperf详解

摘自:https://www.cnblogs.com/machangwei-8/p/16922788.html 参考:https://www.51cto.com/article/454889.html发端:iperf -u -c <收端IP> -i 1 -b 800m -t 999 -l 1400 收端:iperf -u -s -i 1 目录一、网络性能评估工具Iperf1、Iperf能做什么二、Iperf的安装与使用…

提升开发效率的秘密:IT团队都在用哪些项目管理工具?

在当今的数字化时代,IT团队的角色已经从传统的技术支持转变为企业发展的战略推动力。随着企业业务的快速扩展,IT项目的复杂性也在增加。如何高效地管理项目、协调团队协作、以及快速响应变化,成为每个IT团队都必须面对的问题。而一个优秀的项目管理工具,不仅能帮助团队提升…

【PCIE716-0】基于PCIe总线架构的XC7Z100 FPGA高性能实时信号处理平台

板卡概述 PCIE716-0是一款基于PCIe总线架构的XC7Z100 FPGA高性能实时信号处理平台。该平台采用Xilinx的ZYNQ SOC系列产品XC7Z100作为主处理器。 该平台的PL端具有1个FMC(HPC)接口,1路PCIe x8主机接口,支持1路UART串口、支持1组64位DDR3 SDRAM大容量缓存、支持1路1000BASE-T…

给网站免费升级https协议

给网站免费升级HTTPS协议,可以通过申请并部署免费的SSL证书来实现。以下是一个详细的步骤指南:一、申请免费SSL证书 选择证书颁发机构: 可以选择像JoySSL这样的公益项目,它提供免费、自动化的SSL/TLS证书颁发服务,适用于各种规模的网站。 免费SSL证书申请入口 提交申请: …

在阿里云快速启动Appsmith搭建前端页面

什么是Appsmith Appsmith是一个开源的低代码开发平台,它使得开发者能够快速地构建内部工具、业务管理系统、CRM系统等。Appsmith通过提供一系列预建的UI组件(如表格、图表、表单等),以及对数据库、API调用的直接支持,简化了开发过程。开发者可以使用这些组件和服务来构建复…

【Anaconda3 2023.03软件下载与安装教程】

1、安装包 Anaconda3py 2023(64bit): 链接:https://pan.quark.cn/s/f77de1704504 提取码:z7k2 2、安装教程 1) 下载解压软件安装包,双击Setup.exe安装,弹窗安装对话框2) 点击Next3) 点击I Agree4) 默认,点击Next5) 选择安装目录,建议…

MoD:轻量化、高效、强大的新型卷积结构 | ACCV24

来源:晓飞的算法工程笔记 公众号,转载请注明出处论文: CNN Mixture-of-Depths论文地址:https://arxiv.org/abs/2409.17016创新点提出新的卷积轻量化结构MoD,在卷积块(Conv-Blocks)内通过动态选择特征图中的关键通道进行集中处理,提高效率。 CNN MoD保留了静态计算图,这…

【Android Studio 2022软件下载与安装教程】

1、安装包 Android Studio 2022: 链接:https://pan.quark.cn/s/9821141ab2c7 提取码:aTaw 2、安装教程 1) 解压下载安装包,双击Setup.exe安装,弹窗安装对话框2) 点击下一步3) 默认,点击下一步4) 选择安装目录,建议选择C盘之外,点击下一步5)…

当然不是草台班子-冲刺日志6

作业所属课程 软件工程2024作业要求 2024秋软工实践团队作业-第三次( Alpha冲刺)作业目标 alpha冲刺完成项目核心功能团队名称 当然不是草台班子团队成员学号 姓名102201427 侯丽珂102201426 郑嘉祺102201241 戴康怡102201218 肖晗涵112200328 谢李东292300304 陈鹭102201242…

教你对接电商拍图识款接口

在网上购物时候,不止可以通过名称搜索商品,也可以拍照上传图片搜索商品。比如某宝上拍个图片就能搜索到对应的商品。腾讯、阿里都提供了类似的图像搜索服务,这类服务原理都差不多:在一个具体的图库上,新增或者删除图片。 通过图片搜索相似的图片。本文对接的是腾讯云的图像…

【Unity】ScriptableObject的应用和3D物体跟随鼠标移动:鼠标放置物体在场景中

使用ScriptableObject类实现资源的配置;实现3D物体跟随鼠标移动;实现物体放置在鼠标点击的世界坐标位置。需求说明 结合前篇,仓库管理 和 获取鼠标点击的世界坐标位置 两篇内容,已经实现了:鼠标或键盘控制玩家移动;玩家触碰物体后,将物体放入仓库;鼠标点击仓库栏中的物…

Kubernetes v1.16.3版本开启 Job ttlSecondsAfterFinished 自动清理机制

前言 Kubernetes v1.23 之前,Job 在处于 Completed 后,默认是不会被清理的。 完成的 Job 通常不需要留存在系统中。在系统中一直保留它们会给 API 服务器带来额外的压力。 Kubernetes v1.23 之后, TTL 控制器所提供的 TTL 机制。 通过设置 Job 的 .spec.ttlSecondsAfterFini…