Skip to content

BabylonJS - 网格

本章探讨在 BabylonJS 中创建各种 3D 形状,即网格(meshes)。我们将主要使用现代的 MeshBuilder API,它提供了一种方便且强大的方式来生成标准的几何形状。

MeshBuilder 提供了诸如 CreateBox, CreateSphere, CreateCylinder 等方法,让你能够轻松定义尺寸(dimensions)、细分(subdivisions)和其他属性。与旧方法相比,它还简化了材质(materials)和纹理(textures)的应用。

让我们首先使用 MeshBuilder.CreateBox 创建一个简单的盒子(立方体)网格(mesh)。

import * as BABYLON from '@babylonjs/core';
import '@babylonjs/loaders'; // 如果加载资源
const canvas = document.getElementById('renderCanvas');
const engine = new BABYLON.Engine(canvas, true);
const createScene = async function() {
const scene = new BABYLON.Scene(engine);
scene.clearColor = new BABYLON.Color4(0.1, 0.1, 0.2, 1.0); // 深蓝色背景
// 创建相机
const camera = new BABYLON.ArcRotateCamera("camera", -Math.PI / 2, Math.PI / 2.5, 10, BABYLON.Vector3.Zero(), scene);
camera.attachControl(canvas, true);
// 创建光源
const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(1, 1, 0), scene);
light.intensity = 0.8;
// 创建一个默认的 PBR 材质
const boxMaterial = new BABYLON.PBRMaterial("boxMat", scene);
boxMaterial.albedoColor = new BABYLON.Color3(0, 1, 0); // 绿色
boxMaterial.metallic = 0.1;
boxMaterial.roughness = 0.7;
// 定义盒子选项(可选)
const boxOptions = {
size: 2 // 创建一个 2x2x2 的盒子
// width: 1.5,
// height: 2,
// depth: 1,
};
// 创建盒子网格
const box = BABYLON.MeshBuilder.CreateBox("myBox", boxOptions, scene);
box.material = boxMaterial;
box.position.y = 1; // 将其位置设置在原点上方一点
// 添加地面平面(可选)
const ground = BABYLON.MeshBuilder.CreateGround("ground", {width: 10, height: 10}, scene);
const groundMaterial = new BABYLON.PBRMaterial("groundMat", scene);
groundMaterial.albedoColor = new BABYLON.Color3(0.5, 0.5, 0.5);
groundMaterial.metallic = 0;
groundMaterial.roughness = 0.9;
ground.material = groundMaterial;
return scene;
};
createScene().then(scene => {
engine.runRenderLoop(function() {
if (scene) {
scene.render();
}
});
});
// 处理窗口大小调整
window.addEventListener('resize', function() {
engine.resize();
});

这段代码设置了一个基础场景,包含相机(camera)、光源(light),然后使用 MeshBuilder.CreateBox 创建一个绿色盒子。我们使用了 PBRMaterial(基于物理的渲染 Physically Based Rendering),这是用于逼真材质的现代标准,提供 metallic 和 roughness 等属性。async function 模式用于 createScene,以处理未来可能出现的异步操作,例如加载资源(assets)。

要将图像纹理(texture)应用到网格(mesh),你需要定义 2D 图像坐标(U, V)如何映射到网格的 3D 表面。MeshBuilder 会自动处理标准形状的基础 UV 映射。

让我们修改上一个示例以添加纹理:

// 在 createScene 函数内部...
// 为带纹理的盒子创建一个 PBR 材质
const texturedBoxMat = new BABYLON.PBRMaterial("texturedBoxMat", scene);
texturedBoxMat.metallic = 0.1;
texturedBoxMat.roughness = 0.8;
// 加载纹理
const texture = new BABYLON.Texture("path/to/your/texture.jpg", scene);
texturedBoxMat.albedoTexture = texture;
// 盒子选项(size 通常足够)
const boxOptions = {
size: 2
};
// 创建盒子网格
const texturedBox = BABYLON.MeshBuilder.CreateBox("texturedBox", boxOptions, scene);
texturedBox.material = texturedBoxMat;
texturedBox.position.y = 1;
// ... 场景的其他设置 ...

在这里,我们创建一个指向我们图像文件的 BABYLON.Texture 对象,并将其赋值给 PBRMaterial 的 albedoTexture 属性。这个属性定义了材质的基础颜色贴图(base color map)。

高级 UV 映射(Sprite Sheets / Atlas)

