结构的 glBufferSubData 偏移量
glBufferSubData offsets for structs
我实际上正在开发OpenGL 3.3渲染引擎,确切地说,我正在尝试在我的场景中创建动态数量的灯光。
为此,我正在使用统一缓冲区对象 (UBO),当我尝试传递数据时遇到问题,并且 UBO 将在具有不同类型数据的结构中读取或写入。
我对点光源和定向光源这样做了,一切都很好,因为我只使用vec3
数据。问题是当我定义焦光时,其结构是:
#version 330 core
#define MAX_NUM_TOTAL_LIGHTS 100
...
struct FocalLight{
vec3 f_light_position;
vec3 f_light_direction;
vec3 f_light_diffuse_intensity;
vec3 f_light_specular_intensity;
float f_apperture_angle;
float f_attenuation;
};
layout(std140) uniform focalLights{
FocalLight f_lights[MAX_NUM_TOTAL_LIGHTS];
};
嗯,位置、方向、漫反射强度和镜面反射强度都很好,我的片段从缓冲区正确接收这些数据。但我无法为f_apperture_angle
和f_attenuation
写入和读取数据。
这是我用来写入缓冲区数据的 CPU 上执行的代码,其中focal_lights
是一个向量,其中包含我的FocalLight
类 (std::vector<FocalLight> focal_lights
) 的实例,我检查的内容是正确的:
if(block_focal_lights_id != -1) {
glUniformBlockBinding(programId, block_focal_lights_id, 2);
//Loading from light vectors
glGenBuffers(1, &buffer_focal_lights_id);
glBindBuffer(GL_UNIFORM_BUFFER, buffer_focal_lights_id);
glBufferData(GL_UNIFORM_BUFFER, sizeof(float) * 24 * focal_lights.size(), 0, GL_DYNAMIC_DRAW);
int offset = 0;
for (unsigned int i=0; i<focal_lights.size(); i++) {
glBufferSubData(GL_UNIFORM_BUFFER, offset, sizeof(float) * 3, focal_lights[i].position);
offset += 16;
glBufferSubData(GL_UNIFORM_BUFFER, offset, sizeof(float) * 3, focal_lights[i].direction);
offset += 16;
glBufferSubData(GL_UNIFORM_BUFFER, offset, sizeof(float) * 3, focal_lights[i].diffuse_intensity);
offset += 16;
glBufferSubData(GL_UNIFORM_BUFFER, offset, sizeof(float) * 3, focal_lights[i].specular_intensity);
offset += 16;
glBufferSubData(GL_UNIFORM_BUFFER, offset, sizeof(float), &focal_lights[i].apperture_angle);
offset += 16;
glBufferSubData(GL_UNIFORM_BUFFER, offset, sizeof(float), &focal_lights[i].attenuation);
offset += 16;
}
}
我探测将f_apperture_angle
的数据类型更改为vec3
,我可以使用之前定义的偏移量读取它,但与使用简单的浮点无关。我确定缓冲区的绑定是正确的,我知道问题出在glBufferData
或glBufferSubdata
代码上。
有人看到问题了吗?
终于可以工作了,谢谢Rabbid76: 2 个焦点灯、2 个定向灯和 1 个点光源
将数据绑定到std140
标准的统一块布局时,必须考虑特殊的对齐规则。
请参阅 OpenGL 4.6 API 兼容性配置文件规范; 7.6.2.2 标准统一块布局; 第 144
页
指定 std140 布局时,可以通过应用下面描述的规则集从统一块的定义中得出统一块中每个制服的偏移量。
- 如果杆件是消耗 N 个基本机器单元的标量,则基本对齐为 N
....
- 如果成员是分量消耗 N 的分量 基本机器单元,底座对齐为4N。
....
如果杆件是结构,则结构的基对齐为 N,
其中 N 是其任何杆件的最大基本对齐值,并四舍五入为 vec4 的基对齐。此子结构的各个成员 然后通过递归应用这组规则来分配偏移量,其中子结构的第一个成员的基本偏移量等于结构的对齐偏移量。结构末端可能有填充;子结构后面杆件的基位偏移向上舍入到结构基对齐的下一个倍数。
如果成员是 S 结构的数组,则根据规则 (9) 按顺序排列数组的 S 元素。
将此规则应用于数据结构时,会产生以下偏移:
struct FocalLight // size 80 (rule 9 and 10)
{
vec3 f_light_position; // offset 0 (rule 3 and 10)
vec3 f_light_direction; // offset 16 (rule 3)
vec3 f_light_diffuse_intensity; // offset 32 (rule 3)
vec3 f_light_specular_intensity; // offset 48 (rule 3)
float f_apperture_angle; // offset 60 (rule 1)
float f_attenuation; // offset 64 (rule 1)
};
layout(std140) uniform focalLights{
FocalLight f_lights[MAX_NUM_TOTAL_LIGHTS];
};
绑定数据:
int offset = 0;
for (unsigned int i=0; i<focal_lights.size(); i++) {
glBufferSubData(GL_UNIFORM_BUFFER, offset, sizeof(float) * 3, focal_lights[i].position);
offset += 16; // rule 3
glBufferSubData(GL_UNIFORM_BUFFER, offset, sizeof(float) * 3, focal_lights[i].direction);
offset += 16; // rule 3
glBufferSubData(GL_UNIFORM_BUFFER, offset, sizeof(float) * 3, focal_lights[i].diffuse_intensity);
offset += 16; // rule 3
glBufferSubData(GL_UNIFORM_BUFFER, offset, sizeof(float) * 3, focal_lights[i].specular_intensity);
offset += 12; // rule 1
glBufferSubData(GL_UNIFORM_BUFFER, offset, sizeof(float), &focal_lights[i].apperture_angle);
offset += 4; // rule 1
glBufferSubData(GL_UNIFORM_BUFFER, offset, sizeof(float), &focal_lights[i].attenuation);
offset += 16; // rules 9 and 10
}
只需调用一次缓冲数据即可。
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(FocalLight)*focal_lights.size(), focal_lights);
使用多个小缓冲区数据副本会阻塞 API 和驱动程序,从而导致性能非常差。
要处理 std140(或最好是 std430)的对齐,您只需要在 c++ 端向结构添加填充或重新排序成员。
struct FocalLight{
vec3 f_light_position;
float f_apperture_angle;
vec3 f_light_direction;
float f_attenuation;
vec3 f_light_diffuse_intensity;
float pad1;
vec3 f_light_specular_intensity;
float pad2;
};
或者,您可以使用编译器内置指令进行__declspec(align(16))
- 有没有办法将谓词中的元素偏移量传递给 std 算法?
- 通过指针偏移量访问结构变量值
- 以线程安全的方式转换 C/C++ 中时区名称字符串的时区偏移量
- librdkafka:rd_kafka_assignment 返回分配分区的偏移量 -1001
- 是否通过向封闭对象的地址添加字节偏移量来访问子对象
- 向指针地址添加 20 个字节偏移量
- glMapBufferRange(..) 中的偏移量关系和 glDrawArraysInstanced(..) 中的第一
- 是否有与 C# Structs/StructLayout 等效的功能,C++中的字段偏移量?
- 我的 sumASCII 函数中的此偏移量是多少?
- boost::序列化中的派生类偏移量计算.有效吗?
- RedisGraph 语法错误在偏移量 8 靠近"创建"
- 胎面偏移量的时间复杂度?
- 如何从 c++ 中的给定标准输入中获取每个字符的偏移量?
- 编译器在构造函数中计算的成员偏移量不正确
- 使用基地址和偏移量获取变量的地址
- c++ 读取进程内存基址 + 偏移量不起作用
- 通过其在 C 中的偏移量调用函数
- ld:无效的字符串偏移量...对于".strtab"部分
- GDB 显示损坏的指令地址偏移量
- 读取文本文件时 seekg() 的奇怪偏移量