• Advertisement
Sign in to follow this  

Build View Matrix From Quaternion

This topic is 620 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello,

 

Recently, I have switched from euler angles to quaternions. For this reason, I cannot use the D3DXMatrixLookAtLH function anymore. So, I'm trying to build my View Matrix from scratch, but everything went wrong. What I want to achieve is the same result that D3DXMatrixLookAtLH offers, but with my own View Matrix the Look At vecotr is completely messed up. Like, positive X is downward, positive Y is on the right and I have no idea what Z is doing.

D3DXMatrixRotationQuaternion(&_orientation, &_quat);
	D3DXMatrixTranslation(&_translation, _position.x, _position.y, _position.z);
	_viewMatrix = _orientation * _translation; 
	D3DXMatrixInverse(&_viewMatrix, NULL, &_viewMatrix);
return _viewMatrix;

_quat is the quaternion obtained from the Euler angles representing the Look At vector.

 

This code is based on another post found on this forum: http://www.gamedev.net/topic/402659-quaternion/#entry3673546

 

What is the problem? I can say it's not a quaternion problem, I tried to switch back to Euler angles and the result is the same. There is something wrong in the logic I'm using.

 

Also, when building your own View Matrix, what about the Up vector? Why am I missing it?

 

Thanks in advance.

Edited by Deathlike

Share this post


Link to post
Share on other sites
Advertisement

So, to answer the question directly, a quaternion is basically a substitute for an orientation matrix. If you understand the 4 by 4 game matrix, the quaternion basically takes the place of the 3 by 3 matrix inside the 4 by 4 matrix which tracks orientation. In other words, it's basically the same thing except the 4 by 4 matrix also has the advantage of storing scale and position in addition to orientation. The quaternion is orientation only. So, those other values have to be stored separately.

 

That being said, you can merely convert the quaternion to a rotation matrix to make it work with your other matrices. Every 3D shader I've seen so far wants the View matrix to be a matrix. So, using quaternions means constantly converting back and forth.

 

Generally, I'm against using quaternions. I've used them enough to get over the fascination with them and now it's simply a matter of what is practical. There are cases where quaternions are the answer. SLERP (Spherical Linear Interpolation) is used in animation because you are calculating rotations between two given rotations. I don't even think you can really do SLERP with matrices and if you can it's far more difficult than using quaternions for it. Outside of SLERP, I've never seen a single valid reason to use quaternions, although I'm open to suggestions.

 

Since the shader wants to be fed matrices, I strongly favor matrices over quaternions. I see quaternions used a fair amount, so I'm sure some will disagree with me. But all I really care about is what is most efficient. If it can be shown that the quaternion is more efficient, then I'm all for it. I've just never seen that case outside of SLERP, yet.

 

This is being a bit pedantic, but no one actually uses Euler angles. Pitch, Yaw, and Roll are most closely related to Tait-Bryan angles. The funny thing is is that the mistake has been made so many times in the game industry that the term Euler angles has basically taken on the new definition. It's like all sodas being cokes, or all facial tissues being klenax, or all adjustable end wrenches being cresent wrenches. Eventually, if enough of the people make the exact same mistake in the language, the definition changes. So, now you have to call actual Euler Angles "Classic" Euler Angles. I include this bit of trivia just for the knowledge as none of this really matter in terms of getting the game working.

 

The "Up" vector is a vector that point to the area above the camera. This is down when you are upside down. Somewhere on this forum, I posted something in the last 48 hours explaining in painful detail how this works.

 

But I think I have the exact solution you're looking for. I have a video on Gimbal Lock on my YouTube channel, VirtuallyProgramming.com. I think it goes into quite a bit of detail about the problem you are facing and how to deal with it because it sounds to me like you are facing Gimbal Lock. People assume quaternions are the way to resolve this, but they are not really the answer. I demonstrate in the video how to obtain Gimbal Lock using quaternions, which is supposedly impossible. It's just as easy to get Gimbal Lock with quaternions as it is with matrices.

 

The real order of the videos is Vectors, Matrices, and then the Gimbal Lock video. So, if you don't understand any of that or are a little shaky on the understanding of those things, I encourage you to watch those videos. It's a whole lot of time (about 4 to 4.5 hours in total), so there went your Saturday. But I think it's well worth it if you are new to these subjects (being biased since I am their author). I basically try to cram a Linear Algebra course into 4.5 hours and so I think that's actually fairly quick for the amount of information. Plus, you can rewatch the videos if you think you need to.

 

