Archive for the 'Graphics Programming' Category

Billboarding

Friday, February 2nd, 2007

Because I chose to use Z as the up direction in my world, I couldn’t use XNA’s built-in Matrix.CreateBillboard function (since it thought that (0,1,0) was up). This meant that yet again, I had to roll my own. I thought the code might be useful for anyone trying to do their own billboarding (or doing something special with billboarding, like centering the object around a point not within the object), so I decided to post it. This is viewpoint-based billboarding, so it has to be done for each object, and could be expensive. I like the effect though, so I’ll probably come up with a way to speed it up later.

// Find the directional vector pointing from the camera to the object
Vector3 diff = Vector3.Normalize(CameraPosition – Position);

// Find the axis of rotation
Vector3 axis;
if (Vector3.UnitZ == diff) axis = Vector3.Zero;
else axis = Vector3.Normalize(Vector3.Cross(Vector3.UnitZ, diff));

// Find the degree by which to rotate
float ang = (float)Math.Acos(Vector3.Dot(Vector3.UnitZ, diff));

// Create the billboard transformation
Matrix BillboardTransformation = Matrix.CreateFromAxisAngle(axis, ang);

Basically, this rotates the object around an arbitrary axis, with the axis and amount of rotation always set up such that the object will be facing the camera. This creates true billboarding, as opposed to cheap billboarding (where all objects are aligned with the viewing plane), so it will be a little more expensive.

This is useful for some things like volume rendering using slicing planes, because you can rotate the whole volume around a central point, and have all of the planes still lined up. Also note that I’ve used Vector3.UnitZ – that is my world’s “up” direction. You could replace it with UnitY if you like, or whatever direction you like to have as up.

Isn’t Z up?

Friday, February 2nd, 2007

X and Y have always represented the axis in a plane. To me, when you added a third dimension, it was like stacking planes on top of each other. As you stack more and more planes upon each other, they grow in height. Therefore, it was natural for me to view Z as pointing upward.

Turns out, Z represents depth. In other words, if you imagine your screen as representing the X,Y plane, then Z extends into or out of your screen. It always has, and I always knew it did, but I still thought of Z as pointing upward in a 3D environment – it just made more sense to me.

This was never a problem until I went to program a camera class for the volume rendering I’m working on. A camera is pretty simple – you need three vectors – the camera’s location, the target’s location and a vector representing up (so you can orient the screen properly). Usually you store two angles and a radius instead of (or in addition to) the target’s location so you can easily change them. I figured, “this problem has already been solved plenty of times – I’ll just find some code to guide me so I don’t make any stupid math mistakes when translating from math to code.”

That was the start of the problem. I found a nice solution, and it was in C# for XNA too, but when I hooked it into my code, it didn’t show anything. Oh, I had a nice CornflowerBlue screen, but that was it. After some hunting, I found out that my camera thought that Y pointed up. So did XNA’s Vector3.Up.  Weird.  So, I tried to fix it.

I emphasize that because of what I did: I tried to fix code that I didn’t fully understand.  I knew how a camera worked, but I thought this code would save me some time, so I didn’t bother to figure out exactly how this code was doing it.  I ended up wasting a few hours messing around until I finally just recoded the whole thing myself.

So, lesson learned: if you’re going to use code someone else has written, make sure it fits your requirements, and if it doesn’t, make sure you understand what’s going on so you can fix it.  I still think Z should be up, and it is in my camera, but it makes it hard to use others’ code.  That’s good for me though – I’m still learning a lot, and I should be making things myself for the time being.