我实际上正在开发一个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 focal lights, 2 directional lights and one point light
答案 0 :(得分:2)
将数据绑定到std140
标准统一块布局时,必须考虑特殊的对齐规则。
请参阅OpenGL 4.6 API Compatibility Profile Specification; 7.6.2.2 Standard Uniform Block Layout; page 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
}
答案 1 :(得分:0)
您只需要一次缓冲数据调用。
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))