hello everyone,
I was wondering if there was any D3DX function similar to D3DXMatrixLookAtLH, I mean, that you send a vector pointing somewhere in the scenery and a vector setting from where you're looking at, and the function returns you a matrix or a quaternion with the rotations needed to "look" at the point, from where the eye is, no matter how far the point is located.
The thing is, I have a point in the scenery, and I can get the rotation in X, Y and Z with trigonometric functions and with its position, but it'd be easier to have a function that does that for me, like LookAtLH, the problem with that function is that when the point is above or below the eye, taking into account the Up vector, the result matrix isn't valid, and I can't change the Up vector, as you do when rotating the camera for example, because the viewer should be static.

thanks in advanced for your help,
gallo
Posted on 2007-07-09 20:01:14 by gallo
There's several solutions that spring to mind.
One is to build your own View matrix, rather than using D3DXMatrixLookAtLH.
Another is to call that function once to build a view matrix for a fixed view, say "straight ahead", and then to concatenate it with a rotation matrix that represents the 3D orientation, and then apply the resulting matrix as your view matrix.
I have written 6DOF camera code in the past, I had no problems using both these solutions.
Yes, the D3DXMatrixLookat function has a couple of mathematical anomolies.
They occur at 90 degrees vertical inclination and declination.
Please search for information on 'avoiding gimbal lock' if you want to find alternatives.
Posted on 2007-07-10 01:51:03 by Homer
hello, well I didn't find any thing very near to what I was looking for, so I wrote the proc by my self, but now I have a little problem, here is the code:

.data
    float_1 REAL4 1.0
.code

QuaternionLookAt proc pQuaternion:LPVOID,pPos:LPVOID
    local front:D3DXVECTOR3
    local pos:D3DXVECTOR3
    local axis:D3DXVECTOR3
    local angle:FLOAT

    mov front.x,0
    mov front.y,0
    m2m front.z,float_1

    invoke D3DXVec3Normalize,addr pos,pPos

    invoke D3DXVec3Cross,addr axis,addr front,addr pos
    invoke D3DXVec3Normalize,addr axis,addr axis

    invoke D3DXVec3Length,addr axis
    fldz
    fcompp
    fstsw ax
    test ah,01000000b    ;==
    jz @F
    m2m axis.x,float_1
    mov axis.y,0
    mov axis.z,0
@@:

    invoke D3DXVec3Dot,addr front,addr pos

    ;arccos
    fld st(0)
    fmul st(0),st(0)
    fld1
    fsubr
    fsqrt
    fxch st(1)
    fpatan

    fstp angle

    invoke D3DXQuaternionRotationAxis,pQuaternion,addr axis,angle

    ret
QuaternionLookAt endp


now, an example of the problem is that when I send as second parameter a vector which points back, the resulting quaternion is:

(LPD3DXQUATERNION) pQuaternion
    x    1.00000
    y    0.000000
    z    0.000000
    w    -4.37114e-008


as you see, the w part is near zero, but it isn't and it should be zero, so, when I use this on a project, frame after frame it will affect the position of something that's being rotated by the resulting quaternion. I don't know if there's some way to correct this, because is not only for the case when the position vector is pointing back but everywhere. I tried to trace the error and it's on a fsincos made on the procedure D3DXQuaternionRotationAxis, and it happens as well in the D3DXMatrixRotationAxis; and, even in the procedure D3DXQuaternionRotationYawPitchRoll, when you set rotation parameters to (0,pi,0), you'll get a not very precise result.
I hope there's some way to overcome this problem, please help me,
thanks in advanced,
gallo.
Posted on 2007-07-17 17:39:24 by gallo
There may be two options in my opinion to resolve this problem.

1- If you are currently setting the precision control of the FPU to 24 bits (REAL4), switching it to 53 bits (REAL8) could help as long as you don't store intermediate results as REAL4 too often during the computation.

2- If the above is not applicable or does not resolve the problem, the only option may be to check the final result for an excessively low value and change it to 0 when advisable. That could be performed either on the FPU, or on the ALU with "integer" instructions even though the result may be stored as a float.
The following is an example of how the latter could be done, assuming that "w" is a REAL4 in memory.

mov  eax,w
rol  eax,9      ;transfer the biased exponent bits to AL
.if  al < 6Ch  ;compare to approx. 10-7
                ;use 6Fh for approx. 10-6
  mov  w,0
.endif


If you haven't done so already and you need a better understanding of floats, see Chapter 2 in the FPU tutorial at
http://www.ray.masmcode.com/tutorial/index.html

Raymond
Posted on 2007-07-17 22:20:25 by Raymond