BabylonJS-Mesh网格

411 阅读11分钟

一、创建网格

利用网格构建器MeshBuilder可以创建各种形状,平面,线以及自定义网格。

例如:

CreateBox创建立方体,CreateSphere创建球体,CreateCylinder创建柱体,CreateCapsule创建胶囊,

CreatePlane创建平面,CreateGround创建地面

CreateDisc创建圆盘或正多边形,CreateTorus创建环面,CreateTorusKnot创建环结,CreateText创建文本

CreateLines创建线,CreateDashedLines创建虚线

...

1.创建立方体与地面(平行于xz平面的水平平面)

import {
  Engine,
  Scene,
  ArcRotateCamera,
  Vector3,
  Color4,
  Color3,
  MeshBuilder,
  SpotLight,
  Mesh,
  Space,
  Tools,
} from '@babylonjs/core'

//创建一个名为 BabylonScene 的类
export class BabylonScene {
  engine: Engine
  scene: Scene

  //private将属性或方法标记为私有,表示它们只能在类的内部被访问,外部无法直接访问。
  constructor(private canvas: HTMLCanvasElement) {
    this.engine = new Engine(this.canvas, true) //渲染引擎
    this.scene = this.CreateScene() //场景
    // 渲染场景
    this.engine.runRenderLoop(() => {
      this.scene.render()
    })
  }

  CreateScene(): Scene {
    const scene = new Scene(this.engine) // 创建场景

    /**
     * 弧形旋转摄像机ArcRotateCamera
     * 配置项:相机名称,初始经度,初始纬度,与焦点距离,位置,场景
     */
    const camera = new ArcRotateCamera(
      'ArcRotateCamera',
      Math.PI / 8,
      Math.PI / 8,
      10,
      new Vector3(0, 0, 0),
      scene
    )

    // 相机定位
    camera.setPosition(new Vector3(0, 10, 10))
    camera.attachControl(this.canvas, true) //让相机控制画布

    /**
     * 聚光灯SpotLight
     * 配置项:名称,位置,方向,角度,指数,场景
     */
    const light = new SpotLight(
      'spotLight',
      new Vector3(0, 10, 0),
      new Vector3(0.5, -1, 0),
      Math.PI / 2,
      3,
      scene
    )

    /**
     * 创建一个立方体
     * 配置项:名称,选项,场景
     */
    const box = MeshBuilder.CreateBox('box', { size: 1 }, scene)

    // 创建地面
    const ground = MeshBuilder.CreateGround(
      'ground',
      { width: 6, height: 6 },
      scene
    )
    ground.position.y = -1
    
    return scene
  }
}

效果如图:

1703728198988.png

立方体选项属性value默认值
size(number)  尺寸1
height(number)  高度大小,覆盖size选项size
width(number)  宽度大小,覆盖size选项size
depth(number)  深度大小,覆盖size选项size
faceColors(Color4[])  Color4(1, 1, 1, 1)
faceUV(Vector4[])  UVs(0, 0, 1, 1)
wrap(boolean)  当为真时,所有垂直边( 0 , 1 , 2 , 3 )将垂直应用图像纹理false
topBaseAt(number)  给定 0 , 1 , 2 , 3 的顶触边底1
bottomBaseAt(number)  给定 0 , 1 , 2 , 3 的下触面底脚0
updatable(boolean)  如果网格是可更新的则为 truefalse
sideOrientation(number)  侧方位DEFAULTSIDE
frontUVs(Vector4)  ONLY WHEN sideOrientation:BABYLON.Mesh.DOUBLESIDE setVector4(0,0, 1,1)
backUVs(Vector4)  ONLY WHEN sideOrientation:BABYLON.Mesh.DOUBLESIDE setVector4(0,0, 1,1)
地面选项属性value默认值
width(number)  宽度1
height(number)  高度1
updatable(boolean)  如果网格是可更新的则为 truefalse
subdivisions(number)  沿每个轴的平方细分数1

创建立方体示例链接

2.创建球体

    // 创建球体
    const sphere = MeshBuilder.CreateSphere(
      'sphere',
      { diameter: 1, segments: 60 },
      scene
    )
    sphere.position.x = 1
    //创建椭球体
    const elliptic = MeshBuilder.CreateSphere('elliptic', {
      diameterX: 1,
      diameterY: 0.5,
      diameterZ: 0.5,
    })
    //创建弧形
    const arc = MeshBuilder.CreateSphere('arc', {
      arc: 0.25,
      sideOrientation: Mesh.DOUBLESIDE,
    })
    //创建弧和切片
    const slice = MeshBuilder.CreateSphere('slice', {
      slice: 0.3,
      sideOrientation: Mesh.DOUBLESIDE,
    })

