• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
BlurEffect

Quaternion camera performs unwanted roll

11 posts in this topic

Hey guys,

 

I've been trying to figure this out all day and I know that there quite some ressources on that rotation/quaternion stuff out there but I still couldn't figure out the problem. I'm creating an editor in DirectX 11 and are currently doing a camera that can be rotated and moved around using the mouse. Moving the camera works fine. For the rotation I want the user to be able to hold down the right mouse button and perform a free look around. In the code, I chose to use quaternions as I read that they would have quite some advantages compared to other rotation techniques. My code almost works as it should but, although the expression "input.m_rotation.z * ROTATION_SPEED.z" in the code below currently always evaluates to 0, there is still some roll occurring when I rotate the camera. I can't figure out where the problem lies, so I hope you have an idea and can show me what I'm missing or doing wrong. I don't really have experience in using quaternions, so if you can share some knowledge on how to improve the code below in general or on alternate implementations, that would be great, too.

 

(the "input" variable in the code contains the delta movement/rotation to be applied for the current frame based on user input)

XMVECTOR pitchQuaternion = XMQuaternionRotationAxis(XMLoadFloat3( &m_right ), XMConvertToRadians( input.m_rotation.x * ROTATION_SPEED.x));
XMVECTOR yawQuaternion = XMQuaternionRotationAxis(XMLoadFloat3( &m_up ), XMConvertToRadians( input.m_rotation.y * ROTATION_SPEED.y));
XMVECTOR rollQuaternion = XMQuaternionRotationAxis(XMLoadFloat3( &m_lookAt ), XMConvertToRadians( input.m_rotation.z * ROTATION_SPEED.z));

XMVECTOR rotationQuaternion = XMQuaternionMultiply(yawQuaternion, pitchQuaternion);
rotationQuaternion = XMQuaternionMultiply(rotationQuaternion, rollQuaternion);

XMMATRIX matTranslation = XMMatrixTranslationFromVector(-XMLoadFloat3(&input.m_movement) * XMLoadFloat3(&MOVEMENT_SPEED));
XMMATRIX matRotation = XMMatrixRotationQuaternion(XMQuaternionConjugate(rotationQuaternion));

XMMATRIX matTransform = XMMatrixMultiply(matTranslation, matRotation);
XMStoreFloat4x4(&m_viewMatrix, XMMatrixMultiply(XMLoadFloat4x4(&m_viewMatrix), matTransform));

If you need more information, please ask. Thank you very much in advance for your effort!

0

Share this post


Link to post
Share on other sites

It looks very similar to the way I did my mouse look code as well. Here are the relevant snippets you might be interested in:

Camera3D:

/// <summary>
/// This increments the camera look-at position by the given radian angles:
///  [yaw, pitch, roll]
/// </summary>
/// <param name="d_xyz">these are the angles to change orientation by.</param>
public void RotateBy(Vector3 d_xyz)
{
m_rotation *= Quaternion.CreateFromAxisAngle(Vector3.Up, d_xyz.X) * Quaternion.CreateFromAxisAngle(Vector3.UnitZ, d_xyz.Y) * Quaternion.CreateFromAxisAngle(Vector3.UnitX, d_xyz.Z);

m_lookAt = m_position + Vector3.Transform(Vector3.UnitX, m_rotation);
m_up = Vector3.Transform(Vector3.Up, m_rotation);

UpdateView();
UpdateFrustum();
}

MouseLook Code:
 

if (Mouse.GetState().RightButton == ButtonState.Pressed)
{
	int yaw = Mouse.GetState().X - m_lastMouse.X;
	int pitch = Mouse.GetState().Y - m_lastMouse.Y;
	if (yaw != 0 || pitch != 0)
	{
		if (Keyboard.GetState().IsKeyDown(Keys.LeftShift))
		{
			m_sceneDB.ActiveCamera.RotateBy(new Vector3(MathHelper.ToRadians(-yaw / 10.0f), MathHelper.ToRadians(-pitch / 10.0f), 0));
		}
		else if (Keyboard.GetState().IsKeyDown(Keys.LeftControl))
		{
			m_sceneDB.ActiveCamera.RotateBy(new Vector3(MathHelper.ToRadians(-yaw * 3.0f), MathHelper.ToRadians(-pitch * 3.0f), 0));
		}
		else
		{
			m_sceneDB.ActiveCamera.RotateBy(new Vector3(MathHelper.ToRadians(-yaw), MathHelper.ToRadians(-pitch), 0));
		}
		
		Mouse.SetPosition(m_lastMouse.X, m_lastMouse.Y);
	}
}

I think one difference between my implementation and yours is that I am simply adding a delta rotation to an existing quaternion rotation and your implementation is creating a new quaternion rotation based on the yaw, pitch and roll values. I'm not sure if that's where the error is coming from, but that might be a good place to look first.

You can also decide to manually set the roll to zero each frame, but that's kind of a hackish solution.

Edited by slayemin
0

Share this post


Link to post
Share on other sites

If you are using free look, and you look up a little and then move the mouse straight left, you will end up with the horizon slanted. Is that what you mean? To avoid that you have to take extra steps which I can't remember right now.

