如何设置默认的OpenGL纹理单元

时间:2016-11-03 23:05:03

标签: opengl glsl

TL / DR:如何为采样器阵列中未使用的采样器指定(默认)纹理单元?

我的OpenGL 4.1应用程序中有以下场景:

scene

如您所见,有2盏灯。每个灯都有自己的阴影贴图。所以我的片段着色器看起来像这样:

#define MAX_LIGHTS 16

uniform samplerCube uShadowMaps[MAX_LIGHTS];

// sample the shadow map of the light
float Shadow(int light) {
    vec3 direction = Position - uLightPositions[light];
    float sampledDepth = 1.0;

    switch (light) {
        case 0: sampledDepth = texture(uShadowMaps[0], direction).r; break;
        case 1: sampledDepth = texture(uShadowMaps[1], direction).r; break;
    }

    // ... the rest of the calculations ...
}

此代码有效,因为正好有2个灯,每个灯都绑定了它自己的阴影贴图。每个灯光运行的代码看起来都像这样:

// make the name of the uniform
std::stringstream shadowMapName;
shadowMapName << "uShadowMaps[" << index << "]";

// bind the shadow map texture and bind the uniform
glActiveTexture(GL_TEXTURE3 + index);  // index is the light number, 3 because there are 3 other textures already bound
glBindTexture(GL_TEXTURE_CUBE_MAP, shadowMapTexture);
auto position = glGetUniformLocation(shaderProgram, shadowMapName.str().c_str());
glUniform1i(position, index + 3);

但是,我想最终在场景中有多个灯光,所以我想编写我的着色器,以便它们可以用于更多灯光。我在着色器中添加了下一个开关盒,如下所示:

// sample the shadow map for the light
float Shadow(int light) {
    // ...

    switch (light) {
        case 0: sampledDepth = texture(uShadowMaps[0], direction).r; break;
        case 1: sampledDepth = texture(uShadowMaps[1], direction).r; break;
        case 2: sampledDepth = texture(uShadowMaps[2], direction).r; break;
    }

    // ...
}

不幸的是,这导致了一个黑色的窗口。

black window

我认为这是因为没有任何约束mShaderMaps[2]。果然,如果我向场景添加另一个灯光,它会再次渲染。

所以我的问题是:如何为未使用的采样器指定(默认)纹理单元?

注意:为什么switch?这不起作用:

// sample the shadow map for the light
float Shadow(int light) {
    // ...

    sampledDepth = texture(uShadowMaps[light], direction).r;

    // ...
}

因为光不是动态均匀的表达。请参阅GLSL, Array of textures of differing size

修改

Shadow函数的调用如下:

// calculate diffuse color for the fragment
for (auto i = 0; i < min(uLightCount, MAX_LIGHTS); ++i) {
    // ... calculate diffuse for the light

    diffuseColor += diffuse * Shadow(i);

}

// ... some more stuff ...

// calculate specular color for the fragment
for (auto i = 0; i < min(uLightCount, MAX_LIGHTS); ++i) {
    // ... calculate specular for the light

    specularColor += specular * Shadow(i);

}

1 个答案:

答案 0 :(得分:0)

嗯,事实证明这很容易。我只是创建一个空的阴影贴图并将其绑定到数组中的每个阴影贴图,每个阴影贴图都有自己的纹理单元。代码如下所示:

auto empty = ShadowMap::CreateEmpty(); // make an empty shadow map

for (auto i = 0; i < 12; ++i) { // 12 is the shadow map array size
    std::stringstream shadowMapName;
    shadowMapName << "uShadowMaps[" << i << "]";

    glActiveTexture(GL_TEXTURE3 + i);  // bind to a separate texture unit
    glBindTexture(GL_TEXTURE_CUBE_MAP, empty->GetId());
    auto position = glGetUniformLocation(shaderProgram, shadowMapName.str().c_str());
    glUniform1i(position, i + 3);
}

之前我无法让它工作的原因是我将一个简单的纹理绑定到未使用的阴影贴图。但是绑定的阴影贴图使用立方体贴图,所以我将不同的纹理类型绑定到数组,这不起作用。