Mesh
撰写时间:2023-09-13
修订时间:2026-04-29
Mesh类代表在场景中要渲染的网格物体。能被渲染为实体、框线、实体及框线。后面此类将扩展为支持纹理贴图。
类图全貌
目前已经实现的Mesh类有较多种,且之间有多重继承关系。其类图全貌(未包含FaceMesh的各个子类)如下图所示:

CompositeMesh既继承于AbstractMesh,同时又是SimpleMesh的聚合。
FaceMesh包含以下子类:
- RegularPolygonMesh
- CircularMesh
- CubeMesh
- CuboidMesh
- BoxMesh
- ConeMesh
- ConeFrustumMesh
- CylinderMesh
一些类借助于Geometries类,通过几何运算,生成几何图形的顶点。该类在下一节讲述。
下面是各个类的源代码。
Mesh
import { GLUHolder } from './WebGLUtils-v11.js';
import {
WebGLBufferUtils as BufUtils,
GLColors,
Geometries as Geo,
vec3, mat4, glMatrix
} from './index-independent.js';
const VERTICES_COMP_SIZE = 3;
export class Mesh {
static RENDER_MODE = {
SOLID: 0,
WIREFRAME: 1,
SOLID_WIREFRAME: 2
};
static WIREFRAME_COLOR = [1.0, 1.0, 1.0, 1.0];
}
定义了RENDER_MODE及WIREFRAME_COLOR两个常量。
MeshInterface
export class MeshInterface extends Mesh {
render() {}
renderInViewport(viewportRenderMode) {}
translate(vector) {}
rotate(degree, vector) {}
}
MeshInterface为接口类,定义了4个接口方法。
当应用程序不使用视口时,可调用render方法来渲染;当使用视口时,则可调用renderInViewport统一渲染为视口中的渲染模式。
translate及rotate方法可让客户端在更抽象层面上方便地对网格物体进行模型变换。
AbstractMesh
AbstractMesh为抽象类,为子类提供了可被继承的属性及默认的方法实现。
export class AbstractMesh extends MeshInterface {
/* --------------- Instance Fields --------------- */
glu = GLUHolder.glu;
modelMatrix = mat4.create();
visible = true;
#renderMode;
vertices;
vertices2D;
set renderMode(value) {
this.#renderMode = value;
}
translate(vector) {
mat4.translate(this.modelMatrix, this.modelMatrix, vector);
}
rotate(degree, vector) {
mat4.rotate(this.modelMatrix, this.modelMatrix, glMatrix.toRadian(degree), vector);
}
render() {
if (this.#renderMode === null || this.#renderMode === undefined) {
throw new Error('Instance field renderMode is not set yet!');
}
const {gl, program} = this.glu;
gl.uniformMatrix4fv(program['uModelMatrix'], false, this.modelMatrix);
switch(this.#renderMode) {
case Mesh.RENDER_MODE.SOLID:
this.renderSolid();
break;
case Mesh.RENDER_MODE.WIREFRAME:
this.renderWireframe();
break;
case Mesh.RENDER_MODE.SOLID_WIREFRAME:
this.renderSolidWireframe();
break;
default:
throw new Error('Unknown or unimplemented RENDER_MODE');
break;
}
}
renderSolid() {
if (this.solidVAO) {
this.glu.renderVAO(this.solidVAO);
}
}
// leave for child to implement
renderWireframe() {}
renderSolidWireframe() {
this.renderSolid();
this.renderWireframe();
}
renderInViewport(viewportRenderMode) {
const {gl, program} = this.glu;
gl.uniformMatrix4fv(program['uModelMatrix'], false, this.modelMatrix);
switch (viewportRenderMode) {
case Mesh.RENDER_MODE.SOLID:
this.renderSolid();
break;
case Mesh.RENDER_MODE.SOLID_WIREFRAME:
this.renderSolidWireframe();
break;
case Mesh.RENDER_MODE.WIREFRAME:
this.renderWireframe();
break;
}
}
}
通用属性
子类不管是WireframeMesh或是SolidMesh,都必然需要存储顶点位置的数据。因此AbstractMesh定义了vertices属性。vertices2D将数据存储为2维数组。
visible属性可用以控制是否显示网格物体。例如,我们可以选择是否需要渲染网格地板等辅助网格物体。
模型变换
每个AbstractMesh都会自动创建一个modelMatrix实例属性,这样可省去客户端自行创建的麻烦。translate及rotate方法中的vector参数可使用3个元素的数组的方式。
渲染
render方法将根据自身的#renderMode属性,调用相应的renderSolid、renderWireframe或renderSolidWireframe方法。
我们的应用框架有一个需求,即当用户在程序运行中,通过键盘快捷键切换网格物体的渲染模式时,要求各个Mesh都能正确响应。而一个纯粹的WireframeMesh,例如,代表坐标系的网格物体,当被要求渲染为实体模式时,它本身就没有这个功能。因此,renderSolid方法运用了适配模式:
如果相应的网格物体没有此功能,则不予渲染,默默地跳过,但不给应用框架增添麻烦。
renderWireframe是每个Mesh必须具备的功能,但因各个Mesh的渲染细节均不一样,因此在这里定义为一个虚方法 (virtual method),由子类负责实现。
renderInViewport方法参数viewportRenderMode,调用相应的renderSolid、renderWireframe或renderSolidWireframe方法,以实现在视口中渲染为统一模式的效果。
render及renderInViewport方法,均在渲染前自动向顶点着色器中的uModelMatrix投喂自身的modalMatrix,以减轻客户端的调用负担。
这里使用了门面模式,render及renderInViewport为门面方法,客户端只需与这两个方法打交道即可。
而从它们的作用来讲,这也是调停者模式 (mediator pattern) 的具体运用。它们根据自身内部的实例属性或方法的参数,在内部进行了中转,以让行为效果与内部状态保持高度一致。
抽象类的意义
作为抽象类,AbstractMesh不能被实例化,因此其没有构造方法。
SimpleMesh
SimpleMesh类开始为其子类WireframeMesh提供构造方法,并实现通用的renderWireframe方法。
export class SimpleMesh extends AbstractMesh {
verticesVBO;
wireframeVAO;
constructor(vertices, wireframeIndices, wireframeColor = Mesh.WIREFRAME_COLOR) {
super();
this.vertices = vertices;
this.vertices2D = Geo.To2DArrays(vertices);
this.verticesVBO = this.glu.createPosVBO(vertices);
this.#initWireframeVAO(wireframeIndices, wireframeColor);
}
#initWireframeVAO(wireframeIndices, wireframeColor) {
let glu = this.glu;
let colorsVBO = glu.createColorVBO(wireframeColor.repeat(this.verticesVBO.verticesNum));
this.wireframeVAO = glu.createVAO(this.verticesVBO, colorsVBO);
if (!wireframeIndices) {
let vertices = BufUtils.GetView(this.verticesVBO, 'aPosition', Float32Array);
let indices = Geo.GetIndicesFromVertices(vertices);
wireframeIndices = Geo.GetLinesIndices(indices, true);
}
glu.createIBO(this.wireframeVAO, wireframeIndices);
}
renderWireframe() {
this.glu.renderVAO(this.wireframeVAO, true);
}
}
每个SimpleMesh都有一个wireframeVAO属性,以供renderWireframe使用。
在私有方法initWireframeVAO中,如果未指定顶点索引值,则自动生成,客户端很喜欢偷懒。
这样,每个能被实例化的Mesh,包括持有聚合SimpleMesh的CompositeMesh,都能统一地渲染为框线模式。
WireframeMesh
export class WireframeMesh extends SimpleMesh {
constructor(vertices, wireframeIndices, wireframeColor = Mesh.WIREFRAME_COLOR) {
super(vertices, wireframeIndices, wireframeColor);
this.renderMode = Mesh.RENDER_MODE.WIREFRAME;
}
}
作为继承自SimpleMesh的子类,WireframeMesh只需在构造方法中指定渲染模式即可。
注意到了此层级,WireframeMesh的代码已经极为简单。因此所有的活,上面的各个类都为它代劳了。
由此可见,在一个有多级继承关系的应用框架中,我们非常喜欢定义位于继承链末端的类,这种类的实现简直不费吹灰之力。
SolidMesh
export class SolidMesh extends WireframeMesh {
solidVAO;
constructor(vertices, colors, solidIndices, wireframeIndices) {
super(vertices, wireframeIndices);
this.#initSolidVAO(colors, solidIndices);
this.renderMode = Mesh.RENDER_MODE.SOLID_WIREFRAME;
}
#initSolidVAO(colors, solidIndices) {
let glu = this.glu;
let colorsVBO = glu.createColorVBO(colors);
this.solidVAO = glu.createVAO(this.verticesVBO, colorsVBO);
if (!solidIndices) {
let vertices = BufUtils.GetView(this.verticesVBO, 'aPosition', Float32Array);
let indices = Geo.GetIndicesFromVertices(vertices);
solidIndices = Geo.GetCCWTriangleIndices(indices);
}
glu.createIBO(this.solidVAO, solidIndices);
}
}
SolidMesh继承自WireframeMesh,只需为其初始化实例属性solidVAO的值、并指定渲染模式即可。渲染方法renderSolid已由位于继承树上方的AbstractMesh代劳。
同样,如果在构造方法中未指定实例顶点索引值,则按逆时针顺序自动生成各个独立的三角形索引值。
SoleColorMesh
SoleColorMesh继承自SolidMesh,用于生成只使用一种颜色的网格物体。
export class SoleColorMesh extends SolidMesh {
constructor(vertices, soleColor = GLColors.GetRandomSoftRGB(), solidIndices, wireframeIndices) {
let colors = soleColor.repeat(vertices.length / VERTICES_COMP_SIZE);
super(vertices, colors, solidIndices, wireframeIndices);
}
}
CompositeMesh
CompositeMesh是一个聚合类。它是设计模式中组合模式的运用。
一个网格对象需要使用两种以上的顶点颜色时,就应使用此类。
例如,当网格地板需用各种颜色标识不同的坐标轴,或者当一个网格对象有多个各不相同颜色的面时,均应使用此类。
export class CompositeMesh extends AbstractMesh {
childMeshes = [];
#renderMode;
set renderMode(value) {
this.#renderMode = value;
for (let childMesh of this.childMeshes) {
childMesh.renderMode = value;
}
}
translate(vector) {
for (let childMesh of this.childMeshes) {
mat4.translate(childMesh.modelMatrix, childMesh.modelMatrix, vector);
}
}
rotate(degree, vector) {
for (let childMesh of this.childMeshes) {
mat4.rotate(childMesh.modelMatrix, childMesh.modelMatrix, glMatrix.toRadian(degree), vector);
}
}
render() {
for (let childMesh of this.childMeshes) {
childMesh.render();
}
}
renderInViewport(viewportRenderMode) {
for (let childMesh of this.childMeshes) {
childMesh.renderInViewport(viewportRenderMode);
}
}
}
childMeshes用于存储各个子网格物体。
为私有实例属性#renderMode声明了一个setter方法,以在CompositeMesh的该属性值被改变时,自动更新所有子对象相应属性值。
同时,也须覆盖MeshInterface所定义的4个方法,委派各个子对象去完成。
HelperMesh
HelperMesh继承自CompositeMesh。
export class HelperMesh extends CompositeMesh {
}
HelperMesh是一种标识类,仅用于标识此类为辅助类
,因此其内容为空。
在应用框架中,仅定义了两种辅助类,分别为GridFloorMesh(网格地板对象)及CoordsAxesMesh(坐标轴对象)。
有此标识后,客户端在程序运行过程中就可以有针对性地隐藏此类网格物体,而保持渲染其他网格物体。
GridFloorMesh
GridFloorMesh继承自HelperMesh,用以渲染一个网格地板。
export class GridFloorMesh extends HelperMesh {
// defined around the origin point
// cellSide: the side length of each cell
// num: the number of cells of half of a floor row
constructor(cellSide = 0.5, num = 10) {
super();
this.GRID_COLOR= [0.2, 0.2, 0.2, 1.0];
this.X_AXIS_COLOR = [0.5, 0.0, 0.0, 1.0];
this.Z_AXIS_COLOR = [0.0, 0.0, 0.9, 1.0];
this.gridVertices = [];
this.buildGridVertices(cellSide, num);
let wireframeIndices = Geo.GetIndicesFromVertices(this.gridVertices);
this.gridWireframeMesh = new WireframeMesh(this.gridVertices, wireframeIndices, this.GRID_COLOR);
this.xVertices = [];
this.buildXVertices(cellSide, num);
this.xWireframeMesh = new WireframeMesh(this.xVertices, [0, 1], this.X_AXIS_COLOR);
this.zVertices = [];
this.buildZVertices(cellSide, num);
this.zWireframeMesh = new WireframeMesh(this.zVertices, [0, 1], this.Z_AXIS_COLOR);
this.childMeshes.push(this.xWireframeMesh);
this.childMeshes.push(this.zWireframeMesh);
this.childMeshes.push(this.gridWireframeMesh);
}
buildGridVertices(cellSide, num) {
let vertices = this.gridVertices;
// horizontal lines
let startX = -cellSide * num;
let endX = -startX;
let startZ = startX;
let endZ = -startZ;
while (startZ <= endZ) {
vertices.push(
startX, 0, startZ,
endX, 0, startZ
);
startZ += cellSide;
}
// vertical lines
startZ = -cellSide * num;
endZ = -startZ;
startX = startZ;
endX = -startX;
while (startX <= endX) {
vertices.push(
startX, 0, startZ,
startX, 0, endZ
);
startX += cellSide;
}
}
buildXVertices(cellSide, num) {
let vertices = this.xVertices;
vertices.push(-cellSide * num, 0.0, 0.0, cellSide * num, 0.0, 0.0);
}
buildZVertices(cellSide, num) {
let vertices = this.zVertices;
vertices.push(0.0, 0.0, -cellSide * num, 0.0, 0.0, cellSide * num);
}
}
用灰色绘制网格,用红色绘制X轴,用蓝色绘制Z轴。Y轴不绘制。
这里使用了建造者模式 (builder pattern),分别建造了3个子组件后,最后装配为CompositeMesh所必须持有的childMeshes实例属性。
CoordsAxesMesh
CoordsAxesMesh继承自HelperMesh,用以渲染一个3D坐标轴。
export class CoordsAxesMesh extends HelperMesh {
constructor(axisLength, markGap = 1, markLen = 0.1) {
super();
this.axisLength = axisLength;
this.markGap = markGap;
this.ARROW_LEN = markLen * 1.5;
this.ARROW_ANGLE = 15;
this.MARK_LEN = markLen;
this.HALF_MARK_LEN = this.MARK_LEN / 2;
this.X_MAIN_COLOR = [0.5, 0.2, 0.2, 1.0];
this.X_MARKS_COLOR = [0.4, 0.2, 0.2, 1.0];
this.X_HALF_MARKS_COLOR = [0.3, 0.2, 0.2, 1.0];
this.Y_MAIN_COLOR = [0.2, 0.5, 0.2, 1.0];
this.Y_MARKS_COLOR = [0.2, 0.4, 0.2, 1.0];
this.Y_HALF_MARKS_COLOR = [0.2, 0.3, 0.2, 1.0];
this.Z_MAIN_COLOR = [0.2, 0.2, 0.7, 1.0];
this.Z_MARKS_COLOR = [0.2, 0.2, 0.6, 1.0];
this.Z_HALF_MARKS_COLOR = [0.2, 0.2, 0.5, 1.0];
this.buildXVertices();
this.buildYVertices();
this.buildZVertices();
this.childMeshes.push(this.xMainWireframeMesh);
this.childMeshes.push(this.xMarksWireframeMesh);
this.childMeshes.push(this.xHalfMarksWireframeMesh);
this.childMeshes.push(this.yMainWireframeMesh);
this.childMeshes.push(this.yMarksWireframeMesh);
this.childMeshes.push(this.yHalfMarksWireframeMesh);
this.childMeshes.push(this.zMainWireframeMesh);
this.childMeshes.push(this.zMarksWireframeMesh);
this.childMeshes.push(this.zHalfMarksWireframeMesh);
}
buildXVertices() {
this.xVertices = {};
// axis main
this.xVertices.main = [];
this.xVertices.main.push(
-this.axisLength/2, 0.0, 0.0,
this.axisLength/2, 0.0, 0.0
);
// axis arrow
let arrowEndX = Math.cos(Geo.RadianFromDegree(this.ARROW_ANGLE)) * this.ARROW_LEN;
let arrowEndY = Math.sin(Geo.RadianFromDegree(this.ARROW_ANGLE)) * this.ARROW_LEN;
this.xVertices.main.push(
this.axisLength/2 - arrowEndX, arrowEndY, 0.0,
this.axisLength/2, 0.0, 0.0,
this.axisLength/2 - arrowEndX, -arrowEndY, 0.0,
this.axisLength/2, 0.0, 0.0,
this.axisLength/2 - arrowEndX, 0.0, -arrowEndY,
this.axisLength/2, 0.0, 0.0,
this.axisLength/2 - arrowEndX, 0.0, arrowEndY,
this.axisLength/2, 0.0, 0.0
);
let mainIndices = Geo.GetIndicesFromVertices(this.xVertices.main);
this.xMainWireframeMesh = new WireframeMesh(this.xVertices.main, mainIndices, this.X_MAIN_COLOR);
// marks
this.xVertices.marks = [];
let currX = 0.0;
while (currX < this.axisLength/2) {
this.xVertices.marks.push(currX, this.MARK_LEN, 0.0);
this.xVertices.marks.push(currX, -this.MARK_LEN, 0.0);
currX += this.markGap;
}
currX = -this.markGap;
while (currX > -this.axisLength/2) {
this.xVertices.marks.push(currX, this.MARK_LEN, 0.0);
this.xVertices.marks.push(currX, -this.MARK_LEN, 0.0);
currX -= this.markGap;
}
let marksIndices = Geo.GetIndicesFromVertices(this.xVertices.marks);
this.xMarksWireframeMesh = new WireframeMesh(this.xVertices.marks, marksIndices, this.X_MARKS_COLOR);
// half marks
this.xVertices.halfMarks = [];
currX = this.markGap/2;
while (currX < this.axisLength/2) {
this.xVertices.halfMarks.push(currX, this.HALF_MARK_LEN, 0.0);
this.xVertices.halfMarks.push(currX, -this.HALF_MARK_LEN, 0.0);
currX += this.markGap;
}
currX = -this.markGap/2;
while (currX > -this.axisLength/2) {
this.xVertices.halfMarks.push(currX, this.HALF_MARK_LEN, 0.0);
this.xVertices.halfMarks.push(currX, -this.HALF_MARK_LEN, 0.0);
currX -= this.markGap;
}
let halfMarksIndices = Geo.GetIndicesFromVertices(this.xVertices.halfMarks);
this.xHalfMarksWireframeMesh = new WireframeMesh(this.xVertices.halfMarks, halfMarksIndices, this.X_HALF_MARKS_COLOR);
}
rotateVertices(vertices, axisAround) {
let srcVec3;
let dstVec3 = vec3.create();
let result = [];
for (let i = 0; i < vertices.length; i += 3) {
srcVec3 = vec3.fromValues(vertices[i], vertices[i+1], vertices[i+2]);
if (axisAround === 'z') {
vec3.rotateZ(dstVec3, srcVec3, [0, 0, 0], Geo.RadianFromDegree(90));
} else if (axisAround === 'y') {
vec3.rotateY(dstVec3, srcVec3, [0, 0, 0], Geo.RadianFromDegree(-90));
}
result.push(dstVec3[0], dstVec3[1], dstVec3[2]);
}
return result;
}
buildYVertices() {
this.yVertices = {};
this.yVertices.main = this.rotateVertices(this.xVertices.main, 'z');
let mainIndices = Geo.GetIndicesFromVertices(this.yVertices.main);
this.yMainWireframeMesh = new WireframeMesh(this.yVertices.main, mainIndices, this.Y_MAIN_COLOR);
this.yVertices.marks = this.rotateVertices(this.xVertices.marks, 'z');
let marksIndices = Geo.GetIndicesFromVertices(this.yVertices.marks);
this.yMarksWireframeMesh = new WireframeMesh(this.yVertices.marks, marksIndices, this.Y_MARKS_COLOR);
this.yVertices.halfMarks = this.rotateVertices(this.xVertices.halfMarks, 'z');
let halfMarksIndices = Geo.GetIndicesFromVertices(this.yVertices.halfMarks);
this.yHalfMarksWireframeMesh = new WireframeMesh(this.yVertices.halfMarks, halfMarksIndices, this.Y_HALF_MARKS_COLOR);
}
buildZVertices() {
this.zVertices = {};
this.zVertices.main = this.rotateVertices(this.xVertices.main, 'y');
let mainIndices = Geo.GetIndicesFromVertices(this.zVertices.main);
this.zMainWireframeMesh = new WireframeMesh(this.zVertices.main, mainIndices, this.Z_MAIN_COLOR);
this.zVertices.marks = this.rotateVertices(this.xVertices.marks, 'y');
let marksIndices = Geo.GetIndicesFromVertices(this.zVertices.marks);
this.zMarksWireframeMesh = new WireframeMesh(this.zVertices.marks, marksIndices, this.Z_MARKS_COLOR);
this.zVertices.halfMarks = this.rotateVertices(this.xVertices.halfMarks, 'y');
let halfMarksIndices = Geo.GetIndicesFromVertices(this.zVertices.halfMarks);
this.zHalfMarksWireframeMesh = new WireframeMesh(this.zVertices.halfMarks, halfMarksIndices, this.Z_HALF_MARKS_COLOR);
}
}
代码虽然显得稍长,但同样也是运用了建造者模式,因此不难理解。
在构建一个相对复杂的网格物体模型时,经常用到建造者模式。例如,当需要分别为比亚迪、奇瑞汽车建模时,给它们安排不同的建造参数即可。
FaceMesh
FaceMesh继承自CompositeMesh,用于渲染一个由多个面组成的网格物体。在实现中,FaceMesh是SoleColorMesh的聚合。
export class FaceMesh extends CompositeMesh {
constructor(vertices, facesIndices, facesColors) {
super();
this.vertices = vertices;
this.vertices2D = Geo.To2DArrays(vertices);
if (facesIndices === null || facesIndices === undefined) {
facesIndices = [];
facesIndices.push(Geo.GetIndicesFromVertices(vertices));
}
if (facesColors === null || facesColors === undefined) {
facesColors = [];
for (let index = 0; index < vertices.length; index++) {
let faceColor = GLColors.GetRandomSoftRGB();
facesColors.push(faceColor);
}
} else if (!Array.isArray(facesColors[0]) && facesColors.length === 4) {
let singleColor = facesColors;
facesColors = [];
for (let index = 0; index < vertices.length; index++) {
facesColors.push(singleColor);
}
} else if (facesColors.length < facesIndices.length) {
let colorNeededNum = facesIndices.length - facesColors.length;
for (let index = 0; index < colorNeededNum; index++) {
let faceColor = GLColors.GetRandomSoftRGB();
facesColors.push(faceColor);
}
}
let index = 0;
for (let faceIndices of facesIndices) {
let solidIndices = Geo.GetCCWTriangleIndices(faceIndices);
let wireframeIndices = Geo.GetLinesIndices(faceIndices, true);
let soleColorMesh = new SoleColorMesh(vertices, facesColors[index++], solidIndices, wireframeIndices);
this.childMeshes.push(soleColorMesh);
}
}
}
构造方法参数中的facesIndices及facesColors均为可选。如果未指定,则自动生成。
FaceMesh太好用了,因此下面这些最常用的网格物体均直接继承于它。并且,均只需一个构造器即可。
RegularPolygonMesh
export class RegularPolygonMesh extends FaceMesh {
constructor(radius, sidesNum, isNeedOrg = false, facesColors) {
if (isNeedOrg === true) {
let vertices = Geo.GenRegularPolygonVertices(radius, sidesNum, isNeedOrg);
let indices = Geo.GetIndicesFromVertices(vertices);
let triangleIndices = Geo.GenTriangleIndicesInCircle(indices);
let facesIndices = Geo.To2DArrays(triangleIndices);
super(vertices, facesIndices, facesColors);
} else {
let vertices = Geo.GenRegularPolygonVertices(radius, sidesNum, isNeedOrg);
super(vertices, null, facesColors);
}
}
}
CircularMesh
export class CircularMesh extends RegularPolygonMesh {
constructor(radius, pointsNum, isNeedOrg = false, facesColors) {
super(radius, pointsNum, isNeedOrg, facesColors);
}
}
CubeMesh
export class CubeMesh extends FaceMesh {
constructor(sideLength, facesColors) {
let wrapper = Geo.GenCube(sideLength);
super(wrapper.vertices, wrapper.faces, facesColors);
}
}
CuboidMesh
export class CuboidMesh extends FaceMesh {
constructor(length, width, height, facesColors) {
let wrapper = Geo.GenCuboid(length, width, height);
super(wrapper.vertices, wrapper.faces, facesColors);
}
}
BoxMesh
export class BoxMesh extends FaceMesh {
constructor(length, width, height, lengthThick, widthThick, bottomThick, facesColors) {
let wrapper = Geo.GenBox(length, width, height, lengthThick, widthThick, bottomThick);
super(wrapper.vertices, wrapper.faces, facesColors);
}
}
ConeMesh
export class ConeMesh extends FaceMesh {
constructor(radius, sidesNum, height, facesColors) {
let wrapper = Geo.GenCone(radius, sidesNum, height);
super(wrapper.vertices, wrapper.faces, facesColors);
}
}
ConeFrustumMesh
export class ConeFrustumMesh extends FaceMesh {
constructor(bottomRadius, sidesNum, height, topRadius, facesColors) {
let wrapper = Geo.GenConeFrustum(bottomRadius, sidesNum, height, topRadius);
super(wrapper.vertices, wrapper.faces, facesColors);
}
}
CylinderMesh
export class CylinderMesh extends FaceMesh {
constructor(radius, sidesNum, height, facesColors) {
let wrapper = Geo.GenCylinder(radius, sidesNum, height);
super(wrapper.vertices, wrapper.faces, facesColors);
}
}