Dark Bit Factory & Gravity
PROGRAMMING => General coding questions => Topic started by: Dr_D on August 25, 2011
-
Hey guys. I'm having a matrix problem here. I'm using FreeBASIC, but as this is a general math problem I put it here. Anyway... here we go. I need to align a 3d object with a polygon normal. To be more precise, I need to align the object's up vector with the polygon normal, while still allowing free rotation about it. In general this isn't a problem... if the current rotation about the up vector isn't important. For what I'm trying to do here here though, it is.
For instance, I can copy the polygon's normal to the up vector. I can then subtract the midpoint from one of the polygon's vertices and normalize to get the right vector . Then I can take the cross product of those two to get the forward vector and complete an orthogonal rotation matrix. All that sounds fine... but not when you're simulating a vehicle. I need to be able to rotate freely about up and keep the angle consistent when a new collision is detected. I tried with an axis-angle approach, but something seems to be off. Has anyone ever dealt with this before? I've been testing different methods for about a week now and it's starting to drive me nuts. :p
-
If I understand it right, you're saying when you move from one triangle to another your matrix construction technique means the 'right' or 'x' vector in your new matrix depends upon the orientation of the triangle and means your vehicle jumps to a new turn orientation.
I'd solve it like this. When you hit the new triangle, instead of starting your matrix from scratch, replace the existing matrix's 'up' or 'y' vector with the new triangle normal, then re-square the matrix, along the 'forward' or 'z' axis first (dot, subtract, unitize), and then cross product to get the 'x' vector.
Jim
-
Yep, you understand it right. However, I'm still not able to get it aligned properly with that technique. I've even tried rotating a point about the up vector at whatever angle my vehicle's current steer angle is and still no dice. That's probably where it's failing... How exactly would you go about constructing the new forward vector?
-
If your polygon represents the ground (and you don't want loopings) I'd start from a 2d rotation around (0,1,0) and re-orthogonalize with the given normal:
Vector y= normal
Vector z= y cross Vector( cos(rot), 0, sin(rot) )
Vector x= y cross z
-
Well. I actually do need to be able to set it from any orientation. Do you know of the old driving game called Stunts? My friend and I are re-making that for Nintendo DS. So... it can be pretty much any arbitrary vector for up.
-
I see. Since you already have an axis-angle (http://en.wikipedia.org/wiki/Axis-angle_representation) representation you can build the matrix (http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToMatrix/index.htm) directly from it.
-
That method is what I tried using in the original test. Actually, here's my axis-angle matrix creation function:
sub mat33_axisangle( matrix as number ptr, v as vec3 ptr, angle as number )
dim as number tc = cos(angle)
dim as number ts = sin(angle)
dim as number tt = 1.0 - tc
vec3_normalize( v )
with *v
matrix[0] = tc + .x*.x*tt
matrix[5] = tc + .y*.y*tt
matrix[10] = tc + .z*.z*tt
dim as number tmp1 = .x*.y*tt
dim as number tmp2 = .z*ts
matrix[4] = tmp1 + tmp2
matrix[1] = tmp1 - tmp2
tmp1 = .x*.z*tt
tmp2 = .y*ts
matrix[8] = tmp1 - tmp2
matrix[2] = tmp1 + tmp2
tmp1 = .y*.z*tt
tmp2 = .x*ts
matrix[9] = tmp1 + tmp2
matrix[6] = tmp1 - tmp2
end with
end sub
It seems to fail at certain angles though... it's hard to explain. I guess it's possible that I'm using a bad method to find the axis and angle? I had this method working a long time ago for a go-kart game, but I've lost that code and apparently the knowledge along with it. :p
Anyway... this is how I calculate the axis and angle:
dim as vec3 r, u, axis
u = poly.normal 'polygon normal
r = vIntersection 'intersection point
vec3_normalize( @r )
vec3_cross( @axis, @r, @u ) 'return the cross product of the normal and the normalized intersection point
dim as single rot = vec3_dot( @u, @r ) 'calculate the angle between them
mat44_axisangle( @tMatrix(0), @axis, rot )
mat44_loadidentity( @oMatrix(0) )
oMatrix(12)=position.x
oMatrix(13)=position.y
oMatrix(14)=position.z
mat44_mul_mat44( @oMatrix(0), @tMatrix(0) )
mat44_rotate( @oMatrix(0), 0, angle, 0 )
-
Hey guys... I haven't worked on it for a while, but I was wondering if anyone had any other suggestions or spots anything funky in my code?
-
Isn't part of the problem this bit ?
rot = vec3_dot( @u, @r )That will only give you an angle between -90 and +90.
Jim
-
New game from Da Doc?!!! Wooohoooo!!!!!!
You have a DS binary I could play with?
-
I think I know what the good doctor is trying to achieve, I've come across similor loss of freedom before. You've solved gimbal lock by forcing all axis to be perpendicular to each other by rotating by an angle then correcting the other axis by applying the crossproduct then normalizing. But now you can no longer rotate one axis freely without it effecting all three? If this is correct then you have not taken maticulous care with exactly which axis you need to correct using the crossproduct.
If you need to rotate only the oriented x axis, it will effect the oriented yz plane. the x axis remains unaffected. so you rotate the y axis conventionally then correct the z axis using crossproduct, finally you normalize z to remove rounding errors. Here is my working code it allows free rotation in yaw, pitch, roll seperately but there is a cost in that you have now lost your euler representation and are working directly in vectors...
// the rotation matrix...
float xx = 1.0f, xy = 0.0f, xz = 0.0f;
float yx = 0.0f, yy = 1.0f, yz = 0.0f;
float zx = 0.0f, zy = 0.0f, zz = 1.0f;
// the rotation routine...
bool CameraTransform(float x, float y, float z)
{
float cx = cos(x), sx = sin(x);
float cy = cos(y), sy = sin(y);
float cz = cos(z), sz = sin(z);
float pn;
// rotate x (affects yz) transform y conventionally, normalize, correct z using crossproduct
yx = yx*cx + zx*sx;
yy = yy*cx + zy*sx;
yz = yz*cx + zz*sx;
pn = 1.0f / sqrt(yx*yx + yy*yy + yz*yz);
yx *= pn;
yy *= pn;
yz *= pn;
zx = xy*yz - xz*yy;
zy = xz*yx - xx*yz;
zz = xx*yy - xy*yx;
// rotate y (affects zx) transform z conventionally, normalize, correct x using crossproduct
zx = zx*cy + xx*sy;
zy = zy*cy + xy*sy;
zz = zz*cy + xz*sy;
pn = 1.0f / sqrt(zx*zx + zy*zy + zz*zz);
zx *= pn;
zy *= pn;
zz *= pn;
xx = yy*zz - yz*zy;
xy = yz*zx - yx*zz;
xz = yx*zy - yy*zx;
// rotate z (affects xy) transform x conventionally, normalize, correct y using crossproduct
xx = xx*cz + yx*sz;
xy = xy*cz + yy*sz;
xz = xz*cz + yz*sz;
pn = 1.0f / sqrt(xx*xx + xy*xy + xz*xz);
xx *= pn;
xy *= pn;
xz *= pn;
yx = zy*xz - zz*xy;
yy = zz*xx - zx*xz;
yz = zx*xy - zy*xx;
// to rotate a vertex using this matrix reduces to the following...
//newx = xx*posx + yx*posy + zx*posz;
//newy = xy*posx + yy*posy + zy*posz;
//newz = xz*posx + yz*posy + zz*posz;
return true;
}
-
Thanks, rain_storm... I'll test it out when I have a chance. Thanks Jim, and you're right, but that isn't actually the problem. Somehow my matrix was becoming non-orthogonal.
Rel, it's that game I've been working on with Mysoft. I jhaven't actually worked on it for a while though. Been working on that Squealers mini-golf game. :D