我使用(更准确地说,“我想使用”)tinygltf库来“刷新”gltf(或glb)格式的网格数据。
我并不依赖于特定的输入文件类型,这是从我的程序中生成的数据,所以我正在研究一个基本的example,它可以从头开始在gltf中创建一个三角形。很难理解这段代码,我设法做的是抽象一个函数来从(float
)顶点数据中创建一个缓冲区(因为这个例子使用了硬编码的单字节十六进制值):
#define BYTE3(value) static_cast<unsigned char> ((value >> 24) & 0xFF)
#define BYTE2(value) static_cast<unsigned char> ((value >> 16) & 0xFF)
#define BYTE1(value) static_cast<unsigned char> ((value >> 8) & 0xFF)
#define BYTE0(value) static_cast<unsigned char> ((value) & 0xFF)
struct VertexData {
uint32_t u;
VertexData(float val)
{
memcpy(&u, &val, sizeof(float));
}
};
std::vector<unsigned char> triangle_to_buffer(
VertexData v1x, VertexData v1y, VertexData v1z,
VertexData v2x, VertexData v2y, VertexData v2z,
VertexData v3x, VertexData v3y, VertexData v3z)
{
return {
// 6 bytes of indices and two bytes of padding
0x00,
0x00,
0x01,
0x00,
0x02,
0x00,
0x00, 0x00,
// 36 bytes of floating point numbers
BYTE0(v1x.u), BYTE1(v1x.u), BYTE2(v1x.u), BYTE3(v1x.u),
BYTE0(v1y.u), BYTE1(v1y.u), BYTE2(v1y.u), BYTE3(v1y.u),
BYTE0(v1z.u), BYTE1(v1z.u), BYTE2(v1z.u), BYTE3(v1z.u),
BYTE0(v2x.u), BYTE1(v2x.u), BYTE2(v2x.u), BYTE3(v2x.u),
BYTE0(v2y.u), BYTE1(v2y.u), BYTE2(v2y.u), BYTE3(v2y.u),
BYTE0(v2z.u), BYTE1(v2z.u), BYTE2(v2z.u), BYTE3(v2z.u),
BYTE0(v3x.u), BYTE1(v3x.u), BYTE2(v3x.u), BYTE3(v3x.u),
BYTE0(v3y.u), BYTE1(v3y.u), BYTE2(v3y.u), BYTE3(v3y.u),
BYTE0(v3z.u), BYTE1(v3z.u), BYTE2(v3z.u), BYTE3(v3z.u), };
}
如何将示例代码泛化到“刷新”网格数据,即数据只是三个点(每个点都有浮点x,y,z坐标),指定组成网格的三角形?通过为每个三角形创建一个缓冲区(和一对访问器等)来泛化示例代码是可接受的解决方案吗?
1条答案
按热度按时间s6fujrry1#
不,永远不应该将每个三角形放入其自己的访问器中。
在缓冲区的开始是6个硬编码的字节,形成一个无符号短数组
[ 0, 1, 2 ]
,在此之后有2个字节的填充(以对齐到32位边界)。当顶点被多个三角形重用时,这些索引可以帮助处理大量的顶点数据。例如,如果您有4个顶点,并希望创建一个四边形,则可以指定一对三角形:上面的索引假设将有4个顶点,并使一对三角形覆盖四边形。与您链接的示例一样,仍然只有2个访问器,每个访问器都有自己的bufferView。每一个的长度会稍微长一点,因为索引现在是6个无符号短,顶点是12个浮点数。
这个特殊的例子可能会给你带来一点伤害,因为它将索引和顶点混合在一起。索引访问器的长度将是三角形的数量乘以每个三角形3个无符号短。另一个访问器的长度取决于顶点的数量(乘以每个顶点3个浮点数),其中顶点可以通过在索引列表中多次指定来重用。
顺序也很重要,至少在不使用
doubleSided
模式时是如此。指数列表应逆时针缠绕在每个三角形的正面。顺时针缠绕表示三角形的背面,当doubleSided
为false时,可以剔除。