joken-前端工程师

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: :: :: 管理 ::
  404 随笔 :: 39 文章 :: 8 评论 :: 20万 阅读

LightProbe 作用,增加材质光照明亮度细节

LightProbe 是 Three.js 中用于捕捉和模拟场景中的间接光照(Indirect Lighting)的一个重要工具。它通过在场景中放置多个探针来采集环境光信息,并将这些信息应用到场景中的物体上,从而增强渲染的真实感。以下是 LightProbe 的主要用途和工作原理:

主要用途

  1. 捕捉间接光照:

    • LightProbe 可以捕捉来自场景中其他物体反射的光线,即间接光照。这种光照信息可以显著提升场景中物体的真实感,特别是在没有直接光源照射的情况下。
  2. 全局照明(Global Illumination, GI):

    • 虽然 Three.js 本身不直接支持全局照明,但 LightProbe 提供了一种近似全局照明的方法。通过在场景中合理布置多个 LightProbe,可以模拟出更真实的光照效果。
  3. 环境贴图的应用:

    • LightProbe 可以从环境贴图(如立方体贴图)中获取光照信息,使得场景中的物体能够反射出周围环境的颜色和亮度,增强了视觉效果。
  4. 动态光照调整:

    • LightProbe 可以根据场景的变化动态更新其采集的光照信息,从而适应不同的光照条件。

工作原理

LightProbe 本质上是一个球形谐波(Spherical Harmonics, SH)采样器,它在场景中特定位置采集环境光信息,并将其存储为球形谐波系数。这些系数可以在渲染时用于计算每个像素点的间接光照贡献。

球形谐波(Spherical Harmonics)

  • 定义: 球形谐波是一种数学函数,常用于表示球面上的函数。在图形学中,它们被用来高效地表示低频光照信息。
  • 作用: 在 LightProbe 中,球形谐波用于压缩和存储环境光信息,以便在渲染时快速查询和应用。

使用示例

以下是一个简单的示例,展示了如何在 Three.js 中使用 LightProbe

import * as THREE from 'three';

// 创建场景、相机和渲染器
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 创建一个基本几何体
const geometry = new THREE.SphereGeometry(1, 32, 32);
const material = new THREE.MeshStandardMaterial({
    color: 0x00ff00,
    metalness: 0.5,
    roughness: 0.5
});
const sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);

// 设置相机位置
camera.position.z = 5;

// 添加方向光
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
scene.add(directionalLight);

// 创建并添加 LightProbe
const lightProbe = new THREE.LightProbe();
lightProbe.intensity = 1.0;
scene.add(lightProbe);

// 加载环境贴图
const cubeTextureLoader = new THREE.CubeTextureLoader();
cubeTextureLoader.load([
    'textures/cube/pisa/px.png', 'textures/cube/pisa/nx.png',
    'textures/cube/pisa/py.png', 'textures/cube/pisa/ny.png',
    'textures/cube/pisa/pz.png', 'textures/cube/pisa/nz.png'
], function (cubeTexture) {
    scene.background = cubeTexture;

    // 从立方体贴图生成 LightProbe 数据
    lightProbe.copy(THREE.LightProbeGenerator.fromCubeTexture(cubeTexture));

    render();
});

function render() {
    requestAnimationFrame(render);
    renderer.render(scene, camera);
}

window.addEventListener('resize', function () {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
});

关键步骤解释

  1. 创建和配置 LightProbe:

    const lightProbe = new THREE.LightProbe();
    lightProbe.intensity = 1.0;
    scene.add(lightProbe);
    
  2. 加载环境贴图并生成 LightProbe 数据:

    const cubeTextureLoader = new THREE.CubeTextureLoader();
    cubeTextureLoader.load([
        'textures/cube/pisa/px.png', 'textures/cube/pisa/nx.png',
        'textures/cube/pisa/py.png', 'textures/cube/pisa/ny.png',
        'textures/cube/pisa/pz.png', 'textures/cube/pisa/nz.png'
    ], function (cubeTexture) {
        scene.background = cubeTexture;
    
        lightProbe.copy(THREE.LightProbeGenerator.fromCubeTexture(cubeTexture));
    
        render();
    });
    
  3. 渲染循环:

    function render() {
        requestAnimationFrame(render);
        renderer.render(scene, camera);
    }
    

