Search code examples
c++directxdirectx-11

Access floats of CXMMatrix - () operator not working


I'm trying to use updated codes of "Frank Luna" book on directX11 where I using VS2017 with WindowsSDK10. I've read some notes about migration from Frank and did eveything he said in the link below : http://www.d3dcoder.net/Data/Book4/d3d11Win10.htm

but got stuck here . I know there was same question from @poncho and answered well : Access floats of XMMatrix - () operator not working

But I have trouble with type CXMMATRIX instead of XMMATRIX and I couldn't get result with the solution provided for him.

So I have to access the rows and columns of an CXMMATRIX :

void ExtractFrustumPlanes(XMFLOAT4 planes[6], CXMMATRIX M)
{
    //
    // Left
    //
    planes[0].x = M(0,3) + M(0,0);
    planes[0].y = M(1,3) + M(1,0);
    planes[0].z = M(2,3) + M(2,0);
    planes[0].w = M(3,3) + M(3,0);
...

But I get :

call of an object of a class type without appropriate operator() or conversion functions to pointer-to-function type

and

term does not evaluate to a function taking 2 arguments

It points to argument M of type CXMMATRIX where defined as below in DirectXMath.h :

// Fix-up for (2nd+) XMMATRIX parameters to pass by reference
typedef const XMMATRIX& CXMMATRIX; 

What's all these errors about !?


Solution

  • Frank Luna's book is overall a great introduction to the Direct 11 API, but unfortunately suffers from heavily utilizing the legacy DirectX SDK which is deprecated per MSDN. One of those aspects is that he's actually using the xnamath library (a.k.a. xboxmath version 2) instead of the DirectXMath library (a.k.a. xboxmath version 3)

    See Book Recommendations and Introducing DirectXMath

    I made a number of changes when reworking the library as DirectXMath. First, the types are actually in C++ namespaces instead of the global namespace. In your headers, you should use full name specification:

    #include <DirectXMath.h>
    
    void MyFunction(..., DirectX::CXMMATRIX M);
    

    In your cpp source files you should use:

    #include <DirectXMath.h>
    
    using namespace DirectX;
    

    Another change was to strongly discourage the use of 'per-element' access on the XMVECTOR and XMMATRIX data types. As discussed in the DirectXMath Programmers Guide, these types are by design proxies for the SIMD register types which cannot be directly accessed by-element. Instead, you covert to the XMFLOAT4X4 representation which allows per-element access because that's a scalar structure.

    You can see this by the fact that the operators you are trying to use are only defined for 'no-intrinsics' mode (i.e. when using scalar instead of SIMD operations like SSE, ARM-NEON, etc.):

    #ifdef _XM_NO_INTRINSICS_
        float operator() (size_t Row, size_t Column) const { return m[Row][Column]; }
        float& operator() (size_t Row, size_t Column) { return m[Row][Column]; }
    #endif
    

    Again, by design, this process is a bit 'verbose' because it lets you know it's not free. Some people find this aspect of DirectXMath a little frustrating to use especially when they are first getting started. In that case, I recommend you take a look at the SimpleMath wrapper in the DirectX Tool Kit. You can use the types Vector3, Vector4, Matrix, etc. and they freely convert (through C++ operators and constructors) as needed to XMVECTOR and XMMATRIX. It's not nearly as efficient, but it's a lot more forgiving to use.

    The particular function you wrote is also a bit problematic. First, it's a little odd to mix XMFLOAT4 and XMMATRIX parameters. For 'in-register, SIMD-friendly' calling convention, you'd use:

    void XM_CALLCONV ExtractFrustumPlanes(XMVECTOR planes[6], FXMMATRIX M)
    

    For details on why, see MSDN.

    If you want to just entirely scalar math, use either the non-SIMD types:

    void ExtractFrustumPlanes(XMFLOAT4 planes[6], const XMFLOAT4X4& M)
    

    or better yet use SimpleMath so you can avoid having to write explicit conversions to/from XMVECTOR or XMMATRIX

    using DirectX::SimpleMath;
    
    void ExtractFrustumPlanes(Vector4 planes[6], const Matrix& M)
    

    Note that the latest version of DirectXMath is on GitHub, NuGet, and vcpkg.