动态网格(Dynamic Meshes)
本文介绍了通过ObjectMeshDynamic类创建动态网格的用法举例。 该类被用来在rum-time(运行时)中程序式创建动态网格和修改它们。 为了修改已有网格,您也可将其作为动态网格来加载。
另请参阅
- 通过UnigineScript脚本中的ObjectMeshDynamic类编辑动态网格
- 路径data/samples/objects/>下存放的如下一组范例:
创建动态网格(Dynamic Mesh)
有3种方法可添加新动态网格:
- 通过UnigineEditor添加新动态网格。
- 通过添加顶点创建新动态网格。
- 从已有网格创建创建新动态网格。
创建新动态网格(New Dynamic Mesh)
本章介绍了如何通过分配内存以及为新网格添加顶点来创建新动态网格。 您可为 中等数量的三角形或为很大数量的顶点分配内存。
添加三角形
您可通过添加一个接一个的三角形来从头创建动态网格。 这种变体适合创建具有中等数量三角形的网格。 要想创建新动态网格,须执行如下操作:
- 首先,在顶点缓冲区中为三角形顶点留出必要空间,并将这些顶点的索引添加到索引缓冲区。 可通过调用如下的某个方法来完成这步操作: 所有这些函数都是为具有相应形式的多边形分配内存。
- 通过addVertex()方法添加相应数量的顶点。
- 待addVertex()函数的每个调用都完成之后,您就可以通过调用如下方法来手动为最后一个添加的顶点设置属性了: 所有这些函数都是可选的,您可按需调用它们。
- 通过updateTangents()计算所有顶点的切向量。
- 通过调用updateBounds()计算已创建网格的包围盒和包围球体。
- 如有所需,您也可移除已创建网格的重复顶点来优化它继而实现快速渲染。 这是使用updateIndices()函数完成的,例如,假如四边形(quad polygon)是通过addTriangles(2)(创建6个顶点)创建的,而没有用带优化效果的addQuads(1)(创建4个顶点)创建,那就可以使用该函数来做优化。
用法举例
下面的例子向您展示了如何通过addTriangleQuads()函数创建四边形(quad polygon)。
int init() {
ObjectMeshDynamic mesh = new ObjectMeshDynamic(); // 创建一动态网格并将其添加进Editor。
engine.editor.addNode(node_remove(mesh));
mesh.setWorldTransform(translate(Vec3(0.0f,0.0f,2.0f)));
mesh.setMaterial("mesh_base","*");
mesh.setProperty("surface_base","*");
mesh.addTriangleQuads(1); // 在顶点缓冲区分配空间并创建顶点索引。
mesh.addVertex(vec3(-1.0f,-1.0f,0.0f)); // 如有所需,可添加顶点并分配纹理坐标。
mesh.addTexCoord(vec4(0,0,0,0));
mesh.addVertex(vec3(1.0f,-1.0f,0.0f));
mesh.addTexCoord(vec4(1,0,0,0));
mesh.addVertex(vec3(1.0f,1.0f,0.0f));
mesh.addTexCoord(vec4(1,1,0,0));
mesh.addVertex(vec3(-1.0f,1.0f,0.0f));
mesh.addTexCoord(vec4(0,1,0,0));
mesh.updateTangents(); // 计算切向量。
//mesh.updateIndices(); // 如有所需,可优化顶点缓冲区和索引缓冲区。
mesh.updateBounds(); // 计算网格的包围盒。
return 1;
}
添加很大数量的顶点
要想创建具有海量顶点的动态网格,最好是使用更优的方法:替代以小块的方式分配内存(这种方式代价高昂),首先重新分配所有必要内存,此后对这些内存做数据填充。
- 通过allocateIndices()在索引缓冲区中为三角形顶点分配空间。
- 通过allocateVertex()在顶点缓冲区中为顶点分配空间。
- 通过addVertex()方法添加相应数量的顶点。
- 通过addIndex()方法添加相应数量的索引。
- 接下来按照上面“添加三角形”中给出的步骤3-6操作。
用法举例
下面的例子向您展示了如何通过逐个添加顶点来创建平面(plane)。
int init() {
ObjectMeshDynamic mesh = new ObjectMeshDynamic(); // 创建一动态网格并将其添加进Editor。
engine.editor.addNode(node_remove(mesh));
mesh.setWorldTransform(translate(Vec3(0.0f,0.0f,2.0f)));
mesh.setMaterial("mesh_base","*");
mesh.setProperty("surface_base","*");
mesh.allocateIndices(6); // 分别在索引缓冲区和顶点缓冲区中分配空间。
mesh.allocateVertex(4);
mesh.addVertex(vec3(-1.0f,-1.0f,0.0f)); // 添加顶点。
mesh.addVertex(vec3(1.0f,-1.0f,0.0f));
mesh.addVertex(vec3(1.0f,1.0f,0.0f));
mesh.addVertex(vec3(-1.0f,1.0f,0.0f));
mesh.addIndex(0); // 为已创建的顶点分配索引。
mesh.addIndex(1);
mesh.addIndex(2);
mesh.addIndex(0);
mesh.addIndex(2);
mesh.addIndex(3);
mesh.updateTangents(); // 计算切向量。
//mesh.updateIndices(); // 如有所需,可优化顶点缓冲区和索引缓冲区。
mesh.updateBounds(); // 计算网格的包围盒。
}
基于已有网格创建动态网格
有多种方式可以从已有网格来创建动态网格,它们是:
- 通过将Mesh类的实例作为参数传递给构造函数的方式来创建ObjectMeshDynamic类的实例的新实例。
- 通过将已保存网格的名称作为参数传递给构造函数的方式来创建ObjectMeshDynamic类的实例的新实例。
- 通过将Mesh类的实例作为参数传递给setMesh()函数的方式将mesh类的实例复制给已有的ObjectMeshDynamic实例。
将网格(Mesh)传递给新动态网格(New Dynamic Mesh)
要想从这种已有网格创建新ObjectMeshDynamic实例,须将已有Mesh类的实例传递给ObjectMeshDynamic类的构造函数。
用法举例
下面的例子向您展示了如何从已有Mesh类的实例创建新动态网格。 这里假设您已经拥有了Mesh实例,不过在本例中我们会创建一个具有box型表面的Mesh类的新实例。
int init() {
/* ... */
// 创建一具有box型表面的mesh
Mesh mesh = new Mesh();
mesh.addBoxSurface("box", vec3(0.2));
// 通过将mesh作为参数传递的方式来创建新ObjectMeshDynamic实例
ObjectMeshDynamic dynamic_mesh = new ObjectMeshDynamic(mesh);
// 分配材质和属性。
dynamic_mesh.setMaterial("mesh_base","*");
dynamic_mesh.setProperty("surface_base","*");
/* ... */
}
将网格名称(Mesh Name)传递给新动态网格(New Dynamic Mesh)
要想从已有.mesh文件创建新动态网格 ,须将存放该文件的路径传递给ObjectMeshDynamic类的构造函数。 其路径是相对于您项目的data/文件夹的。
用法举例
下面的例子向您展示了如何从已有.mesh文件创建新动态网格。 这里假设您已经有了一个网格文件,并且您会将存放该文件的路径作为参数传递给ObjectMeshDynamic构造函数。 本例中的雕像网格(statue mesh)取自Unigine范例(samples)。
int init() {
/* ... */
// 创建一新ObjectMeshDynamic实例,
// 方法是通过将已有网格的存放路径作为参数传递。
ObjectMeshDynamic dynamic_mesh = new ObjectMeshDynamic("/samples/common/meshes/statue.mesh");
engine.editor.addNode(node_remove(dynamic_mesh));
// 分配材质和属性。
dynamic_mesh.setMaterial("mesh_base","*");
dynamic_mesh.setProperty("surface_base","*");
/* ... */
}
将网格(Mesh)复制给已有动态网格(Existing Dynamic Mesh)
要想将Mesh实例的网格复制给已有动态网格,须使用setMesh()函数并将Mesh实例作为参数传递给该函数。 此函数会将所给网格复制进当前动态网格。
用法举例
下面的例子向您展示了如何将Mesh实例的网格复制给ObjectMeshDynamic实例。 这里假设您已经拥有了Mesh实例,不过在本例中我们会创建一个具有box型表面的Mesh类的新实例。
int init() {
/* ... */
// 具有box型表面的已有mesh
Mesh mesh = new Mesh();
mesh.addBoxSurface("box", vec3(0.2));
// 创建一新ObjectMeshDynamic
ObjectMeshDynamic dynamic_mesh = new ObjectMeshDynamic();
engine.editor.addNode(node_remove(dynamic_mesh));
// 将已有网格复制给ObjectMeshDynamic
dynamic_mesh.setMesh(mesh);
// 分配材质和属性
dynamic_mesh.setMaterial("mesh_base","*");
dynamic_mesh.setProperty("surface_base","*");
/* ... */
}
为动态网格添加物理(Physics)
要想给动态网格添加一些物理属性以便其能够参与对象间或外部物理作用力间的交互,那动态网格就须拥有body(实体)。 您能通过UnigineScript脚本或UnigineEditor可以很容易地分配body。
用法举例
下面的例子向您展示了如何将具有shape(形状)的刚体添加给动态网格。 在本例中,动态网格是从具有box型表面的已有网格创建的。
/* ... */
// 创建一具有box型表面的mesh实例
Mesh mesh = new Mesh();
mesh.addBoxSurface("box", vec3(0.2));
// 从Mesh实例创建一新动态网格并将其添加给Editor
ObjectMeshDynamic dynamic_mesh = new ObjectMeshDynamic(mesh);
engine.editor.addNode(node_remove(dynamic_mesh));
// 为动态网格分配材质和属性
dynamic_mesh.setMaterial("mesh_base","*");
dynamic_mesh.setProperty("surface_base","*");
// 为动态网格分配body和shape
BodyRigid body = class_remove(new BodyRigid(dynamic_mesh));
ShapeBox shape = class_remove(new ShapeBox(body, vec3(0.2f)));
/* ... */
另请参阅
- Unigine中的物理实体(Physical bodies)章节。
- Unigine中的形状(Shapes)章节。
与动态网格的相交(Intersections)
要想检测动态网格是否与线,或与指定包围体的边界相交,须使用如下的某个函数:
- Object.getIntersection() - 该函数用来检测指定对象与轨迹线的相交。 另请参阅此跳转章节给出的对象相交的用法举例。
- engine.world.getIntersection() - 世界相交函数用来检测指定包围体的所有对象和节点,或是检测与不可见轨迹线的首个对象的相交。 另请参阅此跳转章节给出的世界相交的例子。
- engine.physics.getIntersection() - 物理相交函数用来检测与实体(bodies)的形状的相交。 如果对象没有body,那该函数就会检测与使用了相交标记选项的对象的表面(多边形)的相交。 另请参阅此跳转章节给出的物理相交的用法举例。
- Shape.getIntersection() - 该函数用来检测指定形状与轨迹线的相交。 另请参阅此跳转章节给出的形状相交的例子。
将动态网格保存进文件
要想将动态网格保存进文件,须将其复制给Mesh类的实例。 通过Mesh类的save()函数,您就能保存带有指定名称的网格。
用法举例
下面的例子向您展示了如何将动态网格保存进文件。 这里假设您已经有了一个要保存的动态网格。 您应将用于存放网格的路径作为参数传递给Mesh类的save()函数。 其路径是相对于您项目的data/文件夹的。
/* ... */
// 创建一mesh实例
Mesh mesh = new Mesh();
// 将动态网格复制给Mesh类的实例
dynamic_mesh.getMesh(mesh);
// 将该mesh保存进路径下文件data/samples/dynamic_mesh.mesh中
mesh.save("samples/dynamic_mesh.mesh");
/* ... */