uniapp 使用 tree.js 解决模型加载不出来的问题

ops/2025/2/9 12:34:15/

网上有很多uniapp使用tree.js的教程,但是我在使用测试中,发现tree.js的官方3d模型中有很多加载不出来,但是也没有报错,全网搜也没搜到方法,最后发现是缩放的问题,这里将代码贴出来,关键的方法是getFitScaleValue()这个方法

<template><view id="app"><canvas id="webgl" ref="webgl" canvas-id="webgl" type="webgl":style="'width:'+mSceneWidth+'px; height:'+mSceneHeight+'px;'"></canvas></view>
</template><script>import * as THREE from 'three'import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls.js'import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader.js';import {FBXLoader} from 'three/examples/jsm/loaders/FBXLoader.js';import {DRACOLoader} from "three/examples/jsm/loaders/DRACOLoader.js";import {OBJLoader} from "three/examples/jsm/loaders/OBJLoader.js";export default {//Soldierdata() {return {mSceneWidth: 0, // 手机屏幕宽度mSceneHeight: 0, // 手机屏幕高度canvas: null,worldFocus: null, // 世界焦点(模型放置,相机围绕的中心)renderer: null,mCanvasId: null,scene: null,mesh: null,camera: null,clock: null,renderAnimFrameId: null, // 渲染帧动画idcontrols: null,timeS: 0,changeFlag: true,mixer: null,previousTime: 0,modelUrl: "/static/Soldier.glb"};},mounted() {// uni.createSelectorQuery().in(this).select('#webgl').fields({// 	node: true// }).exec(res=> {// 	console.log(JSON.stringify(res))// 	this.mCanvasId = res[0].node.id;// 	// 注册画布// 	const mCanvas = THREE.global.registerCanvas(this.mCanvasId, res[0].node);// 	// 开始初始化// 	this.init(mCanvas);// })	},// 页面加载时onLoad(option) {// 获取手机屏幕宽高this.mSceneWidth = uni.getWindowInfo().windowWidth;this.mSceneHeight = uni.getWindowInfo().windowHeight;// 设置世界中心this.worldFocus = new THREE.Vector3(0, 0, 0);},// 页面加载完毕后onReady() {this.init()},onShow() {},onHide() {this.disposes()cancelAnimationFrame(this.animate())},methods: {// 在不需要时释放资源disposes() {// 释放几何体this.scene.traverse((object) => {if (object.geometry) {object.geometry.dispose();}// 释放材质if (object.material) {if (Array.isArray(object.material)) {object.material.forEach(material => material.dispose());} else {object.material.dispose();}}});// 释放渲染器if (this.renderer) {this.renderer.dispose();}// 清除场景while (this.scene.children.length > 0) {this.scene.remove(this.scene.children[0]);}},getFitScaleValue(scene) {let box=new THREE.BoxGeometry(3,3,3)let mail=new THREE.MeshBasicMaterial({color:0xff6600})let mesh=new THREE.Mesh(box,mail)var boxes = new THREE.Box3().setFromObject( scene );var maxDiameter =  Math.max((boxes.max.x - boxes.min.x), (boxes.max.y - boxes.min.y), (boxes.max.z - boxes.min.z)); //数值越大,模型越小console.log(maxDiameter)return Math.ceil(this.mSceneHeight / maxDiameter/4);},init() {// 创建一个场景this.scene = new THREE.Scene()//三位坐标线// const axesHelper = new THREE.AxesHelper(5);// this.scene.add(axesHelper);//创建相机对象,45是相机的视角  , 宽高比是屏幕的宽高比 , 最近能看到0.1 , 最远能看到10000// this.camera = new THREE.OrthographicCamera(-s * k, s * k, s , -s, 1, 1000);// this.camera.position.set(0, 20, 300);const lod = new THREE.LOD();// 创建不同细节级别的几何体const highDetailGeometry = new THREE.BoxGeometry(1, 1, 1);const mediumDetailGeometry = new THREE.BoxGeometry(0.5, 0.5, 0.5);const lowDetailGeometry = new THREE.BoxGeometry(0.25, 0.25, 0.25);// 创建材质const material = new THREE.MeshBasicMaterial({color: 0xff0000});// 创建不同细节级别的网格const highDetailMesh = new THREE.Mesh(highDetailGeometry, material);const mediumDetailMesh = new THREE.Mesh(mediumDetailGeometry, material);const lowDetailMesh = new THREE.Mesh(lowDetailGeometry, material);// 将不同细节级别的网格添加到LOD对象中lod.addLevel(highDetailMesh, 0); // 距离0lod.addLevel(mediumDetailMesh, 5); // 距离5lod.addLevel(lowDetailMesh, 10); // 距离10this.scene.add(lod);this.camera = new THREE.PerspectiveCamera(75, this.mSceneWidth / this.mSceneHeight, 0.1, 2000);//100,300 ,500this.camera.position.set(0, 0, 5); //设置相机位置//this.camera.position.set(100, -800, 500);this.scene.add(this.camera)this.camera.lookAt(this.scene.position); //设置相机方向(指向的场景对象)// 执行一个渲染函数this.rendererGLR()/* 光源设置*/this.pointLight()this.clock = new THREE.Clock()//创建控件对象this.change()//更新轨道控件let fileName = this.modelUrl.lastIndexOf(".")let fileFormat = this.modelUrl.substring(fileName + 1, this.modelUrl.length).toLowerCase()if (fileFormat == 'fbx') {this.fbxLoader()} else if (fileFormat == 'glb') {this.gblLoader()} else if (fileFormat == 'obj') {this.objLoader()}//this.renderer.render(this.scene, this.camera);},pointLight() {let ambientLight = new THREE.AmbientLight(0xffffff, 1);this.scene.add(ambientLight);const directional_light = new THREE.DirectionalLight(0xffffff, 1);directional_light.position.set(0, 1, 0);directional_light.castShadow = true;this.scene.add(directional_light);let a = 1,b = 0.6,c = 10;let directionalLight1 = new THREE.DirectionalLight(0xffffff, b);directionalLight1.position.set(-a, -a, a * c).normalize();let directionalLight2 = new THREE.DirectionalLight(0xffffff, b);directionalLight2.position.set(a, -a, -a * c).normalize();let directionalLight3 = new THREE.DirectionalLight(0xffffff, b);directionalLight3.position.set(-a, a, -a * c).normalize();let directionalLight4 = new THREE.DirectionalLight(0xffffff, b);directionalLight4.position.set(a, a, a * c).normalize();this.scene.add(directionalLight1);this.scene.add(directionalLight2);this.scene.add(directionalLight3);this.scene.add(directionalLight4);},//渲染函数rendererGLR() {this.$nextTick(() => {const element = document.getElementById('webgl')this.canvas = elementthis.renderer.setSize(element.clientWidth, element.clientHeight);element.appendChild(this.renderer.domElement);})this.renderer = new THREE.WebGLRenderer({alpha: true,antialias: true,powerPreference: "high-performance",precision: "mediump"}); //alpha:true背景透明this.renderer.setPixelRatio(window.devicePixelRatio * 2);this.renderer.toneMapping = THREE.ACESFilmicToneMapping;this.renderer.toneMappingExposure = 1.0;this.renderer.outputColorSpace = THREE.SRGBColorSpace;this.renderer.shadowMap.enabled = true;this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;},//创建控件对象change() {this.controls = new OrbitControls(this.camera, this.renderer.domElement);this.controls.minDistance = 300this.controls.maxDistance = 1000this.controls.addEventListener('change', () => {this.renderer.render(this.scene, this.camera);}); //监听鼠标、键盘事件//禁止缩放this.controls.enableZoom = this.changeFlag//禁止旋转this.controls.enableRotate = this.changeFlag//禁止右键拖拽this.controls.enablePan = this.changeFlag},//更新轨道控件animate() {if (this.renderer) {// console.log(this.stats)// this.stats.update()let T = this.clock.getDelta()let renderT = 1 / 30this.timeS = this.timeS + Tif (this.timeS > renderT) {this.controls.update();this.renderer.render(this.scene, this.camera);this.timeS = 0}requestAnimationFrame(this.animate);if (!this.changeFlag) {this.controls.autoRotateSpeed = 16}this.controls.autoRotate = false // 是否自动旋转}//创建一个时钟对象//this.clock = new THREE.Clock()//this.scene.rotateY(0.01)//获得两帧的时间间隔  更新混合器相关的时间if (this.mixer) {this.mixer.update(this.clock.getDelta()*100)}},objLoader() {let that = thisconst loader = new OBJLoader();uni.showLoading({title: "正在加载"})// load a resourceloader.load(// resource URLthat.modelUrl,// called when resource is loadedfunction(object) {console.log(object)uni.hideLoading()var scale = that.getFitScaleValue(object)console.log(scale)object.scale.set(scale, scale, scale);that.scene.add(object);setTimeout(function() {//that.renderer.render(that.scene, that.camera);that.animate()}, 1000);},// called when loading is in progressfunction(xhr) {console.log((xhr.loaded / xhr.total * 100) + '% loaded');},// called when loading has errorsfunction(error) {console.log('An error happened');});},//导入FBX模型文件fbxLoader() {let that = thisconst loader = new FBXLoader();loader.load(this.modelUrl, function(mesh) {that.scene.add(mesh);that.ownerInstance.callMethod('onload')})},//导入GLB模型文件gblLoader() {uni.showLoading({title: "正在加载",})let that = thisconst loader = new GLTFLoader();const dracoloader = new DRACOLoader();dracoloader.setDecoderPath("/static/draco/");loader.setDRACOLoader(dracoloader);loader.load(that.modelUrl, function(gltf) {uni.hideLoading()//that.mesh = gltf.sceneif (gltf.animations.length > 0) {that.mixer = new THREE.AnimationMixer(gltf.scene)const action = that.mixer.clipAction(gltf.animations[0])// 让动画进入播放状态action.play()}var scale = that.getFitScaleValue(gltf.scene)console.log(scale)gltf.scene.scale.set(scale, scale, scale);that.scene.add(gltf.scene);setTimeout(function() {//that.renderer.render(that.scene, that.camera);that.animate()}, 1000);}, function(xhr) {console.log((xhr.loaded / xhr.total * 100) + '% loaded');}, function(err) {console.log(err)});},// 触摸开始// 触摸事件处理onTouchStart(event) {const touch = event.touches[0];const rect = this.canvas.getBoundingClientRect();const x = touch.clientX - rect.left;const y = touch.clientY - rect.top;// 在这里处理触摸开始事件},onTouchMove(event) {const touch = event.touches[0];const rect = this.canvas.getBoundingClientRect();const x = touch.clientX - rect.left;const y = touch.clientY - rect.top;// 在这里处理触摸移动事件},onTouchEnd() {// 在这里处理触摸结束事件}}}
</script><style lang="scss">
</style>

未调用缩放方法,就是空白,调用后:


http://www.ppmy.cn/ops/156968.html

相关文章

MySQL基于binlog和gtid主从搭建方案

MySQL基于binlog和gtid主从搭建方案 一.主库配置 1.1 确认 binlog 是否开启 SHOW VARIABLES LIKE %log_bin%; 1.2 创建日志目录并设置权限 mkdir -p /opt/mysql/log_bin chown -R mysql:mysql /usr/local/mysql chmod -R 755 /usr/local/mysql 1.3 修改 my.cnf 配置文件 …

【Linux】28.Linux 多线程(2)

文章目录 5. Linux线程互斥5.1 进程线程间的互斥相关背景概念5.2 互斥量mutex5.2.1 互斥量的接口5.2.2 销毁互斥量5.2.3 互斥量加锁和解锁 5.3 互斥量实现原理探究5.4 互斥量的封装 6. 可重入VS线程安全6.1 常见的线程不安全的情况&#xff1a;6.2 常见的线程安全的情况6.3 常见…

LeetCode 106.从中序与后序遍历序列构造二叉树

题目描述 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 示例 1: 输入&#xff1a;inorder [9,3,15,20,7], postorder [9,15,7,20,3] 输出&am…

LIMO:少即是多的推理

25年2月来自上海交大、SII 和 GAIR 的论文“LIMO: Less is More for Reasoning”。 一个挑战是在大语言模型&#xff08;LLM&#xff09;中的复杂推理。虽然传统观点认为复杂的推理任务需要大量的训练数据&#xff08;通常超过 100,000 个示例&#xff09;&#xff0c;但本文展…

OSPF基础(2):数据包详解

OSPF数据包(可抓包) OSPF报文直接封装在IP报文中&#xff0c;协议号89 头部数据包内容&#xff1a; 版本(Version):对于OSPFv2&#xff0c;该字段值恒为2(使用在IPV4中)&#xff1b;对于OSPFv3&#xff0c;该字段值恒为3(使用在IPV6中)。类型(Message Type):该OSPF报文的类型。…

51单片机看门狗系统

在 STC89C52 单片机中&#xff0c;看门狗控制寄存器的固定地址为 0xE1。此地址由芯片厂商在硬件设计时确定&#xff0c;但是它在头文件中并未给出&#xff0c;因此在使用看门狗系统时需要声明下这个特殊功能寄存器 sfr WDT_CONTR 0xE1; 本案将用一个小灯的工作状况来展示看门…

unity碰撞的监测和监听

1.创建一个地面 2.去资源商店下载一个火焰素材 3.把procedural fire导入到自己的项目包管理器中 4.给magic fire 0 挂在碰撞组件Rigidbody , Sphere Collider 5.创建脚本test 并挂在magic fire 0 脚本代码 using System.Collections; using System.Collections.Generic; usi…

redis高级数据结构布隆过滤器

文章目录 背景什么是布隆过滤器Redis 中的布隆过滤器布隆过滤器使用注意事项实现原理空间占用估计 背景 我们在使用新闻客户端看新闻时&#xff0c;它会给我们不停地推荐新的内容&#xff0c;它每次推荐时要去重&#xff0c;去掉那些已经看过的内容。问题来了&#xff0c;新闻…