Anyway, I suspect you will find those videos very helpful.

 

Since you are doing DX, you may want to check out my bare bones game engine code on my website:

http://virtuallyprogramming.com/DirectX11/Tutorials/Tutorials.html

 

There you have all the C++ and DX code to put models on the screen and move them around as well as basic input to move the camera around the scene and such. I include different versions of the projects as I build it up from scratch. So, you can look at the earlier versions to make it less confusing than having to deal with all the code at once. Seeing how the more basic version works might be helpful in understand it. But the final version has a model class that uses a custom model importer I wrote in Python to export Blender models into the engine and a C# program to read the data in those files more easily. All the code is including including the HLSL, Python, and C# code.

 

But if nothing else, I would recommend watching my Gimbal Lock video, because that sounds like exactly what you are facing. It's demonstrated with XNA, because that was the fastest way to code it, but it's all math and will apply to anything you do. So, it also covers how to create the problem and how to resolve it in code.

Share this post


Link to post
Share on other sites

Thanks for answer, I'm currently watching the videos. The idea you gave of the gimbal clock is much clearer than wikipedia. :)

 

However, still it doesn't answer to my question. Am I doing something wrong with my View Matrix? Or should I revert everything and use a matrix to store rotations like you did in your video?

Share this post


Link to post
Share on other sites

Speaking of Wikipeidia, I can't even begin to tell you how many years I struggled to learn quaternions. I know I have at least one complete book on nothing but quaternions in my library somewhere. I may have as many as 3 books that are only about quaternions.

 

Learning matrices was what really helped me figure out quaternions more than anything because you use them pretty much the same way you use matrices.

 

