3D模型点光源扩散效果实现指南:从基础原理到Three.js实战

1次阅读
没有评论

共计 2660 个字符,预计需要花费 7 分钟才能阅读完成。

image.webp

光的基础原理:平方反比定律

点光源的光照强度遵循平方反比定律(Inverse-square law),用公式表示为:

3D 模型点光源扩散效果实现指南:从基础原理到 Three.js 实战

I = P / (4πr²)

其中:
– I 是光照强度(Intensity)
– P 是光源总功率(Power)
– r 是到光源的距离(Distance)

通过这个 ASCII 示意图可以直观理解:

     光源
       *
      /|\
     / | \  光照强度随距离
    /  |  \ 呈指数级衰减
   /   |   \
  A    B    C
 (1m) (2m) (3m)

技术方案对比

  1. Three.js 方案
  2. 优势:API 简洁,文档完善,适合快速开发
  3. 劣势:高阶效果需要自定义 Shader

  4. WebGL 原生方案

  5. 优势:性能最优,完全可控
  6. 劣势:开发成本高,需要深入图形学知识

  7. Babylon.js 方案

  8. 优势:内置更多特效(如 SSAO)
  9. 劣势:学习曲线较陡

核心实现步骤

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);
}

性能优化策略

  1. 光源数量控制
  2. 测试数据:RTX 3060 显卡下

    • 1 个光源:60FPS
    • 5 个光源:45FPS
    • 10 个光源:22FPS
  3. 使用 LightProbe

    const lightProbe = new THREE.LightProbe();
    lightProbe.fromScene(scene); // 将场景光照烘焙到探针 

避坑指南

常见问题排查

  1. 光照不生效
  2. 检查材质类型(StandardMaterial/PhysicalMaterial 才能接收光照)
  3. 确认场景中未添加环境光(AmbientLight 会冲淡效果)
  4. 验证光源是否在摄像机视野内

  5. 性能骤降

  6. 使用 stats.js 监控帧率
  7. 减少实时阴影计算(castShadow/receiveShadow)

移动端适配

  • 降低光源质量:pointLight.shadow.mapSize.width = 512
  • 使用性能模式:renderer.setPixelRatio(window.devicePixelRatio)

延伸思考

  1. 动态光源跟随

    function updateLightPosition() {pointLight.position.x = Math.sin(Date.now() * 0.001) * 3;
    }

  2. 多光源颜色混合

  3. 线性叠加:color1.add(color2).clamp()
  4. 使用色调映射(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)能显著提升帧率。

正文完
 0
评论(没有评论)