简体   繁体   中英

GL_INVALID_OPERATION when attempting to sample cubemap texture

I'm working on shadow casting using this lovely tutorial. The process is, we render the scene to a frame buffer, attached to which is a cubemap to hold the depth values. Then, we pass this cubemap to a fragment shader which samples it and gets the depth values from there.

I took a slight deviation from the tutorial in that instead of using a geometry shader to render the entire cubemap at once, I instead render the scene six times to get the same effect - largely because my current shader system doesn't support geometry shaders and for now I'm not too concerned about the performance hit.

The depth cubemap is being drawn to fine, here's a screenshot from gDEBugger:

深度立方体贴图

Everything seems to be in order here.

However, I'm having issues in my fragment shader when I attempt to sample this cubemap. After the call to glDrawArrays , a call to glGetError returns GL_INVALID_OPERATION , and as best as I can tell, it's coming from here: (The offending line has been commented)

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;
}

Commenting out the aforementioned line seems to make everything work fine - so I'm assuming it's the call to the texture sampler that's causing issues. I saw that this can be attributed to using two textures of different types in the same texture unit - but according to gDEBugger this isn't the case:

纹理清单

Texture 16 is the depth cube map.

In case it's relevant, here's how I'm setting up the FBO: (called only once)

// 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);

Here's how I'm drawing with it: (called every frame)

// 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);

And here's how I'm binding it before drawing:

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

Thank you for reading, and please let me know if I can supply more information!

It is old post, but i think it may be useful for other people from the search. Your problem here:

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

This replacement should fix problem:

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

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

It set texture unit number for shader sampler

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM