共计 2660 个字符,预计需要花费 7 分钟才能阅读完成。
光的基础原理:平方反比定律
点光源的光照强度遵循平方反比定律(Inverse-square law),用公式表示为:

I = P / (4πr²)
其中:
– I 是光照强度(Intensity)
– P 是光源总功率(Power)
– r 是到光源的距离(Distance)
通过这个 ASCII 示意图可以直观理解:
光源
*
/|\
/ | \ 光照强度随距离
/ | \ 呈指数级衰减
/ | \
A B C
(1m) (2m) (3m)
技术方案对比
- Three.js 方案
- 优势:API 简洁,文档完善,适合快速开发
-
劣势:高阶效果需要自定义 Shader
-
WebGL 原生方案
- 优势:性能最优,完全可控
-
劣势:开发成本高,需要深入图形学知识
-
Babylon.js 方案
- 优势:内置更多特效(如 SSAO)
- 劣势:学习曲线较陡
核心实现步骤
1. 场景搭建
// 初始化场景(Scene)、相机(Camera)和渲染器(Renderer)const scene = new THREE.Scene();
scene.background = new THREE.Color(0x111111);
// 坐标系示意:Y 轴向上,Z 轴朝向屏幕外
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);
2. 创建点光源
// 参数说明:// color - 光源颜色(十六进制)// intensity - 光照强度(默认 1)// distance - 光照有效距离(0 表示无限远)// decay - 衰减系数(默认 2,符合物理规律)const pointLight = new THREE.PointLight(
0xff8844, // 暖橙色
1, // 强度
10, // 照射距离
2 // 衰减
);
pointLight.position.set(0, 2, 0);
scene.add(pointLight);
// 添加光源辅助线(调试用)const lightHelper = new THREE.PointLightHelper(pointLight);
scene.add(lightHelper);
3. 配置接受光照的材质
// 使用 PBR 材质(基于物理的渲染)const material = new THREE.MeshStandardMaterial({
color: 0x6699ff,
roughness: 0.1, // 表面粗糙度(0-1)metalness: 0.9, // 金属质感程度(0-1)envMapIntensity: 0.2 // 环境贴图影响
});
const sphere = new THREE.Mesh(new THREE.SphereGeometry(1, 32, 32),
material
);
scene.add(sphere);
渲染循环与性能优化
function animate() {requestAnimationFrame(animate);
// 旋转物体观察光照效果
sphere.rotation.y += 0.01;
renderer.render(scene, camera);
}
性能优化策略
- 光源数量控制
-
测试数据:RTX 3060 显卡下
- 1 个光源:60FPS
- 5 个光源:45FPS
- 10 个光源:22FPS
-
使用 LightProbe
const lightProbe = new THREE.LightProbe(); lightProbe.fromScene(scene); // 将场景光照烘焙到探针
避坑指南
常见问题排查
- 光照不生效
- 检查材质类型(StandardMaterial/PhysicalMaterial 才能接收光照)
- 确认场景中未添加环境光(AmbientLight 会冲淡效果)
-
验证光源是否在摄像机视野内
-
性能骤降
- 使用 stats.js 监控帧率
- 减少实时阴影计算(castShadow/receiveShadow)
移动端适配
- 降低光源质量:
pointLight.shadow.mapSize.width = 512 - 使用性能模式:
renderer.setPixelRatio(window.devicePixelRatio)
延伸思考
-
动态光源跟随
function updateLightPosition() {pointLight.position.x = Math.sin(Date.now() * 0.001) * 3; } -
多光源颜色混合
- 线性叠加:
color1.add(color2).clamp() - 使用色调映射(ToneMapping)避免过曝
完整示例代码
// 初始化基础组件
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
camera.position.z = 5;
const renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 创建光源系统
const pointLight = new THREE.PointLight(0xff8844, 1, 10, 2);
pointLight.position.set(0, 2, 0);
scene.add(pointLight);
// 创建可交互物体
const geometry = new THREE.SphereGeometry(1, 32, 32);
const material = new THREE.MeshStandardMaterial({
color: 0x6699ff,
roughness: 0.1,
metalness: 0.9
});
const sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);
// 启动渲染循环
function animate() {requestAnimationFrame(animate);
sphere.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
通过这个完整案例,你应该已经掌握了 3D 场景中点光源的核心实现方法。在实际项目中,建议先从简单效果开始,逐步增加复杂度。遇到性能问题时,记住光照计算永远是性能瓶颈,合理使用烘焙光照(Baked Lighting)或光照探针(Light Probe)能显著提升帧率。
正文完
发表至: 未分类
近两天内
