这一节主要编写生成导航盒模型的代码,将以创造自定义模型为中心进行讲解。想阅览相关官方文档的小伙伴可以自行前往(https://doc.babylonjs.com/features/featuresDeepDive/mesh/creation/custom/custom)
说到自定义生成模型,我们很难离开VertexData,VertexData对Mesh的各项基础buffer的设置和获取提供了一层封装,我们可以使用VertexData去读取/修改/设置Mesh的基本Buffer。它常用的几个字段如下
class VertexData{
position:number[]; //顶点数组 顶点数*3
colors:number[]; //颜色数组 顶点数*3或4
indices:number[]; //索引数组 面数*3
normals:number[]; //法线数组 顶点数*3
uvs:number[] //uv0数组 顶点数*2
......
uvs6:number[] //uv6数组 顶点数*2
}
我们在实例化Mesh之前,我们需要准备好需要用到的基础数据的数组,normals法线一般使用VertexData.ComputeNormals直接计算得出。
在这个案例中,我们需要准备positions, indices和uvs,然后通过计算获取normals。下为创建Mesh过程的步骤代码,对准备顶点数据的过程有兴趣的小伙伴可以前往PG。
//自定义数据接口
interface ICustomVertexData {
positions: number[],
indices: number[],
uvs: number[]
}
class DirectBoxCreator {
//创建盒子
static create(scene: BABYLON.Scene, size: number, edgePercent: number) {
const front = B.Vector3.Forward();
const back = B.Vector3.Backward();
const right = B.Vector3.Right();
const left = B.Vector3.Left();
const up = B.Vector3.Up();
const down = B.Vector3.Down();
const data: ICustomVertexData = {
positions: [],
indices: [],
uvs: [],
}
//创建6个面
//创建正面
this.createFace(size,edgePercent,back, up, right, new B.Vector2(0, 0), data);
......
//创建8个角
// 创建左上前角
this.createEdge(size,edgePercent,new B.Vector3(-size, size, -size), right, down, front, data);
......
//准备VertexData
const vertexData = new B.VertexData();
vertexData.positions = data.positions;
vertexData.indices = data.indices;
vertexData.uvs = data.uvs;
const normals: number[] = [];
B.VertexData.ComputeNormals(data.positions, data.indices, normals);
vertexData.normals = normals;
//创建Mesh
const mesh = new B.Mesh("DirectBox", scene);
//创建材质
const material = new B.StandardMaterial("DirectBoxMat", scene);
mesh.material = material;
material.disableLighting = true;
material.emissiveTexture = new BABYLON.Texture("https://moriyer.github.io/BabylonTexture/JianShu/Texture/DirectBox.jpg", scene, undefined, false);
//将vertexData数据应用进Mesh
vertexData.applyToMesh(mesh);
return {
mesh,
material,
};
}
private static createFace(size: number, edgePercent: number, origin: BABYLON.Vector3, up: BABYLON.Vector3, right: BABYLON.Vector3, uvOffset: BABYLON.Vector2, data: ICustomVertexData) {
//计算过程,uvOffset参数是因为贴图问题手动配置偏置
}
private static createEdge(size: number, edgePercent: number, origin: BABYLON.Vector3, dir1: BABYLON.Vector3, dir2: BABYLON.Vector3, dir3: BABYLON.Vector3, data: ICustomVertexData) {
//计算过程
}
}
(https://playground.babylonjs.com/?#ENABP9#6)
此时的盒子已经完成,美中不足的是棱角不够明显,我们可以给Mesh加上Edge让棱角突出
mesh.enableEdgesRendering(0.99); //激活Edge
mesh.edgesWidth = 6; //设置Edge宽度
mesh.edgesColor.set(0, 0, 0, 1); //设置黑色
(https://playground.babylonjs.com/?#ENABP9#7)
image.png
添加Edge后,棱角有明显的线条,但是会发现棱角粗细不一,旋转的时候棱角闪烁,这是一个典型的z-fight问题,深度距离接近导致有些角度Edge被盒子遮住,从而产生闪烁。对于这种问题,我们可以让盒子沿着法线的z轴缩放一点点。
mesh.material.zOffset = 1;
PS:最终的PG:https://playground.babylonjs.com/?#ENABP9#8