效果如图:

1703728573495.png

选项属性value默认值
segments(number)  水平段数32
diameter(number)  球的直径1
diameterX(number)  X 轴上的直径,覆盖直径选项diameter
diameterY(number)  Y 轴上的直径,覆盖直径选项diameter
diameterZ(number)  Z 轴上的直径,覆盖直径选项diameter
arc(number)  圆周(纬度)在 0 与 1 之间的比率1
slice(number)  0 与 1 之间的高度(经度)比1
updatable(boolean)  如果网格是可更新的则为 truefalse
sideOrientation(number)  侧方位DEFAULTSIDE
frontUVs(Vector4)  ONLY WHEN sideOrientation:BABYLON.Mesh.DOUBLESIDE setVector4(0, 0, 1,1)
backUVs(Vector4)  ONLY WHEN sideOrientation:BABYLON.Mesh.DOUBLESIDE setVector4(0, 0, 1,1)

创建球体示例链接 

建立椭球体示例链接 

创建弧示例链接 

创建弧和切片示例链接

3.创建圆柱体或圆锥体

    //创建圆柱体
    const cylinder = MeshBuilder.CreateCylinder(
      'cylinder',
      { height: 2 },
      scene
    )
    cylinder.position.x = 2
    //创建圆锥体
    const cone = MeshBuilder.CreateCylinder(
      'cone',
      { height: 2, diameterTop: 0 },
      scene
    )
    cone.position.x = 1
    //创建棱柱
    const prism = MeshBuilder.CreateCylinder('prism', {
      tessellation: 5,
    })
    //创建弧形
    const arc = MeshBuilder.CreateCylinder('arc', {
      arc: 0.6,
      sideOrientation: Mesh.DOUBLESIDE,
    })
    arc.position.x = -2
    //创建蛋糕切片
    const slice = MeshBuilder.CreateCylinder('slice', {
      arc: 0.1,
      height: 0.3,
      sideOrientation: Mesh.DOUBLESIDE,
      enclose: true,
    })
    slice.position.x = -2
    slice.position.z = 1

效果如图:

1703727980904.png

选项属性value默认值
height(number)  高度2
diameterTop(number)  上盖的直径,可以为零创建一个圆锥体,覆盖直径选项1
diameterBottom(number)  底盖的直径,不能为零,覆盖直径选项1
diameter(number)  两个瓶盖的直径1
tessellation(number)  径向边数24
subdivisions(number)  环数1
faceColors(Color4[])  Color4(1, 1, 1, 1)
faceUV(Vector4[])  UVs(0, 0, 1, 1)
arc(number)  0 与 1 的周长比1
hasRings(boolean)  使细分相互独立,所以它们变成不同的面false
enclose(boolean)  每细分一个圆柱体上添加两个额外的面以使其围绕高度轴关闭false
updatable(boolean)  如果网格是可更新的则为 truefalse
sideOrientation(number)  侧方位DEFAULTSIDE
frontUVs(Vector4)  ONLY WHEN sideOrientation:BABYLON.Mesh.DOUBLESIDE setVector4(0,0, 1,1)
backUVs(Vector4)  ONLY WHEN sideOrientation:BABYLON.Mesh.DOUBLESIDE setVector4(0,0, 1,1)

创建圆柱体示例链接

创建圆锥示例链接

创建三棱柱示例链接

创建弧示例链接

创建蛋糕切片示例链接

