Glsl OpenGL阴影映射的奇异性与均匀数组

Glsl OpenGL阴影映射的奇异性与均匀数组,glsl,nvidia,opengl-3,shadow-mapping,optimus,Glsl,Nvidia,Opengl 3,Shadow Mapping,Optimus,我试着运行一个朋友写的小游戏/演示,主要是为了教育目的。我注意到我的计算机上出现了一些非常奇怪的行为,尽管据报道该应用程序在几个nVidia和ATI GPU上使用了相对较新的驱动程序成功运行 片段着色器类似于以下内容: #version 150 #define SHADOW_MAP_NUM 32 in vec3 w_vPos; uniform sampler2DArrayShadow uShadowMap; uniform mat4 uShadowCP[SHADOW_MAP_NUM]; u

我试着运行一个朋友写的小游戏/演示,主要是为了教育目的。我注意到我的计算机上出现了一些非常奇怪的行为,尽管据报道该应用程序在几个nVidia和ATI GPU上使用了相对较新的驱动程序成功运行

片段着色器类似于以下内容:

#version 150

#define SHADOW_MAP_NUM 32

in vec3 w_vPos;

uniform sampler2DArrayShadow uShadowMap;
uniform mat4 uShadowCP[SHADOW_MAP_NUM];
uniform int uNumUsedShadowMaps;

out vec4 vFragColor;

const float kMaxShadow = 0.8;

float Visibility() {
  float bias = 0.01;
  float visibility = 1.0;
  int num_shadow_casters = min(uNumUsedShadowMaps, SHADOW_MAP_NUM);

  // For every shadow casters
  for(int i = 0; i < num_shadow_casters; ++i) {
    vec4 shadowCoord = uShadowCP[i] * vec4(w_vPos, 1.0);

    visibility -= kMaxShadow * (1 - texture(
      uShadowMap,
      vec4( // x, y, slice, depth
        shadowCoord.xy, i,
        (shadowCoord.z - bias) / shadowCoord.w
      )
    ));

    if (visibility <= 0.0) {
      return 0.0;
    }
  }

  return visibility;
}


void main() {
  vec3 color = vec3(Visibility(w_vPos));
  vFragColor = vec4(color, 1.0);
}
现在,一件更奇怪的事情发生了:比以前少投了一个影子。事实上,我们通过将外部循环替换为

  for(int i = -1; i < num_shadow_casters - 1; ++i) {
当然,上面的分支实际上是无操作的,因为可见性从1.0开始,并且在循环中总是减小。片段着色器的行为方式与
#pragma optimize(off)
相同,即正确操作需要伪分支

人工制品仅在我的机器上生产,具有以下GPU和驱动程序(相关行取自
glxinfo
):

服务器glx是虚拟的,因为我使用大黄蜂/Primus来使用Optimus图形卡进行渲染。我使用3.11.6内核运行Arch Linux

有人能解释一下发生了什么吗?我用相同的结果尝试了不同的nVidia驱动程序版本,所以我认为我们不可能遇到驱动程序错误。上面的片段着色器有什么问题

更新:我意识到内部循环中带有分支的片段着色器的版本有以下示例:

如果访问的纹理使用mipmapping或各向异性过滤 任何类型,那么任何不是“Lod”或“Grad”的纹理函数都将 检索未定义的结果

因为我们的阴影贴图不使用mip贴图或纹理过滤,所以我认为这不适用。修复损坏索引的方法是将分支放回,因此我们可能触发了一些与非统一控制流相关的驱动程序行为?

#pragma optimize(off)
在大多数GLSL编译器上可能不会起任何作用。您应该查看
#pragma optionNV(fastmath off)
#pragma optionNV(ifcvt none)
#pragma optionNV(strict on)
,因为这是一个NV问题。
  for(int i = -1; i < num_shadow_casters - 1; ++i) {
if (visibility > 99) {
  return 0;
}
server glx vendor string: VirtualGL
server glx version string: 1.4
OpenGL vendor string: NVIDIA Corporation
OpenGL renderer string: GeForce GT 540M/PCIe/SSE2
OpenGL version string: 4.4.0 NVIDIA 331.20
OpenGL shading language version string: 4.40 NVIDIA via Cg compiler