BabylonJS - 反射探针
Babylon.js - 反射探针
Section titled “Babylon.js - 反射探针”ReflectionProbe 是 Babylon.js 中一个强大的工具,用于捕捉场景中特定点周围的环境并生成一个立方体贴图纹理。然后,这个立方体贴图可以应用于材质(如 StandardMaterial 或 PBRMaterial)作为反射纹理,在镜子、抛光金属或水面等物体上创建逼真的反射。
可以把反射探针想象成一个位于特定点的小型摄像机,捕捉 360 度视图(上、下、左、右、前、后)。这个捕获的视图被存储为 CubeTexture。当应用于材质时,物体看起来会反射探针捕捉的环境。
创建反射探针
Section titled “创建反射探针”通过提供名称、生成的立方体贴图面的尺寸(2 的幂次方,例如 512)以及场景来创建 ReflectionProbe。
import * as BABYLON from '@babylonjs/core';
// Assuming 'scene' is definedconst probeResolution = 512; // Quality of the reflection texture (e.g., 256, 512, 1024)
const reflectionProbe = new BABYLON.ReflectionProbe("myProbe", probeResolution, scene);
// By default, the probe captures everything. You often want to specify WHICH meshes// should appear in the reflection. Add meshes to the probe's render list:// reflectionProbe.renderList.push(meshToIncludeInReflection1);// reflectionProbe.renderList.push(meshToIncludeInReflection2);探针的位置决定了反射捕捉的视点。默认情况下,它位于 (0,0,0),但你可以将其附加到网格或手动设置其位置:reflectionProbe.position = new BABYLON.Vector3(x, y, z);。
将探针应用于材质
Section titled “将探针应用于材质”要使用探针使对象具有反射性,请将探针生成的立方体纹理(probe.cubeTexture)分配给对象材质的 reflectionTexture 属性。
// Assuming 'reflectiveMesh' and its 'material' (Standard or PBR) are defined
// Assign the probe's cube map to the material's reflection texture slotmaterial.reflectionTexture = reflectionProbe.cubeTexture;
// Optional: Control reflection intensity and appearance// For StandardMaterial:// material.reflectionFresnelParameters = new BABYLON.FresnelParameters();// material.reflectionFresnelParameters.bias = 0.1; // Controls falloff
// For PBRMaterial (reflection is controlled by metallic/roughness/reflectivity):// material.metallic = 1.0;// material.roughness = 0.1;// or// material.reflectivityColor = new BABYLON.Color3(1, 1, 1); // Full reflection// material.microSurface = 0.1; // Smooth surfaceprobe.renderList 至关重要。它是一个数组,包含应渲染到反射探针立方体贴图中的网格。如果列表为空(或为 null,这是默认值),探针会尝试渲染场景中的 所有 网格,这可能效率低下,并可能包含不需要的对象(例如反射对象本身,导致无限反射)。最佳实践是明确只将必要的周围网格添加到 renderList 中。
与 Mirror Texture 的比较
Section titled “与 Mirror Texture 的比较”Babylon.js 还具有 MirrorTexture,它创建平面反射(类似于平面镜)。ReflectionProbe 创建立方体贴图反射,适用于反射整个周围环境的曲面或复杂表面。
此演示显示一个中央反射的绳结,反射周围的几个球体和一个带纹理的地面平面。
<!DOCTYPE html><html><head> <meta charset="utf-8"/> <title>Babylon.js - Reflection Probe Demo</title> <script src="https://cdn.babylonjs.com/babylon.js"></script> <script src="https://cdn.babylonjs.com/loaders/babylonjs.loaders.min.js"></script> <style> html, body { overflow: hidden; width: 100%; height: 100%; margin: 0; padding: 0; } #renderCanvas { width: 100%; height: 100%; touch-action: none; } </style></head><body> <canvas id="renderCanvas"></canvas> <script type="text/javascript"> const canvas = document.getElementById("renderCanvas"); const engine = new BABYLON.Engine(canvas, true);
const createScene = function () { const scene = new BABYLON.Scene(engine); scene.clearColor = new BABYLON.Color4(0.1, 0.1, 0.1, 1.0);
const camera = new BABYLON.ArcRotateCamera("camera1", -Math.PI / 2, Math.PI / 2.5, 15, BABYLON.Vector3.Zero(), scene); camera.attachControl(canvas, true); camera.wheelPrecision = 50; camera.minZ = 0.1;
const light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0.5, 1, 0.2), scene); light.intensity = 0.9;
// Reflective Object const knot = BABYLON.MeshBuilder.CreateTorusKnot("knot", { radius: 1, tube: 0.4, radialSegments: 128, tubularSegments: 64, p: 2, q: 3 }, scene); const knotMaterial = new BABYLON.PBRMaterial("knotMat", scene); // Using PBR for better reflections knotMaterial.metallic = 1.0; // Make it fully metallic knotMaterial.roughness = 0.1; // Make it quite smooth/shiny knot.material = knotMaterial;
// Objects to be reflected const yellowSphere = BABYLON.MeshBuilder.CreateSphere("yellowSphere", { diameter: 1.5 }, scene); yellowSphere.position = new BABYLON.Vector3(3, 0, 0); const yellowMat = new BABYLON.StandardMaterial("yellowMat", scene); yellowMat.diffuseColor = BABYLON.Color3.Yellow(); yellowSphere.material = yellowMat;
const blueSphere = BABYLON.MeshBuilder.CreateSphere("blueSphere", { diameter: 1.5 }, scene); blueSphere.position = new BABYLON.Vector3(-3, 0, 0); const blueMat = new BABYLON.StandardMaterial("blueMat", scene); blueMat.diffuseColor = BABYLON.Color3.Blue(); blueSphere.material = blueMat;
const greenSphere = BABYLON.MeshBuilder.CreateSphere("greenSphere", { diameter: 1.5 }, scene); greenSphere.position = new BABYLON.Vector3(0, 0, 4); const greenMat = new BABYLON.StandardMaterial("greenMat", scene); greenMat.diffuseColor = BABYLON.Color3.Green(); greenSphere.material = greenMat;
// Ground const ground = BABYLON.MeshBuilder.CreateGround("ground", { width: 20, height: 20 }, scene); const groundMaterial = new BABYLON.StandardMaterial("groundMat", scene); try { // Use a texture for the ground (ensure 'textures/ground.jpg' exists) const groundTexture = new BABYLON.Texture("textures/ground.jpg", scene); groundTexture.uScale = 5; groundTexture.vScale = 5; groundMaterial.diffuseTexture = groundTexture; } catch (err) { console.warn("Ground texture not found. Using color."); groundMaterial.diffuseColor = new BABYLON.Color3(0.5, 0.4, 0.3); } groundMaterial.specularColor = new BABYLON.Color3(0.1, 0.1, 0.1); // Dull specular ground.material = groundMaterial; ground.position.y = -2;
// --- Reflection Probe Setup --- const reflectionProbe = new BABYLON.ReflectionProbe("mainProbe", 512, scene); reflectionProbe.position = knot.position; // Center the probe on the knot
// Add ONLY the surrounding objects to the probe's render list reflectionProbe.renderList.push(yellowSphere); reflectionProbe.renderList.push(blueSphere); reflectionProbe.renderList.push(greenSphere); reflectionProbe.renderList.push(ground); // DO NOT add the 'knot' itself to avoid self-reflection issues
// Apply the probe to the knot's material knotMaterial.reflectionTexture = reflectionProbe.cubeTexture; // For PBR, setting metallic/roughness is usually enough. // For StandardMaterial, you'd add Fresnel parameters here. // ------------------------------
// Animate spheres for visual interest let angle = 0; scene.onBeforeRenderObservable.add(() => { angle += 0.01; yellowSphere.position.y = Math.sin(angle * 2) * 0.5; blueSphere.position.y = Math.cos(angle * 3) * 0.5; greenSphere.position.y = Math.sin(angle * 1.5 + Math.PI / 4) * 0.5; });
return scene; };
const scene = createScene(); engine.runRenderLoop(function () { scene.render(); }); window.addEventListener("resize", function () { engine.resize(); }); </script></body></html>此演示显示一个中央闪亮的金属绳结。周围有黄色、蓝色和绿色球体略微上下浮动,下方是一个带纹理的地面平面。由于反射探针位于绳结中心,中央绳结的表面逼真地反射了这些周围的球体和地面。当你旋转摄像机时,反射会根据观察角度动态变化。请注意,绳结本身不会出现在其反射中,因为它被排除在探针的 renderList 之外。
为了显示地面纹理,你需要在 HTML 文件相对位置的 textures 文件夹中放置一个名为 ground.jpg 的图像文件。
性能注意事项
Section titled “性能注意事项”反射探针会增加渲染开销,因为它需要渲染场景(或 renderList 中指定的场景部分)六次(立方体贴图的每个面一次)。应战略性地在关键的反射对象上使用它们,而不是过度使用。降低探针的分辨率(probeResolution)可以提高性能,但会牺牲反射的清晰度。对于静态场景,反射可能只需渲染一次。对于对象或反射表面移动的动态场景,探针可能需要定期更新。