4.创建胶囊

    //创建胶囊
    const capsule = MeshBuilder.CreateCapsule('capsule', { height: 2 }, scene)
    capsule.position.x = 3
    //使用细分创建胶囊
    const capsule1 = MeshBuilder.CreateCapsule(
      'capsule1',
      {
        height: 2,
        radius: 0.5,
        tessellation: 4, //胶囊上的圆柱部分的数量
        capSubdivisions: 1, //平行于方向运行的胶囊帽部分上的子段数
        topCapSubdivisions: 12, //顶部细分
      },
      scene
    )
    capsule1.position.x = 2
    //胶囊方向
    const capsule2 = MeshBuilder.CreateCapsule(
      'capsule2',
      {
        height: 2,
        radius: 0.25,
        tessellation: 36,
        capSubdivisions: 6,
        subdivisions: 6, //平行于方向的胶囊管段上的子段数
        orientation: Vector3.Forward(), //开始时的方向
      },
      scene
    )
    //不同半径的胶囊
    const capsule3 = MeshBuilder.CreateCapsule(
      'capsule3',
      { height: 3, radius: 0.5, radiusTop: 0.8 },
      scene
    )
    capsule3.position.x = -2

效果如图:

1703730417517.png

选项属性value默认值
orientation?(Vector3)  开始时的方向Vector3.Up
subdivisions(number)  平行于方向的胶囊管段上的子段数2
tessellation(number)  胶囊上的圆柱部分的数量.16
height(number)  高度(长度)1
radius(number)  半径0.25
capSubdivisions(number)  平行于方向运行的胶囊帽部分上的子段数6
radiusTop?(number)  顶部半径 
radiusBottom?(number)  底部半径 
topCapSubdivisions?(number)  顶部细分 
bottomCapSubdivisions?(number)  底部细分

创建默认胶囊示例链接

使用细分创建胶囊示例链接

有方向的胶囊示例链接

有不同半径的胶囊示例链接

5.创建平面(平行于xy平面的平面)

    //创建单面平面
    const plane = MeshBuilder.CreatePlane(
      'plane',
      { height: 2, width: 1 },
      scene
    )
    //创建双面平面
    const plane1 = MeshBuilder.CreatePlane(
      'plane1',
      { height: 2, width: 1, sideOrientation: Mesh.DOUBLESIDE },
      scene
    )
    plane1.position.x = -2

单面平面旋转到后方是看不到的,双面平面前后方都可以看到。效果如图:

1703731470405.png

1703731566832.png

选项属性value默认值
size(number)  尺寸1
width(number)  宽度size
height(number)  高度size
updatable(boolean)  如果网格是可更新的则为 truefalse
sideOrientation(number)  侧方位DEFAULTSIDE
sourcePlane(Plane)  源平面(math)网格将转换为源平面null
frontUVs(Vector4)  ONLY WHEN sideOrientation:BABYLON.Mesh.DOUBLESIDE setVector4(0,0, 1,1)
backUVs(Vector4)  ONLY WHEN sideOrientation:BABYLON.Mesh.DOUBLESIDE setVector4(0,0, 1,1)

建立单面平面示例链接

建立双面平面示例链接

6.创建圆盘或正多边形

    //创建圆盘
    const disc = MeshBuilder.CreateDisc('disc', {sideOrientation: Mesh.DOUBLESIDE}, scene)
    disc.position.x = 2
    //创建正三角形
    const disc1 = MeshBuilder.CreateDisc('disc1', { tessellation: 3,sideOrientation: Mesh.DOUBLESIDE }, scene)
    //创建扇区
    const disc2 = MeshBuilder.CreateDisc(
      'disc2',
      { tessellation: 12, arc: 5 / 6,sideOrientation: Mesh.DOUBLESIDE },
      scene
    )
    disc2.position.x = -2

效果如图:

1703732100503.png

选项属性value默认值
radius(number)  圆盘或多边形的半径0.5
tessellation(number)  圆盘/多边形边数64
arc(number)  弧,0 与 1 的周长比1
updatable(boolean)  如果网格是可更新的则为 truefalse
sideOrientation(number)  侧方位DEFAULTSIDE

创建圆盘示例链接

创建三角形示例链接

创建扇区示例链接

7.创建环面与环结