Quaternions themselves are a good way to short circuit your brain and cause it to explode. :-) They are hyper-dimensional imaginary numbers. (Technically, they are 4 dimensional complex numbers, a complex number having 1 real component and 3 imaginary components. Most people's brains explode just trying to understand imaginary numbers let alone all this other stuff.)

 

Fortunately, we only use one extremely special type of quaternions known as "unit quaternions". Since quaternions live in 4 dimensional reality, and we live in 3 dimensional reality, I don't even know if it's truly possible to really conceptualize them. It's kind of like if you only lived in a 2D world, like a photograph, and you were trying to understand our 3D world we live in. The 2D image just isn't quite the same as the 3D world. At best, you can kind of move things around to shift that dimension you can't directly experience, so you can see it some of the time. If you have some extra time, YouTube has some explanations of how to conceptualize a 4th dimension.

 

I looked for a qood video explaining unit quaternions but can't find one. Wish I could.

 

I'm not really against using quaternions. Personally, I use matrices for pretty much everything. That's mainly because the input of the shader that draws everything is usually 3 matrices (world, view, and projection) and if you use quaternions, you eventually have to convert it back to matrices in the end anyway. Matrices also have the advantage of storing position and scale which quaternions cannot.

 

I would recommend learning to use both quaternions and matrices and then use whichever you think is best for what you are doing.

 

As for the view matrix. My Gimbal Lock video shows how to store an orientation of an object as a quaternion. So, the difference between that and a view/camera matrix is that the view/camera matrix does everything backwards. I mostly explain this in my matrix video. So, any operation you apply to it must be inversed.

 

So, if your view/camera is a quaternion, start with an identity quaternion which will have it facing down a known given axis. That gets you started from a known place. Remember that the quaternion can't store position. So, you've got to work that out separately. With only quaternions, the camera can rotate but can never move from the world's origin.

 

So, if you want to rotate, you build a quaternion containing that rotation. Say when the user hits the D button you build a quaternion that rotates a given amount per frame around the Y axis (which will say is the up & down axis). Every frame while the D key is being held you apply that quaternion to the view/camera quaternion.

 

You can do the same thing in the opposite direction. And you can do the same thing for the other two axes connecting them to the WASD keys. Maybe use Q & E for the 3rd axis.

 

So, for a normal object, you would convert the quaternion that holds the current orientation to a rotation matrix and that would be the object's world matrix. You could think of this as the object having an identity (empty) matrix (making it face down a known given axis) and you multiply the rotation matrix to re-orient it to face the new direction for this frame. But that's like multiplying any number times 1; the rotation matrix by itself does the same thing.

 

However, the view/camera matrix is backwards. So you have to run the rotation matrix through the inverse function to make it backwards. Viola, you now have a correct view matrix using quaternions.

 

What I'm suggesting is to not build the view matrix every frame with a LookAt function, but rather store the orientation from one frame to the next either in a quaternion or my preference a matrix (the matrix can also store position and allow the camera to actually move to a new position).

 

However, if you really want to have the equivilent of a LookAt function using a quaternion, here is what I would do. We're only dealing with a single frame here (which in some ways makes it easier to understand). So, we start with an identity matrix as our view matrix (camera). This centers the camera at the world origin looking straight down the axis (Z I believe in DirectX and most software). Still you really need to store the orientation from frame to frame in a quaternion or matrix or you are pretty much guaranteed to get gimbal lock. As long as you stay on a 2D plane in 3D space you can make it so the bad gimbal is on the axis you never use. This mostly eliminates the problem for just walking around, but heaven forbid if you are making a flight simulator and doing pitch, yaw, and roll.

 

So, you should have an orientation quaternion that started as an identity (empty) quaternion and you applied rotation quaternions to in order to rotate it into the orientation you want. Turn that into a rotation matrix.

 

Then you can take your 3D position and turn that into a translation matrix. Combine the two into one matrix by multiplying them together. (The order of multiplication matters here. Reverse it if it's wrong.) Then, use the inverse function to invert that matrix. Now combine (multiply) that matrix times your identity matrix you started with for the camera (or don't since this is the same thing as multiplying by 1 and will give you the same thing you started with).

 

There, you just build a view matrix out of a quaternion.

 

As I think about it, a LookAt function doesn't really make sense with a quaternion. LookAt takes a known position, a position to look towards, and a direction that points up. The whole point of a LookAt function is to build a matrix that you can easily understand. But the matrix can hold a position, the quaternion cannot. So, for a quaternion, the LookAt fuction would need to output a quaternion and a 3D position to hold the same information as a matrix. The position is whatever the position you gave it was. So, really all you're trying to do is produce a quaternion that faces a given direction. That's probably most easily built by the functions that allow you to build quaternions.

 

I think the easiest way to do this is to use the standard LookAt function to build a matrix and then convert the orientation info in the matrix into a quaternion. So, your quaternion LookAt function would be to use a matrix LookAt function to build a quaternion and a 3D position.

 

I can't imagine a more efficient way to do this. You pretty much have to have 3 orthogonal vectors in order to build a quaternion. That's what a LookAt function does when it builds a 4 by 4 matrix. Actually, you could do it by building a 3 by 3 orientation matrix, the 4th row and column is for the position that the quaternion doesn't know what to do with. That's the only way I can think of to tell a quaternion how to look at a given spot other than your quaternion functions that rotate the quaternion.

 

You can build a quaternion from yaw, pitch, and roll for a single frame (just don't use Yaw, Pitch, and Roll to store the orientation between frames or you will have a disaster. Use the quaternion to store orienation information, or a matrix).

https://msdn.microsoft.com/en-us/library/windows/desktop/bb281651(v=vs.85).aspx

 

But the easiest way I know to get a quaternion to look at a given spot is to use the LookAt function to build a matrix. Then use the "convert matrix to quaternion" function.

https://msdn.microsoft.com/en-us/library/windows/desktop/bb281650(v=vs.85).aspx

 

Then you'll have a quaternion that looks at a specific direction. You've lost the position information at that point unless you stored that separately somewhere. So, the quaternion only describes the direction. You'll have to somehow marry that back to the position in order to have it actually look at a given spot.

 

The quaternion is basically the equivilent of a rotation matrix (when you build a new rotation matrix it does not yet contain position data which you can add by combining it with a translation matrix which is only position by multiplying the two together). And you can convert back and forth between a rotation matrix and a quaternion. The advantage of the quaternion is to hold that orientation info from frame to frame and especially to use SLERP to calculate an orientation a given percentage of the way between two orientations probably over many frames.

 

I would probably recommend forgetting the quaternions until you've mastered the matrices. There's no reason you can't use quaternions, but there's several reasons I think matrices are a better answer until you find a specific case (like SLERP for 3D keyframe animation) where quaternions do a better job.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement