调整相机位置与天体尺寸后Three.js PointLight失效问题求助
Three.js 修改天体尺寸与相机位置后 PointLight 失效解决方案
我是Three.js新手,编写代码创建了太阳、地球和火星三个天体对象,原本代码运行正常,但修改相机位置、放大太阳与地球的尺寸后,发现PointLight不再生效。以下是可正常运行的代码与失效的代码,希望得到解决方案。
正常运行代码
import * as THREE from 'three'; import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'; import { GUI } from 'dat.gui'; // 导入静态资源 import stars from './static/stars.jpg'; import sunTexture from './static/sun.jpg'; import earthTexture from './static/earth.jpg'; import marsTexture from './static/mars.jpg'; // 创建场景 const scene = new THREE.Scene(); const cubeTextureLoader = new THREE.CubeTextureLoader(); scene.background = cubeTextureLoader.load([ stars, stars, stars, stars, stars, stars, ]); const camera = new THREE.PerspectiveCamera( 45, // 视场角 window.innerWidth / window.innerHeight, 0.1, 1000, ); camera.position.set(0, 30, 50); const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); const textureLoader = new THREE.TextureLoader(); const gui = new GUI(); const options = { displayAxis: false, sunRotate: true, }; gui.add(options, 'sunRotate'); gui.add(options, 'displayAxis'); const sunGeometry = new THREE.SphereGeometry(1); const sunMaterial = new THREE.MeshBasicMaterial({ color: 0xFFFFFF, map: textureLoader.load(sunTexture), }); const sun = new THREE.Mesh(sunGeometry, sunMaterial); scene.add(sun); const createPlanet = (size, positions, texture) => { // 与太阳创建逻辑一致 const planetGeometry = new THREE.SphereGeometry(size); const planetMaterial = new THREE.MeshStandardMaterial({ map: textureLoader.load(texture), }); const planet = new THREE.Mesh(planetGeometry, planetMaterial); planet.position.x = positions[0] || 0; planet.position.y = positions[1] || 0; planet.position.z = positions[2] || 0; const sunStar = new THREE.Object3D(); sunStar.add(planet); scene.add(sunStar); return { planet, sunStar }; }; const earth = createPlanet(0.3, [3], earthTexture); const mars = createPlanet(0.5, [10, 0, 5], marsTexture); const pointLight = new THREE.PointLight(0xFFFFFF, 10, 300); scene.add(pointLight); const ambientLight = new THREE.AmbientLight(0x333333, 2); scene.add(ambientLight); const pointLightHelper = new THREE.PointLightHelper(pointLight, 300); scene.add(pointLightHelper); new OrbitControls(camera, renderer.domElement); const axesHelper = new THREE.AxesHelper(100); scene.add(axesHelper); const animate = () => { // 跟随屏幕刷新率刷新画面 requestAnimationFrame(animate); if (options.sunRotate) { sun.rotateY(0.001); } earth.planet.rotateY(0.03); earth.sunStar.rotateY(0.005); mars.planet.rotateY(0.019); mars.sunStar.rotateY(0.001); if (options.displayAxis) { scene.add(axesHelper); } else { scene.remove(axesHelper); } renderer.render(scene, camera); }; window.addEventListener('resize', () => { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); }); animate();
失效代码
import * as THREE from 'three'; import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'; import { GUI } from 'dat.gui'; // 导入静态资源 import stars from './static/stars.jpg'; import sunTexture from './static/sun.jpg'; import earthTexture from './static/earth.jpg'; import marsTexture from './static/mars.jpg'; // 创建场景 const scene = new THREE.Scene(); const cubeTextureLoader = new THREE.CubeTextureLoader(); scene.background = cubeTextureLoader.load([ stars, stars, stars, stars, stars, stars, ]); const camera = new THREE.PerspectiveCamera( 45, // 视场角 window.innerWidth / window.innerHeight, 0.1, 1000, ); camera.position.set(-90, 140, 140); const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); const textureLoader = new THREE.TextureLoader(); const gui = new GUI(); const options = { displayAxis: false, sunRotate: true, }; gui.add(options, 'sunRotate'); gui.add(options, 'displayAxis'); const sunGeometry = new THREE.SphereGeometry(16); const sunMaterial = new THREE.MeshBasicMaterial({ map: textureLoader.load(sunTexture), }); const sun = new THREE.Mesh(sunGeometry, sunMaterial); scene.add(sun); const createPlanet = (size, positions, texture) => { // 与太阳创建逻辑一致 const planetGeometry = new THREE.SphereGeometry(size); const planetMaterial = new THREE.MeshStandardMaterial({ map: textureLoader.load(texture), }); const planet = new THREE.Mesh(planetGeometry, planetMaterial); planet.position.x = positions[0] || 0; planet.position.y = positions[1] || 0; planet.position.z = positions[2] || 0; const sunStar = new THREE.Object3D(); sunStar.add(planet); scene.add(sunStar); return { planet, sunStar }; }; const earth = createPlanet(6, [63], earthTexture); const mars = createPlanet(0.5, [10, 0, 5], marsTexture); const pointLight = new THREE.PointLight(0xFFFFFF, 1, 300, 2); scene.add(pointLight); const ambientLight = new THREE.AmbientLight(0x333333, 2); scene.add(ambientLight); const pointLightHelper = new THREE.PointLightHelper(pointLight, 300); scene.add(pointLightHelper); new OrbitControls(camera, renderer.domElement); const axesHelper = new THREE.AxesHelper(100); scene.add(axesHelper); const animate = () => { // 跟随屏幕刷新率刷新画面 requestAnimationFrame(animate); if (options.sunRotate) { sun.rotateY(0.001); } earth.planet.rotateY(0.03); earth.sunStar.rotateY(0.005); mars.planet.rotateY(0.019); mars.sunStar.rotateY(0.001); if (options.displayAxis) { scene.add(axesHelper); } else { scene.remove(axesHelper); } renderer.render(scene, camera); }; window.addEventListener('resize', () => { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); }); animate();
问题原因与解决方案
核心原因
- PointLight强度不足:失效代码中把PointLight的强度从10降到了1,但场景中天体尺寸放大了数倍(太阳半径从1变16,地球半径从0.3变6),光照强度不足以照亮远处的地球。
- 火星尺寸与位置未适配新尺度:火星仍使用原尺寸0.5和x=10的位置,被半径16的太阳完全遮挡,且位置过近无法体现光照效果。
- 灯光位置逻辑不合理:PointLight直接添加到场景原点,虽然太阳也在原点,但将灯光作为太阳子对象更符合天体光照逻辑,避免后续太阳移动时灯光脱节。
修改步骤
- 恢复/提升PointLight强度:将PointLight的强度参数改回10(或根据场景尺度调整为20),同时可简化衰减参数(保持默认即可):
const pointLight = new THREE.PointLight(0xFFFFFF, 10, 300);
- 将PointLight挂载到太阳对象下:让灯光跟随太阳旋转或移动,更符合真实场景:
sun.add(pointLight); // 替换原来的 scene.add(pointLight)
- 调整火星的尺寸与位置:适配新的场景尺度,避免被太阳遮挡:
const mars = createPlanet(3, [80, 0, 10], marsTexture);
- 可选:调整PointLightHelper尺寸:如果需要辅助查看灯光范围,可修改helper的尺寸为适配新场景的值:
const pointLightHelper = new THREE.PointLightHelper(pointLight, 50);
修改后重新运行代码,PointLight即可正常照亮地球和火星,同时场景尺度逻辑更合理。
内容的提问来源于stack exchange,提问作者Chicky
相关产品推荐
相关产品推荐

