Archive

Archive for the ‘Programming’ Category

The Trouble With Quaternions

September 6th, 2010

So earlier this week I decided to write up a 6DOF Quaternion Camera that allows full movement along Yaw / Pitch. After all, I’ve used Quats to great success on animation systems. Anyway after I coded up the camera, I quickly I discovered that if I applied rotation on one axis I was fine (for instance, simply rotated my Camera along Y-Axis). However, if I moved along both Yaw & Pitch then the resulting Quaternion concatenation would incur Roll and lead to undesired effects.

(Note: I’m using a custom Quaternion class that consists of 4 floats however its the equivalent of a D3DXQuaternion)

Code sample:


Quaternion q1 = Quaternion::getIdentity();

//pitch up
Vector3 up(1,0,0);
Quaternion temp(up, 3.14f); //radians
q1 = q1 * temp;

//Look at angle-axis
Vector3 q_axis;
float q_angle;
q1.to_axis_angle(q_axis, q_angle); //debug

//now rotate along Y-axis like a camera
Vector3 heading(0,1,0);
Quaternion temp2(heading, 1.28f);
q1 = q1 * temp2;
q1.to_axis_angle(q_axis, q_angle); //debug

Log("quat test #1 - angle-axis #1 %f %f %f %f\n",q_axis.x,q_axis.y,q_axis.z,q_angle);

Vector3 euler;
q1.getEulerAngles(euler);
Log("euler %f %f %f\n",euler.x,euler.y,euler.z);

This was the program output:

quat test #1 - angle-axis #1 0.802096 0.000476 0.597195 angle: 3.140315
euler 3.141136 0.001526 -1.280000

Notice, in the Euler conversion you can see a little bit of leakage into Roll. The problem is discussed in more detail here at StackOverflow forums. So it looks the general wisdom is to split up the incoming angles, track those separately, then generate the Quaternion from scratch every frame if you go this route. That really is a bloody shame however, since you are completely regenerating a Quaternion every frame. And worst, you later use this Quaternion to most likely rotate a view vector. If you use the traditional method to rotate a vector with a Quaternion you are not really using playing to its’ strength.

Code example:

Vector3 axis(0,1,0); //y-axis rotation
Quaternion q(axis, 1.28f); //angle in radians
q.rotate(ViewVector);

Funny thing is you can do the same exact thing with angle-axis like so (not to mention its faster to transform a Vector via a matrix):

Vector3 axis(0,1,0); //y-axis rotation
Matrix3 m(axis, 1.28f); //angle in radians
m.Mul(ViewVector);

However, since Quaternions are non-commutative you could first apply rotation along Y-axis and then pitch the quaternion via X-Axis. The resulting output in this case is a nice clean Quaternion like one might expect:


quat test #2 - angle-axis #1 0.000476 0.802096 -0.597195 angle: 3.140315
euler 1.280000 0.000000 3.140000

So, simply by applying the rotations in a different order we prevented the leakage. So it is possible to cleanly combine two quaternions and prevent unwanted leakage if you maintain the proper order. However, you can still get into trouble if you perform additional Quaternion math on this concatenated Quaternion later.

Here is an interesting trick though. If you take the Conjugate of the Unit Quaternion you will end up with an Inverse Quaternion. Take this Quaternion and generate a Matrix. If you later use this Matrix to get your Up & Right vectors you can continue to use concatenated Quaternions.


const Quaternion& GetRotation()
{
return m_rot;
}

void SetRotation(const Quaternion& q)
{
m_rot = q;

//Inside the actor/camera class, use the Quaternion inverse to generate a matrix. However, store off your original Quaternion.
Quaternion q1 = q;
q1.conjugate();
q1.normalize();
QuaternionToMatrix(q1, m_quaternionInvMatrix); //Matrix generated using Quaternion inverse
}

Now you have a matrix that was built using the Quaternion inverse. You can actually use this as an actors rotation matrix (like for the spaceship, etc) and put in a 4×4 Matrix along with Translation. The cool thing is that you can also use this Quaternion later and navigate around leakage like so.


