Does OpenGL position the screen in front of the camera?

Viewed 92

I am attempting to convert a mouse click to a global position. Even though the worldspace is 3d, I am currently trying to find the x and y coordinates of the click at z = 0.

I have written up some code that does the converting, and it is almost correct. But there seems to be an error that grows with distance from (0,0). It seems to grow too quickly to be a rounding error, so I believe that the screen is not set to exactly the camera position.

For this testing, I am focused on the x coordinate.

variables

screenWidth = 512;
screenHeight = 512;
cameraPos = glm::vec3(0.0f, 0.0f, 4.0f);

converting logic

    std::cout << "mouse float x: " << inMouseX << ", mouse float y: " << inMouseY << std::endl;


    float mouseX = (inMouseX / ((float)screenWidth * 0.5f)) - 1.0f;
    float mouseY = (inMouseY / ((float)screenHeight * 0.5f)) - 1.0f;

    std::cout << "mouse adjusted screen width x: " << (float)screenWidth * 0.5f << ", mouse adjusted screen height y: " << (float)screenHeight * 0.5f << std::endl;
    std::cout << "mouse 2nd adjusted x: " << ((inMouseX / (float)screenWidth * 0.5f)) << ", mouse 2nd adjusted y: " << ((inMouseY / (float)screenHeight * 0.5f)) << std::endl;

    std::cout << "mouse converted x: " << mouseX << ", mouse converted y: " << mouseY << std::endl;

    glm::mat4 invVP = glm::inverse(*projection * *view);

    glm::vec4 mouseClickVector = invVP * glm::vec4(mouseX, -mouseY, 1.0f, 1.0f);

    glm::vec3 norm = glm::normalize(glm::vec3(mouseClickVector));

    float t = (0 - (*cameraPos)[2]) / norm[2];

    glm::vec3 trueWorldPos = *cameraPos + (norm * t);

    return trueWorldPos;

example responses

------------case 1------------
expected:
mouse world position x: 0

actual:
mouse float x: 256, mouse float y: 255
mouse adjusted screen width x: 256, mouse adjusted screen height y: 256
mouse 2nd adjusted x: 0.25, mouse 2nd adjusted y: 0.249023
mouse converted x: 0, mouse converted y: -0.00390625
mouse world position x: 0, mouse world y: 0.0162761

------------case 2------------
expected:
mouse world position x: 5

actual:
mouse float x: 189, mouse float y: 251
mouse adjusted screen width x: 256, mouse adjusted screen height y: 256
mouse 2nd adjusted x: 0.18457, mouse 2nd adjusted y: 0.245117
mouse converted x: -0.261719, mouse converted y: -0.0195313
mouse world position x: 5.23121, mouse world y: 0.0813803

------------case 3------------
expected:
mouse world position x: 7

actual:
mouse float x: 82, mouse float y: 254
mouse adjusted screen width x: 256, mouse adjusted screen height y: 256
mouse 2nd adjusted x: 0.0800781, mouse 2nd adjusted y: 0.248047
mouse converted x: -0.679688, mouse converted y: -0.0078125
mouse world position x: 7.25648, mouse world y: 0.0325521

I expect there to be some fluctuations due to me being imprecise with a mouse and possibly some minor rounding issues, but it is much larger than I expected.

1 Answers

Assuming some standard conventions for the view matrix, this does not make sense:

glm::vec4 mouseClickVector = invVP * glm::vec4(mouseX, -mouseY, 1.0f, 1.0f);

glm::vec3 norm = glm::normalize(glm::vec3(mouseClickVector));

Usually, the view matrix contains both the orientation and position of the camera. You seem to treat mouseClickVector as it is just a direction. But if your camera isn't at the world space center, this normalization will yield totally bogus results.

To get the correct world space position of your unprojected point, you can't ignore the w component anymore:

glm::vec3 posWorld = (1.0f / mouseClickVector.w) * glm::vec3(mouseClickVector)

That would just yield the unprojected point on the back plane (as you set the NDC z to 1.0). You still need to calculate your view ray from the camera position to this point so that you can calculate your intersection with some world space plane.

Related