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.