Camera rotation based on Camera.view > target vector
category: general [glöplog]
Here it's a newbie questions.
I have a Camera object, with a target, and I'm trying to get the rotationX, rotationY, rotationZ of the camera (which is later used on the raster loop) from the Camera.view > Camera.target vector.
This is more or less what I have so far (yes, you can laugh):
But I'm not getting too far, it's hard to control what's going on... Any ideas?
I have a Camera object, with a target, and I'm trying to get the rotationX, rotationY, rotationZ of the camera (which is later used on the raster loop) from the Camera.view > Camera.target vector.
This is more or less what I have so far (yes, you can laugh):
Code:
var vector : Point3D = new Point3D();
vector.add(this); // view vector
vector.sub(target);
vector.normalise();
rotationX = Math.atan2(vector.y, vector.z);
rotationY = -Math.atan2(vector.z, vector.x) + NumberUtils.deg2rad(90);
rotationZ = Math.atan2(vector.y, vector.x);
But I'm not getting too far, it's hard to control what's going on... Any ideas?
hum? if you take the dot-product of the camera vector and target vector you get the cosine-angle between them. im not sure if that's what you're out after?
maybe if u tell why you need these rotationx rotationy it will be simplier...
trace, with rotationx and rotationy (if these are width and height in the screen), you should make the scene look in the direction of the camera. Then the rotation z is just the roll
rydi is right but why do you need the rotation angles at all? usually you set up a camera matrix and then work with that matrix instead of individual rotation angles ?!
hermes, the rotation matrix is the same as rotating by angles... I suppose trace want to do it with angles because his engine is based in rotations... so he doesn't have to make the matrix multiplier
trace: you can read about Camera matrix.
Also, about the cameras based in 2 vertex (eye and target). The vector of it doesn't contain all the camera information, you don't have the roll. The roll should be stored elsewhere. (Also, you don't have the fov and any other camera properties)
Also, about the cameras based in 2 vertex (eye and target). The vector of it doesn't contain all the camera information, you don't have the roll. The roll should be stored elsewhere. (Also, you don't have the fov and any other camera properties)
cheap CPU-wise....is intelligent ! why burn cycles for unneeded math ? ( directX suxx btw ;) )
texel: no, the rotation matrix is usually used to rotate around two or three vectors if one counts the up-vector as the latter one.
dont forget to perspective project your 3d-coordinates before rasterization. that's not a bad thing to do. :)
rydi, sorry, I wrote it not very good... What I wanted to say is that with a rotation matrix you can do the same as doing 3 rotations at the same time.
cocoon, I believe he is coding in Flash, so no DX
Code:
vector = (target-this)^0
rotation_y = atan2(vector.x, vector.z)
rotation_x = atan2(|vector.xz|, vector.y)
rotation_z = 0
i keep forgetting which way atan2 takes its parameters, which handed the coordinates are etc but with enough permuting you should get it right :)
the up vector is just like (0,0,1); you can tweak these values.
to get the camera working you can try this code...
to get the camera working you can try this code...
Code:
void Camera(Vector &pos, Vector &tar, Vector &up)
{
Vector n = eye - tar;
Vector u = crossproduct(up, n);
u.Normalize();
n.Normalize();
Vector v = crossproduct(n, u);
//create the viewmatrix
float viewmatrix[16] =
{
u.X, v.X, n.X, 0.0f,
u.Y, v.Y, n.Y, 0.0f,
u.Z, v.Z, n.Z, 0.0f,
-(pos * u), -(pos * v), -(pos * n), 1.0f
}
//multiply matrix with all vertices or something..
}
multiplying the matrix with your object/world-space vectors you can just make a function that does this for you:
//nv is the new translated vector and can be rasterized after the perspective projection transform.
Vector nv;
float *m = &viewmatrix;
//usually you lookup vector-coords via face/triangle-indeces before transformation, but here are the matrix->vector multiplier:
for (int i=0; i<object->num_vertices; i++)
{
Vector *v = object->get_vertex(i);
nv.x = m[0] * v->x + m[1] * v->y + m[2] * v->z;
nv.y = m[3] * v->x + m[4] * v->y + m[5] * v->z;
nv.z = m[6] * v->x + m[7] * v->y + m[8] * v->z;
//perspective transform (3d->2d screencoordinates)
//rasterize with new coords
}
//nv is the new translated vector and can be rasterized after the perspective projection transform.
Vector nv;
float *m = &viewmatrix;
//usually you lookup vector-coords via face/triangle-indeces before transformation, but here are the matrix->vector multiplier:
for (int i=0; i<object->num_vertices; i++)
{
Vector *v = object->get_vertex(i);
nv.x = m[0] * v->x + m[1] * v->y + m[2] * v->z;
nv.y = m[3] * v->x + m[4] * v->y + m[5] * v->z;
nv.z = m[6] * v->x + m[7] * v->y + m[8] * v->z;
//perspective transform (3d->2d screencoordinates)
//rasterize with new coords
}
bah the last code was messy and probably wrong too, here's a new one:
anyway, you get the idea... just tweak the values until it works :P
anyway, you get the idea... just tweak the values until it works :P
Code:
//nv is the new translated vector and can be rasterized after the perspective projection transform.
Vector nv;
float *m = &viewmatrix;
//usually you lookup vector-coords via face/triangle-indeces before transformation, but here are the matrix->vector multiplier:
for (int i=0; i<object->num_vertices; i++)
{
Vector *v = object->get_vertex(i);
nv.x = m[0] * v->x + m[1] * v->y + m[2] * v->z;
nv.y = m[4] * v->x + m[5] * v->y + m[6] * v->z;
nv.z = m[8] * v->x + m[9] * v->y + m[10] * v->z;
nv.w = m[12] * v->x + m[13] * v->y + m[14] * v->z;
//perspective transform (3d->2d screencoordinates)
//rasterize with new coords
}
Just to clear things up, this is the projection code I have. I think it's the called euler angles transformation.. or something, I'm really bad for names... It was just faster than matrix transformations (all this is for flash/actionscript).
216 reply looks more like what I was after. I'm going to play a bit with that. Thanks everyone!
Code:
x1 = (point.x * mesh.scaleX) * mesh.cosZ - (point.y * mesh.scaleY) * mesh.sinZ;
y1 = (point.y * mesh.scaleY) * mesh.cosZ + (point.x * mesh.scaleX) * mesh.sinZ;
x2 = x1 * mesh.cosY - (point.z * mesh.scaleZ) * mesh.sinY;
z1 = (point.z * mesh.scaleZ) * mesh.cosY + x1 * mesh.sinY;
y2 = y1 * mesh.cosX - z1 * mesh.sinX;
z2 = z1 * mesh.cosX + y1 * mesh.sinX;
x2 += mesh.x;
y2 += mesh.y;
z2 += mesh.z;
x2 -= camera.x;
y2 -= camera.y;
z2 -= camera.z;
x3 = x2 * camera.cosZ - y2 * camera.sinZ;
y3 = y2 * camera.cosZ + x2 * camera.sinZ;
z3 = z2 * camera.cosY + x3 * camera.sinY;
x4 = x3 * camera.cosY - z2 * camera.sinY;
y4 = y3 * camera.cosX - z3 * camera.sinX;
z4 = z3 * camera.cosX + y3 * camera.sinX;
point.sz = camera.focus / (camera.focus + ( camera.z - z4 ));
point.sx = camera.target.x + x4 * point.sz;
point.sy = camera.target.y - y4 * point.sz;
216 reply looks more like what I was after. I'm going to play a bit with that. Thanks everyone!
forget about atan2 btw ;)
SLOW!
SLOW!
Cameras are serious business. I'm trying to figure out how to do a decent camera for ages.
Slow doesn't matter if you only calculate angles say once per frame. The problem is that as previously mentioned two vertices don't contain all the information necessary for the world->camera space transform (roll is missing), so of course it's hard to control the behaviour of the camera when it has an undefined property.
You can maintain roll separately, but you have to invent that behaviour yourself. In the end you'll find it's much easier to think of camera space as three vectors moving around in world space. One points in the direction the camera is viewing, one points "up" (from the camera's perspective), always at a right angle to the first, and the third is perpendicular to the direction and the up vector. Translation from world space to camera space is then a straightforward change from one orthonormal basis to another.
So, take your camera position C, your target position T and an "up" vector u. This gives you:
Origin of camera space expressed in world space coordinates: C
Normalised direction vector: cz = (T - C)/dist(T, C)
Up vector: cy = u
Third vector/axis: cx = cz x cy (cross product)
With cx, cy and cz being column vectors, the camera matrix is then M = [ cx cy cz ]. Because M is orthonormal (all columns are vectors of length one and all are perpendicular), its inverse, M^-1, is equal to its transpose M^T, and then the translation of any point P from world to camera space is simply:
f( P ) = M^T * (P - C)
No sin or cos necessary, and no angles required. You also eliminate the headaches caused by the order in which you do the three separate rotations. On top of that, in code form, the above expression is much simpler than the code you pasted.
For a target camera, you still need some way to determine cy, but with this approach you only have to think of it as asking "from the observer's perspective, which direction is up?" Give any unambiguous answer like "up is as directly towards the sky as possible" or "up is towards this other point that I'm moving around along with the camera" or "up is as close as possible to what it was in the previous frame", and you'll always be able to construct a solution from that.
The same applies to your objects, actually. The whole thing gets soooo much simpler if they're described as meshes in local object spaces. You'll even find that the transformation from object to world to camera space reduces to a single matrix multiplication giving you the most FPS for your MHz.
You can maintain roll separately, but you have to invent that behaviour yourself. In the end you'll find it's much easier to think of camera space as three vectors moving around in world space. One points in the direction the camera is viewing, one points "up" (from the camera's perspective), always at a right angle to the first, and the third is perpendicular to the direction and the up vector. Translation from world space to camera space is then a straightforward change from one orthonormal basis to another.
So, take your camera position C, your target position T and an "up" vector u. This gives you:
Origin of camera space expressed in world space coordinates: C
Normalised direction vector: cz = (T - C)/dist(T, C)
Up vector: cy = u
Third vector/axis: cx = cz x cy (cross product)
With cx, cy and cz being column vectors, the camera matrix is then M = [ cx cy cz ]. Because M is orthonormal (all columns are vectors of length one and all are perpendicular), its inverse, M^-1, is equal to its transpose M^T, and then the translation of any point P from world to camera space is simply:
f( P ) = M^T * (P - C)
No sin or cos necessary, and no angles required. You also eliminate the headaches caused by the order in which you do the three separate rotations. On top of that, in code form, the above expression is much simpler than the code you pasted.
For a target camera, you still need some way to determine cy, but with this approach you only have to think of it as asking "from the observer's perspective, which direction is up?" Give any unambiguous answer like "up is as directly towards the sky as possible" or "up is towards this other point that I'm moving around along with the camera" or "up is as close as possible to what it was in the previous frame", and you'll always be able to construct a solution from that.
The same applies to your objects, actually. The whole thing gets soooo much simpler if they're described as meshes in local object spaces. You'll even find that the transformation from object to world to camera space reduces to a single matrix multiplication giving you the most FPS for your MHz.
Well, using atan or atan2 won't affect much to performance... as I would be doing it only twice per camera movement position change. Is not that it's going to be done for each vertex/frame...
Thanks a lot for the explanation "Christmas Device", it's all starting to make much more sense to my average mind. It also helped some raycasting tests I did recently.
I got the feeling I'll be moving my engine to matrix mode in the end. But this will be after I get this project I'm working on sorted out.
I got the feeling I'll be moving my engine to matrix mode in the end. But this will be after I get this project I'm working on sorted out.
Matrices ftw (beware of normals and lighting).
alternatively, trace, pick up this thingy:
http://www.amazon.com/exec/obidos/ASIN/1556229119/
has all the basics in rather clear/pragmatic way.
dunno how far you wanna go with all this..
http://www.amazon.com/exec/obidos/ASIN/1556229119/
has all the basics in rather clear/pragmatic way.
dunno how far you wanna go with all this..
I really thing the best way to learn is with rotations first, and then understand how it relates to matrices.
If you want, I can draw the rotation based way, to be easy to understand. With some illustrations it would be very easy.
Then, about matrices, I'm not sure if trace have knowledge of how matrices works, not sure if he studied it or not. Since matrices are powerful tools, it is interesting to learn it. But, just in the end, matrix multiplication are just a compact way to write a lot of sums/multiplies, and nothing more.
I believe it is really important to know what is being done in the background, and not just to implement a matrix multiplier and then some few formulas you got from a book without having an idea of what it does.
If you want, I can draw the rotation based way, to be easy to understand. With some illustrations it would be very easy.
Then, about matrices, I'm not sure if trace have knowledge of how matrices works, not sure if he studied it or not. Since matrices are powerful tools, it is interesting to learn it. But, just in the end, matrix multiplication are just a compact way to write a lot of sums/multiplies, and nothing more.
I believe it is really important to know what is being done in the background, and not just to implement a matrix multiplier and then some few formulas you got from a book without having an idea of what it does.