环结是一个连续的形状,围绕着环面的表面旋转。匝数由绕组整数p和q决定。最简单的打结结是用2和3为p和q的组合。创建的环结的起源是在底层环面的中心。

    //创建环面
    const torus = MeshBuilder.CreateTorus(
      'torus',
      {
        thickness: 0.25, //厚度
        diameter: 1, //直径
      },
      scene
    )
    torus.position.x = 2
    //创建低pq环结
    const torusKnot = MeshBuilder.CreateTorusKnot(
      'torusKnot',
      {
        radius: 0.5,
        tube: 0.1, //厚度
        radialSegments: 128, //径向段数
        p: 6,
        q: 4,
      },
      scene
    )
    //创建高pq环结
    const torusKnot1 = MeshBuilder.CreateTorusKnot(
      'torusKnot1',
      {
        radius: 0.5,
        tube: 0.01, //厚度
        radialSegments: 1024, //径向段数
        p: 100,
        q: 120,
      },
      scene
    )
    torusKnot1.position.x = -2
    //创建高非整数pq环结
    const torusKnot2 = MeshBuilder.CreateTorusKnot(
      'torusKnot2',
      {
        radius: 0.5,
        tube: 0.01, //厚度
        radialSegments: 1024, //径向段数
        p:-117.885,
        q:-169.656465,
      },
      scene
    )
    torusKnot2.position.x = -2
    torusKnot2.position.z = -2

效果如图:

1703734991021.png

环面选项属性value默认值
diameter(number)  环面直径1
thickness(number)  厚度0.5
tessellation(number)  沿着圆的段数16
updatable(boolean)  如果网格是可更新的则为 truefalse
sideOrientation(number)  侧方位DEFAULTSIDE
frontUVs(Vector4)  ONLY WHEN sideOrientation:BABYLON.Mesh.DOUBLESIDE setVector4(0,0, 1,1)
backUVs(Vector4)  ONLY WHEN sideOrientation:BABYLON.Mesh.DOUBLESIDE setVector4(0,0, 1,1)
环结选项属性value默认值
radius(number)  环结半径2
tube(number)  厚度0.5
radialSegments(number)  径向段数32
tubularSegments(number)  管状段数32
p(number)  绕组数2
q(number)  绕组数3
updatable(boolean)  如果网格是可更新的则为 truefalse
sideOrientation(number)  侧方位DEFAULTSIDE
frontUVs(Vector4)  ONLY WHEN sideOrientation:BABYLON.Mesh.DOUBLESIDE setVector4(0,0, 1,1)
backUVs(Vector4)  ONLY WHEN sideOrientation:BABYLON.Mesh.DOUBLESIDE setVector4(0,0, 1,1)

创建环面示例链接

低Pq创建圆环结示例链接

高Pq环结示例链接

高非整数Pq环结示例链接

8.创建线、虚线

    //创建线
    const myPoint = [
      new Vector3(-2, -1, 0),
      new Vector3(0, 1, 0),
      new Vector3(2, -1, 0),
    ]
    //线的颜色
    const myColors = [
      new Color4(1, 0, 0, 1),
      new Color4(0, 1, 0, 1),
      new Color4(0, 0, 1, 1),
      new Color4(1, 1, 0, 1),
    ]
    //闭合线
    myPoint.push(myPoint[0])
    const lines = MeshBuilder.CreateLines('lines', {
      points: myPoint,
      colors: myColors,
    })
    lines.position.x = 1

    //创建螺旋线
    const myPoints = []
    const deltaTheta = 0.2
    const deltaY = 0.005
    const radius = 1
    let theta = 0
    let Y = 0

    for (let i = 0; i < 400; i++) {
      myPoints.push(
        new Vector3(radius * Math.cos(theta), Y, radius * Math.sin(theta))
      )
      theta += deltaTheta
      Y += deltaY
    }
    const lines1 = MeshBuilder.CreateLines('lines1', {
      points: myPoints,
      updatable: true,
    })
    lines1.position.x = -2
    
    //创建虚线
    const points = [
      new Vector3(-2, -1, 0),
      new Vector3(0, 1, 0),
      new Vector3(2, -1, 0),
    ]

    points.push(points[0])
    const lines2 = MeshBuilder.CreateDashedLines('lines2', {
      points: points,
      dashSize: 1000, //破折号的大小
      gapSize: 500, //间隙大小
      dashNb: 80, //预定的破折号数
    })
    lines2.color = Color3.Red()
    lines2.position.x = -2
    lines2.position.z = 1

效果如图:

1703746086015.png

线选项属性value默认值
points(Vector3[])  点,路径(必选) 
updatable(boolean)  如果网格是可更新的则为 truefalse
instance(LineMesh)  要更新的线网格实例null
colors(Color4[])  每个点的颜色null
useVertexAlpha(boolean)  如果不需要 alpha 混合,则为 false 。true
虚线选项属性value默认值
points(Vector3[])   点,路径(必选) 
dashSize(number)  破折号的大小3
gapSize(number)  间隙大小1
dashNb(number)  预定的破折号数200
updatable(boolean)  如果网格是可更新的则为truefalse
instance(LineMesh)  要更新的线网格实例null

