使用ArrayMesh

本教程将介绍使用 ArrayMesh 的基础知识

为此, 我们将使用函数 add_surface_from_arrays() , 它最多需要四个参数. 前两个参数是必须的, 后两个参数是可选的.

第一个是 PrimitiveType, 这是一个OpenGL的概念, 指示GPU如何根据给定的顶点来安排基元, 是三角形, 线, 点等. 完整的列表可以在 Mesh 类参考页面下找到.

第二种是存储网格信息的实际 Array。该数组是一个普通的 Godot 数组,用空括号 [] 构造。它为每一种类型的信息存储一个 Pool**Array(如 PoolVector3Array、PoolIntArray 等)。

  • ARRAY_VERTEX = 0 | PoolVector3Array or PoolVector2Array

  • ARRAY_NORMAL = 1 | PoolVector3Array

  • ARRAY_TANGENT = 2 | 4 个浮点数一组的 PoolRealArray。前 3 个浮点数决定切线,最后一个决定双法线方向,为 -1 或 1。

  • ARRAY_COLOR = 3 | PoolColorArray

  • ARRAY_TEX_UV = 4 | PoolVector2Array or PoolVector3Array

  • ARRAY_TEX_UV2 = 5 | PoolVector2Array or PoolVector3Array

  • ARRAY_BONES = 6 | 4组浮点数的PoolRealArray或4组ints的PoolIntArray

  • ARRAY_WEIGHTS = 7 | 4个浮点的浮动数组

  • ARRAY_INDEX = 8 | PoolIntArray

顶点阵列是必须的. 所有其他的都是可选的, 只有在包含的情况下才会使用.

除了索引数组外, 每个数组的元素数量需要和顶点数组相同. 对于像切线这样的数组, 一个元素是4个浮动数组. 所以数组的大小将是顶点数组大小的4倍, 但它们的元素数是一样的

索引数组是唯一的.

第三个参数是网格要使用的混合形状数组. 虽然本教程不涉及混合形状的使用, 但在从数组创建曲面时, 可以指定它们.

最后一个参数是压缩标志, 指定哪些数组要用一半的比特数来存储. 这些值可以在 VisualServer 的classref中的 ArrayFormat 下找到.

对于正常的使用, 你会发现最好将最后两个参数留空.

ArrayMesh

在Mesh实例中添加一个 ArrayMesh . 通常情况下, 在编辑器中添加ArrayMesh是没有用的, 但在这种情况下, 允许从代码中访问ArrayMesh, 而不需要创建一个.

接下来, 在MeshInstance中添加一个脚本.

_ready() 下创建一个新的数组.

GDScript

  1. var arr = []

这将是保存表面信息的数组, 将保存表面需要的所有数据数组.Godot希望它的大小最大是 Mesh.ARRAY_MAX , 所以要相应调整.

GDScript

  1. var arr = []
  2. arr.resize(Mesh.ARRAY_MAX)

接下来, 为您将使用的每种数据类型创建数组.

GDScript

  1. var verts = PoolVector3Array()
  2. var uvs = PoolVector2Array()
  3. var normals = PoolVector3Array()
  4. var indices = PoolIntArray()

一旦你用几何体填充了你的数据数组, 就可以通过将每个数组添加到 surface_array , 然后提交到网格中来创建网格.

GDScript

  1. arr[Mesh.ARRAY_VERTEX] = verts
  2. arr[Mesh.ARRAY_TEX_UV] = uvs
  3. arr[Mesh.ARRAY_NORMAL] = normals
  4. arr[Mesh.ARRAY_INDEX] = indices
  5. mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arr) # No blendshapes or compression used.

注解

在这个例子中, 使用了 Mesh.PRIMITIVE_TRIANGLES , 但你也可以使用mesh中的任何基本类型.

完整的代码如下:

GDScript

  1. extends MeshInstance
  2. func _ready():
  3. var arr = []
  4. arr.resize(Mesh.ARRAY_MAX)
  5. # PoolVectorXXArrays for mesh construction.
  6. var verts = PoolVector3Array()
  7. var uvs = PoolVector2Array()
  8. var normals = PoolVector3Array()
  9. var indices = PoolIntArray()
  10. #######################################
  11. ## Insert code here to generate mesh ##
  12. #######################################
  13. # Assign arrays to mesh array.
  14. arr[Mesh.ARRAY_VERTEX] = verts
  15. arr[Mesh.ARRAY_TEX_UV] = uvs
  16. arr[Mesh.ARRAY_NORMAL] = normals
  17. arr[Mesh.ARRAY_INDEX] = indices
  18. # Create mesh surface from mesh array.
  19. mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arr) # No blendshapes or compression used.

中间可以放你想要的任何代码. 下面将介绍一些放在中间的示例代码.

生成几何体

这是生成球体的示例代码。尽管代码是用 GDScript 编写的,但是 Godot 并没有指定用特定的方式来实现它。这种实现方式与 ArrayMesh 无关,仅仅是一种通用的生成球体的方式。如果您觉得这比较难以理解,或者想更全面地了解程序式几何体,可以在网上寻找相关的教程进行学习。

GDScript

  1. extends MeshInstance
  2. var rings = 50
  3. var radial_segments = 50
  4. var height = 1
  5. var radius = 1
  6. func _ready():
  7. # Set up the PoolVectorXArrays.
  8. # Vertex indices.
  9. var thisrow = 0
  10. var prevrow = 0
  11. var point = 0
  12. # Loop over rings.
  13. for i in range(rings + 1):
  14. var v = float(i) / rings
  15. var w = sin(PI * v)
  16. var y = cos(PI * v)
  17. # Loop over segments in ring.
  18. for j in range(radial_segments):
  19. var u = float(j) / radial_segments
  20. var x = sin(u * PI * 2.0)
  21. var z = cos(u * PI * 2.0)
  22. var vert = Vector3(x * radius * w, y, z * radius * w)
  23. verts.append(vert)
  24. normals.append(vert.normalized())
  25. uvs.append(Vector2(u, v))
  26. point += 1
  27. # Create triangles in ring using indices.
  28. if i > 0 and j > 0:
  29. indices.append(prevrow + j - 1)
  30. indices.append(prevrow + j)
  31. indices.append(thisrow + j - 1)
  32. indices.append(prevrow + j)
  33. indices.append(thisrow + j)
  34. indices.append(thisrow + j - 1)
  35. if i > 0:
  36. indices.append(prevrow + radial_segments - 1)
  37. indices.append(prevrow)
  38. indices.append(thisrow + radial_segments - 1)
  39. indices.append(prevrow)
  40. indices.append(prevrow + radial_segments)
  41. indices.append(thisrow + radial_segments - 1)
  42. prevrow = thisrow
  43. thisrow = point
  44. # Commit to the ArrayMesh.

与上面的代码相结合, 这段代码将生成一个球体.

当谈到用ArrayMesh生成几何体时, 你需要了解每个数组中的内容, 然后可以按照任何语言和引擎的教程将其转换为Godot.

保存中

最后,Godot提供了一个单一的方法, 使用 ResourceSaver 类来保存ArrayMeshes. 当你想生成一个网格, 然后在以后使用它而不需要重新生成时, 这个方法很有用.

GDScript

  1. # Saves mesh to a .tres file with compression enabled.
  2. ResourceSaver.save("res://sphere.tres", mesh, 32)