Section titled “高级 UV 映射(Sprite Sheets / Atlas)”

有时,你可能会使用包含多个较小图像的单个图像文件(即精灵表 sprite sheet 或纹理图集 texture atlas)。要将此图集的特定部分映射到网格(mesh)的不同面(如盒子),你可以使用 faceUV 选项。

faceUV 需要一个 BABYLON.Vector4 对象数组,网格的每个面对应一个(盒子有 6 个面)。每个 Vector4(x, y, z, w) 定义了用于该面的纹理矩形区域,其中:

  • x: 左下角的 U 坐标(0.0 到 1.0)
  • y: 左下角的 V 坐标(0.0 到 1.0)
  • z: 右上角的 U 坐标(0.0 到 1.0)
  • w: 右上角的 V 坐标(0.0 到 1.0)

想象你的纹理图集(texture atlas)被分割成一个网格。如果你有一个 3x2 的网格(3 列,2 行):

// 在 createScene 函数内部...
const atlasTexture = new BABYLON.Texture("path/to/your/atlas.png", scene);
const atlasMat = new BABYLON.PBRMaterial("atlasMat", scene);
atlasMat.albedoTexture = atlasTexture;
atlasMat.metallic = 0;
atlasMat.roughness = 1.0; // 减少反射以清晰查看纹理
const hSpriteNb = 3; // 水平精灵数(列)
const vSpriteNb = 2; // 垂直精灵数(行)
const faceUV = new Array(6);
// 示例:将 3x2 网格中的前 6 个精灵映射到盒子的 6 个面
// 面 0: 左上角精灵(第 0 列,第 0 行)
faceUV[0] = new BABYLON.Vector4(0 / hSpriteNb, 0 / vSpriteNb, (0 + 1) / hSpriteNb, (0 + 1) / vSpriteNb);
// 面 1: 中上部精灵(第 1 列,第 0 行)
faceUV[1] = new BABYLON.Vector4(1 / hSpriteNb, 0 / vSpriteNb, (1 + 1) / hSpriteNb, (0 + 1) / vSpriteNb);
// 面 2: 右上角精灵(第 2 列,第 0 行)
faceUV[2] = new BABYLON.Vector4(2 / hSpriteNb, 0 / vSpriteNb, (2 + 1) / hSpriteNb, (0 + 1) / vSpriteNb);
// 面 3: 左下角精灵(第 0 列,第 1 行)
faceUV[3] = new BABYLON.Vector4(0 / hSpriteNb, 1 / vSpriteNb, (0 + 1) / hSpriteNb, (1 + 1) / vSpriteNb);
// 面 4: 中下部精灵(第 1 列,第 1 行)
faceUV[4] = new BABYLON.Vector4(1 / hSpriteNb, 1 / vSpriteNb, (1 + 1) / hSpriteNb, (1 + 1) / vSpriteNb);
// 面 5: 右下角精灵(第 2 列,第 1 行)
faceUV[5] = new BABYLON.Vector4(2 / hSpriteNb, 1 / vSpriteNb, (2 + 1) / hSpriteNb, (1 + 1) / vSpriteNb);
const atlasBoxOptions = {
width: 2,
height: 2,
depth: 2,
faceUV: faceUV
};
const atlasBox = BABYLON.MeshBuilder.CreateBox("atlasBox", atlasBoxOptions, scene);
atlasBox.material = atlasMat;
atlasBox.position.y = 1;
// ... 场景的其他设置 ...

这种技术需要根据你的图集布局仔细计算 UV 坐标。有一些工具可以帮助从纹理打包软件(texture packing software)中自动生成这些坐标。

创建圆柱体等其他形状也类似,使用相应的 MeshBuilder 方法。

// 在 createScene 函数内部...
// 圆柱体的材质(例如线框)
const cylinderMat = new BABYLON.PBRMaterial("cylinderMat", scene);
cylinderMat.albedoColor = new BABYLON.Color3(0.8, 0.8, 1.0); // 浅蓝色
cylinderMat.wireframe = true; // 显示线框
// 圆柱体选项
const cylinderOptions = {
height: 4,
diameterTop: 1,
diameterBottom: 2,
tessellation: 24 // 圆周上的段数
};
const cylinder = BABYLON.MeshBuilder.CreateCylinder("myCylinder", cylinderOptions, scene);
cylinder.material = cylinderMat;
cylinder.position = new BABYLON.Vector3(-3, 2, 0); // 设置位置
// ... 场景的其他设置 ...