实际应用中的注意事项

  1. 探针的数量和位置:

    • 为了获得最佳效果,通常需要在场景中放置多个 LightProbe,并且这些探针的位置应尽量覆盖场景的主要区域。
  2. 性能考虑:

    • LightProbe 的计算成本较高,尤其是在高分辨率或复杂场景中。因此,合理控制探针的数量和分布非常重要。
  3. 与其他光源的结合:

    • LightProbe 通常与直接光源(如 DirectionalLightPointLight)结合使用,以提供更完整的光照效果。

总结

LightProbe 是一种强大的工具,用于捕捉和应用场景中的间接光照信息,从而提升渲染的真实感。通过合理配置和使用 LightProbe,你可以在 Three.js 场景中实现更逼真的光照效果,特别是在需要模拟全局照明的情况下。虽然它不能完全替代复杂的全局照明解决方案,但在很多情况下,它可以提供足够的视觉质量提升。

LightProbe 会影响哪些材质

LightProbe 在 Three.js 中主要用于捕捉和模拟场景中的间接光照(Indirect Lighting),并通过球形谐波(Spherical Harmonics, SH)系数将这些信息应用到场景中的物体上。然而,LightProbe 并不会自动作用于场景中的所有几何体,而是需要在材质中显式地启用对环境光遮蔽(Ambient Occlusion)和环境反射(Reflections)的支持。

LightProbe 如何影响几何体

  1. 材质支持:

    • LightProbe 的光照信息主要通过 MeshStandardMaterialMeshPhysicalMaterial 材质来应用。这些材质支持基于物理的渲染(PBR),能够利用 LightProbe 提供的间接光照信息。
    • 如果几何体使用的是不支持间接光照的材质(如 MeshBasicMaterial),那么即使场景中有 LightProbe,这些几何体也不会受到其影响。
  2. 手动关联:

    • LightProbe 需要被添加到场景中,并且场景中的几何体需要使用支持间接光照的材质才能受其影响。
    • 通常情况下,你不需要为每个几何体单独设置 LightProbe,只要它们使用了合适的材质并且 LightProbe 被正确添加到场景中即可。

示例代码

以下是一个示例,展示了如何在 Three.js 场景中使用 LightProbe 并确保它对场景中的几何体产生影响:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>three.js webgl - light probe effect</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
    <style>
        body { margin: 0; }
        canvas { display: block; }
    </style>
</head>
<body>

<script type="importmap">
{
    "imports": {
        "three": "../build/three.module.js",
        "three/addons/": "./jsm/"
    }
}
</script>

<script type="module">

import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { LightProbeGenerator } from 'three/addons/lights/LightProbeGenerator.js';
import { LightProbeHelper } from 'three/addons/helpers/LightProbeHelper.js';

let renderer, scene, camera;
let lightProbe, lightProbeHelper;

init();
animate();

function init() {

    // 创建渲染器
    renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);

    // 创建场景
    scene = new THREE.Scene();

    // 创建相机
    camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
    camera.position.set(10, 10, 10);
    camera.lookAt(0, 0, 0);

    // 创建控件
    const controls = new OrbitControls(camera, renderer.domElement);
    controls.addEventListener('change', render); // use if there is no animation loop
    controls.minDistance = 5;
    controls.maxDistance = 50;
    controls.target.set(0, 0, 0);
    controls.update();

    // 创建并添加 LightProbe
    lightProbe = new THREE.LightProbe();
    lightProbe.intensity = 1.0;
    scene.add(lightProbe);

    // 加载环境贴图并生成 LightProbe 数据
    const genCubeUrls = function (prefix, postfix) {
        return [
            prefix + 'px' + postfix, prefix + 'nx' + postfix,
            prefix + 'py' + postfix, prefix + 'ny' + postfix,
            prefix + 'pz' + postfix, prefix + 'nz' + postfix
        ];
    };

    const urls = genCubeUrls('textures/cube/pisa/', '.png');
    new THREE.CubeTextureLoader().load(urls, function (cubeTexture) {
        scene.background = cubeTexture;

        lightProbe.copy(LightProbeGenerator.fromCubeTexture(cubeTexture));

        // 添加 LightProbeHelper 来可视化 LightProbe
        lightProbeHelper = new LightProbeHelper(lightProbe, 1);
        scene.add(lightProbeHelper);

        // 创建一些几何体以便观察光照效果
        const geometry = new THREE.BoxGeometry(2, 2, 2);
        const material = new THREE.MeshStandardMaterial({
            color: 0x00ff00,
            metalness: 0.5,
            roughness: 0.5,
            envMap: cubeTexture,
            envMapIntensity: 1.0
        });

        for (let i = 0; i < 5; i++) {
            const mesh = new THREE.Mesh(geometry, material);
            mesh.position.set(-4 + i * 2, 0, 0);
            scene.add(mesh);
        }

        render();
    });

    // 监听窗口大小变化
    window.addEventListener('resize', onWindowResize);

}

