【问题标题】:OpenGL shader storage buffer contains incomplete dataOpenGL着色器存储缓冲区包含不完整的数据
【发布时间】:2014-08-06 03:10:05
【问题描述】:

在阅读了this tutorial 的基本光照后,我决定扩展着色器代码以处理任意数量的光照。根据我的谷歌搜索结果,推荐的方法是创建一个着色器存储缓冲区对象 (SSBO),并在 Lamp 结构数组中创建一个缓冲区来表示灯光:

// all vec3 objects are from glm
struct Lamp {
    vec3 pos;
    float power;
    vec3 color;
    vec3 lightDirectionCameraSpace;
    // this constructor is omitted in the struct definition in the shaders
    Lamp(vec3 a, float b, vec3 c) {
        pos = a;
        power = b;
        color = c;
    }
};

// global variable
vector<Lamp> lights;

Lamp lmp1(vec3(0.0f, 0.0f, 10.0f), 40.0f, vec3(0.3f, 0.7f, 0.9f));
Lamp lmp2(vec3(0.0f, 0.0f, -10.0f), 40.0f, vec3(1.0f, 0.7f, 0.7f));
lights.push_back(lmp1);
lights.push_back(lmp2);

GLuint LightID;
glGenBuffers(1, &LightID);

然后,每个渲染通道,我将灯光缓冲到着色器中定义的 SSBO(见下文):

glBindBuffer(GL_SHADER_STORAGE_BUFFER, LightID);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(Lamp)*lights.size(), &(lights[0]), GL_STATIC_DRAW);

// using binding 0 for the SSBO
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, LightID);

相关顶点着色器代码:

#version 430

...

struct Lamp {
    vec3 pos;
    float power;
    vec3 color;
    vec3 lightDirectionCameraSpace;
};

layout(std430, binding = 0) buffer LightArray {
    Lamp[] lights;
} LightArr;

void main() {

...

    for (int i = 0; i < LightArr.lights.length(); i++) {
        // Vector that goes from the vertex to the light, in camera space. M is ommited because it's identity.
        vec3 LightPosition_cameraspace = ( V * vec4(LightArr.lights[i].pos, 1)).xyz;
        LightArr.lights[i].lightDirectionCameraSpace = LightPosition_cameraspace + EyeDirection_cameraspace;
    }

...

相关片段着色器代码:

#version 430 core

...

// Ouput data
out vec3 glcolor;

struct Lamp {
    vec3 pos;
    float power;
    vec3 color;
    vec3 lightDirectionCameraSpace;
};

layout(std430, binding = 0) buffer LightArray {
    Lamp[] lights;
} LightArr;

void main(){

    // Material properties
    vec3 MaterialDiffuseColor = texture2D( myTextureSampler, UV ).rgb;
    vec3 MaterialAmbientColor = vec3(0.1,0.1,0.1) * MaterialDiffuseColor;
    vec3 MaterialSpecularColor = vec3(0.3,0.3,0.3);

    glcolor = vec3(0, 0, 0);

    for (int i = 0; i < LightArr.lights.length(); i++) {
        // Distance to the light
        float distance = length( LightArr.lights[i].pos - Position_worldspace );

        // Normal of the computed fragment, in camera space
        vec3 n = normalize( Normal_cameraspace );
        // Direction of the light (from the fragment to the light)
        vec3 l = normalize( LightArr.lights[i].lightDirectionCameraSpace );
        // Cosine of the angle between the normal and the light direction, 
        // clamped above 0
        //  - light is at the vertical of the triangle -> 1
        //  - light is perpendicular to the triangle -> 0
        //  - light is behind the triangle -> 0
        float cosTheta = clamp( dot( n,l ), 0,1 );

        // Eye vector (towards the camera)
        vec3 E = normalize(EyeDirection_cameraspace);
        // Direction in which the triangle reflects the light
        vec3 R = reflect(-l,n);
        // Cosine of the angle between the Eye vector and the Reflect vector,
        // clamped to 0
        //  - Looking into the reflection -> 1
        //  - Looking elsewhere -> < 1
        float cosAlpha = clamp( dot( E,R ), 0,1 );

        glcolor +=
            // Ambient : simulates indirect lighting
            // MaterialAmbientColor +
            // Diffuse : "color" of the object
            MaterialDiffuseColor * LightArr.lights[i].color * LightArr.lights[i].power * cosTheta / (distance*distance) +
            // Specular : reflective highlight, like a mirror
            MaterialSpecularColor * LightArr.lights[i].color * LightArr.lights[i].power * pow(cosAlpha,5) / (distance*distance);
    }

    // compute total light, then add ambient
    // Ambient : simulates indirect lighting
    glcolor = MaterialAmbientColor + glcolor;
}

问题是当程序运行时,它只渲染添加到列表中的第一盏灯(这里是蓝色的)(但显示得非常正确)。我做了一些调试,发现不管我有多少灯,LightArr.lights.length() == 1。可能与此相关的是从宽法线角度照亮的表面上的一些闪烁,而当我只使用一盏灯时,这是不存在的。

编辑:我设法解决了这个问题,但我不知道为什么我的解决方案有效。我在vec3 color;vec3 lightDirectionCameraSpace; 之后将未使用的虚拟浮点变量(float foo;float bar;)添加到我的Lamp 结构(在着色器内部和外部)。现在,两盏灯都显示了,尽管在没有理由的情况下闪烁仍然存在。为什么添加垃圾变量会改变着色器渲染的灯光数量?

【问题讨论】:

    标签: opengl visual-c++ shader


    【解决方案1】:

    您的解决方案有效的原因是 OpenGL 结构打包规则。 OpenGL 期望 vec3 在 vec4 边界上对齐。请查看 OpenGL 4.3 规范的第 7.6.2 节,尤其是第 7.6.2.2 节,了解 OpenGL 如何在统一块中布局结构的详细信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多