在这里,CreateCylinder 接受 height、diameterTop、diameterBottom(如果直径不同则允许创建圆锥体)以及 tessellation(控制平滑度)等选项。我们应用了一个线框材质用于可视化。

请查阅 BabylonJS 文档,了解 MeshBuilder 的其他方法,如 CreateSphere, CreatePlane, CreateTorus, CreateIcoSphere 等,以及它们各自的选项。

检测网格何时重叠(即碰撞 intersect)对于游戏逻辑、物理和交互至关重要。BabylonJS 提供了 intersectsMesh 方法。

// 在 createScene 函数内部...
// 创建一个目标网格(例如一个静态盒子)
const targetBox = BABYLON.MeshBuilder.CreateBox("target", {size: 3}, scene);
targetBox.position = new BABYLON.Vector3(5, 1.5, 0);
const targetMat = new BABYLON.PBRMaterial("targetMat", scene);
targetMat.albedoColor = new BABYLON.Color3(1, 0.5, 0); // 橙色
targetBox.material = targetMat;
// 创建移动的球体
const sphereMat = new BABYLON.PBRMaterial("sphereMat", scene);
sphereMat.albedoColor = new BABYLON.Color3(0, 1, 1); // 青色
const sphere1 = BABYLON.MeshBuilder.CreateSphere("sphere1", {diameter: 1}, scene);
sphere1.material = sphereMat;
sphere1.position = new BABYLON.Vector3(0, 1, 0);
// 动画 / 移动逻辑
let angle = 0;
scene.onBeforeRenderObservable.add(() => {
// 将 sphere1 向目标盒子移动
sphere1.position.x += 0.02;
// 检查是否碰撞
if (sphere1.intersectsMesh(targetBox, false)) {
// 精确检查 = false(优先使用包围盒,更快)
// 精确检查 = true(使用几何体,较慢但更准确)
sphere1.material.emissiveColor = new BABYLON.Color3(1, 0, 0); // 碰撞时发红光
targetBox.material.emissiveColor = new BABYLON.Color3(1, 0, 0);
} else {
sphere1.material.emissiveColor = BABYLON.Color3.Black(); // 重置发光
targetBox.material.emissiveColor = BABYLON.Color3.Black();
}
// 简单旋转示例(与碰撞检测无关)
targetBox.rotation.y += 0.01;
});
// ... 场景的其他设置 ...

在这个示例中,sphere1 向 targetBox 移动。在 scene.onBeforeRenderObservable 内部(它在每一帧渲染之前运行),我们调用 sphere1.intersectsMesh(targetBox, false)。第二个参数(false)表示使用包围盒(bounding boxes)进行不那么精确但更快的检查。将其设置为 true 将根据实际网格几何体执行更精确的检查。我们改变 emissiveColor(使对象发光)以视觉上指示碰撞。

你还可以使用 intersectsPoint 检查 3D 空间中的某个特定点是否位于网格的包围盒内。

// 在 scene.onBeforeRenderObservable 内部...
const checkPoint = new BABYLON.Vector3(5.1, 1.6, 0.1); // 目标盒子附近的一个点
// 可视化点(可选)
// const pointMarker = BABYLON.MeshBuilder.CreateSphere("marker", {diameter: 0.2}, scene);
// pointMarker.position = checkPoint;
// pointMarker.material = new BABYLON.StandardMaterial("markerMat", scene);
// pointMarker.material.emissiveColor = BABYLON.Color3.Yellow();
if (targetBox.intersectsPoint(checkPoint)) {
console.log("Point is inside the target box!");
// 你可以在此处触发一个动作
}

mesh.intersectsPoint(vector3) 如果给定的 BABYLON.Vector3 在网格的包围盒(bounding box)内,则返回 true,否则返回 false。

拾取(Picking)允许你确定鼠标光标下是哪个网格(如果有的话)。这对于用户交互至关重要,例如选择对象或在场景中放置物品。

BabylonJS 使用 scene.onPointerObservable 来处理指针事件(pointer events)(鼠标点击、触摸、移动)。