function onWindowResize() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
    render();
}

function animate() {
    requestAnimationFrame(animate);
    render();
}

function render() {
    renderer.render(scene, camera);
}

</script>

</body>
</html>

关键点解释

1. 使用支持间接光照的材质

const material = new THREE.MeshStandardMaterial({
    color: 0x00ff00,
    metalness: 0.5,
    roughness: 0.5,
    envMap: cubeTexture,
    envMapIntensity: 1.0
});
  • 这里使用了 MeshStandardMaterial,这是一种基于物理的材质,支持间接光照和环境贴图。envMap 属性用于指定环境贴图,envMapIntensity 用于调整环境贴图的强度。

2. 添加 LightProbe 到场景

lightProbe = new THREE.LightProbe();
lightProbe.intensity = 1.0;
scene.add(lightProbe);
  • 创建了一个 LightProbe 实例,并将其添加到场景中。

3. 加载环境贴图并生成 LightProbe 数据

new THREE.CubeTextureLoader().load(urls, function (cubeTexture) {
    scene.background = cubeTexture;

    lightProbe.copy(LightProbeGenerator.fromCubeTexture(cubeTexture));
});
  • 使用 CubeTextureLoader 加载立方体贴图,并将该贴图设置为场景的背景。
  • 使用 LightProbeGenerator.fromCubeTexture 方法从立方体贴图生成 LightProbe 数据,并应用到 LightProbe 实例上。

LightProbe 对几何体的影响

  • 间接光照: LightProbe 捕捉场景中的间接光照信息,并将其应用于使用支持间接光照材质的几何体。这意味着只有那些使用了 MeshStandardMaterialMeshPhysicalMaterial 等支持间接光照的材质的几何体才会受到 LightProbe 的影响。

  • 环境贴图: 如果你在材质中设置了 envMap,则 LightProbe 会与环境贴图一起工作,提供更真实的反射效果。

总结

虽然 LightProbe 不会自动作用于场景中的所有几何体,但如果你的几何体使用了支持间接光照的材质(如 MeshStandardMaterial),那么它们就会受到 LightProbe 的影响。为了确保 LightProbe 正确发挥作用,请确保:

  1. 几何体使用了支持间接光照的材质。
  2. LightProbe 已被正确添加到场景中,并且其数据已从适当的光源或环境贴图中生成。

通过这种方式,你可以有效地利用 LightProbe 来增强场景的真实感和视觉质量。

不加LightProbe 会怎么样

如果几何体使用了支持间接光照的材质(如 MeshStandardMaterialMeshPhysicalMaterial),但场景中没有配置 LightProbe,这些几何体会依赖其他方式来获取间接光照信息。以下是几种常见的情况和它们对几何体的影响:

1. 环境贴图 (Environment Map)

如果没有 LightProbe,但场景中有设置环境贴图(例如立方体贴图),几何体仍然可以利用环境贴图来进行反射计算。环境贴图提供了周围环境的颜色和亮度信息,使得物体能够反射出周围的环境,从而增强真实感。

示例代码片段:

const material = new THREE.MeshStandardMaterial({
    color: 0x00ff00,
    metalness: 0.5,
    roughness: 0.5,
    envMap: cubeTexture, // 环境贴图
    envMapIntensity: 1.0
});
  • 效果:即使没有 LightProbe,几何体仍能从环境贴图中获得反射信息,从而在表面上产生逼真的反射效果。但是,由于缺乏 LightProbe 提供的间接光照数据,物体表面可能会显得较为平淡,缺乏细腻的阴影和光斑变化。

