【问题标题】:C++ GLSL data alignment/paddingC++ GLSL 数据对齐/填充
【发布时间】:2013-11-18 10:29:06
【问题描述】:

我有一个 C++ 类 Matrix4x4,它有一个包含 16 个浮点数且没有虚方法的数组:

class Matrix4x4
{
public:
    float values[16];

    Matrix4x4();
    Matrix4x4(float v0, float v1, float v2, float v3, float v4, float v5, float v6, float v7, float v8, float v9, float v10, float v11, float v12, float v13, float v14, float v15);
    Matrix4x4(const Quaternion &quat, const Vector3 &pos);
    void convertToQuatPos(Quaternion &quat, Vector3 &pos);
    void loadIdentity();
    void setValues(float v0, float v1, float v2, float v3, float v4, float v5, float v6, float v7, float v8, float v9, float v10, float v11, float v12, float v13, float v14, float v15);
    void setPerspective(float fov, float aspect, float nearPlane, float farPlane);
    void setOrthographic(float top, float left, float bottom, float right, float nearPlane, float farPlane);
    ...

    static void multiply3x3(const Matrix4x4 &m1, const Matrix4x4 &m2, Matrix4x4 &result);
    static void multiply4x4(const Matrix4x4 &m1, const Matrix4x4 &m2, Matrix4x4 &result);
    ...

    Matrix4x4 operator*(const Matrix4x4 &a);
    Vector3 operator*(const Vector3 &a);
    Vector4 operator*(const Vector4 &a);
};

我像这样将这些矩阵的向量传递给 GLSL(其中骨骼是 Matrix4x4 的 std::vector):

glUniformMatrix4fv(glGetUniformLocation(shader->getProgram(), "boneMatrices"), bones.size(), false, (GLfloat*) &bones[0].values[0]);

这显然假设一个 Matrix4x4 对象将只占用 16 个浮点数的内存而没有对齐或填充问题。使用 MSVC 可以正常工作,是否可以安全地假设它应该在其他平台(Linux、OSX、将来的 Android)等上工作?我应该对齐值数组并确保没有填充吗?

【问题讨论】:

  • 这是关于 C 而不是 C++ 但可能是相关的stackoverflow.com/questions/1066681/…
  • 首先,如果您担心便携性,请不要使用float。 OpenGL 有自己的一组 typedef,因为 API 有更严格的规则来控制最小位大小和浮点/定点数据类型的范围。实现可能需要使用与内在 C 类型不同的数据类型来满足 OpenGL 的规则,因此 GLfloat 是您应该始终使用的数据类型来存储单精度浮点值以供 OpenGL 使用;很有可能它与您系统的 float 类型相同,但没有便携保证。
  • 这个问题实际上确实出现在某些平台上。例如,iOS 有一个 typedef:CGFloat,在 32 位 iPhone 5 上是单精度(32 位),在 64 位 iPhone 5s 上是双精度(64 位)。如果您传递的函数需要 GLfloat *CGFloat *,您会希望您没有在 iPhone 5s 上 - 编译器也无济于事,它会很高兴地允许您重新转换指针,即使底层表示是不兼容。
  • @AndonM.Coleman - 你在这里没有真正提供反例;你引入了另一种类型。
  • @BrettHale:他问的是移动平台之间的可移植性。许多 iOS 示例都是使用 CGFloat 编写的,直到在 iPhone 5 上引入 64 位 iOS 之前,大多数开发人员似乎都认为它始终与 GLfloat 相同的大小和类型,甚至一些 Apple 示例代码使用它。换句话说,C 类型和其他平台标准类型与 GL 类型不同。

标签: c++ opengl alignment glsl padding


【解决方案1】:

向标头添加静态断言至少可以防止(非常不可能的)Matrix4x4 数组的元素被填充的可能性:

#include <type_traits>
...

static_assert(
    (sizeof(Matrix4x4) == (sizeof(GLfloat) * 16) &&
     std::is_standard_layout<Matrix4x4>::value),

    "Matrix4x4 does not satisfy contiguous storage requirements");

见:std::is_standard_layout

【讨论】:

  • 好极了,我从来不知道它存在,看起来很有用。现在出于好奇,如果我有一个包含多个不同大小数据成员的类,我应该担心对齐吗?例如,如果我关心类/结构的数组/向量如何写入二进制文件,我是否也不应该关心如何将数据传递给 GLSL 之类的东西(我知道我不需要在这种情况下,我说的是一种假设情况)?
  • 这取决于。对于顶点属性,您可以在没有填充的情况下工作,但是例如对于统一缓冲区,您必须考虑布局。另请参阅这个出色的答案:stackoverflow.com/questions/21676280/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-19
  • 2018-03-04
  • 2016-08-17
  • 2010-12-13
  • 2015-09-28
  • 2017-07-25
  • 1970-01-01
相关资源
最近更新 更多