Reputation:
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
Reputation: 45352
I have encountered a situation where passing a
glm::vec3
to theglm::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