2. 直接光源 (Direct Light Sources)

如果没有 LightProbe,但场景中有足够的直接光源(如 DirectionalLightPointLightSpotLight),这些光源会为几何体提供直接光照。然而,直接光源只能提供直射光的效果,无法模拟复杂的间接光照(如漫反射、镜面反射等)。

示例代码片段:

const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.position.set(10, 10, 10);
scene.add(directionalLight);
  • 效果:几何体将受到直接光源的影响,表现出明显的明暗对比。但由于缺乏间接光照信息,物体表面的细节和真实感可能会有所欠缺,特别是在阴影区域和角落处,可能会显得过于黑暗或不自然。

3. 默认光照 (Ambient Light)

如果没有 LightProbe 和直接光源,Three.js 默认会提供一个全局的环境光(AmbientLight)。这种光照是均匀分布在整个场景中的,不会产生阴影,也不会有方向性。

示例代码片段:

const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
  • 效果:几何体会被均匀照亮,但光照效果非常平淡,缺乏层次感和真实感。由于没有方向性和阴影,物体看起来会显得平面化,缺乏立体感。

4. 无光照 (No Lighting)

如果场景中没有任何光源(包括 LightProbe、直接光源、环境贴图等),且几何体使用的是支持间接光照的材质(如 MeshStandardMaterial),那么这些几何体的表现将取决于材质的默认属性。

示例代码片段:

const material = new THREE.MeshStandardMaterial({
    color: 0x00ff00,
    metalness: 0.5,
    roughness: 0.5
});
  • 效果:在这种情况下,几何体可能会呈现出纯色或材质的基本颜色,但不会有任何光照效果。这通常会导致物体看起来非常不真实和平淡。

5. 混合使用

在实际项目中,通常会结合多种光源和光照技术来达到最佳效果。例如:

  • 使用 DirectionalLightPointLight 提供主要的直接光照。
  • 使用 LightProbe 提供间接光照,增强物体表面的真实感。
  • 使用环境贴图提供反射信息,使物体能够反映出周围环境。

综合示例:

// 创建直接光源
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.position.set(10, 10, 10);
scene.add(directionalLight);

// 加载环境贴图
const cubeTextureLoader = new THREE.CubeTextureLoader();
cubeTextureLoader.load([
    'textures/cube/pisa/px.png', 'textures/cube/pisa/nx.png',
    'textures/cube/pisa/py.png', 'textures/cube/pisa/ny.png',
    'textures/cube/pisa/pz.png', 'textures/cube/pisa/nz.png'
], function (cubeTexture) {
    scene.background = cubeTexture;

    // 创建并添加 LightProbe
    const lightProbe = new THREE.LightProbe();
    lightProbe.copy(THREE.LightProbeGenerator.fromCubeTexture(cubeTexture));
    scene.add(lightProbe);

    // 创建几何体
    const geometry = new THREE.BoxGeometry(2, 2, 2);
    const material = new THREE.MeshStandardMaterial({
        color: 0x00ff00,
        metalness: 0.5,
        roughness: 0.5,
        envMap: cubeTexture,
        envMapIntensity: 1.0
    });

    const mesh = new THREE.Mesh(geometry, material);
    scene.add(mesh);

    render();
});

总结

如果没有 LightProbe,支持间接光照的几何体将依赖于以下几种方式来获取光照信息:

  1. 环境贴图:提供反射信息,但缺乏间接光照的细微变化。
  2. 直接光源:提供明确的光照方向和阴影,但无法模拟复杂的间接光照效果。
  3. 默认环境光:均匀照亮整个场景,但缺乏真实感和层次感。
  4. 无光照:仅显示材质的基本颜色,没有光照效果。

为了实现更真实的光照效果,建议结合使用 LightProbe、直接光源和环境贴图等多种光照技术。这样可以使场景中的物体更加逼真,提升整体视觉质量。

posted on   joken1310  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
历史上的今天:
2018-03-06 linux拷贝文件夹cp
2018-03-06 docker 小结
点击右上角即可分享
微信分享提示