I'm currently working on a 2d-sicescrolling jump'n'run with opengl. I currently want to check for my enemies if they are rendered on screen to stop collision calculations for enemies which are not visible. To do that, I check in each frame if the position in NDC is between [-1, 1] for the x- and y-axis. This is done by the following method:
bool Enemy::checkWithCameraArea(glm::mat4 cameraView, glm::mat4 proj, glm::vec3 scale) {
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, position);
model = glm::scale(model, scale);
glm::vec4 posInClip = proj * cameraView * model * glm::vec4(position, 1.0f);
glm::vec3 posDehom = glm::vec3(posInClip.x / posInClip.w, posInClip.y / posInClip.w, posInClip.z / posInClip.w);
if (posDehom.x <= 1.0f && posDehom.x >= -1.0f &&
posDehom.y <= 1.0f && posDehom.y >= -1.0f) {
return true;
}
return false;
}
The view matrix is calculated like this: glm::lookAt(_position, _position + _front, _up);
and the projection matrix like this: glm::perspective(45.0f, (float)Width / (float)Height, 5.0f, 15.0f);
These values are updated each frame based on the cameras movement to the right.
The same values are used in my vertex shader to transform the position to clip space and from a rendering perspective everything works fine. But the calculation for each enemy only seems to work at the beginning. If the camera moves to the right, the area which is calculated by my "checkWithCameraArea"-Method seems to lag behind. So enemies who are out of the screen to the left are still calculated and enemies who entered the screen from the right are not yet calculated. Please help me, I have no idea where my error lies.
EDIT #1
Removed the line with scaling, since that does not make sense for a single position (as pointed out in the comments). Since some one asked, the position i'm checking against is the bottom left corner. But the problem I have also persists when the whole object is on the screen, which can be seen here. In this video I visualized the problem: The result of the checkWithCameraArea-Method determines if the enemy texture (on true) or that green box (on false) is drawn
As pointed out in the comments by user BDL I was applying the position twice (once in the translate and once when multiplying with MVP). I also deleted the scaling, since its not necessary for a single point. The method now looks like this and works as I wanted:
bool Enemy::checkWithCameraArea(glm::mat4 view, glm::mat4 proj) {
glm::vec4 posInClip = proj * view * glm::vec4(position, 1.0f);
glm::vec3 posDehom = glm::vec3(posInClip.x / posInClip.w, posInClip.y / posInClip.w, posInClip.z / posInClip.w);
if (posDehom.x <= 1.0f && posDehom.x >= -1.0f &&
posDehom.y <= 1.0f && posDehom.y >= -1.0f) {
return true;
}
return false;
}