This page has been translated automatically.
Programming
Fundamentals
Setting Up Development Environment
UnigineScript
High-Level Systems
C++
C#
UUSL (Unified UNIGINE Shader Language)
File Formats
Rebuilding the Engine and Tools
GUI
Double Precision Coordinates
API
Containers
Common Functionality
Controls-Related Classes
Engine-Related Classes
Filesystem Functionality
GUI-Related Classes
Math Functionality
Node-Related Classes
Networking Functionality
Pathfinding-Related Classes
Physics-Related Classes
Plugins-Related Classes
Rendering-Related Classes
注意! 这个版本的文档是过时的,因为它描述了一个较老的SDK版本!请切换到最新SDK版本的文档。
注意! 这个版本的文档描述了一个不再受支持的旧SDK版本!请升级到最新的SDK版本。

Mesh类

Mesh类提供了一种加载,操纵和保存mesh(网格)的接口。

通过使用该类,您就能创建mesh,然后为其添加geometry(几何体)(比如添加box(盒体)型,plane(平面)型,capsule(胶囊)型或cylinder(缸体)型的表面),为其添加动画和骨骼(前提是您想要创建骨骼蒙皮),再之后使用其创建如下对象:

Mesh(网格)的特性列举如下:

  • mesh的每个表面支持多个变形目标(Morph Targets)。
  • 为获得更好的加载速度,每个表面都拥有基于四元数的相切基础。
  • 支持8位顶点颜色(colors)。
  • 表面的每个顶点都拥有2组索引:坐标索引和三角形索引。 这样不仅提高了加载速度,还减少了数据的重复。
  • 表面的每个顶点都拥有2个UV集。
  • 每个mesh的绑定姿势(bind pose)变换都会被存储(即便没有动画(animations)和动画帧(animation frames)也会如此)。 另请参阅:getBoneTransfroms()函数。
    注意
    第1个动画帧不应包含绑定姿势。

顶点的索引

每个顶点都存储了包括自身位置,法线,副法线,切线和纹理坐标在内的信息。 这里存在2种独立的顶点缓冲区:

  • CVertex型坐标缓冲区,该缓冲区只存储顶点坐标。
  • TVertex型三角形缓冲区,该缓冲区存储了像法线,副法线,切线,颜色,UV坐标这样的顶点属性(attributes)。

在下图中,箭头用来表示法向(normals)

包含了2个相邻三角形的表面。 这里的C0...C4指坐标顶点,T0...T5指三角形顶点

坐标缓冲区(coordinate buffer)就是坐标顶点的数组。 为了减少数据的重复,拥有相同坐标的表面的顶点只在缓冲区中被保存一次。 例如,上图中给出的表面,其坐标缓冲区为:

输出
CB = [C0,C1,C2,C3]
表面的每个多边形都拥有3个坐标。 我们使用了2个多边形,因此就拥有了6个顶点,不过在CVertex型顶点缓冲区中却只保存了4个顶点,原因就是这6个顶点中有2个拥有相同坐标。 每个坐标顶点都包含了该顶点自身的坐标(float[3]类型)。
注意
顶点的数量和坐标顶点的数量是相等的。

三角形缓冲区(triangle buffer)就是三角形顶点的数组。 例如,上图中给出的表面,其三角形缓冲区为:

输出
TB = [T0,T1,T2,T3,T4,T5]
每个三角形顶点都可以存储如下内容:
  • 法线(Normal)
  • 副法线(Binormal)
  • 切线(Tangent)
  • 第1UV贴图纹理坐标(1st UV map texture coordinates)
  • 第2UV贴图纹理坐标(2nd UV map texture coordinates)
  • 颜色(Color)
注意
顶点的数量和三角形顶点的数量可以是不同的。
三角形顶点的数量取决于顶点所属的三角形的数量。 例如,如果2个三角形拥有的1对相邻顶点,它们的法向(normals)对每个三角形而言都不同,那这2个三角形顶点就都会被存储(上图中的1号顶点和3号顶点)。 不过,如果所有相邻三角形的分量都相同,那就只有1个三角形顶点会被存储。

坐标顶点和三角形顶点都拥有索引。 这里存在2种索引缓冲区,可用于获取mesh的每个三角形本身的cvertex型顶点数据和tvertex型顶点数据:

  • CIndex型缓冲区 — 指坐标索引,也就是链接到cvertex型顶点的链接。
  • TIndex型缓冲区 — 指三角形索引,也就是链接到tvertex型顶点的链接。
通过使用索引,您就能获取每个mesh的三角形本身的cvertex型顶点数据和tvertex型顶点数据。

坐标索引

每个坐标顶点都拥有坐标索引。 坐标索引的数量等于3*三角形的数量。 对给定表面而言,坐标索引的数组为:

输出
CIndices = [Ci0,Ci1,Ci3,Ci1,Ci2,Ci3]
其中:
  • 前3个元素是第1个(底)三角形的坐标索引。
  • 后3个元素是第2个(顶)三角形的坐标索引。

