Skip to content

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 通道中或作为单独的高度图)。

要在 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 通道中,或作为一个单独的灰度高度图提供。