着色器存储缓冲区对象的长度为零,glMapBufferRange 不起作用
Posted
技术标签:
【中文标题】着色器存储缓冲区对象的长度为零,glMapBufferRange 不起作用【英文标题】:Shader Storage Buffer Object has zero length, glMapBufferRange not working 【发布时间】:2014-02-27 17:17:47 【问题描述】:我一直在尝试实现平铺延迟着色,但一段时间以来我一直被困在一个问题上。我正在尝试存储一个结构数组,这些结构由我想要初始化的点光源组成并发送到计算着色器,在那里我可以进一步处理它。我为此使用了着色器存储缓冲区对象,并尝试使用 glMapBufferRange 来提供值。我添加了一些检查,以便如果数组大小为 0,我会将屏幕绘制为红色,如果大于 0,则为黄色,到目前为止,我似乎无法让它工作。
这是计算着色器:
#version 430
#define MAX_WORK_GROUP_SIZE 16
#define SCREEN_WIDTH 1280.0f
#define SCREEN_HEIGHT 720.0f
uniform sampler2D positionMap;
uniform sampler2D colorMap;
uniform sampler2D normalMap;
uniform sampler2D depthMap;
layout(binding = 4, rgba32f) uniform writeonly image2D finalImage;
layout(binding = 5, rgba32f) uniform writeonly image2D otherImage;
struct PointLight
vec3 position; //4,8,12
vec3 color; // 16,20, 24
float radius; //28
float diffuseIntensity; //32
float ambientIntensity; //36
float Constant; //40
float Linear; //44
float Exp; //48
;
layout(std430, binding = 6) buffer BufferObject
PointLight pointLights[];
;
shared uint minDepth;
shared uint maxDepth;
layout(local_size_x = MAX_WORK_GROUP_SIZE, local_size_y = MAX_WORK_GROUP_SIZE)in;
void main()
if(gl_LocalInvocationIndex == 0)
minDepth = 0xFFFFFFFF;
maxDepth = 0;
ivec2 pixelPos = ivec2(gl_GlobalInvocationID.xy);
vec2 uv = vec2(pixelPos.x / SCREEN_WIDTH, pixelPos.y / SCREEN_HEIGHT);
float d = texture(depthMap,uv).z;
uint depth = uint(d * 0xFFFFFFFF);
//compares the content of minDepth to depth and writes the minimum value to minDepth
atomicMin(minDepth, depth);
// barrier();
//compares the content of maxDepth to depth and writes the maximum value to the maxDepth
atomicMax(maxDepth, depth);
///Write a single texel into an image
/* barrier();
imageStore(finalImage, pixelPos, vec4(float(float(maxDepth) / float(0xFFFFFFFF))));
barrier();
imageStore(otherImage, pixelPos, vec4(float(float(minDepth) / float(0xFFFFFFFF))));
*/
PointLight p = pointLights[0];
PointLight p2 = pointLights[1];
if(pointLights.length() == 0)
barrier();
imageStore(finalImage, pixelPos, vec4(1.0,0.0,0.0,1.0));
barrier();
imageStore(otherImage, pixelPos, vec4(1.0,0.0,0.0,1.0));
if(pointLights.length() > 0)
barrier();
imageStore(finalImage, pixelPos, vec4(1.0,1.0,0.0,1.0));
barrier();
imageStore(otherImage, pixelPos, vec4(1.0,1.0,0.0,1.0));
这是我尝试使用一些测试值初始化缓冲区的方式:
My3dVector currentColor(1.0f,1.0f,1.0f);
glGenBuffers(1,&m_pointLightBuffer);
glBindBuffer(GL_SHADER_STORAGE_BUFFER,m_pointLightBuffer);
glBufferData(GL_SHADER_STORAGE_BUFFER,NUM_OF_LIGHTS*sizeof(struct TDPointLight), NULL, GL_STATIC_DRAW);
struct TDPointLight* pointlights = (struct TDPointLight*) glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, NUM_OF_LIGHTS*sizeof(struct TDPointLight), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT );
int shit = ARRAY_SIZE_IN_ELEMENTS(pointlights);
for(int i = 0; i < NUM_OF_LIGHTS; ++i)
float Max = 80.0f;
float Min = -80.0f;
float MaxZ = 80.0f;
float MinZ = -80.0f;
float ranx = ((float(rand()) / float(RAND_MAX)) * (Max - Min)) + Min;
float ranz = ((float(rand()) / float(RAND_MAX)) * (Max - Min)) + Min;
int maxCol = 8;
int minCol = 1;
//int ranCol = ((rand() / RAND_MAX) * (maxCol - minCol)) + minCol;
int ranCol = (rand()%(maxCol-minCol))+minCol;
if(ranCol == 0)
printf("error, color 8 doesnt exist");
if(ranCol == 1)
currentColor = COLOR_WHITE;
if(ranCol == 2)
currentColor = COLOR_RED;
if(ranCol == 3)
currentColor = COLOR_GREEN;
if(ranCol == 4)
currentColor = COLOR_CYAN;
if(ranCol == 5)
currentColor = COLOR_BLUE;
if(ranCol == 6)
currentColor = COLOR_PURPLE;
if(ranCol == 7)
currentColor = COLOR_ORANGE;
if(ranCol == 8)
printf("error, color 8 doesnt exist");
pointlights[i].position = My3dVector(1.0f,1.0f,1.0f);
pointlights[i].color = My3dVector(1.0f,0.0f,0.0f);
pointlights[i].radius = 10.0f;
pointlights[i].diffuseIntensity = 10.0f;
pointlights[i].ambientIntensity = 0.1f;
//pointlights[i].color = currentColor;
//pointlights[i].position = My3dVector(ranx,3.0f,ranz);
//m_pointLight[i].m_Position = My3dVector(0.0f,2.0f,0.0f);
pointlights[i].Constant = 0.0f;
pointlights[i].Linear = 0.0f;
pointlights[i].Exp = 0.6f;
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
然后这个过程是这样的:
-
使用计算着色器
设置所有制服,然后使用此代码绑定一些延迟纹理和其他东西
for(unsigned int i = 0; i<ARRAY_SIZE_IN_ELEMENTS(m_textures); ++i)
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_2D, m_textures[TDGBuffer_TEXTURE_TYPE_POSITION + i]);
glUniform1i(glGetUniformLocation(program,"depthMap"),3);
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D,m_depthTexture);
//glActiveTexture(GL_TEXTURE4);
//glBindTexture(GL_TEXTURE_2D,m_finalTexture);
glBindImageTexture(4, m_finalTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
glBindImageTexture(5,m_otherTexture,0,GL_FALSE,0,GL_WRITE_ONLY,GL_RGBA32F);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER,6,m_pointLightBuffer);
最后在主循环中调用这些函数
glDispatchCompute((window_width/MAX_WORK_GROUP_SIZE), (window_height/MAX_WORK_GROUP_SIZE), 1);
glFinish();
它不适用于代码中任何地方的任何内存屏障,但由于我没有在任何地方修改内容,这应该不是问题,因为它只是被初始化一次,然后永远保持不变。
【问题讨论】:
PointLight
结构的对齐方式错误。两个vec3
s 没有紧密地打包在一起,它们与vec4
边界对齐。您应该稍微重新安排您的数据结构,并将您的 float
s 之一放在两个 vec3
s 之间。
另外,你为什么要标记这个 OpenGL ES? ES 没有计算着色器。
感谢您的回复,我会修复标签,一定错过了那一点。我尝试重新排列所有内容,以便在 vec3 之间有一个浮点数,然后将我的 TDPointlight 结构更改为具有相同的顺序,但不幸的是它产生了相同的结果
是的,我认为这不会解决您的问题,但这绝对违反了std140
/std430
对齐规则。 430 唯一改变的是结构数组中每个元素的大小不必那么严格,因此结束填充(在这种情况下这不是问题,因为整个东西是 4N 的倍数)没有待添加。
我一直在关注此演示文稿education.siggraph.org/media/conference/S2012_Materials/…,我尝试初始化数据,然后只使用 glBufferData 而不是添加 NULL,而是添加了也不起作用的数组。我只是不确定在哪里看,我在尝试绑定缓冲区之前激活了计算着色器程序,真的不知道为什么它们的长度为零
【参考方案1】:
看来我刚刚犯了一个愚蠢的错误。在重新排列结构以匹配 vec4s 的大小后,我可以使用
打印出正确的颜色和位置PointLight p = pointLights[3];
PointLight p2 = pointLights[55];
//vec3 test = vec3(p.posX,p.posY,p.posZ);
//vec3 test2 = vec3(p2.posX,p2.posY,p2.posZ);
vec4 test = p.color;
vec4 test2 = p2.color;
barrier();
imageStore(finalImage, pixelPos, test);
barrier();
imageStore(otherImage, pixelPos, test2);
我仍然从长度中得到零大小,但我相信这是因为着色器不知道数组的大小已更新
【讨论】:
以上是关于着色器存储缓冲区对象的长度为零,glMapBufferRange 不起作用的主要内容,如果未能解决你的问题,请参考以下文章