0

Projecting the points (-1, 0, 0) and (1, 0, 0) with XMVector3Project gives me the result:

P: (589.75,512,0.999683) <-> (1458.25,512,0.999683)

Unprojecting these points with XMVector3Unproject gives:

U: -0.000416635,0,-23.99 <-> 0.000416635,0,-23.99

Now, suitably baffled by the latter, what mistake have I made here? My expectation is that unprojecting would give me approximately x = -5 and x = 5. I've included a repo below (console app, requires Windows SDK):

#include <iostream>
#include <D3D11.h>
#include <DirectXMath.h>

#pragma comment(lib, "d3d11.lib")

int main()
{
    // Viewport.

    float viewport_width = 2048;
    float viewport_height = 1024;
    float viewport_near = 0.01f;
    float viewport_far = 100.0f;

    // Camera sits on -z looking towards the origin.

    DirectX::XMVECTOR eye = DirectX::XMVectorSet(0.0f, 0.0f, -24.0f, 0.0f);
    DirectX::XMVECTOR at = DirectX::XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f);
    DirectX::XMVECTOR up = DirectX::XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);

    // Camera matrices.

    DirectX::XMMATRIX view = DirectX::XMMatrixLookAtLH(eye, at, up);
    DirectX::XMMATRIX projection = DirectX::XMMatrixPerspectiveFovLH(DirectX::XM_PIDIV4 / 8, 2.0f, viewport_near, viewport_far);
    DirectX::XMMATRIX world = DirectX::XMMatrixIdentity();

    // Project the points (-5, 0) and (5, 0) onto the display

    DirectX::XMVECTOR vector_left;
    DirectX::XMVECTOR vector_right;
    DirectX::XMFLOAT4 projected_left;
    DirectX::XMFLOAT4 projected_right;
    DirectX::XMFLOAT4 unprojected_left;
    DirectX::XMFLOAT4 unprojected_right;

    vector_left = DirectX::XMVector3Project(DirectX::XMVectorSet(-1.0f, 0.0f, 0.0f, 1.0f),
                                            0,
                                            0,
                                            viewport_width,
                                            viewport_height,
                                            0.0f,
                                            1.0f,
                                            projection,
                                            view,
                                            world);

    DirectX::XMStoreFloat4(&projected_left, vector_left);

    vector_right = DirectX::XMVector3Project(DirectX::XMVectorSet(1.0f, 0.0f, 0.0f, 1.0f),
                                             0,
                                             0,
                                             viewport_width,
                                             viewport_height,
                                             0.0f,
                                             1.0f,
                                             projection,
                                             view,
                                             world);

    DirectX::XMStoreFloat4(&projected_right, vector_right);

    std::cout << "P: "
              << projected_left.x << ","
              << projected_left.y << ","
              << projected_left.z << " <-> "        
              << projected_right.x << ","
              << projected_right.y << ","
              << projected_right.z << std::endl;

    // Unproject both resulting points.

    vector_left = DirectX::XMVector3Unproject(DirectX::XMVectorSet(projected_left.x, projected_left.y, 0.0f, 1.0f),
                                              0,
                                              0,
                                              viewport_width,
                                              viewport_height,
                                              0.0f,
                                              1.0f,
                                              projection,
                                              view,
                                              world);

    DirectX::XMStoreFloat4(&unprojected_left, vector_left);

    vector_right = DirectX::XMVector3Unproject(DirectX::XMVectorSet(projected_right.x, projected_right.y, 0.0f, 1.0f),
                                               0,
                                               0,
                                               viewport_width,
                                               viewport_height,
                                               0.0f,
                                               1.0f,
                                               projection,
                                               view,
                                               world);

    DirectX::XMStoreFloat4(&unprojected_right, vector_right);

    std::cout << "U: "
              << unprojected_left.x  << ","
              << unprojected_left.y  << ","
              << unprojected_left.z  << " <-> "
              << unprojected_right.x << ","
              << unprojected_right.y << ","
              << unprojected_right.z << std::endl;
}
Robinson
  • 9,666
  • 16
  • 71
  • 115
  • You aren't projecting back the original point. If you pass ``vector_left`` and ``vector_right`` into the UnProject, it's much closer to the original value. – Chuck Walbourn Nov 18 '20 at 04:21
  • I've saved vector_left and vector_right into projected_left and projected_right, so it's the same point Chuck? – Robinson Nov 18 '20 at 06:32
  • 1
    No. You provide a different .z value. – Chuck Walbourn Nov 18 '20 at 07:10
  • Forgive me, that was a typo in my demo (well, a previous experiment). The results I posted at the top are correct for it now, and haven't changed. I edited the sample. – Robinson Nov 18 '20 at 07:18
  • OK, I see what I did there now. If I pass in projected.z as the z coordinate, I get back more or less the correct result. So I suppose the question is, why does the initial projection change the z value at all? It changes it from 0 to ~1. – Robinson Nov 18 '20 at 07:50
  • 1
    It\'s scaling to MinZ/MaxZ – Chuck Walbourn Nov 18 '20 at 20:18
  • Thanks very much Chuck. I think I understand how it works now. – Robinson Nov 19 '20 at 14:52

0 Answers0