三角形索引

每个三角形顶点都拥有三角形索引。 三角形索引的数量等于3*三角形的数量。 对给定表面而言,三角形索引的数组为:

输出
TIndices = [Ti0,Ti1,Ti5,Ti2,Ti3,Ti4]
其中:
  • 前3个元素是第1个(底)三角形的三角形索引。
  • 后3个元素是第2个(顶)三角形的三角形索引。

注意
坐标的数量和三角形的索引数量是相等的。

另请参阅

将一个Mesh复制进另一Mesh

您可通过Mesh类将一个mesh复制进另一mesh。

在下面的例子中,我们会通过让Mesh类作为容器(container)的方式将ObjectMeshDynamic网格复制给新ObjectMeshDynamic类的实例。 其执行序列如下:

  • 这里假设您已经拥有了一个要复制的ObjectMeshDynamic。 创建一个Mesh类的实例来作为ObjectMeshDynamic网格的容器。
  • 通过getMesh()函数将ObjectMeshDynamic网格复制给Mesh。
  • 通过ObjectMeshDynamic类的重载构造函数从Mesh创建新的ObjecteMeshDynamic实例。

源代码 (UnigineScript)
/* ... */
// 创建ObjectMeshDynamic实例和Mesh实例
ObjectMeshDynamic dynamicMesh = new ObjectMeshDynamic();
Mesh firstMesh = new Mesh();

// 获取ObjectMeshDynamic并将其复制给Mesh类的实例
dynamicMesh.getMesh(firstMesh);

// 从firstMesh网格创建新的ObjectMeshDynamic实例 
ObjectMeshDynamic dynamicMesh_2 = new ObjectMeshDynamic(firstMesh);
/* ... */

此外,您也可通过setMesh()函数复制mesh。 例如,在下面的代码中,我们会将mesh实例设置给已经创建了的ObjectMeshDynamic网格。 其执行序列如下:

  • 这里假设您已经拥有了2个ObjectMeshDynamic类的实例。 创建一个Mesh类的实例来作为容器。
  • 通过getMesh()函数将ObjectMeshDynamic复制给Mesh 。
  • 通过setMesh()函数将mesh设置给第2个ObjectMeshDynamic实例。
源代码 (UnigineScript)
/* ... */
// 创建ObjectMeshDynamic实例 
ObjectMeshDynamic dynamicMesh = new ObjectMeshDynamic();
ObjectMeshDynamic dynamicMesh_2 = new ObjectMeshDynamic();

// 创建Mesh实例
Mesh firstMesh = new Mesh();

// 获取ObjectMeshDynamic并将其复制给Mesh类的实例
dynamicMesh.getMesh(firstMesh);

// 将secondMesh网格设置给dynamicMesh_2实例
dynamicMesh_2.setMesh(firstMesh);
/* ... */
注意
在不创建新ObjectMeshDynamic实例的情况下,您可以将Mesh类的变换网格返回给同一ObjectMeshDynamic实例。

您能通过构造函数可以很容易地将一个mesh实例复制给一个新的mesh实例,同时还可将mesh实例作为参数传递:

源代码 (UnigineScript)
Mesh firstMesh = new Mesh();
Mesh secondMesh = new Mesh(firstMesh);

复制网格(Mesh)的表面

通过使用Mesh类,您就能将一个mesh的表面复制别的mesh。

在下面的例子中,我们会创建2个带有不同表面的网格。 第1个mesh拥有capsule型表面,第2个mesh拥有box型表面。 我们会将来自第2个mesh的box型表面复制给第一个mesh。 其执行序列如下:

  • 创建2个Mesh类的实例,并为它们添加表面。
  • 通过addMeshSurface()函数从mesh_2网格添加box型表面,并将其添加给mesh_1网格。
  • 从mesh_1实例创建新ObjectMeshDynamic网格。
  • 将动态网格添加给Editor,并为其设置材质,属性和名称。
源代码 (UnigineScript)
// 创建2个mesh实例
Mesh mesh_1 = new Mesh();
Mesh mesh_2 = new Mesh();

// 为已添加的网格添加表面
mesh_1.addCapsuleSurface("capsule_surface", 1.0f, 2.0f, 200, 100);
mesh_2.addBoxSurface("box_surface", vec3(2.2));

// 将mesh_2的表面作为新表面添加给mesh_1
// 使用的名称为"new_box_surface"
mesh_1.addMeshSurface("new_box_surface", mesh_2, 0);

// 从mesh_1对象创建ObjectMeshDynamic
ObjectMeshDynamic dynamicMesh = new ObjectMeshDynamic(mesh_1);

// 将dynamicMesh作为Node对象添加给Editor 
engine.editor.addNode(node_remove(dynamicMesh));