// 在 createScene 函数内部...
// 创建一个可点击的地面平面
const ground = BABYLON.MeshBuilder.CreateGround("ground", {width: 10, height: 10}, scene);
const groundMat = new BABYLON.PBRMaterial("groundMat", scene);
groundMat.albedoColor = new BABYLON.Color3(0.3, 0.5, 0.3); // 偏绿色
ground.material = groundMat;
// 创建一个点击时放置的小球体
const placementSphere = BABYLON.MeshBuilder.CreateSphere("placementSphere", {diameter: 0.5}, scene);
const placementMat = new BABYLON.PBRMaterial("placementMat", scene);
placementMat.albedoColor = new BABYLON.Color3(1, 0, 0); // 红色
placementSphere.material = placementMat;
placementSphere.position = new BABYLON.Vector3(0, -10, 0); // 初始隐藏
// 用于点击的指针可观察对象
scene.onPointerObservable.add((pointerInfo) => {
switch (pointerInfo.type) {
case BABYLON.PointerEventTypes.POINTERDOWN:
console.log("Pointer Down");
// 执行拾取操作
const pickResult = scene.pick(scene.pointerX, scene.pointerY);
if (pickResult.hit) {
console.log("Hit mesh:", pickResult.pickedMesh.name);
console.log("Hit point coordinates:", pickResult.pickedPoint);
// 如果我们击中地面,将放置球体移动到击中点
if (pickResult.pickedMesh.name === "ground") {
placementSphere.position = pickResult.pickedPoint.clone(); // 使用 clone()
placementSphere.position.y += 0.25; // 将其放置在地面上方一点
}
}
break;
case BABYLON.PointerEventTypes.POINTERUP:
console.log("Pointer Up");
break;
case BABYLON.PointerEventTypes.POINTERMOVE:
// 可用于悬停效果、拖放等。
break;
}
});
// ... 场景的其他设置 ...

我们为 scene.onPointerObservable 添加一个观察者(observer)。当 POINTERDOWN 事件发生时,我们调用 scene.pick(scene.pointerX, scene.pointerY) 来获取该屏幕坐标下光标处的信息。pickResult 对象包含:

  • hit:一个布尔值,指示是否击中网格。
  • pickedMesh:被击中的网格(如果 hit 为 true)。
  • pickedPoint:一个 Vector3,表示在 pickedMesh 表面上发生击中的精确 3D 坐标。

在示例中,如果点击了地面(pickResult.pickedMesh.name === "ground"),我们将红色的 placementSphere 移动到 pickedPoint。注意在赋值位置时使用了 .clone(),以避免间接修改原始的 pickedPoint 向量。

射线投射涉及从一个点沿特定方向投射一条看不见的线(即射线 ray),并检测它与哪些网格相交。它用于 AI 的视线(line-of-sight)、模拟弹丸(simulated projectiles)或更复杂的拾取场景等。

你创建一个 BABYLON.Ray 对象并使用 scene.pickWithRay。

// 在 createScene 函数内部...
// 一个将投射射线的中心盒子
const casterBox = BABYLON.MeshBuilder.CreateBox("casterBox", {size: 1}, scene);
casterBox.position.y = 0.5;
const casterMat = new BABYLON.PBRMaterial("casterMat", scene);
casterMat.albedoColor = new BABYLON.Color3(0.5, 0.5, 1); // 蓝色
casterBox.material = casterMat;
casterBox.isPickable = false; // 通常,投射者本身不应该被自己的射线拾取到
// 一些目标盒子
const targetMatRed = new BABYLON.PBRMaterial("targetRed", scene);
targetMatRed.albedoColor = new BABYLON.Color3(1, 0, 0);
const targetMatGreen = new BABYLON.PBRMaterial("targetGreen", scene);
targetMatGreen.albedoColor = new BABYLON.Color3(0, 1, 0);
const target1 = BABYLON.MeshBuilder.CreateBox("target1", {size: 2}, scene);
target1.position = new BABYLON.Vector3(5, 1, 0);
target1.material = targetMatRed;
const target2 = BABYLON.MeshBuilder.CreateBox("target2", {size: 2}, scene);
target2.position = new BABYLON.Vector3(-5, 1, 0);
target2.material = targetMatGreen;
// 用于可视化的 Ray 和 RayHelper
const ray = new BABYLON.Ray();
const rayHelper = new BABYLON.RayHelper(ray);
rayHelper.show(scene, new BABYLON.Color3(1, 1, 0)); // 黄色射线可视化
scene.onBeforeRenderObservable.add(() => {
// 使投射盒子旋转
casterBox.rotation.y += 0.01;
// 定义相对于投射盒子的射线属性
const origin = casterBox.position;
// 根据投射者的旋转获取向前方向
const forward = new BABYLON.Vector3(0, 0, 1); // 本地 Z 轴向前
const worldMatrix = casterBox.getWorldMatrix();
const direction = BABYLON.Vector3.TransformNormal(forward, worldMatrix).normalize();
const length = 10; // 射线应该行进多远
// 更新 ray 对象
ray.origin = origin;
ray.direction = direction;
ray.length = length;
// 执行射线投射
// 可选的 predicate 函数用于过滤网格:
// const predicate = function(mesh) {
// return mesh.isPickable && mesh.isEnabled() && mesh.name !== "ground";
// }
// const pickInfo = scene.pickWithRay(ray, predicate);
const pickInfo = scene.pickWithRay(ray);
// 重置目标颜色/效果
target1.scaling.y = 1;
target2.scaling.y = 1;
target1.material.emissiveColor = BABYLON.Color3.Black();
target2.material.emissiveColor = BABYLON.Color3.Black();
if (pickInfo.hit && pickInfo.pickedMesh) {
//console.log("Ray hit:", pickInfo.pickedMesh.name);
// 对击中的网格应用效果
pickInfo.pickedMesh.scaling.y = 1.5;
pickInfo.pickedMesh.material.emissiveColor = new BABYLON.Color3(0.8, 0.8, 0); // 黄色发光
}
});
// ... 场景的其他设置(需要相机) ...
const camera = new BABYLON.ArcRotateCamera("camera", -Math.PI / 2.2, Math.PI / 2.5, 15, new BABYLON.Vector3(0,1,0), scene);
camera.attachControl(canvas, true);