创建线示例链接

创建闭合线示例链接

创建多色线示例链接

创建螺旋线示例链接

创建虚线示例链接

二、网格的变换(位置、旋转、缩放)

为了充分理解在场景中定位网格的所有方法,我们需要了解参考系。

当在场景中创建一个世界时,我们使用 世界空间 中的参考框架;场景中的每一个网格也都有自己的 局部空间,其在世界空间中的局部原点为(-1,2,1)。

即使用世界坐标系和局部坐标系两种坐标系作为参考框架。

所有的位置、旋转和尺寸大小都由三维向量来描述,可以使用 new Vector3(x,y,z) 来分别设置它们。

1.位置

     /**
     * 创建一个立方体
     * 配置项:名称,选项(可以为物体设置长宽,体积等),场景
     */
    const box = MeshBuilder.CreateBox('box', { size: 1 }, scene)
    
    // 对于一个网格,不管它是否被旋转,下列都是正确的。
    box.position.x = 2
    box.position.y = 3
    box.position.z = 4
    // box.position = new Vector3(2, 3, 4) //(2, 3, 4)
    // box.position.addInPlace(new Vector3(2, 3, 4)) //(-1 + 2, 2 + 3, 1 + 4) = (1, 5, 5)
    // box.translate(new Vector3(2, 3, 4), 1, Space.WORLD) //(-1 + 2, 2 + 3, 1 + 4) = (1, 5, 5)

    // 使用以下方法得到的位置取决于网格的方向。在不知道网格旋转的情况下,不可能给出一个结果位置。
    // box.translate(new Vector3(2, 3, 4), 1, Space.LOCAL);
    // box.setPositionWithLocalVector(new Vector3(2, 3, 4))
    // box.locallyTranslate(new Vector3(2, 3, 4));

2.旋转

在网格创建时,旋转中心是网格的局部原点,并且旋转总是逆时针的。

使用局部坐标轴旋转物体时,首先绕y轴旋转,然后绕x轴旋转,最后绕z轴旋转。

使用世界坐标轴旋转物体时,首先绕z轴旋转,然后绕x轴旋转,最后绕y轴旋转。

     /**
     * 创建一个立方体
     * 配置项:名称,选项(可以为物体设置长宽,体积等),场景
     */
    const box = MeshBuilder.CreateBox('box', { size: 1 }, scene)

    //旋转
    box.rotation.x = Math.PI / 4
    box.rotation.y = Tools.ToRadians(45)
    box.rotation.z = Math.PI / 3
    // box.rotation = new Vector3(Math.PI / 4, Tools.ToRadians(45), Math.PI / 3)

    //排序旋转,进行首先是关于x轴,然后是y轴,然后是z轴的一系列的旋转,利用addRotation方法
    // box.addRotation(Math.PI / 2, 0, 0)
    // box.addRotation(0, 0, Math.PI / 3)
    // box.addRotation(0, Math.PI / 8, 0)

    // box.rotation.addRotation(Math.PI / 2, 0, 0).addRotation(0, 0, Math.PI / 3).addRotation(0, Math.PI / 8);

地球在倾斜轴上旋转示例链接

3.缩放

     /**
     * 创建一个立方体
     * 配置项:名称,选项(可以为物体设置长宽,体积等),场景
     */
    const box = MeshBuilder.CreateBox('box', { size: 1 }, scene)

    //缩放
    box.scaling.x = 0.5
    box.scaling.y = 2
    box.scaling.z = 0.5

    // box.scaling = new Vector3(0.5, 2, 0.5)

三、网格克隆与实例

     /**
     * 创建一个立方体
     * 配置项:名称,选项(可以为物体设置长宽,体积等),场景
     */
    const box = MeshBuilder.CreateBox('box', { size: 1 }, scene)
    //克隆
    const box1 = box.clone('box2')
    box1.position.x = -2

    //创建实例,使用硬件加速渲染来绘制大量相同网格
    for (let index = 0; index < 10; index++) {
      let newInstance = box.createInstance('i' + index)
      newInstance.position.x = index
      newInstance.position.z = index
    }

创建实例示例链接

更多网格相关知识可以去官网 网格 学习。