1
\$\begingroup\$

I am working on my first 3D game, which contains several vehicles placed on a board. I want to implement mouse picking of the vehicles. I found this great tutorial and used its code. But I don't understand part of the math.

Early in the function (listed below), I convert the input mouse coordinates into the -1 to +1 range:

// Create picking ray from camera position and mouse click
void VehiclePicker::SetPickingRay(LONG mouseX, LONG mouseY) {
    float pointX, pointY;

    /* Conversion to -1 to +1 here: */
    // Move the mouse cursor coordinates into the -1 to +1 range.
    pointX = ((2.0f * static_cast<float>(mouseX)) / static_cast<float>(SCREEN_WIDTH)) - 1.0f;
    pointY = (((2.0f * static_cast<float>(mouseY)) / static_cast<float>(SCREEN_HEIGHT)) - 1.0f) * -1.0f;

    ...

Next, I adjust the points using the projection matrix. Listed below:

    XMFLOAT4X4 prMtrx;
    // Convert projectionMatrix from XMMATRIX into XMFLOAT4X4 in order to pick its members
    XMStoreFloat4x4(&prMtrx, _d3d->GetProjectionMatrix());
    pointX = pointX / prMtrx._11;
    pointY = pointY / prMtrx._22;

I don't understand what is exactly done here. I understand that I should somehow transform the points using the inverted projection matrix into world space. But in the tutorial they are using non-inverted projection matrix and using only two elements from it for dividing the points. Why? In tutorial, they say they want "Adjust the points using the projection matrix to account for the aspect ratio of the viewport." Could somebody please explain it?

The same question is for the next part of the code. In tutorial they say "Calculate the direction of the picking ray in view space." Could you please also explain this one?

    // Get the inverse of the view matrix.
    XMFLOAT4X4 invViewMtrx;
    // Convert inverseViewMatrix from XMMATRIX into XMFLOAT4X4 in order to pick its members
    XMStoreFloat4x4(&invViewMtrx, XMMatrixInverse(nullptr, _camera->GetViewMatrix()));
    XMFLOAT3 dir;
    dir.x = (pointX * invViewMtrx._11) + (pointY * invViewMtrx._21) + invViewMtrx._31;
    dir.y = (pointX * invViewMtrx._12) + (pointY * invViewMtrx._22) + invViewMtrx._32;
    dir.z = (pointX * invViewMtrx._13) + (pointY * invViewMtrx._23) + invViewMtrx._33;
    _pickingRayDirection = XMLoadFloat3(&dir);

I understand that the goal is to invert the process of rendering 3D scene into 2D screen. But I don't understand the math used.

Here's the rest of the function, for context:

    // Get the origin of the picking ray which is the position of the camera.
    _pickingRayOrigin = _camera->GetPosition();

    // And finally I must normalize the final vector
    _pickingRayDirection = XMVector3Normalize(_pickingRayDirection);
}
\$\endgroup\$
1
\$\begingroup\$

Your world geometry is translated to the view via your world and projection matrix. Your raycast is starting in the screen space and needs to be converted back to world space. Usually your world space is an identity matrix. To convert your Ray firstly you have established it's co-ordinates in the screen/projection view. You then invert your projection matrix to convert your Ray back into world space so then you can test collisions with your world.

What you will find us that the next trick is to effectively test your Ray against the world objects is to convert the ray to local space of each object. You can then use things such as AABB tests etc to detect collisions.

Good luck

\$\endgroup\$
  • \$\begingroup\$ Thank you. I understand that I must invert the process of rendering 3D scene into 2D screen. But what is exactly done with the projection matrix (I don't understand the math)? Why is the projection matrix not inverted? \$\endgroup\$ – Jan Pazdera Aug 22 '18 at 20:37
  • \$\begingroup\$ HI, depending on the ray calculation you are using, you may need to use the inverted projection matrix to determine its cast in the worldspace, hence the inverted projection matrix. BUT, this as this gives you ray in world space, not local model space, if you want to then do OBB ray cast, you need to then use the models world matrix (inverted of course) to then transform the rays start and end point for OBB intersection. Be aware, do not transfrom the ray vector, but the start and end, then calculate the ray. Of course you can use more course tests like ray/sphere test prior to OBB. \$\endgroup\$ – ErnieDingo Sep 3 at 1:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.