void Pitch(float angle)
{
Vector3 dir = m_quaternionInvMatrix.GetRight();
dir.Normalize();

Quaternion t(dir, -angle); //angle-axis to Quaternion

Quaternion q = GetRotation();
q = q * t;
SetRotation(q);
}

Performing rotation along the Y-axis would be the exact same:

void RotateY(float angle)
{
Vector3 dir = m_quaternionInvMatrix.GetUp();
dir.Normalize();

Quaternion t(dir, angle); //angle-axis to quaternion

Quaternion q = GetRotation();
q = q * t;
SetRotation(q);
}

Now you have an Actor that can accurately accumulate Quaternions in a fairly predictable manner. While I used it, I didn’t notice any leakage into Roll and everything worked nicely. I searched around the net for other topics on this but didn’t find anything. However, keep in mind you could also just go with 3×3 rotation matrices as well. Like Quaternions, you will evade the gimbal lock issue and many will find they are very ease to use.

Code example of using angle-axis which also avoids Gimbal Lock and will may possibly be superior to the Quaternion alternative for this purpose. Additionally, you can perform vector interpolation and weigh that against Quaternion::slerp if you like


void Pitch(float angle)
{
Vector3 dir = m_orientation.GetRight();
dir.Normalize();

Matrix3 tm(dir, -angle); //angle-axis to matrix
m_orientation *= tm;
}

Programming

Deferred Rendering

July 31st, 2010

Deferred rendering seems to be all the rage these days. Everyone seems to be implementing it from Starcraft 2 to Uncharted 2 (actually it’s Light Prepass) to Killzone, etc. So we thought we’d dive into this and give it a whirl. The current GODZ demo now has a deferred rendering pipe. My fellow colleague, Wa Kan, hooked up the GBuffer implementation to the engine. I did the deferred lighting side (directional / point lighting). In the current demo, you’ll find that the point lights that are attached to the characters will light up all the pixels within range. I think it looks pretty cool.

Right now the deferred renderer is noticeably slower than the forward renderer (you can hit a key to switch between the two). There’s a few optimizations I can do to speed up the deferred side but I do not expect it to match the forward renderer in performance. However, what deferred rendering brings to the table is a very nice dynamic, per pixel lighting system that can handle multiple lights with fair ease. If I were to try to hookup point lights to the forward renderer, I would have to spend a lot of effort managing the lights.

Programming, Projects

Tools…

May 1st, 2010

Worked on the editor a little bit more over the past few weeks. The C# editor is hooked up to Microsoft SQL Server now. Levels are basically stored directly into the database and can be exported out into the engine’s custom format if required. The editor basically owns it’s own HashString table which it tracks in SQL Server as well. During runtime, most things are now in crc32 format unless a string is absolutely necessary.

Programming

GODZ and Tools

April 11th, 2010

Uploaded a new demo today. This one features more realistic movement for Bot AI. Messing with the tech demo, I am seeing a few areas I’d like to improve next such as Character vs Character collision, etc. However most of the basic elements I’ve always wanted is in place now. I must say, getting the Navigation Mesh and A* algorithm going was a very quick process. I really cant see any reason why any devs would choose path node navigation over meshes off hand.

GODZ Navigation Mesh network is generated online when the game starts atm (eventually I’ll move this offline). Next, all of the entities on the map find their position on the Navigation Mesh (this too, can be moved offline to the editor). After that, the Bot AI actually runs on a different thread, planning it’s navigation to the player using a generic A* algorithm. Everything works fairly nicely and was fairly quick to implement during my sparing free time.

