user11779843
user11779843

Reputation:

Passing a vec3 to glm::lookAt appears to modify it

I have encountered a situation where passing a glm::vec3 to the glm::lookAt function appears to modify it.

The following code is about shadow frustum calculation in a C++ / OpenGL game engine. The problem arises in the glm::lookAt function, at the end.

void Shadows::updateFrustumBoundingBox()
{

  // Here we convert main camera frustum coordinates in light view space
  std::array<glm::vec3,8> points = {
    // Near plane points
    lightView * glm::vec4(cameraPtr->ntl, 1.0),
    lightView * glm::vec4(cameraPtr->ntr, 1.0),
    lightView * glm::vec4(cameraPtr->nbl, 1.0),
    lightView * glm::vec4(cameraPtr->nbr, 1.0),
    // Far plane points
    lightView * glm::vec4(cameraPtr->ftl, 1.0),
    lightView * glm::vec4(cameraPtr->ftr, 1.0),
    lightView * glm::vec4(cameraPtr->fbl, 1.0),
    lightView * glm::vec4(cameraPtr->fbr, 1.0)};

  // Here we find the shadow bounding box dimensions
  bool first = true;
  for (int i=0; i<7; ++i)
  {
    glm::vec3* point = &points[i];

    if (first)
    {
            minX = point->x;
            maxX = point->x;
            minY = point->y;
            maxY = point->y;
            minZ = point->z;
            maxZ = point->z;
      first = false;
    }

        if (point->x > maxX)
            maxX = point->x;
    else if (point->x < minX)
            minX = point->x;

        if (point->y > maxY)
            maxY = point->y;
    else if (point->y < minY)
            minY = point->y;

        if (point->z > maxZ)
            maxZ = point->z;
    else if (point->z < minZ)
            minZ = point->z;
  }

  frustumWidth = maxX - minX;
  frustumHeight = maxY - minY;
  frustumLength = maxZ - minZ;

  // Here we find the bounding box center, in light view space
  float x = (minX + maxX) / 2.0f;
  float y = (minY + maxY) / 2.0f;
  float z = (minZ + maxZ) / 2.0f;
  glm::vec4 frustumCenter = glm::vec4(x, y, z, 1.0f);

  // Here we convert the bounding box center in world space
  glm::mat4 invertedLight = glm::mat4(1.0f);
  invertedLight = glm::inverse(lightView);
  frustumCenter = invertedLight * frustumCenter;

  // Here we define the light projection matrix (shadow frustum dimensions)
  lightProjection = glm::ortho(
    -frustumWidth/2.0f, // left
    frustumWidth/2.0f, // right
    -frustumHeight/2.0f, // down
    frustumHeight/2.0f, // top
    0.01f, // near
    SHADOW_DISTANCE); // far


  // Here we define the light view matrix (shadow frustum position and orientation)
  lightDirection = glm::normalize(lightDirection);
  target =  glm::vec3(0.0f, 100.0f, 200.0f) + lightDirection;

  lightView = glm::lookAt(
                  // Shadow box center
                     glm::vec3(0.0f, 100.0f, 200.0f), // THIS LINE
                  // glm::vec3(frustumCenter), // ALTERNATIVELY, THIS LINE. Here I convert it as a vec3 because it is a vec4

                  // Light orientation
                  target,

                  // Up vector
                  glm::vec3( 0.0f, 1.0f,  0.0f));

  cout << "frustumCenter: " << frustumCenter.x << " " << frustumCenter.y << " " << frustumCenter.z << endl;

  // Final matrix calculation
  lightSpaceMatrix = lightProjection * lightView;
}

As is, the first glm::lookAt parameter is glm::vec3(0.0f, 100.0f, 200.0f), and it works correctly. The glm::vec4 frustumCenter variable isn't used by glm::lookAt, and outputs correct values each frame.

frustumCenter: 573.41 -93.2823 -133.848 1

But if I change the first glm::lookAt parameter to "glm::vec3(frustumCenter)":

frustumCenter: nan nan nan nan

How can it be?

Upvotes: 0

Views: 636

Answers (1)

derhass
derhass

Reputation: 45352

I have encountered a situation where passing a glm::vec3 to the glm::lookAt function appears to modify it."

I don't think so. You use frustumCenter to caclucalte lightView, but before you do that, you use lightView to calculate frustumCenter: frustumCenter = invertedLight * frustumCenter;

So my educated guess on what happens here is:

The lightView matrix is not properly initialized / initialized to a singular matrix (like all zeros). As such, the inverse will be not defined, resulting in frustumCenter becoming all NaN, which in turn results in lightView becoming all NaN.

But if you not use frustumCenter in the first iteration, lightView will be properly initialized, and frustumCenter will be calculated to a sane value in the next iteration.

Upvotes: 0

Related Questions