You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调整相机位置与天体尺寸后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();

问题原因与解决方案

核心原因

  1. PointLight强度不足:失效代码中把PointLight的强度从10降到了1,但场景中天体尺寸放大了数倍(太阳半径从1变16,地球半径从0.3变6),光照强度不足以照亮远处的地球。
  2. 火星尺寸与位置未适配新尺度:火星仍使用原尺寸0.5和x=10的位置,被半径16的太阳完全遮挡,且位置过近无法体现光照效果。
  3. 灯光位置逻辑不合理:PointLight直接添加到场景原点,虽然太阳也在原点,但将灯光作为太阳子对象更符合天体光照逻辑,避免后续太阳移动时灯光脱节。

修改步骤

  1. 恢复/提升PointLight强度:将PointLight的强度参数改回10(或根据场景尺度调整为20),同时可简化衰减参数(保持默认即可):
const pointLight = new THREE.PointLight(0xFFFFFF, 10, 300);
  1. 将PointLight挂载到太阳对象下:让灯光跟随太阳旋转或移动,更符合真实场景:
sun.add(pointLight); // 替换原来的 scene.add(pointLight)
  1. 调整火星的尺寸与位置:适配新的场景尺度,避免被太阳遮挡:
const mars = createPlanet(3, [80, 0, 10], marsTexture);
  1. 可选:调整PointLightHelper尺寸:如果需要辅助查看灯光范围,可修改helper的尺寸为适配新场景的值:
const pointLightHelper = new THREE.PointLightHelper(pointLight, 50);

修改后重新运行代码,PointLight即可正常照亮地球和火星,同时场景尺度逻辑更合理。

内容的提问来源于stack exchange,提问作者Chicky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 02:44:54