关键要素:

  • BABYLON.Ray(origin, direction, length):定义射线。origin 和 direction 是 Vector3,length 是一个数字。
  • BABYLON.RayHelper:一个在场景中可视化射线(ray)的工具(对调试有用)。
  • BABYLON.Vector3.TransformNormal(localVector, worldMatrix):在此处用于根据投射者(caster)的当前旋转,将其局部向前方向(0,0,1)转换为世界空间方向。
  • scene.pickWithRay(ray, predicate):执行投射。它返回一个类似于 scene.pick 的 PickingInfo 对象。可选的 predicate 函数接收被射线击中的每个潜在网格,如果该网格应被此射线视为可拾取,则应返回 true,否则返回 false。这允许进行过滤(例如,忽略地面或不可见的对象)。

在示例中,中心盒子旋转,射线从它指向前方。当射线击中 target1 或 target2 时,该目标会稍微放大并发出黄色光。

阴影通过显示物体如何阻挡光线来增加真实感(realism)。设置基础阴影涉及一个能够投射阴影的光源(light source)和一个 ShadowGenerator。

// 在 createScene 函数内部...
// 创建一个能够投射阴影的光源(定向光 DirectionalLight 或聚光灯 SpotLight)
const light = new BABYLON.DirectionalLight("dirLight", new BABYLON.Vector3(-0.5, -1, -0.5), scene);
light.position = new BABYLON.Vector3(10, 20, 10);
light.intensity = 0.8;
// 创建一个阴影生成器
// 第一个参数是阴影贴图大小(2 的幂次方,例如 1024, 2048)
// 值越高意味着阴影越锐利但使用更多资源。
const shadowGenerator = new BABYLON.ShadowGenerator(1024, light);
// 配置阴影属性(可选)
shadowGenerator.useBlurExponentialShadowMap = true; // 更柔和的阴影(存在其他选项)
// shadowGenerator.usePoissonSampling = true;
shadowGenerator.blurKernel = 32;
shadowGenerator.darkness = 0.5; // 阴影有多暗
// shadowGenerator.bias = 0.01; // 有助于防止阴影痤疮(自身阴影伪影)
// 创建一个接收阴影的地面
const ground = BABYLON.MeshBuilder.CreateGround("ground", {width: 10, height: 10}, scene);
const groundMat = new BABYLON.PBRMaterial("groundMat", scene);
groundMat.albedoColor = new BABYLON.Color3(0.5, 0.5, 0.5);
// *** 关键:在地面材质上启用阴影接收 ***
// ground.receiveShadows = true; // 对于 StandardMaterial
// 如果启用了光照,PBRMaterial 会自动处理接收。
// 如果你正在使用 PBR,请确保场景环境纹理或光源已正确设置。
// 在这里,为了简单起见,我们可以在此处使用 StandardMaterial 强制启用,或确保 PBR 设置完整。
// 在这里,为了清晰展示 receiveShadows 示例,我们使用 StandardMaterial:
const groundStdMat = new BABYLON.StandardMaterial("groundStdMat", scene);
groundStdMat.diffuseColor = new BABYLON.Color3(0.5, 0.5, 0.5);
ground.material = groundStdMat;
ground.receiveShadows = true; // 启用阴影接收
// 创建一个投射阴影的盒子
const shadowBox = BABYLON.MeshBuilder.CreateBox("shadowBox", {size: 2}, scene);
shadowBox.position = new BABYLON.Vector3(0, 1.1, 0);
const boxMat = new BABYLON.PBRMaterial("boxMat", scene);
boxMat.albedoColor = new BABYLON.Color3(1, 0, 0); // 红色
shadowBox.material = boxMat;
// *** 将盒子添加到阴影投射者列表 ***
shadowGenerator.addShadowCaster(shadowBox);
// 或者添加多个网格:shadowGenerator.getShadowMap().renderList.push(mesh1, mesh2);
// 创建另一个投射阴影的对象(例如球体)
const shadowSphere = BABYLON.MeshBuilder.CreateSphere("shadowSphere", {diameter: 1.5}, scene);
shadowSphere.position = new BABYLON.Vector3(3, 0.8, 2);
const sphereMat = new BABYLON.PBRMaterial("sphereMat", scene);
sphereMat.albedoColor = new BABYLON.Color3(0, 0, 1); // 蓝色
shadowSphere.material = sphereMat;
shadowGenerator.addShadowCaster(shadowSphere);
// 动画化盒子(可选)
scene.onBeforeRenderObservable.add(() => {
shadowBox.rotation.y += 0.01;
shadowBox.rotation.x += 0.005;
});
// ... 场景的其他设置(需要相机) ...
const camera = new BABYLON.ArcRotateCamera("camera", -Math.PI / 2.2, Math.PI / 2.5, 15, new BABYLON.Vector3(0,1,0), scene);
camera.attachControl(canvas, true);

