Three.js设置emissiveIntensity后场景消失问题咨询
Three.js修改代码后场景消失的原因
我是Three.js新手,跟着一份3D文本教程操作时遇到问题:添加textMesh.material[0].emissiveIntensity = glow;后首次编译正常,3D文本、发光效果及场景都能正常显示;但修改文本位置textMesh.position.x = 10再次编译后,整个场景(包括文本)消失,只剩空白屏幕。用VSCode的ctrl-z撤销位置修改后,问题还是存在。
移除动画函数中的textMesh.material[0].emissiveIntensity = glow;后,场景就能正常加载。
我的问题是:为什么首次运行正常,添加该行代码后场景会全部消失?
我的代码:
import './style.css' import * as THREE from 'three'; import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'; import { TTFLoader } from 'three/examples/jsm/loaders/TTFLoader'; import { FontLoader } from 'three/examples/jsm/loaders/FontLoader'; import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry'; import { Reflector } from 'three/examples/jsm/objects/Reflector.js'; /* CREATE CAMERA */ const camera = new THREE.PerspectiveCamera( 100, window.innerWidth / window.innerHeight, 0.01, 1000); camera.position.setZ(65); camera.position.setX(300); camera.position.setY(20); /* END CAMERA */ /* CREATE SCENE & FOG */ const scene = new THREE.Scene(); var setcolor = 0x707070; //scene.fog = new THREE.Fog(setcolor, 1, 100); //scene.fog = new THREE.FogExp2(setcolor, 0.05); /* END SCENE & FOG */ /* CREATE RENDERER */ const renderer = new THREE.WebGLRenderer( { antialias: true, alpha: true } ); renderer.setSize( window.innerWidth, window.innerHeight ); renderer.setAnimationLoop( animation ); renderer.setPixelRatio( window.devicePixelRatio ); renderer.shadowMap.enabled = true document.body.appendChild( renderer.domElement ); /* END RENDERER */ /* CREATE ORBIT CONTROLS */ const controls = new OrbitControls(camera, renderer.domElement); /* END ORBIT CONTROLS */ /* CREATE LIGHTS */ const ambientLight = new THREE.AmbientLight(0xaaaaaa) scene.add(ambientLight) const light1 = new THREE.PointLight() light1.position.set(10, 200, 10) light1.castShadow = true light1.shadow.bias = -0.0002 light1.shadow.mapSize.height = 2048 light1.shadow.mapSize.width = 2048 scene.add(light1) let glow = 0.5; const textReactLight = new THREE.RectAreaLight( 0xf9d71c, glow, 150, 30); scene.add( textReactLight ); textReactLight.position.set( 5, 23, 5 ); textReactLight.lookAt( 0, 0, 120 ); /* END LIGHTS */ /* CREATE 3D FONT */ let text = "B\nR\nY\nC\nE"; let textMesh; const loader = new FontLoader(); loader.load('node_modules/three/examples/fonts/droid/droid_serif_regular.typeface.json', function (font) { const textGeometry = new TextGeometry(text, { font: font, size: 12, height: 5, curveSegments: 12, bevelEnabled: true, bevelThickness: 5, bevelSize: 2, bevelOffset: 2, bevelSegments: 15 }); textMesh = new THREE.Mesh(textGeometry, [ new THREE.MeshPhongMaterial({ emissive: 0xf9d71c, emissiveIntensity: glow }), new THREE.MeshPhongMaterial({ color: 0xffffff }) ]); scene.add( textMesh ); textMesh.position.y = 278; textMesh.position.x = 22 textMesh.position.z = -10 textMesh.rotation.y = Math.PI / 2 textMesh.castShadow = true; textMesh.receiveShadow = true; }) /* CREATE CITY */ // Floor const floorTexture = new THREE.TextureLoader().load('images/Concrete044B_2k_Color.jpg'); const floorNormalTexture = new THREE.TextureLoader().load('images/Concrete044B_2k_NormalDX.jpg'); const floor = new THREE.Mesh( new THREE.PlaneGeometry( 1000, 1000 ), new THREE.MeshBasicMaterial({ map: floorTexture, normalMap: floorNormalTexture, }) ); floor.rotateX( - Math.PI / 2 ); scene.add(floor); //Buildings const building1Texture = new THREE.TextureLoader().load('images/Facade002_4k_Color.jpg'); const building1 = new THREE.Mesh( new THREE.BoxGeometry( 100, 70, 45 ), new THREE.MeshBasicMaterial({ map: building1Texture, }) ); building1.position.y = 35 building1.position.x = -50 building1.position.z = -20 //scene.add( building1 ); const building2Texture = new THREE.TextureLoader().load('images/Facade005_4k_Color.jpg'); const building2 = new THREE.Mesh( new THREE.BoxGeometry( 150, 500, 150 ), new THREE.MeshBasicMaterial({ map: building2Texture, }) ); building2.position.y = 50 building2.position.x = -50 building2.position.z = -75 scene.add( building2 ); const building3Texture = new THREE.TextureLoader().load('images/Facade006_4k_Color.jpg'); const building3 = new THREE.Mesh( new THREE.BoxGeometry( 35, 85, 35 ), new THREE.MeshBasicMaterial({ map: building3Texture, }) ); building3.position.y = 35 building3.position.x = -50 building3.position.z = 35 //scene.add( building3 ); /* END CITY CREATION */ // Window resize update window.addEventListener('resize', onWindowResize, false) function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight camera.updateProjectionMatrix() renderer.setSize(window.innerWidth, window.innerHeight) animation() } //Animation function animation() { glow = Math.random() + 1; textMesh.material[0].emissiveIntensity = glow; //this is the line causing problems textReactLight.intensity = glow; controls.update(); renderer.render( scene, camera ); }
问题原因及解决办法
核心问题是字体加载是异步操作,textMesh在页面初始化阶段是undefined。首次运行时,可能字体加载完成的时机刚好早于动画函数执行到那行代码的时间,所以没报错;但后续编译刷新时,动画函数会在字体加载完成前就尝试访问textMesh.material[0],导致JavaScript抛出Cannot read properties of undefined错误,中断整个渲染流程,场景因此显示空白。
解决办法:在动画函数中添加判断,确保textMesh已初始化后再修改材质属性:
function animation() { glow = Math.random() + 1; // 先判断textMesh是否存在,避免未初始化时报错 if (textMesh) { textMesh.material[0].emissiveIntensity = glow; } textReactLight.intensity = glow; controls.update(); renderer.render( scene, camera ); }
另外补充:你设置的textMesh.position.y = 278位置偏高,就算修复报错,可能也需要调整相机位置才能清晰看到文本,但这不是场景消失的直接原因。
内容的提问来源于stack exchange,提问作者john jacobs
相关产品推荐
相关产品推荐

