尝试对立方体贴图纹理进行采样时出现 GL_INVALID_OPERATION

Posted

技术标签:

【中文标题】尝试对立方体贴图纹理进行采样时出现 GL_INVALID_OPERATION【英文标题】:GL_INVALID_OPERATION when attempting to sample cubemap texture 【发布时间】:2016-08-30 06:08:23 【问题描述】:

我正在使用this lovely tutorial. 进行阴影投射。这个过程是,我们将场景渲染到一个帧缓冲区,附加一个立方体贴图来保存深度值。然后,我们将此立方体贴图传递给片段着色器,片段着色器对其进行采样并从中获取深度值。

我与教程略有不同,因为我没有使用几何着色器一次渲染整个立方体贴图,而是渲染场景六次以获得相同的效果 - 主要是因为我当前的着色器系统不支持几何着色器,现在我不太担心性能损失。

深度立方体贴图绘制得很好,这是来自 gDEBugger 的截图:

这里似乎一切正常。

但是,当我尝试对此立方体贴图进行采样时,我的片段着色器出现问题。调用glDrawArrays 之后,调用glGetError 返回GL_INVALID_OPERATION,据我所知,它来自这里:(违规行已被评论)

struct PointLight

  vec3 Position;
  float ConstantRolloff;
  float LinearRolloff;
  float QuadraticRolloff;
  vec4 Color;
  samplerCube DepthMap;
  float FarPlane;
;
uniform PointLight PointLights[NUM_POINT_LIGHTS];

[...]

float CalculateShadow(int lindex)

  // Calculate vector between fragment and light
  vec3 fragToLight = FragPos - PointLights[lindex].Position;

  // Sample from the depth map (Comment this out and everything works fine!)
  float closestDepth = texture(PointLights[lindex].DepthMap, vec3(1.0, 1.0, 1.0)).r;

  // Transform to original value
  closestDepth *= PointLights[lindex].FarPlane;

  // Get current depth
  float currDepth = length(fragToLight);

  // Test for shadow
  float bias = 0.05;
  float shadow = currDepth - bias > closestDepth ? 1.0 : 0.0;
  return shadow;

注释掉上述行似乎使一切正常 - 所以我假设是对纹理采样器的调用导致了问题。 I saw that this can be attributed to using two textures of different types in the same texture unit - 但根据 gDEBugger 的说法,情况并非如此:

纹理 16 是深度立方体贴图。

如果相关,这里是我设置 FBO 的方式:(仅调用一次)

// Generate frame buffer
glGenFramebuffers(1, &depthMapFrameBuffer);

// Generate depth maps
glGenTextures(1, &depthMap);

// Set up textures
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, depthMap);
for (int i = 0; i < 6; ++i)
  glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT,
    ShadowmapSize, ShadowmapSize, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);

// Set texture parameters
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);

// Attach cubemap to FBO
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFrameBuffer);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthMap, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
  ERROR_LOG("PointLight created an incomplete frame buffer!\n");
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);

这是我用它绘制的方式:(调用每一帧)

// Set up viewport
glViewport(0, 0, ShadowmapSize, ShadowmapSize);

// Bind frame buffer
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFrameBuffer);

// Clear depth buffer
glClear(GL_DEPTH_BUFFER_BIT);

// Render scene
for(int i = 0; i < 6; ++i)

  sh->SetUniform("ShadowMatrix", lightSpaceTransforms[i]);
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
    GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, depthMap, 0);
  Space()->Get<Renderer>()->RenderScene(sh);


// Unbind frame buffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);

这是我在绘制之前绑定它的方式:

std::stringstream ssD;
ssD << "PointLights[" << i << "].DepthMap";
glActiveTexture(GL_TEXTURE4 + i);
glBindTexture(GL_TEXTURE_CUBE_MAP, pointlights[i]->DepthMap()); // just returns the ID of the light's depth map
shader->SetUniform(ssD.str().c_str(), i + 4); // just a wrapper around glSetUniform1i

感谢您的阅读,如果我能提供更多信息,请告诉我!

【问题讨论】:

您的错误可能正如您在片段着色器中所说的那样。编译着色器后使用glGetShaderInfoLog 函数,让我们看看着色器编译错误。 对不起,忘记在 OP 中提及这一点。在编译片段和顶点着色器后,我确实已经调用了 glGetShaderInfoLog,并且在链接后我调用了 glGetProgramInfoLog - 着色器编译和链接似乎没有警告或错误。 【参考方案1】:

这是旧帖子,但我认为它可能对搜索中的其他人有用。 你的问题在这里:

glActiveTexture(GL_TEXTURE4 + i);
glBindTexture(GL_TEXTURE_CUBE_MAP, pointlights[i]->DepthMap()); 

这个替换应该可以解决问题:

glActiveTexture(GL_TEXTURE4 + i);
glUniform1i(glGetUniformLocation("programId", "cubMapUniformName"), GL_TEXTURE4 + i);

glBindTexture(GL_TEXTURE_CUBE_MAP, pointlights[i]->DepthMap()); 

它为着色器采样器设置纹理单元号

【讨论】:

"它为着色器采样器设置纹理单元编号"。不,您将采样器 uniform 设置为某个 GL 枚举值,但它需要使用从零开始的纹理单元索引。

以上是关于尝试对立方体贴图纹理进行采样时出现 GL_INVALID_OPERATION的主要内容,如果未能解决你的问题,请参考以下文章

如何使用立方体贴图对未展开的模型进行纹理处理

OpenGL+OpenCV实现立方体贴图

将 .FBX 从 Blender 导入 Unity 时出现深色纹理

如何使用立方体贴图纹理非展开的模型

OpenGL立方体贴图面顺序和采样问题

用OpenGL进行立方体表面纹理贴图