So if i'd use matrices, would you guys then look at my idea (3d shapes in a voxel editor)?
Or should i start a new thread for that and leave this thread for arguing matrix vs quat ?
Hi nikki, I carefully re-read your original post.
Since it sounds like you just want a way to rotate the voxels in your models by angles other than 90 degree steps, I would recommend sticking to matrices. Note that if you want to only rotate around the height vector, but by any angle, you can just use a simple angle. But if you want to rotate in other ways, you'll need to use a matrix or quaternion.
The real trick for you will be:
- First get a simple system up and running that will let you transform voxels by a matrix. If you can find a matrix library and play around with it, that will be easiest. I don't recommend to write your own matrix library as it's very error-prone, even if you know the math very well.
- Learn a few basic ways of describing rotations, conceptually. Euler angles, which is basically saying "rotate by A degrees around the X axis, then B degrees around the Y axis, then C degrees around the Z axis" may seem simple-- but they can actually be awkward to work with. So this is a pitfall to avoidFollowing up on the above idea, the most useful way I have for thinking about rotations is "align" transformations.
Imagine you have a vector, V_source = (0, 0, -1)
Imagine this is a "stick" model, just an ordinary stick that might be on a tree. It's x and y dimensions will be small and square, let's say, but it will point straight up (z = -1) so it's z dimension will be long. So you've got this simple rectangular prism which has dimensions such as (1, 1, 10) and it's textured to look like a branch.
Now you are making a tree out of this, and you want the branch to stick out at an angle from the trunk. Here's how you can do it using "align" transformations:1. First, we need to randomly choose a way for it to stick out. We'll do this like so:
V_dest = (rn () * 2 - 1, rn () * 2 - 1, -3)
What this will result in is a vector that looks maybe like one of these:
(0.235, -0.422, -3)
(0.983, 0.368, -3)
(-0.288, -0.717, -3)
You get the idea. Vector with a smallish x and y part, and a z part that is always -3.2. The next thing we do is normalize the vector, so it's length is 1.
V_dest_n = normalize (V_dest)3. What we would like to do now, is this:
Create a matrix, M, that will "align" our source vector V_source (this is a line pointing straight up) to our dest vector V_dest_n (this is a line pointing MOSTLY up, but also out at some random amount, in some random direction.)4. How do we do this?
]Well first, when you create a rotation using a matrix, one of the most basic ways to do it is "axis angle". What this means is you specify an axis to rotate around (can be any vector at all, not just the x/y/z axes) and an angle to rotate by. If you use a matrix library, you will almost definitely have a function like this-- and don't confuse it by euler angles, they are very different. "Axis angle" is basically the MOST useful and practical way to think about rotations.5. So the trick will be describing the above "align" operation in terms of axis angle.
Well, it turns out there is a way to do this without much difficulty at all.
I won't go into the math here, but you should learn about cross products and dot products. A cross product takes two input vectors and gives you an output vector that is perpendicular to both. If you want to be good at 3D, PRACTICE VISUALIZING THIS. Visualize different vectors in 3D, and then see if you can imagine a vector pointing that is perpendicular to them. Anyhow, what we want to do is rotate by this perpendicular vector:
V_axis_of_rotation = cross_product (V_source, V_dest_n)
Now we have the axis to rotate around, we are almost ready to build the matrix we need. 6. We just need an angle to tell our matrix library. It turns out that we can do this very simply:
angle_of_rotation = acos (dot_product (V_source, V_dest_n))
Again, I won't go into the math. You should definitely learn what a dot product is-- it takes two vectors, and gives you a number -1..1 describing how closely they line up. 0 means they are perpendicular, -1 means they point exactly in the opposite direction.7. We have our axis and angle, so we can do:
M = axis_angle_matrix (axis_of_rotation, angle_of_rotation)
And apply it to every point in our original branch:
transformed_stick = M.apply_to_mesh (original_stick_mesh)8. There are two degenerate cases.
Basically, the cross product will not work when the two vectors are exactly the same or exactly opposite. In case they are extremely close, it may fail as well due to numerical issues. For that reason, we should check when we are building our matrix that we didn't try to create a degenerate rotaton, which we can do quite easily if the absolute value of the dot product is too great (say, greater than 0.99999)
This might seem complex, but please DO READ IT! Read it over and look up the things described in it. If you really want to do free rotations, this is a great way to start thinking about them and describing them.
Long post! Class dismissed =)