BabylonJS - 网格
BabylonJS - 使用网格
Section titled “BabylonJS - 使用网格”本章探讨在 BabylonJS 中创建各种 3D 形状,即网格(meshes)。我们将主要使用现代的 MeshBuilder API,它提供了一种方便且强大的方式来生成标准的几何形状。
MeshBuilder 提供了诸如 CreateBox, CreateSphere, CreateCylinder 等方法,让你能够轻松定义尺寸(dimensions)、细分(subdivisions)和其他属性。与旧方法相比,它还简化了材质(materials)和纹理(textures)的应用。
使用 MeshBuilder 创建盒子
Section titled “使用 MeshBuilder 创建盒子”让我们首先使用 MeshBuilder.CreateBox 创建一个简单的盒子(立方体)网格(mesh)。
基础盒子示例
Section titled “基础盒子示例”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)。
应用纹理(UV 映射)
Section titled “应用纹理(UV 映射)”要将图像纹理(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 等,以及它们各自的选项。
网格交互:碰撞检测
Section titled “网格交互:碰撞检测”检测网格何时重叠(即碰撞 intersect)对于游戏逻辑、物理和交互至关重要。BabylonJS 提供了 intersectsMesh 方法。
碰撞检测示例
Section titled “碰撞检测示例”// 在 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。
网格拾取(鼠标交互)
Section titled “网格拾取(鼠标交互)”拾取(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 向量。
射线投射(Raycasting)
Section titled “射线投射(Raycasting)”射线投射涉及从一个点沿特定方向投射一条看不见的线(即射线 ray),并检测它与哪些网格相交。它用于 AI 的视线(line-of-sight)、模拟弹丸(simulated projectiles)或更复杂的拾取场景等。
你创建一个 BABYLON.Ray 对象并使用 scene.pickWithRay。
射线投射示例
Section titled “射线投射示例”// 在 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 和 RayHelperconst 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);阴影设置步骤:
- 创建一个合适的光源(
DirectionalLight定向光 或SpotLight聚光灯)。PointLight点光源可以投射阴影但需要立方体纹理(更复杂)。HemisphericLight半球光不能投射阴影。 - 实例化
BABYLON.ShadowGenerator,传入阴影贴图大小和光源。 - 对于应该接收阴影的网格(如地面),设置
mesh.receiveShadows = true;。(注意:这主要针对StandardMaterial。PBRMaterial通常根据光照设置自动处理,但在某些配置中可能需要显式设置)。 - 对于应该投射阴影的网格,使用
shadowGenerator.addShadowCaster(mesh)或将其推送到shadowGenerator.getShadowMap().renderList中,将其添加到阴影生成器的列表中。 - 调整阴影生成器的属性(
useBlurExponentialShadowMap,blurKernel,darkness,bias)以微调外观和性能。
更多网格概念(简要概述)
Section titled “更多网格概念(简要概述)”除了基础创建和交互之外,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 官方文档以获取深入解释和示例。