使用OpenGL和GLSL处理采样器时非常奇怪的行为

时间:2014-09-19 18:21:14

标签: opengl glsl shader fragment-shader glsles

我只使用一个点光源成功实现了立方体贴图阴影贴图。

为了渲染这个场景,我在第一个渲染过程几何着色器中使用它来调度6个截头。在第二个渲染过程中,我使用片段着色器中的samplerCubeShadow来计算阴影因子。

我使用NVIDIA GeForce GTX 780M的OpenGL / GLSL版本4.40。

以下是截图:

enter image description here

但现在我想实现多个立方体贴图阴影贴图,使用几个点光源渲染阴影。

我的片段着色器中有一些代码安静:

[...]

/*
** Shadow Cube sampler array.
*/
uniform samplerCubeShadow ShadowCubeSampler[5]; //Max point light by scene = 5

[...]

float ConvertDistToClipSpace(vec3 lightDir_ws)
{
    vec3 AbsVec = abs(lightDir_ws);
    float LocalZcomp = max(AbsVec.x, max(AbsVec.y, AbsVec.z));

    float NormZComp = (NearFar.y + NearFar.x)/(NearFar.y - NearFar.x)
        - (2.0f * NearFar.y * NearFar.x)/(LocalZcomp * NearFar.y - NearFar.x);

    return ((NormZComp + 1) * 0.5f);
}

float GetCubeShadowFactor(vec3 vertexPosition_ws, float shadowFactor, int idx)
{
    vec3 lightToVertexDir_ws = vertexPosition_ws - LightPos_ws.xyz;
    float LightToVertexClipDist = ConvertDistToClipSpace(lightToVertexDir_ws);

    float LightToOccluderClipDist = texture(
        ShadowCubeSampler[idx], vec4(lightToVertexDir_ws, LightToVertexClipDist));

    if (LightToOccluderClipDist < LightToVertexClipDist)
    {
        shadowFactor = 0.0f;
    }
    return (shadowFactor);
}

void main(void)
{
    [...]

    for (int idx = 0; idx < 1; idx++) //Test first with 1 point light
    {
        float ShadowFactor = GetCubeShadowFactor(Position_ws.xyz, ShadowFactor, idx);
    }
    [...]
}

问题是我有错误1282(INVALID_OPERATION)。为了恢复这里的情况,我希望使用SINGLE点光源显示与上图完全相同的场景,但这次使用的是samplerCubeShadow数组。令人惊奇的是,如果我用“ShadowCubeSampler [0]”替换函数“texture”'ShadowCubeSampler [idx]'的第一个参数就可以了!但是'idx'的值始终为'0'。我尝试了以下代码但没有成功:

int toto = 0;

float LightToOccluderClipDist = texture(ShadowCubeSampler[toto], vec4(lightToVertexDir_ws, LightToVertexClipDist));

我已经有错误1282!索引的类型是相同的(int)!

我已经使用'sampler2DShadow'或'sampler2D'数组而没有问题。

那么,为什么使用'samplerCubeShadow'并且解决方案'ShadowCubeSampler [0]'不起作用而不能正常工作?

PS:如果我定义一个2的数组,如果我使用2个立方体贴图,那么2点光源就可以了。因此,如果我加载了一些比碎片着色器中指定的数量更差的立方体贴图,它就会失败!

我没有编译错误,也没有链接错误。这是我用来检查着色器程序状态的代码:

void video::IEffectBase::Log(void) const
{
    GLint errorLink = 0;

    glGetProgramiv(this->m_Handle, GL_LINK_STATUS, &errorLink);

    if (errorLink != GL_TRUE)
    {
        GLint sizeError = 0;

        glGetProgramiv(this->m_Handle, GL_INFO_LOG_LENGTH, &sizeError);

        char *erreur = new char[sizeError + 1];

        glGetShaderInfoLog(this->m_Handle, sizeError, &sizeError, erreur);

        erreur[sizeError] = '\0';

        std::cerr << erreur << std::endl;

        glDeleteProgram(this->m_Handle);

        delete[] erreur;
    }
}

关于纹理单位限制:

std::cout << GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS << std::endl;
std::cout << GL_MAX_TEXTURE_IMAGE_UNITS << std::endl;

$> 35660
$> 34930

如果我使用'ShadowCubeSampler [0]','0'直接写在代码中我有相同的显示,就像图片一样,我的帖子开头没有错误。如果我使用idx = 0的'ShadowCubeSampler [idx]',我有以下显示:

enter image description here

如您所见,尚未渲染共享此着色器的所有几何体。但是我没有任何链接错误。你怎么解释这个?系统是否可以取消连接着色器程序?

更新

假设我的samplerCubeShadow数组可以包含2个最大采样器(uniform samplerCubeShadow tex_shadow 2)。

我注意到如果我只加载一个点光源,那么一个立方体贴图:

CASE 1

uniform samplerCubeShadow tex_shadow[1]; //MAX POINT LIGHT = 1
for (int i=0; i < 1; i++) {tex_shadow[i];} //OK
for (int i=0; i < 1; i++) {texture(tex_shadow[i], ...);} //OK
for (int i=0; i < 1; i++) {texture(tex_shadow[0], ...);} //OK

CASE 2

uniform samplerCubeShadow tex_shadow[2]; //MAX POINT LIGHT = 2
for (int i=0; i < 1; i++) {tex_shadow[i];} //NOT OK - 1282
for (int i=0; i < 1; i++) {texture(tex_shadow[i], ...);} //NOT OK - 1282
for (int i=0; i < 1; i++) {texture(tex_shadow[0], ...);} //OK

CASE 3

uniform samplerCubeShadow tex_shadow[2]; //MAX POINT LIGHT = 2
for (int i=0; i < 2; i++) {tex_shadow[i];} //OK
for (int i=0; i < 2; i++) {texture(tex_shadow[i], ...);} //OK
for (int i=0; i < 2; i++) {texture(tex_shadow[0], ...);} //OK

结论:如果采样器的最大数量等于加载的采样器数量,我可以循环遍历数组中包含的采样器。如果数字较差,则不起作用!每次使用着色器程序时,我最多可以使用32个纹理单元。我使用samplerCube关键字时遇到同样的问题。

这很奇怪,因为我使用sampler2D或sampler2DShadow进行聚光灯影计算没有任何问题。

我用NSight检查我在片段着色器文件中放置了一个断点,当然还有断点。这就像着色器程序没有关联,但事实并非如此。

您是否认为这可能是有关cubeMap采样器的问题,或者问题来自立方体贴图初始化?

有人可以帮助我吗?

2 个答案:

答案 0 :(得分:0)

我从来没有在glsl里面使用过数组,而且我现在没有设备这么做, 但你有没有尝试在glsl中使用unsigned int uint。

float GetCubeShadowFactor(vec3 vertexPosition_ws, float shadowFactor, uint idx) {
....
}

另请注意,您不能在着色器中使用无限采样器。

答案 1 :(得分:0)

OpenGL根据目标版本对opaque类型的数组有特殊限制(纹理就是其中之一)。在OpenGL 4循环这样的数组之前是不可能的。您可以在此处查看详细信息:OpenGL Wiki - Data Types