阴影设置步骤:

  1. 创建一个合适的光源(DirectionalLight 定向光 或 SpotLight 聚光灯)。PointLight 点光源可以投射阴影但需要立方体纹理(更复杂)。HemisphericLight 半球光不能投射阴影。
  2. 实例化 BABYLON.ShadowGenerator,传入阴影贴图大小和光源。
  3. 对于应该接收阴影的网格(如地面),设置 mesh.receiveShadows = true;。(注意:这主要针对 StandardMaterial。PBRMaterial 通常根据光照设置自动处理,但在某些配置中可能需要显式设置)。
  4. 对于应该投射阴影的网格,使用 shadowGenerator.addShadowCaster(mesh) 或将其推送到 shadowGenerator.getShadowMap().renderList 中,将其添加到阴影生成器的列表中。
  5. 调整阴影生成器的属性(useBlurExponentialShadowMap,blurKernel,darkness,bias)以微调外观和性能。

除了基础创建和交互之外,BabylonJS 还提供了许多高级网格特性:

  • 高级材质: 探索 PBRMaterial 的属性(metallic、roughness、clearcoat、subsurface scattering)、用于自定义可视化着色器创建的 NodeMaterial,以及用于直接在 GLSL 中编写着色器的 ShaderMaterial。
  • 细节层级(LOD): 当网格远离相机时,显示其更简单的版本以提高性能(mesh.addLODLevel)。
  • 实例(Instances): 高效渲染网格的多个相同副本,带有位置、旋转和缩放的变化(mesh.createInstance)。
  • 形变目标(Morph Targets): 使网格在不同形状之间平滑变形,常用于面部动画或形状变化效果。
  • 资源加载(Asset Loading): 使用 glTF/GLB 等格式导入在 3D 建模软件(如 Blender, Maya)中创建的复杂网格(SceneLoader.ImportMeshAsync)。
  • 实体粒子系统(SPS): 高效管理和动画化数千个网格(粒子)。
  • 高亮层(Highlight Layer): 轻松为网格添加轮廓或高亮效果,用于选择或强调(HighlightLayer)。

这些主题代表了在 BabylonJS 中掌握网格操作和渲染的下一步。请查阅 BabylonJS 官方文档以获取深入解释和示例。