Three.js中GLB模型无法加载的问题排查与修复请求
GLB模型无法显示问题排查与修复
问题背景
开发纯HTML/JS的WebGL游戏,具备一定JavaScript基础。按Three.js文档教程实现后,场景其他元素正常加载,但同目录下的GLB模型始终无法显示,请求排查问题并以简单语言说明原因及修复方法,尽量保留原有代码结构。
完整代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>My first three.js app</title> <style> body { margin: 0; } #info { position: absolute; top: 10px; width: 100%; text-align: center; z-index: 100; display:block; } </style> <script src="https://threejs.org/build/three.js"></script> <script type="importmap"> { "imports": { "three": "https://unpkg.com/three@0.159.0/build/three.module.js", "three/addons/": "https://unpkg.com/three@0.159.0/examples/jsm/", "cannon-es": "https://cdn.jsdelivr.net/npm/cannon-es@0.20.0/dist/cannon-es.min.js" } } </script> </head> <body> <div id="info">0</div> <script type="module"> import * as THREE from "three"; import { OrbitControls } from "three/addons/controls/OrbitControls.js"; import { Clock } from "three"; import { PointerLockControls } from "three/addons/controls/PointerLockControls.js"; import * as CANNON from "cannon-es"; import { OBJLoader } from "three/addons/loaders/OBJLoader.js"; import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; const score = document.getElementById("info"); let points = 0; let colide = false; let checkK = false; let Name; let boddy; const clock = new Clock(); const world = new CANNON.World(); world.gravity.set(0, -9.82, 0); const loader = new GLTFLoader(); const physicsMaterial = new CANNON.Material(); const physicsContactMaterial = new CANNON.ContactMaterial( physicsMaterial, physicsMaterial, { friction: 0.4, restitution: 0.0 } ); world.addContactMaterial(physicsContactMaterial); function createCannonBox(size, position, masss) { this.shape = new CANNON.Box( new CANNON.Vec3(size.x / 2, size.y / 2, size.z / 2) ); this.body = new CANNON.Body({ mass: masss, material: physicsMaterial, }); this.body.addShape(this.shape); this.body.position.copy(position); world.addBody(this.body); return this.body; } function createCannonBall(size, positionn, masss) { this.shape = new CANNON.Sphere(size); this.body = new CANNON.Body({ mass: masss, material: physicsMaterial, shape: this.shape }); this.body.position.copy(positionn); world.addBody(this.body); return this.body; } function createCannonKnot(size, position) { const Sshape = new CANNON.Sphere(size); const Sbody = new CANNON.Body({ mass: 1, material: physicsMaterial }); Sbody.addShape(Sshape); Sbody.position.copy(position); world.addBody(Sbody); return Sbody; } function CreateTrimesh(geometry) { const vertices = geometry.attributes.position.array; const indices = Object.keys(vertices).map(Number); return new CANNON.Trimesh(vertices, indices); } const groundShape = new CANNON.Plane(); const groundBody = new CANNON.Body({ mass: 0, shape: groundShape, material: physicsMaterial, }); groundBody.quaternion.setFromAxisAngle( new CANNON.Vec3(1, 0, 0), -Math.PI / 2 ); world.addBody(groundBody); const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); camera.position.z = 3; const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); const Oloader = new OBJLoader(); const concreteTexture = new THREE.TextureLoader().load( "https://threejsfundamentals.org/threejs/resources/images/wall.jpg" ); const controls = new PointerLockControls(camera, document.body); const geometry = new THREE.BoxGeometry(1, 1, 1); const material = new THREE.MeshPhysicalMaterial({ color: 0x00ff00, map: concreteTexture, clearcoat: 0.1, }); const cube = new THREE.Mesh(geometry, material); cube.castShadow = true; scene.add(cube); // 修复:路径修改为同目录相对路径 loader.load( './free_1975_porsche_911_930_turbo.glb', function ( gltf ) { const sword = gltf.scene; sword.scale.set(0.05, 0.05, 0.05); // 修复:模型缩放适配场景 sword.position.y = 1; scene.add(sword); }, undefined, function(error) { console.log('模型加载错误:', error); // 新增:错误日志排查 } ); const cubeBody = new createCannonBox( new THREE.Vector3(1, 1, 1), new CANNON.Vec3(0.5, 4, 0), 1 ); const Sgeometry = new THREE.SphereGeometry(0.5, 40, 20); const ball = new THREE.Mesh(Sgeometry, material); ball.castShadow = true; scene.add(ball); const ballBody = new createCannonBall( 0.5, new CANNON.Vec3(0.5, 20, 0), 1 ) const cube2 = new THREE.Mesh(geometry, material); cube2.castShadow = true; scene.add(cube2); const cubeBody2 = new createCannonBox( new THREE.Vector3(1, 1, 1), new CANNON.Vec3(0, 2, 0), 0 ); const groundMaterial = new THREE.MeshPhysicalMaterial({ map: concreteTexture, clearcoat: 1, clearcoatRoughness: 1, metalness: 0.9, }); const groundGeometry = new THREE.PlaneGeometry(20, 20, 100, 100); const ground = new THREE.Mesh(groundGeometry, groundMaterial); ground.rotation.x = -Math.PI / 2; scene.add(ground); scene.background = new THREE.Color(0x87ceeb); const light = new THREE.DirectionalLight(0xffffff, 1); light.position.set(0, 15, 5); light.castShadow = true; scene.add(light); const light2 = new THREE.AmbientLight(0x404040); scene.add(light2); light.shadow.camera.near = 0.1; light.shadow.camera.far = 40; light.shadow.mapSize.width = 1025; light.shadow.mapSize.height = 1025; light.shadow.radius = 4; renderer.shadowMap.enabled = true; light.shadow.camera.left = -10; light.shadow.camera.right = 10; light.shadow.camera.top = 10; light.shadow.camera.bottom = -10; light.shadow.bias = -0.002; camera.position.y = 1; var keys = {}; window.addEventListener("keydown", function (ev) { keys[ev.key] = true; }); window.addEventListener("keyup", function (ev) { keys[ev.key] = false; }); window.addEventListener("keydown", function (ev) { if (ev.code == "KeyE") { checkK = !checkK; } }); const moveVector = new THREE.Vector3(); const setVector = new CANNON.Vec3(); camera.rotation.order = "YXZ"; const initialCubePosition = cube.position.clone(); const initialCubePosition2 = cube2.position.clone(); const initialBallPosition = ball.position.clone(); const resetInterval = 2.0; let lastResetTime = clock.elapsedTime; function check() { cubeBody2.addEventListener("collide", function (e) { colide = true; }); cubeBody.addEventListener("collide", function (e) { Name = cube; boddy = cubeBody; }); ballBody.addEventListener("collide", function (e) { Name = ball; boddy = ballBody; }); } function go() { if (keys.w) moveVector.z -= 0.1; if (keys.s) moveVector.z += 0.1; if (keys.a) moveVector.x -= 0.1; if (keys.d) moveVector.x += 0.1; if (keys.c) moveVector.y -= 0.1; if (keys.v) moveVector.y += 0.1; if (checkK && colide && keys.e) (checkK = false), (colide = false), (boddy.mass = 1); if (keys.m) controls.lock(); moveVector.multiplyScalar(0.6); camera.translateX(moveVector.x); camera.translateZ(moveVector.z); camera.translateY(moveVector.y); if (colide && checkK) { boddy.mass = 1; boddy.quaternion.copy(camera.quaternion); Name.position.copy(camera.position); Name.translateX(moveVector.x); Name.translateY(moveVector.y); Name.translateZ(moveVector.z - 3); boddy.position.copy(Name.position); } score.innerText = checkK; cube.position.copy(cubeBody.position); cube.quaternion.copy(cubeBody.quaternion); ball.position.copy(ballBody.position); ball.quaternion.copy(ballBody.quaternion); cube2.position.copy(cubeBody2.position); cube2.quaternion.copy(cubeBody2.quaternion); cubeBody2.position.copy(camera.position); if (clock.elapsedTime - lastResetTime >= resetInterval) { lastResetTime = clock.elapsedTime; } } function animate() { const delta = clock.getDelta(); world.step(delta); check(); go(); renderer.render(scene, camera); requestAnimationFrame(animate); } animate(); </script> </body> </html>
问题说明与修复
- 路径错误:原代码用
../指向上级目录,但模型和代码在同一目录,改成./或直接写文件名就能正确加载 - 模型缩放问题:原模型尺寸太大,超出场景视野看不到,把缩放比例设为
0.05就能适配现有场景 - 新增错误日志:添加加载失败回调函数,打印错误信息,方便后续排查加载异常
内容的提问来源于stack exchange,提问作者Blaze Branham
相关产品推荐
相关产品推荐