0

Share this post


Link to post
Share on other sites

First of all: Thanks guys for your swift answers!

The question of NumberXaero brought me on the right track because currently I'm actually not updating the m_right, m_up, and m_lookAt vectors at all. That's probably the reason for the weird behaviour of the camera. I can't believe I didn't think of that myself, I assume I just sat too long in front of that code yesterday.

So, how can I update these vectors if I have a quaternion for the camera rotation? Can I simply multiply them with the quaternion?

Cheers guys!

0

Share this post


Link to post
Share on other sites

Ok, I've figured it out myself, kind of...

Updating the lookAt and up vector for the given rotation quaternion works just fine and the camera seems to behave just as I want it to. But when I additionally update the right vector in a similar fashion (which I thought should also be necessary) I get this unwanted roll again when rotating the camera. I also tried to get the new right vector by calculating the cross product of up and lookAt vector but that didn't improve anything. I'm posting the code below. Any hints?

XMVECTOR v = XMQuaternionMultiply(rotationQuaternion, XMLoadFloat3( &m_up ));
XMStoreFloat3(&m_up, XMQuaternionMultiply(v, XMQuaternionConjugate(rotationQuaternion)));
	
v = XMQuaternionMultiply(rotationQuaternion, XMLoadFloat3( &m_lookAt ));
XMStoreFloat3(&m_lookAt, XMQuaternionMultiply(v, XMQuaternionConjugate(rotationQuaternion)));
	
// if I include the two lines below I get the unwanted roll, if I leave it commented out the camera seems to work properly
v = XMQuaternionMultiply(rotationQuaternion, XMLoadFloat3( &m_right ));
XMStoreFloat3(&m_right, XMQuaternionMultiply(v, XMQuaternionConjugate(rotationQuaternion)));

// This is what I tried as an alternative to the line above, with no success
XMStoreFloat3(&m_right, XMVector3Cross(XMLoadFloat3(&m_up), XMLoadFloat3(&m_lookAt)));
0

Share this post


Link to post
Share on other sites

I don't even use a right vector in my camera code. I figure that the "up" and "lookat" vectors are enough. If I need a right vector, I can derive it from those two vectors by using a cross product. The only time I'd really need a right/left vector is for moving the camera on its lateral axis. But, that can be accomplished with a transform as well. Here is my code for panning the camera which demonstrates this:

 

/// <summary>
/// This pans the camera along its left direction vector by an amount
/// </summary>
/// <param name="amount">The amount to pan by (use negative values to pan right)</param>
public void Pan(float amount)
{
	Vector3 DirVec = Vector3.Transform(Vector3.Forward, m_rotation) * amount;
	m_position += DirVec;
	m_lookAt += DirVec;
	UpdateView();
	UpdateFrustum();
}
0

Share this post


Link to post
Share on other sites

But what about the pitch rotation? I thought you would need the current "right" vector to properly calculate that rotation. It's just weird that it works perfectly without doing anything to the right vector and I don't like that I don't really understand it.

0

Share this post


Link to post
Share on other sites

Ive had this problem before when using input values to incrementally rotate. The way I fixed it was to track the total rotation about each axis, and then rebuild the orientation each frame. So...

 

// Get Input
vec3 pitchYawRoll;   // add up your angles here, clamp, wrap, convert to radians, etc

// Updating
quat qPitch, qYaw;
qPitch.FromAxisAngle(UNIT_X, pitchYawRoll.x);        // build pitch
qYaw.FromAxisAngle(UNIT_Y, pitchYawRoll.y);          // build yaw

quat qPitchYaw = qYaw * qPitch;
vec3 forward = qPitchYaw * UNIT_Z;    // create forward

quat qRoll;
qRoll.FromAxisAngle(forward, pitchYawRoll.z);    // roll about current forward

quat final = qRoll * qPitchYaw;

 

// then if you want up and right

vec3 right = final * UNIT_X;

vec3 up = final * UNIT_Y;

// or calc 1 of the above and do cross product with forward to get the other

 

Your rotation order may be different, etc, but thats the general idea I use.

Edited by NumberXaero
0

Share this post


Link to post
Share on other sites

I went with a similar solution to what NumberXaero posted and it worked fine. Thanks everybody for your effort!

0

Share this post


Link to post
Share on other sites

I went with a similar solution to what NumberXaero posted and it worked fine. Thanks everybody for your effort!

If you want to have a better understand why NumberXaero method works is because you are not accumulating the rotation over time. The reason why you get this weird tilt is because i bet you were doing rotation*=currentRotation, so the tilt you were getting is correct. By rebuilding the rotation matrix you change the order in wich the rotation are applied which in terms give you the correct orientation.

0

Share this post


Link to post
Share on other sites

Interesting... will it not brake camera rotation aroud itself? I know that just changing the multiplication order also gives this effect, but it brake camera rotation on 360 degrees and make it rotation not arount itself, but around "north and south" poles and also flipping on 180 degrees on the each pole.

Edited by BlackJoker
0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0