opengl-esandroid-ndkprojectionray-picking

Unprojecting Screen coords to world in OpenGL es 2.0


Long time listener, first time caller. So I have been playing around with the Android NDK and I'm at a point where I want to Unproject a tap to world coordinates but I can't make it work. The problem is the x and y values for both the near and far points are the same which doesn't seem right for a perspective projection. Everything in the scene draws OK so I'm a bit confused why it wouldn't unproject properly, anyway here is my code please help thanks

//x and y are the normalized screen coords
ndk_helper::Vec4 nearPoint = ndk_helper::Vec4(x, y, 1.f, 1.f);
ndk_helper::Vec4 farPoint = ndk_helper::Vec4(x, y, 1000.f, 1.f);

ndk_helper::Mat4 inverseProjView = this->matProjection * this->matView;
inverseProjView = inverseProjView.Inverse();

nearPoint = inverseProjView * nearPoint;
farPoint = inverseProjView * farPoint;

nearPoint = nearPoint *(1 / nearPoint.w_);
farPoint = farPoint  *(1 / farPoint.w_);

Solution

  • Well, after looking at the vector/matrix math code in ndk_helper, this isn't a surprise. In short: Don't use it. After scanning through it for a couple of minutes, it has some obvious mistakes that look like simple typos. And particularly the Vec4 class is mostly useless for the kind of vector operations you need for graphics. Most of the operations assume that a Vec4 is a vector in 4D space, not a vector containing homogenous coordinates in 3D space.

    If you want, you can check it out here, but be prepared for a few face palms:

    https://android.googlesource.com/platform/development/+/master/ndk/sources/android/ndk_helper/vecmath.h

    For example, this is the implementation of the multiplication used in the last two lines of your code:

    Vec4 operator*( const float& rhs ) const
    {
        Vec4 ret;
        ret.x_ = x_ * rhs;
        ret.y_ = y_ * rhs;
        ret.z_ = z_ * rhs;
        ret.w_ = w_ * rhs;
        return ret;
    }
    

    This multiplies a vector in 4D space by a scalar, but is completely wrong if you're operating with homogeneous coordinates. Which explains the results you are seeing.

    I would suggest that you either write your own vector/matrix library that is suitable for graphics type operations, or use one of the freely available libraries that are tested, and used by others.

    BTW, the specific values you are using for your test look somewhat odd. You definitely should not be getting the same results for the two vectors, but it's probably not what you had in mind anyway. For the z coordinate in your input vectors, you are using the distances of the near and far planes in eye coordinates. But then you apply the inverse view-projection matrix to those vectors, which transforms them back from clip/NDC space into world space. So your input vectors for this calculation should be in clip/NDC space, which means the z-coordinate values corresponding to the near/far plane should be at -1 and 1.