如何在 AIR 中访问网格#
Air 支持访问构成场景的静态网格。
网格结构体#
每个网格都用以下结构体表示。
struct MeshPositionVertexBuffersResponse {
Vector3r position;
Quaternionr orientation;
std::vector<float> vertices;
std::vector<uint32_t> indices;
std::string name;
};
- 位置和朝向均采用引擎坐标系。
- 网格本身是一个三角形网格,由顶点和索引表示。
- 这种三角形网格类型通常被称为 面顶点(Face-Vertex) 网格。这意味着每个索引三元组都保存着构成三角形/面的顶点的索引。
- 所有顶点的 x、y、z 坐标都存储在一个向量中。这意味着顶点向量是 N×3 的,其中 N 是顶点的数量。
- 顶点的位置是引擎坐标系中的全局位置。这意味着它们已经根据位置和方向进行了变换。
如何使用#
获取场景网格的 API 非常简单。但是需要注意的是,该函数调用开销很大,因此应尽量避免调用。通常情况下,这没有问题,因为该函数仅访问静态网格,而对于大多数应用程序来说,这些网格在程序运行期间不会发生变化。
请注意,您需要使用第三方库或自定义代码才能与接收到的网格进行交互。下面我使用 libigl 的 Python 绑定来可视化接收到的网格。
import airsim
AIRSIM_HOST_IP='127.0.0.1'
client = airsim.VehicleClient(ip=AIRSIM_HOST_IP)
client.confirmConnection()
# 通过此函数接收返回的网格列表。
meshes=client.simGetMeshPositionVertexBuffers()
index=0
for m in meshes:
# 在 Blocks 环境中找到一个立方体网格。
if 'cube' in m.name:
# 从这里开始的代码依赖于 libigl。
# libigl 使用 pybind11 封装 C++ 代码。
# 因此,这里构建的 pyigl.so 库与示例代码位于同一目录下。
# 之所以在此说明,是因为您自己的网格库代码也可能需要类似的实现。
from pyigl import *
from iglhelpers import *
# 将列表转换为numpy数组
vertex_list=np.array(m.vertices,dtype=np.float32)
indices=np.array(m.indices,dtype=np.uint32)
num_vertices=int(len(vertex_list)/3)
num_indices=len(indices)
# Libigl 要求形状为 Nx3,其中 N 为顶点数或索引数。
# 它还要求顶点的实际类型为 double(float64),三角形/索引的实际类型为 int64。
vertices_reshaped=vertex_list.reshape((num_vertices,3))
indices_reshaped=indices.reshape((int(num_indices/3),3))
vertices_reshaped=vertices_reshaped.astype(np.float64)
indices_reshaped=indices_reshaped.astype(np.int64)
# Libigl 函数用于转换为 Eigen 内部格式
v_eig=p2e(vertices_reshaped)
i_eig=p2e(indices_reshaped)
# 查看网格
viewer = igl.glfw.Viewer()
viewer.data().set_mesh(v_eig,i_eig)
viewer.launch()
break