Heya...
I'm currently using D3DXMatrixLookAtLH to implement a fixed view of a 3d scene, and having done some digging around, there seems to be a few schools of thought about which is the better way to update the viewmatrix (read "cameramatrix") when rotation in multiple axes is desired. I don't want to talk about Quaternions here. When we rotate the view around an axis, it messes up the other axes, so obviously it's craptarded to manipulate the vectors used in a call to D3DXMatrixLookAtLH, this is a cheesy solution and it leads to gimbal lock, which is a mathematical effect seen when we rotate 90 degrees on an axis, we have effectively switched some axes around, and everything goes haywire.
A better solution is to build the viewmatrix ourselves, taking into account the combined rotations and / or translations of the camera (us).
Here is a c++ function which is supposed to do it, followed by my asm translation of the same. Unfortunately, mine isn't working, and I'm not sure why.
My personal first impression was that since we are entirely building the matrix, there seems to be no need for the initial call to create an IdentityMatrix :)
Someone please call me an idiot and tell me that this is EXACTLY what D3DXMatrixLookAtLH does internally, and put me out of my misery :rolleyes:

//-- ---------------------------------------------------------------------------
// Name : updateViewMatrix()
// Desc : Builds a view matrix suitable for Direct3D.
//
// Here's what the final matrix should look like:
//
// | rx ux lx 0 |
// | ry uy ly 0 |
// | rz uz lz 0 |
// | -(r.e) -(u.e) -(l.e) 1 |
//
// Where r = Right vector
// u = Up vector
// l = Look vector
// e = Eye position in world space
// . = Dot-product operation
//
//-----------------------------------------------------------------------------
void updateViewMatrix( void )
{
D3DXMATRIX view;
D3DXMatrixIdentity( &view );

D3DXVec3Normalize( &g_vLook, &g_vLook );
D3DXVec3Cross( &g_vRight, &g_vUp, &g_vLook );
D3DXVec3Normalize( &g_vRight, &g_vRight );
D3DXVec3Cross( &g_vUp, &g_vLook, &g_vRight );
D3DXVec3Normalize( &g_vUp, &g_vUp );

view._11 = g_vRight.x;
view._12 = g_vUp.x;
view._13 = g_vLook.x;
view._14 = 0.0f;

view._21 = g_vRight.y;
view._22 = g_vUp.y;
view._23 = g_vLook.y;
view._24 = 0.0f;

view._31 = g_vRight.z;
view._32 = g_vUp.z;
view._33 = g_vLook.z;
view._34 = 0.0f;

view._41 = -D3DXVec3Dot( &g_vEye, &g_vRight );
view._42 = -D3DXVec3Dot( &g_vEye, &g_vUp );
view._43 = -D3DXVec3Dot( &g_vEye, &g_vLook );
view._44 = 1.0f;

g_pd3dDevice->SetTransform( D3DTS_VIEW, &view );
}

==========================================

Now for my version..

updateViewMatrix proc
local view:D3DXMATRIX
local fptemp:FLOAT
; invoke D3DXMatrixIdentity ,addr view ;unnecessary, since we are filling the entire Matrix

m2m view._11 , g_vRight.x
m2m view._12 , g_vUp.x;
m2m view._13 , g_vLook.x;
m2m view._14 , fp0

m2m view._21 , g_vRight.y;
m2m view._22 , g_vUp.y;
m2m view._23 , g_vLook.y;
m2m view._24 , fp0

m2m view._31 , g_vRight.z;
m2m view._32 , g_vUp.z;
m2m view._33 , g_vLook.z;
m2m view._34 , fp0

mov fptemp,eax
fld fptemp
fchs
fstp view._41

mov fptemp,eax
fld fptemp
fchs
fstp view._42

mov fptemp,eax
fld fptemp
fchs
fstp view._43
m2m view._44 , fp1

mov ecx,CApp_OnlyInstance
ret
updateViewMatrix endp

As always, I appreciate any and all feedback in respect to my humble postings.
Homer.
Posted on 2003-12-16 02:42:59 by Homer
This may seem a little crass, but would it be a workable solution to calculate the LookAt position vector by projecting a ray (from the Camera Position) an arbitrary distance in the LookIn direction, and then simply using D3DXMatrixLookAtLH to generate an acceptable viewmatrix? Could we use trig to calc this, and would it avoid gimbal lock, given that we can perform trig-based math on fixed axes?
Posted on 2003-12-16 03:11:43 by Homer
Afternoon, EvilHomer2k.

You are an idiot ;) .

The following code has been cut out of my "fly" example. The proggy had a "space-buggy" for the player, plus a spacebuggy for the enemy. The camera was set behind and above the players' spacebuggy (the code for placing the camera behind/above has been removed from the following code).

``````
;#########################################
;   the camera (view)

fldz
fst matView.D3DXMATRIX._14
fst matView.D3DXMATRIX._24
fstp matView.D3DXMATRIX._34
fld1
fstp matView.D3DXMATRIX._44

fld right_vector.x
fstp matView.D3DXMATRIX._11
fld up_vector.x
fstp matView.D3DXMATRIX._12
fld lookat_vector.x
fstp matView.D3DXMATRIX._13

fld right_vector.y
fstp matView.D3DXMATRIX._21
fld up_vector.y
fstp matView.D3DXMATRIX._22
fld lookat_vector.y
fstp matView.D3DXMATRIX._23

fld right_vector.z
fstp matView.D3DXMATRIX._31
fld up_vector.z
fstp matView.D3DXMATRIX._32
fld lookat_vector.z
fstp matView.D3DXMATRIX._33

fchs
fstp matView.D3DXMATRIX._41
fchs
fstp matView.D3DXMATRIX._42
fchs
fstp matView.D3DXMATRIX._43
``````

Some things to note:

rollmatrix, yawmatrix and pitchmatrix are just:
``````
LOCAL rollmatrix:D3DMATRIX
LOCAL pitchmatrix:D3DMATRIX
LOCAL yawmatrix:D3DMATRIX
``````

inside the same proc (since they're recreated each time they're used).

Roll, Yaw and Pitch are angles of the object in radians (meaning... 0 or 2*PI is no rotation, while PI would be a 180 degree rotation).

lookat_vector, right_vector, up_vector and position_vector are just:
``````
lookat_vector       D3DXVECTOR3     <0.0f, 0.0f, 1.0f>
up_vector           D3DXVECTOR3     <0.0f, 1.0f, 0.0f>
right_vector        D3DXVECTOR3     <1.0f, 0.0f, 0.0f>
position_vector     D3DXVECTOR3     <0.0f, 10.0f, -30.0f>
``````

inside the programs .data section.
Remember: the camera needs a postion in world space (position_vector) plus a direction (the other vectors).

matView is just your typical D3DMATRIX matrice. It can either be in your .data section or used as LOCALs.
i.e.
``````
...
LOCAL matView:D3DMATRIX
...
mov ecx,CApp_OnlyInstance
``````

~~~~~~~~~~~~~~~~~~~~~

Using movement/rotation code like this makes it *very* easy to move something around.
i.e.
To move an object (camera/particle/pig) forward/backwards in the directions it's facing, you just:
``````
fld lookat_vector.x
fmul fpSpeed
fstp position_vector.x

fld lookat_vector.y
fmul fpSpeed
fstp position_vector.y

fld lookat_vector.z
fmul fpSpeed
fstp position_vector.z
``````

just before you build the matrice (i.e. just *after* the last D3DXVec3TransformCoord call).

Lastly:
The D3DXVec3Dot calculations have their signs changed (using fchs) because position_vector is in *world* coordinates, and we're wanting to change it (back) to *view* coordinates.

Cheers,
Scronty
Posted on 2003-12-16 06:49:47 by Scronty
This is wonderful - I was wondering to myself earlier today how I might manage to combine a PitchYawRoll matrix with a viewmatrix, and you have answered a question which I hadn't even gotten around to answering yet :)
I'm grateful as always for your input, and I do appreciate you taking the time to help me out. Every little thing I pick from ur brain brings me closer to realizing my dream of garage Indy, 80's fashion. Dare to dream :alright:
Posted on 2003-12-16 07:27:38 by Homer
Afternoon, EvilHomer2k.

Stop greasing. Ya making me hungry (grease == grilled lamb chops to me).

A few things I forgot to inlcude in my previous post:

The supplied code is used for all objects in a game (whether they be a camera or computer-controlled or the player/s themselves).
This means that it'd actually make sense to chuck that code into its own proc and just call it for every object.

There're no comments in that code as it was copy/pasted from the first commented code.
So I'll comment it now...;)

The D3DXVec3Normalize, D3DXVec3Cross, D3DXVec3Normalize, D3DXVec3Cross, D3DXVec3Normalize lines are to get rid of gimbal-lock. For people who don't know what this is: When you rotate objects on all three axis, a small error creeps into the calculations due to floating-point rounding errors. Recalculating the look/right/up vectors each time eliminates this error.

The D3DXMatrixRotationAxis, D3DXVec3TransformCoord, D3DXVec3TransformCoord, etc lines are for rotation about the X/Y/Z axis (yaw/pitch/roll). Looking at the code, you'll see that every calculation for each rotation matrice (roll/pitch/yaw) updates their opposing vectors. i.e. the Roll matrix updates the up/right vectors. This makes sure that the main vectors (look/up/right) are always at right-angles to each other.

This stuff:
``````    fldz
fst matView.D3DXMATRIX._14
fst matView.D3DXMATRIX._24
fstp matView.D3DXMATRIX._34
fld1
fstp matView.D3DXMATRIX._44

.. etc
``````

... loads up our matrix (whether a camera or any other object) with the correct values.

And finally, this bit:
``````
just makes sure the position of the object is correct.

Note that the previous code-snippet creates a matrice in view space.
To get a normal objects real matrix (i.e. a normal object is everything that *isn't* a camera), I use immediately after the previous code:
``` Posted on 2003-12-16 19:42:34 by Scronty ```
``` Building a Camera Matrix Yep, that works. Hey, that c++ code was pretty close imho to your version, as was my translation. 1000 ways to skin a cat, as they say. I don't mean to piss in your pocket, but yes, u have more experience than me in this field and on this platform. I tend to call a spade a friggin shovel. Thanks. I'll be away for a few days at the Metal For The Brain gig in Canberra, as a pretence for buying a crapload of fireworks for New Year. Hopefully I'll finish implementing a cheapass version of ArcBall camera control before I leave, and if so I'll post again, if not, it can wait until I get back. Have you ever tried animating a camera view using animation keyframe data? Does Maya and/or 3DS export camera path matrix keys as a series of view matrices, or as separate position/rotation/scale keys? (I am guessing the latter, which seems redundant in respect to a single camera's viewpoint) IE when u draw some curves and then attach a camera to the curve... I'm obviously talking about cutscenes here :) If as seems likely that I won't be around much for the rest of the Silly Season, have a great Christmas/New Year, and don't get too wasted daddy :) (My son is about to start high school and I feel so old lol) Posted on 2003-12-16 20:45:45 by Homer ```
``` <!-- google_ad_client = "ca-pub-5565452985039448"; /* Header */ google_ad_slot = "3725908010"; google_ad_width = 728; google_ad_height = 90; //--> var _gaq = _gaq || []; _gaq.push(['_setAccount', 'UA-11286174-1']); _gaq.push(['_trackPageview']); (function() { var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); })(); ```