Faces of cube map not fitting together

Started by
4 comments, last by monophonic 8 years, 5 months ago

Hi,

I am trying to render a scene to a cube map but the faces are not fitting together. I think there is something wrong with the perspective:

Unbenannt.jpg

I define a framebuffer and render the scene six times with different viewing directions (one renderpass for each face of the cube map). Then I place the camera at the origin and render a unit cube with the cube map.

The creation of the cube map:


TextureCubeMap::TextureCubeMap(const unsigned int size) : _size(size), _boundSlot(-1){
  glGenTextures(1, &_texID);
  glBindTexture(GL_TEXTURE_CUBE_MAP, _texID);

  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0);
  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, 0);
  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  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);

  for (int loop = 0; loop < 6; ++loop)
  {
    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + loop, 0, GL_RGB, size, size, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
  }

  glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
}

int TextureCubeMap::bind(){
  ...
    glEnable(GL_TEXTURE0 + _boundSlot);
    glActiveTexture(GL_TEXTURE0 + _boundSlot);
    glEnable(GL_TEXTURE_CUBE_MAP);
    glBindTexture(GL_TEXTURE_CUBE_MAP, _texID);
  ...
  return _boundSlot;
}

void TextureCubeMap::unbind(){
  ...
  glActiveTexture(GL_TEXTURE0 + _boundSlot);
  glBindTexture(GL_TEXTURE_2D, 0);
  ...
}

And this is the part where I render the scene to the cube map sixe times:


void RenderToCubeMap::render(SceneContext& scene_context){
  glBindFramebuffer(GL_FRAMEBUFFER, _fboID);
  const GLenum drawBuffer = { GL_COLOR_ATTACHMENT0 };
  glDrawBuffers(1, &drawBuffer);
  
  glViewport(0, 0, (GLsizei)_cubeMap->getSize(), (GLsizei)_cubeMap->getSize());
  SceneContext cubeMapContext = scene_context; //Contains all relevant matrices like projection-, view- and modelmatrix
  cubeMapContext._P = glm::perspective(90.f, 1.f, 1.f, 1000.f);
  
  _cubeMap->bind();
  for (unsigned int iFace = 0; iFace < 6; iFace++){
    glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + iFace, _cubeMap->getTexID(), 0);
    IRenderPass::startRenderPass(); //Enable depth test, backface culling, clear depth & draw buffer

    glm::vec3 viewDir, up;
    switch (GL_TEXTURE_CUBE_MAP_POSITIVE_X + iFace){
    case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
      viewDir = glm::vec3(1.0f, 0.0f, 0.0f);
      up = glm::vec3(0.f, -1.f, 0.f);
      break;
    case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
      viewDir = glm::vec3(-1.0f, 0.0f, 0.0f);
      up = glm::vec3(0.f, -1.f, 0.f);
      break;
    case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
      viewDir = glm::vec3(0.0f, 1.0f, 0.0f);
      up = glm::vec3(0.f, 0.f, 1.f);
      break;
    case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
      viewDir = glm::vec3(0.0f, -1.0f, 0.0f);
      up = glm::vec3(0.f, 0.f, -1.f);
      break;
    case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
      viewDir = glm::vec3(0.0f, 0.0f, 1.0f);
      up = glm::vec3(0.f, -1.f, 0.f);
      break;
    case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
      viewDir = glm::vec3(0.0f, 0.0f, -1.0f);
      up = glm::vec3(0.f, -1.f, 0.f);
      break;
    }
    
    auto viewMatrix = glm::lookAt(glm::vec3(scene_context._camPos), glm::vec3(viewDir + scene_context._camPos), up);
    cubeMapContext._V = viewMatrix;
    cubeMapContext._MV = viewMatrix * cubeMapContext._M;
    cubeMapContext._MVP = cubeMapContext._P * cubeMapContext._MV;
    _sceneGraph->renderSubtree(cubeMapContext);
  }
  _cubeMap->unbind();
  glBindFramebuffer(GL_FRAMEBUFFER, 0);
  IRenderPass::endRenderPass(); //Disable depth test, backface culling
}

What am I doing wrong? Is there something wrong with the projection matrix? I am really thankful for any input.

Best regards,

Stan

Advertisement

Your result looks like you are rendering the sides with too high a field of view or from a little too far back. But you have 90 for the field of view variable, so that should be fine. This leaves inconsistency of the camera position as the likely culprit.