// 为mesh设置位置
dynamicMesh.setWorldTransform(translate(Vec3(10.0f,10.0f,10.0f)));
// 将材质设置给mesh
dynamicMesh.setMaterial("mesh_base","*");
// 将属性设置给mesh
dynamicMesh.setProperty("surface_base","*");
// 为mesh设置名称
dynamicMesh.setName("Dynamic Mesh");
注意
在不为当前mesh创建新表面的情况下,您可以从源mesh复制表面并将其添加给当前mesh的已有表面。

这时ObjectMeshDynamic网格便会出现在Editor中:

添加顶点(Vertices)以及更改它们的属性(Attributes)

您可通过Mesh类更改顶点的属性(attributes)。

在下面的例子中,我们会通过将顶点添加给mesh来创建一个plane,并更改这些顶点中的一些的属性(attributes)。 让我们将其阐述如下:

  • 创建Mesh类的实例并为其添加4个顶点。
  • 添加6个索引来创建一个plane。
  • 在那之后,通过函数createTangents()createNormals()创建切线和法线。
  • 2个顶点的法线的当前值会被显示在控制台中。 待更改完之后,新值也将被显示在控制台中。
  • 切线会被显示在控制台中,之后它会被更改,并再次被显示在控制台中。
  • 从mesh实例创建新ObjectMeshDynamic网格。
  • 将动态网格添加给Editor,并为其设置材质,属性和名称。
源代码
// 创建一mesh实例
Mesh mesh = new Mesh();

// 添加一新表面
mesh.addSurface("surface_0");
 
// 为plane添加顶点
mesh.addVertex(vec3(0.0f,0.0f,0.0f),0);
mesh.addVertex(vec3(0.0f,0.0f,1.0f),0);
mesh.addVertex(vec3(0.0f,1.0f,0.0f),0);
mesh.addVertex(vec3(0.0f,1.0f,1.0f),0);

// 添加索引 
mesh.addIndex(0,0);
mesh.addIndex(1,0);
mesh.addIndex(2,0);

mesh.addIndex(3,0);
mesh.addIndex(2,0);
mesh.addIndex(1,0);

// 创建切线
mesh.createTangents();

// 创建法线
mesh.createNormals(0);

// 在控制台中显示更改之前,有关第1条法线
// 和第2条法线的法线信息
log.message("the first normal is: %s and the second is: %s\n", typeinfo(mesh.getNormal(0, 0, 0)), typeinfo(mesh.getNormal(1, 0, 0)));

// 为法线设置新值
mesh.setNormal(0, vec3(1,1,0), 0, 0);
mesh.setNormal(1, vec3(1,1,1), 0, 0);

// 在控制台中显示法线值
log.message("the first normal is: %s and the second is: %s\n", typeinfo(mesh.getNormal(0, 0, 0)), typeinfo(mesh.getNormal(1, 0, 0)));

// 在控制台中显示切线值
log.message("tangent is: %s\n", typeinfo(mesh.getTangent(0,0,0)));

// 为切线设置新值
mesh.setTangent(0, quat(0.0,-0.0,-0.0,1), 0,0);

// 待更改完切线值之后显示其新值
log.message("tangent is: %s\n", typeinfo(mesh.getTangent(0,0,0)));

// 从Mesh对象创建ObjectMeshDynamic 
ObjectMeshDynamic dynamicMesh = new ObjectMeshDynamic(mesh);

// 将dynamicMesh作为Node对象添加给Editor 
engine.editor.addNode(node_remove(dynamicMesh));

// 为mesh设置位置
dynamicMesh.setWorldTransform(translate(Vec3(10.0f,10.0f,10.0f)));
// 将材质设置给mesh
dynamicMesh.setMaterial("mesh_base","*");
// 将属性设置给mesh
dynamicMesh.setProperty("surface_base","*");
// 为mesh设置名称
dynamicMesh.setName("new_mesh");

当您启动项目时,您就会在控制台中看到如下信息:

输出
the first normal is:vec3: -1 0 0 and the second is:vec3: -1 0 0
the first normal is:vec3: 1 1 0 and the second is:vec3: 1 1 1
tangent is:quat: 0.5 -0.5 -0.5 0.5
tangent is:quat: 0 0 0 0.999962

待函数setTangent()setNormal()被调用之后,法线值和切线值就被更改了。

让我们为如下这部分代码添加注释:

源代码 (UnigineScript)
// 在控制台中显示切线值
log.message("tangent is: %s\n", typeinfo(mesh.getTangent(0,0,0)));

// 为切线设置新值
mesh.setTangent(0, quat(0.0,-0.0,-0.0,1), 0,0);

// 待更改完切线值之后显示其新值
log.message("tangent is: %s\n", typeinfo(mesh.getTangent(0,0,0)));
执行结果会是不同的。 您将看到切线对顶点的影响:左边是切线做了更改的plane,右边是切线未做更改的plane。

最新更新: 2017-07-03
Build: ()