在OSX上使用OpenGL统一缓冲区的奇怪行为

时间:2018-07-02 10:56:40

标签: macos opengl

在我的爱好OpenGL4.1引擎中,我在使用统一缓冲区时表现出一些奇怪的行为。

在Windows上,一切正常(英特尔和Nvidia GPU),但在我的MacBook(也为英特尔)上,此功能无法正常工作。

所以要解释一下OSX上发生的情况:如果我将所有Uniform Buffer变量硬编码到实际的片段着色器代码中,那么我可以很好地渲染,但是如果将它们重新设置为变量,我什么也没得到。

使用apitrace来查看OpenGL状态,所有变量值都很完美,因此我对这里发生的事情有些困惑。

我希望这只是一个代码错误,而不是驱动程序的一些潜在问题。

下面是片段着色器代码,如果我对所有DirectionLight变量进行硬编码,一切都可以正常工作。

#version 410

struct DirectionalLightData
{
  vec4 Colour;
  vec3 Direction;
  float Intensity;
};

layout(std140) uniform ObjectBuffer
{
  mat4 Model;
};

layout(std140) uniform FrameBuffer
{
  mat4 Projection;
  mat4 View;  
  DirectionalLightData DirectionalLight;
  vec3 ViewPos;
};

uniform sampler2D PositionMap;
uniform sampler2D NormalMap;
uniform sampler2D AlbedoSpecMap;

layout(location = 0) in vec2 TexCoord;

out vec4 FinalColour;

float CalcDiffuseContribution(vec3 lightDir, vec3 normal)
{
  return max(dot(normal, -lightDir), 0.0f);
}

float CalcSpecularContribution(vec3 lightDir, vec3 viewDir, vec3 normal, float specularExponent)
{
  vec3 reflectDir = reflect(lightDir, normal);
  vec3 halfwayDir = normalize(lightDir + viewDir);
  return pow(max(dot(normal, halfwayDir), 0.0f), specularExponent);
}


float CalcDirectionLightFactor(vec3 viewDir, vec3 lightDir, vec3 normal)
{
  float diffuseFactor = CalcDiffuseContribution(lightDir, normal);
  float specularFactor = CalcSpecularContribution(normal, viewDir, normal, 1.0f);
  return diffuseFactor * specularFactor;
}


void main()
{
  vec3 position = texture(PositionMap, TexCoord).rgb;
  vec3 normal = texture(NormalMap, TexCoord).rgb;
  vec3 albedo = texture(AlbedoSpecMap, TexCoord).rgb;

  vec3 viewDir = normalize(ViewPos - position);
  float directionLightFactor = CalcDirectionLightFactor(viewDir, DirectionalLight.Direction, normal) * DirectionalLight.Intensity;

  FinalColour.rgb = albedo * directionLightFactor * DirectionalLight.Colour.rgb;
  FinalColour.a = 1.0f * DirectionalLight.Colour.a;
}

这是我更新和绑定UBO的顺序(由于有太多代码无法在此处复制粘贴,因此我已将它们从apitrace中拉出):

glGetActiveUniformBlockName(5, 0, 255, NULL, FrameBuffer);
glGetUniformBlockIndex(5, FrameBuffer) = 0;
glGetActiveUniformBlockName(5, 1, 255, NULL, ObjectBuffer);
glGetUniformBlockIndex(5, ObjectBuffer) = 1;

glBindBuffer(GL_UNIFORM_BUFFER, 1);
glMapBufferRange(GL_UNIFORM_BUFFER, 0, 172,GL_MAP_WRITE_BIT);
memcpy(0x10b9f8000, [binary data, size = 172 bytes], 172);
glUnmapBuffer(GL_UNIFORM_BUFFER);

glBindBufferBase(GL_UNIFORM_BUFFER, 0, 2);
glBindBufferBase(GL_UNIFORM_BUFFER, 1, 1);

glBindBuffer(GL_UNIFORM_BUFFER, 2);
glMapBufferRange(GL_UNIFORM_BUFFER, 0, 64, GL_MAP_WRITE_BIT);
memcpy(0x10b9f9000, [binary data, size = 64 bytes], 64);
glUnmapBuffer(GL_UNIFORM_BUFFER);

glUniformBlockBinding(5, 1, 0);
glUniformBlockBinding(5, 0, 1);

glDrawArrays(GL_TRIANGLES, 0, 6);

请注意,FrameBuffer UBO的ID为1,ObjectBuffer UBO的ID为2

2 个答案:

答案 0 :(得分:0)

我认为当您使用std140布局时,您的数据成员应按字节对齐,因此您不能混合使用vec4和vec3或浮点数保留所有变量mat4和vec4,否则dnt使用std140布局,并在应用程序端计算ubo对齐和变量的偏移量在ubo上并设置值。查看GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT的用法。 在实验中,将所有变量都更改为mat4和vec4,然后您的问题就会消失。

如果未将std140布局用于块,则需要查询块中每个统一的字节偏移。 OpenGL规范说明了每种基本类型的存储,但没有说明类型之间的对齐方式。与常规制服一样,结构成员每个​​成员都有一个单独的偏移,必须单独查询。

答案 1 :(得分:0)

经过几天的挖掘,我似乎已经找到了问题。

绑定另一个着色器程序后,我没有调用glBindBufferBase()。

这种愚蠢的错误使我非常悲痛。

感谢大家的帮助。