BabylonJS - 视差贴图
Babylon.js - 视差映射 (Parallax Mapping)
Section titled “Babylon.js - 视差映射 (Parallax Mapping)”视差映射 (Parallax mapping),也称为偏移映射 (offset mapping) 或虚拟位移映射 (virtual displacement mapping),是一种用于增强 3D 模型上深度和表面细节幻觉的技术,而无需实际添加更多几何体。它通过根据高度图和观察角度来偏移纹理坐标来实现。这使得砖墙、鹅卵石路或岩石地形等表面看起来具有更多的“起伏”或凹凸感,尤其是在从某个角度观察时。
在 Babylon.js 中,视差映射通常作为 StandardMaterial 和 PBRMaterial 的一部分实现。它需要一个“凹凸贴图”(bump map)或“法线贴图”(normal map),该贴图还包含高度信息(通常存储在 alpha 通道中或作为单独的高度图)。
启用视差映射
Section titled “启用视差映射”要在 StandardMaterial 或 PBRMaterial 上启用基本的视差映射,你需要指定一个凹凸/法线纹理,并将 useParallax 属性设置为 true。
import * as BABYLON from '@babylonjs/core';
// 假设 'scene' 和 'mesh' 已定义
const material = new BABYLON.StandardMaterial("parallaxMat", scene);
// 分配一个 diffuse 纹理 (主颜色/图案)material.diffuseTexture = new BABYLON.Texture("textures/stone_diffuse.jpg", scene);
// 分配一个包含高度信息的 bump 纹理// 这可能是一个 normal map,其 alpha 通道包含高度信息,或一个专门用作 bump 的高度图material.bumpTexture = new BABYLON.Texture("textures/stone_normal_height.png", scene);
// 启用视差映射material.useParallax = true;
// 控制效果的强度/深度 (根据需要调整)material.parallaxScaleBias = 0.05; // 通常 0.02 到 0.1 之间的值比较合适
// 可选: 改善高光material.specularPower = 1000.0;material.specularColor = new BABYLON.Color3(0.5, 0.5, 0.5);
mesh.material = material;视差遮蔽映射 (Parallax Occlusion Mapping - POM)
Section titled “视差遮蔽映射 (Parallax Occlusion Mapping - POM)”为了获得更高级和逼真的效果,你可以启用视差遮蔽映射 (Parallax Occlusion Mapping - POM)。POM 在基础视差映射的基础上进行了改进,模拟了位移细节中的自阴影 (self-shadowing),使得深度幻觉更加逼真,尤其是在观察角度较陡时。
// 在前面的示例基础上:
// 启用视差遮蔽映射 (需要 useParallax = true)material.useParallaxOcclusion = true;
// POM 通常允许更高的 scale bias 以获得更强的深度效果material.parallaxScaleBias = 0.1; // 根据纹理的不同,可能可以使用高达 0.2 或略高的值material.bumpTexture: 提供法线 (normal) 和/或高度 (height) 数据的纹理。对于视差映射至关重要。material.useParallax = true;: 启用基本视差映射。material.useParallaxOcclusion = true;: 启用更高级的视差遮蔽映射 (需要useParallax为 true)。material.parallaxScaleBias = 0.05;: 控制视差效果的深度或强度。值越高,视差越明显。根据你的高度图仔细调整此值。material.specularPower / PBR properties: 确保光照和高光 (specular)/粗糙度 (roughness) 属性设置得当,以配合凹凸效果。
这个示例创建一个盒子,并应用一个启用了视差遮蔽映射的材质,使用了石头纹理。
<!DOCTYPE html><html><head> <meta charset="utf-8"/> <title>Babylon.js - Parallax Mapping 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.2, 0.2, 0.25, 1.0);
const camera = new BABYLON.ArcRotateCamera("camera", -Math.PI / 2.2, Math.PI / 2.5, 8, BABYLON.Vector3.Zero(), scene); camera.attachControl(canvas, true); camera.wheelPrecision = 100; camera.minZ = 0.1;
const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0.5, 1, 0.25), scene); light.intensity = 0.8; const pointLight = new BABYLON.PointLight("pointLight", new BABYLON.Vector3(2, 3, -3), scene); pointLight.intensity = 0.6;
const box = BABYLON.MeshBuilder.CreateBox("box", { size: 2 }, scene);
// Material Setup const material = new BABYLON.StandardMaterial("parallaxMat", scene);
// Define texture paths (ensure these files exist in a 'textures' folder) const stoneDiffURL = "textures/stone_diffuse.jpg"; // 颜色纹理 const stoneBumpURL = "textures/stone_normal_height.png"; // 法线贴图 + 高度图
try { material.diffuseTexture = new BABYLON.Texture(stoneDiffURL, scene); material.bumpTexture = new BABYLON.Texture(stoneBumpURL, scene); console.log("Textures loaded successfully."); // 纹理加载成功。
// Enable Parallax Occlusion Mapping material.useParallax = true; material.useParallaxOcclusion = true; material.parallaxScaleBias = 0.1; // 调整以获得期望的深度
// Adjust lighting interaction material.specularColor = new BABYLON.Color3(0.3, 0.3, 0.3); material.specularPower = 64;
} catch(err) { console.error("Error loading textures: ", err); // 纹理加载错误: // Fallback: Simple color if textures fail material.diffuseColor = new BABYLON.Color3(0.5, 0.5, 0.5); // 回退:纹理失败时使用简单颜色 }
box.material = material;
// Rotate the box slowly scene.onBeforeRenderObservable.add(() => { // 缓慢旋转盒子 box.rotation.y += 0.005; box.rotation.x += 0.002; });
return scene; };
const scene = createScene(); engine.runRenderLoop(function () { scene.render(); }); window.addEventListener("resize", function () { engine.resize(); }); </script></body></html>这个示例展示了一个缓慢旋转的立方体。如果纹理文件 stone_diffuse.jpg 和 stone_normal_height.png 正确地放在 textures 文件夹中并成功加载,立方体将看起来像由石头制成,具有显著的表面深度和细节。随着立方体旋转以及你用鼠标改变观察角度,视差遮蔽效果将使凹凸和裂缝看起来更加三维,并在细节内部可见微妙的自阴影。如果纹理加载失败,它将显示一个简单的灰色立方体。
视差映射很大程度上依赖于高质量的纹理。你需要一个漫反射贴图 (diffuse map - 颜色贴图) 和一个对应的凹凸/法线贴图 (bump/normal map),它们能准确地表示表面细节。对于视差遮蔽,凹凸贴图必须包含高度信息,通常编码在其 alpha 通道中,或作为一个单独的灰度高度图提供。