如何将法线打包到GL_INT_2_10_10_10_REV中

nik*_*pui 6 opengl

在我的宠物项目中,视频内存开始成为一个问题,因此我研究了各种技术来减少内存占用.我尝试过使用GL_INT_2_10_10_10_REV,但是使用我的打包方法得到了照明工件.这些工件似乎不是不准确的结果,因为使用标准化char[3]short[3]完美无缺地工作.由于其他无用的填充,我宁愿使用更节省空间GL_INT_2_10_10_10_REV.

这是包装代码:

union Vec3IntPacked {
    int i32;
    struct {
        int a:2;
        int z:10;
        int y:10;
        int x:10;
    } i32f3;
};

int vec3_to_i32f3(const Vec3* v) {
    Vec3IntPacked packed;
    packed.i32f3.x = to_int(clamp(v->x, -1.0f, 1.0f) * 511);
    packed.i32f3.y = to_int(clamp(v->y, -1.0f, 1.0f) * 511);
    packed.i32f3.z = to_int(clamp(v->z, -1.0f, 1.0f) * 511);
    return packed.i32;
} // NOTE: to_int is a static_cast
Run Code Online (Sandbox Code Playgroud)

如果我正确地阅读规范(第10.3.8节"打包顶点数据格式"和2.1和2.2中的转换规则),这应该可行,但事实并非如此.

我还应该注意,上面的代码是在多个操作系统上测试的(尽管int仍然是64位,但仍然应该是32位)和显卡供应商检查它是否是驱动程序相关的问题.

此外,还使用了OpenGL 3.3核心配置文件.

顶点结构如下:

struct BasicVertex {
     float position[3];
     unsigned short uv[2];
     int normal;
     int tangent;
     int bitangent;
} // resulting in a 4-byte aligned 28 byte structure
Run Code Online (Sandbox Code Playgroud)

希望我提供了足够的信息,有人可以阐明如何正常包装法线GL_INT_2_10_10_10_REV.

Ret*_*adi 8

位域声明中的顺序看起来不正确.根据规范文档(3.3规范第32页的"2.8.2压缩顶点数据格式"一节),每个组件的位范围为:

x: bits 0-9
y: bits 10-19
z: bits 20-29
w: bits 30-31
Run Code Online (Sandbox Code Playgroud)

经过一些搜索后,看起来比特字段中的位顺序不是由C标准定义的.例如,参见位字段的哪一端是最重要的位?

我见过的编译器通常使用从最低到最高的位顺序.例如,Microsoft为其编译器定义了这个:

位字段在从最低有效位到最高有效位的整数内分配.

如果您依赖于使用此订单的编译器,您的声明应如下所示:

union Vec3IntPacked {
    int i32;
    struct {
        int x:10;
        int y:10;
        int z:10;
        int w:2;
    } i32f3;
};
Run Code Online (Sandbox Code Playgroud)

为保证完全可移植性,您可以使用移位运算符来构建值,而不是使用位域.

根据您在顶点着色器中声明和使用属性的方式,您可能还需要确保将w组件设置为1.当然,如果不在w顶点着色器中使用该组件,则不需要.