Lately I’ve also being playing with moving my ‘bridge’ code into Managed C++. The Managed C++ interface is a bit cleaner than the C-DLL style exports I was using previously. Most devs still write their game engines using unmanaged C++. However for the studio tools, a lot of devs actually write these in C# (like the Editor for example) and setup a middle Managed C++ layer to link the editor to the game engine. Off hand, I’d like to point out that Bioware’s Dragon Age Origins seems to use a C# editor (checkout their SDK) which hooks up to SQL for the back end. This is pretty much what I’ve had planned too so if you’ve played with their editor then you know what I’m striving for

Still not done porting over my Tools from Win32 to C#. But hopefully I’ll make some significant progress in this area in the next few weeks. The plan is to setup a SQL Server backend which the Editor will access. The game engine will rarely use C strings. Instead CRC32 codes are used which gives faster compares then C-style strings plus occupies less memory. There’s still a lot of work to be done but everything is coming together at a nice rate

Programming

Navigation

March 31st, 2010

Valve put up documentation describing their tech behind Left for Dead 2. It’s interesting to see how they solved the issue whereas the navmesh polygons will give you a jagged path.

Currently in GODZ the Bot AI will use a jagged path to chase the player down. However soon I hope to upload a new build that smooths out the path to make the AI look a bit more natural

Programming

NavigationMeshes and Tools

March 23rd, 2010

Been working on porting over the old godz win32 editor over to C# which has been going pretty well so far. I was basically faced with the choice of using either MFC or C# if I wanted to make the UI more current. Choose C# due it’s nice, clean interface and updated components.

The managed editor interfaces with the unmanaged DLL passing pointers back and forth via IntPtrs, etc. Unmanaged objects are wrapped by proxies on the C# side of the fence. All of the engine functions are exposed as C functions so their names do not get mangled. Levels can be put together in pieces that can be streamed / unloaded during runtime seamlessly. The goal, as always, is to never force the user to sit idle while resources load. So, if you need to load a package, etc you can start the operation and do something else as the package loads in the background

The engine can now generate a Navigationmesh based on a collision mesh that’s passed into it. Once the navmesh is constructed, it can be passed to multiple AI threads which can asynchronously access the navmesh and plan their path navigation using an A* algorithm I just cranked out last night. Currently, I have a bot that will follow me around whereever I go as a simple test

After I’m fairly sure everything is stable, etc I’ll upload a new demo.

Programming, Projects

Fixing Pathfinding Once and For All

February 17th, 2010

So I was browsing the web reading up on Navigation Meshes and ran across and interesting article called Fixing Pathfinding Once and For All. What’s pretty cool is that this article starts off by presenting various examples of failed AI (bots running into walls, etc) and then elaborates how this can be resolved.

As much as I loved Bayonetta, I could’ve sworn I saw an AI get stuck in it’s pathfinding on a wall. On the flipside, I was always in awe when I played Left for Dead 2 (which uses Navigation Meshes). I can’t count how many times I saw the AI pull off something really crazy. Hell, we were practically begging the AI to mess up on several occasions as we tried in vain running around inside of a mall searching for gas cans- trying to get the Tank to lose us.

One of these days I’m thinking I’ll try to put together a demo of some bots running around on a Navigation mesh….

Programming

Power PC / Xbox 360

February 3rd, 2009

Some good reading I’ve checked out lately. And did I forget to mention I love PiX-xbox360? Probably not, but I love it. While reading up on code optimization also came across a good article by my former colleague, Becky Heineman.

Programming

C#

January 15th, 2009

So I’ve been playing around with C# programming language a bit recently. Really just poking around setting up a simple application. I’ve been pretty impressed with it so far. Code seems a bit cleaner then what I’m used to (MFC / Win32).

Programming

New GODZ Build

January 1st, 2009

Just uploaded a new build of GODZ. In this build, I re-enabled the shadowmap quads however they must be turned on in the Default.lua file if you want to see them. Fixed an issue whereas sometimes the shadows would work and other times they would fail completely. I noticed this bug on a friend’s machine and thought that was odd so decided to track it down today. Lastly, I implemented the Animation Blending feature so we can Ease In and Ease Out of animations.

I’m pretty happy with this build seems pretty solid.

Projects