Path: chuka.playstation.co.uk!news
From: Peter Passmore
Newsgroups: scee.yaroze.programming.3d_graphics
Subject: Re: RotMatrixBUG????
Date: Sat, 04 Jul 1998 02:54:38 +0100
Organization: PlayStation Net Yaroze (SCEE)
Lines: 151
Message-ID: <359D8B5E.54DE@mdx.ac.uk>
References: <01bda686$31300120$4fa1f7c2@manolo>
NNTP-Posting-Host: staff-dialup2.mdx.ac.uk
Mime-Version: 1.0
Content-Type: text/plain; charset=iso-8859-1
Content-Transfer-Encoding: 8bit
X-Mailer: Mozilla 3.04 (Win95; I)
Emanuele Diotallevi wrote:
>
> Why Rotmatrix function rotate the object on local Z,Y axes and on Daddy's X
> axe .
>
> How we can rotate the object on his X local axe without using RotMatrixX
> that has a scale matrix side effect??????
Short answer: to both questions is probably, concatenate your existing
object matrix with your new rotation matrix (don't ever reset the object
matrix) but 'condition' it by calling the function AdjustCoordinate2
below after concatenation in your rotateModel function
Long answer below: sorry I'm in writing tutorials mode at the moment
>Why Rotmatrix function rotate the object on local Z,Y axes and on Daddy's X
>axe .
Probably you are just adding up the rotations around each axis and
storing them in a rotation matrix rather than concatenating subsequent
rotations into the object's matrix. I recommended this in my 3Dtutorial
which was aimed at producing a driving game or other game based on
rotations in the plane for which this works fine, and avoids your second
problem below.
However this scheme doesn't work when you rotate around more than one
axis and causes the kind of problems you are finding. So an alternative
method is to keep on concatenating all new rotations into your matrix .
(ie don't reset your matrix to the identity matrix when applying
rotation) - which then causes your second problem.
>How we can rotate the object on his X local axe without using RotMatrixX
>that has a scale matrix side effect??????
There was some discussion of this problem but it disappeared off the
news The problem with matrix concatenation is that precision errors
accumulate and build up to produce scaling and shearing of your object.
This happens very quickly for integer based matrices but also occurs for
eventually for floating point matrices.
Any row or column in the rotation matrix should always be a unit vector
to avoid shearing or scaling.
ie:
Sqrt(x*x+y*y+z*z) =1
and row or column vectors should be orthogonal (at 90 degrees) to each
other - which you should see is clearly true for the identity matrix:
1 0 0
0 1 0
0 0 1
and in fact rotation matrices.
A solution: 'condition' the matrix from time to time by normalising the
matrix rows and columns, you can generally get away with normalising one
row or column vector at a time.
To normalise a vector you divide it's components by it's magnitude or
length ie:
Length= sqrt(x*x+y*y+z*z)
And then
x'=x/length,y'=y/length,z'=z/length
Problem: the sqrt function is unacceptably slow so you need to use
approximation methods or lookup tables. I used a lookup table of squared
terms from 0-4096 which on normalising one vector a frame cost 1-2
vsyncs and got rid of the problem, which is not bad but has the memory
cost of the LUT. The best route seems to be to use a method from our
Japanese friends which is a wicked example of serious games programming
which appears to use mostly bit-shifting to work out the vector length
and some scheme based on calculating subcomponents of the matrix
discriminant. The example is from somewhere on the SCEI site in a
directory called ROTATE, but the crucial functions (from module
adjust.c) are listed below:
/*
s-֘A
Programmed by Co
Nazca SOFTWARE 1996-1997
*/
#include
//K (ox,y,zONE -T̂)
static long NormalScale(long x,long y,long z){
long nx,ny,nz,n;
nx=(x+(1<<8))>>9;
ny=(y+(1<<8))>>9;
nz=(z+(1<<8))>>9;
n=(nx*nx+ny*ny+nz*nz+(1<<3))>>4;
if(n<(1<<26)){
n*=10; n+=9<<26; n/=19;
} else {
n*=10; n+=11<<26; n/=21;
}
n=(n+(1<<13))>>14; // if(!n) n=1;
return n;
}
//'s-o
void AdjustCoordinate2(GsCOORDINATE2 *coord){
MATRIX *mp=&coord->coord;
long x,y,z,n;
#define ax mp->m[0][0]
#define ay mp->m[0][1]
#define az mp->m[0][2]
#define bx mp->m[1][0]
#define by mp->m[1][1]
#define bz mp->m[1][2]
#define cx mp->m[2][0]
#define cy mp->m[2][1]
#define cz mp->m[2][2]
switch(PSDCNT%3){ //vZop"x-v' (݂-1/3Â)
case 0:
x=by*cz-bz*cy;
y=bz*cx-bx*cz;
z=bx*cy-by*cx;
n=NormalScale(x,y,z); x/=n; y/=n; z/=n;
if(ax!=x || ay!=y || az!=z){ ax=x; ay=y; az=z; coord->flg=0; }
break;
case 1:
x=cy*az-cz*ay;
y=cz*ax-cx*az;
z=cx*ay-cy*ax;
n=NormalScale(x,y,z); x/=n; y/=n; z/=n;
if(bx!=x || by!=y || bz!=z){ bx=x; by=y; bz=z; coord->flg=0; }
break;
case 2:
x=ay*bz-az*by;
y=az*bx-ax*bz;
z=ax*by-ay*bx;
n=NormalScale(x,y,z); x/=n; y/=n; z/=n;
if(cx!=x || cy!=y || cz!=z){ cx=x; cy=y; cz=z; coord->flg=0; }
break;
}
}
To use this just comment out the #include statement, include the code in
your program, and call AdjustCoordinate2 after applying your rotation.
Does anybody want to give a detailed explanation of this function (Graig
G)?
Peter.