auto viewMatrix = glm::lookAt(glm::vec3(scene_context._camPos), glm::vec3(viewDir + scene_context._camPos), up);
cubeMapContext._V = viewMatrix;
cubeMapContext._MV = viewMatrix * cubeMapContext._M;
cubeMapContext._MVP = cubeMapContext._P * cubeMapContext._MV;
_sceneGraph->renderSubtree(cubeMapContext);

I bolded the line that immediately seemed suspicious to me. Where do you set cubeMapContext._M? It looks like it is supposed to be the identity matrix. Double check that this is really the case or just drop it from the multiplication (which leaves just the assignment). Also make sure you are multiplying the matrices in the correct order, I don't know glm so I don't know which way that is supposed to go.

I have tried out your suggestion but the problem remains. I have even fixed the camera position to the origin:


auto viewMatrix = glm::lookAt(glm::vec3(0), glm::vec3(viewDir + glm::vec3(0)), up);
cubeMapContext._V = cubeMapContext._MV = viewMatrix;
cubeMapContext._MVP = cubeMapContext._P * cubeMapContext._MV;
_sceneGraph->renderSubtree(cubeMapContext);

What I have also tried out is loading a cube map to see if my cube map rendering works correctly. And indeed it is, when loading a cube map everything fits perfectly together. Only when I generate the cube map myself as described above the faces don't fit together. Here is my shader code for the cube map rendering:


#version 430

layout(location=0) in vec3 vertex;

out vec3 ex_uv;

uniform mat4 mvp;

void main(){
  ex_uv = vertex;
  gl_Position = mvp * vec4(vertex, 1.f);
}

#version 430

in vec3 ex_uv;

out vec4 color;

uniform samplerCube cubeMap;

void main(){
  color = texture(cubeMap, ex_uv);
}

And this is the client code initiating the rendering of the cube map:


void render(const SceneContext& context, const glm::mat4x4& tmat){
  glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
  _shader->bind(); //Calls: glUseProgram(shaderProgramID);
  _shader->loadMatrix4("mvp", glm::value_ptr(context._MVP)); // int _uniID = glGetUniformLocation(shaderProgramID, "mvp"); 
                                                             // glUniformMatrix4fv(_uniID, 1, GL_FALSE, valuePtr);
  _shader->loadUniform("cubeMap", _cubeMap->bind()); // glUniform1i(uniID, x); //uniID = _cubeMap->bind()
  _unitCube->bindVertices(0); // glEnableVertexAttribArray(location); //location = 0
                              // glBindBuffer(GL_ARRAY_BUFFER, _vBufferID);
                              // glVertexAttribPointer(location, 3, GL_FLOAT, GL_FALSE, 0, 0);
                              // glBindBuffer(GL_ARRAY_BUFFER, 0);
  _unitCube->render(); // glDrawArrays(GL_TRIANGLES, 0, _vertices.size());
  _unitCube->unbind(); // glDisableVertexAttribArray(0);
  _shader->unbind(); // glUseProgram(0);
  glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
}

Is there maybe conceptually something wrong? I only want to create an environment map/panoramic view of my sponza scene. Isn't it possible to do it the way I do?

Regards,

Stan

But you have 90 for the field of view variable, so that should be fine.

Math libraries tend to use radians instead of degrees.
90 radians is 5156.62 degrees! If you assume that it wraps every 360 degrees, then you get a remainder of 116.62 degrees... which is coincidentally, only just a tad higher than 90 degrees, causing only the slight excess in perspective seen in the pictures.

You actually want to be passing Pi/2 radians as the fov argument smile.png

Thanks Hodgman! That was exactly the problem.smile.png After passing the fov in radians everything worked perfectly fine. I somewhere defined the symbol GLM_FORCED_RADIANS and from then on the function took the angle in radians and not in degrees. rolleyes.gif

But you have 90 for the field of view variable, so that should be fine.

Math libraries tend to use radians instead of degrees.
90 radians is 5156.62 degrees! If you assume that it wraps every 360 degrees, then you get a remainder of 116.62 degrees... which is coincidentally, only just a tad higher than 90 degrees, causing only the slight excess in perspective seen in the pictures.

You actually want to be passing Pi/2 radians as the fov argument smile.png

Well spotted. I thought I checked that the function took degrees, but apparently I did not...

Thanks Hodgman! That was exactly the problem.smile.png After passing the fov in radians everything worked perfectly fine. I somewhere defined the symbol GLM_FORCED_RADIANS and from then on the function took the angle in radians and not in degrees. rolleyes.gif

... then again maybe I did. :) May I take a moment to express my hatred towards APIs that change their contract based on a single tidbit anywhere in the code and does not communicate this possibility in the naming of its functions?

This topic is closed to new replies.

Advertisement