Blitz3D C++ geometry code
Blitz3D Forums/Blitz3D Programming/Blitz3D C++ geometry code
| ||
Hi, I frequently get asked questions about Blitz3D's internal math routines. So here, in all its glory, is the geom.h file from Blitz3D. It's in C++, so it may be a bit confusing, but the math should be pretty obvious. Have fun - and please let me know if you find any bugs! Mark #ifndef GEOM_H #define GEOM_H #include <math.h> class Vector; class Line; class Plane; class Matrix; class Transform; const float PI=3.14159265359f; //180 degrees const float TWOPI=PI*2.0f; //360 degrees const float HALFPI=PI*.5f; //90 degrees const float QUARTERPI=PI*.25f; //45 degrees const float EPSILON=.000001f; //small value const float INFINITY=10000000.0f; //big value class Vector{ public: float x,y,z; Vector():x(0),y(0),z(0){ } Vector( float x,float y,float z ):x(x),y(y),z(z){ } operator float*(){ return &x; } operator const float *(){ return &x; } float &operator[]( int n ){ return (&x)[n]; } float operator[]( int n )const{ return (&x)[n]; } Vector operator-()const{ return Vector( -x,-y,-z ); } Vector operator*( float scale )const{ return Vector( x*scale,y*scale,z*scale ); } Vector operator*( const Vector &q )const{ return Vector( x*q.x,y*q.y,z*q.z ); } Vector operator/( float scale )const{ return Vector( x/scale,y/scale,z/scale ); } Vector operator/( const Vector &q )const{ return Vector( x/q.x,y/q.y,z/q.z ); } Vector operator+( const Vector &q )const{ return Vector( x+q.x,y+q.y,z+q.z ); } Vector operator-( const Vector &q )const{ return Vector( x-q.x,y-q.y,z-q.z ); } Vector &operator*=( float scale ){ x*=scale;y*=scale;z*=scale;return *this; } Vector &operator*=( const Vector &q ){ x*=q.x;y*=q.y;z*=q.z;return *this; } Vector &operator/=( float scale ){ x/=scale;y/=scale;z/=scale;return *this; } Vector &operator/=( const Vector &q ){ x/=q.x;y/=q.y;z/=q.z;return *this; } Vector &operator+=( const Vector &q ){ x+=q.x;y+=q.y;z+=q.z;return *this; } Vector &operator-=( const Vector &q ){ x-=q.x;y-=q.y;z-=q.z;return *this; } bool operator<( const Vector &q )const{ if( fabs(x-q.x)>EPSILON ) return x<q.x ? true : false; if( fabs(y-q.y)>EPSILON ) return y<q.y ? true : false; return fabs(z-q.z)>EPSILON && z<q.z; } bool operator==( const Vector &q )const{ return fabs(x-q.x)<=EPSILON && fabs(y-q.y)<=EPSILON && fabs(z-q.z)<=EPSILON; } bool operator!=( const Vector &q )const{ return fabs(x-q.x)>EPSILON || fabs(y-q.y)>EPSILON || fabs(z-q.z)>EPSILON; } float dot( const Vector &q )const{ return x*q.x+y*q.y+z*q.z; } Vector cross( const Vector &q )const{ return Vector( y*q.z-z*q.y,z*q.x-x*q.z,x*q.y-y*q.x ); } float length()const{ return sqrtf(x*x+y*y+z*z); } float distance( const Vector &q )const{ float dx=x-q.x,dy=y-q.y,dz=z-q.z;return sqrtf(dx*dx+dy*dy+dz*dz); } Vector normalized()const{ float l=length();return Vector( x/l,y/l,z/l ); } void normalize(){ float l=length();x/=l;y/=l;z/=l; } float yaw()const{ return -atan2f( x,z ); } float pitch()const{ return -atan2f( y,sqrtf( x*x+z*z ) ); } void clear(){ x=y=z=0; } }; class Line{ public: Vector o,d; Line(){ } Line( const Vector &o,const Vector &d ):o(o),d(d){ } Line operator+( const Vector &q )const{ return Line( o+q,d ); } Line operator-( const Vector &q )const{ return Line( o-q,d ); } Vector operator*( float q )const{ return o+d*q; } Vector nearest( const Vector &q )const{ return o+d*(d.dot(q-o)/d.dot(d)); } }; class Plane{ public: Vector n; float d; Plane():d(0){ } //normal/offset form Plane( const Vector &n,float d ):n(n),d(d){ } //point/normal form Plane( const Vector &p,const Vector &n ):n(n),d(-n.dot(p)){ } //create plane from tri Plane( const Vector &v0,const Vector &v1,const Vector &v2 ){ n=(v1-v0).cross(v2-v0).normalized();d=-n.dot(v0); } Plane operator-()const{ return Plane( -n,-d ); } float t_intersect( const Line &q )const{ return -distance(q.o)/n.dot(q.d); } Vector intersect( const Line &q )const{ return q*t_intersect(q); } Line intersect( const Plane &q )const{ Vector lv=n.cross( q.n ).normalized(); return Line( q.intersect( Line( nearest( n*-d ),n.cross(lv) ) ),lv ); } Vector nearest( const Vector &q )const{ return q-n*distance(q); } void negate(){ n=-n;d=-d; } float distance( const Vector &q )const{ return n.dot(q)+d; } }; struct Quat{ float w; Vector v; Quat():w(1){ } Quat( float w,const Vector &v ):w(w),v(v){ } Quat operator-()const{ return Quat( w,-v ); } Quat operator+( const Quat &q )const{ return Quat( w+q.w,v+q.v ); } Quat operator-( const Quat &q )const{ return Quat( w-q.w,v-q.v ); } Quat operator*( const Quat &q )const{ return Quat( w*q.w-v.dot(q.v),q.v.cross(v)+q.v*w+v*q.w ); } Vector operator*( const Vector &q )const{ return (*this * Quat(0,q) * -*this).v; } Quat operator*( float q )const{ return Quat( w*q,v*q ); } Quat operator/( float q )const{ return Quat( w/q,v/q ); } float dot( const Quat &q )const{ return v.x*q.v.x+v.y*q.v.y+v.z*q.v.z+w*q.w; } float length()const{ return sqrtf( w*w+v.x*v.x+v.y*v.y+v.z*v.z ); } void normalize(){ *this=*this/length(); } Quat normalized()const{ return *this/length(); } Quat slerpTo( const Quat &q,float a )const{ Quat t=q; float d=dot(q),b=1-a; if( d<0 ){ t.w=-t.w;t.v=-t.v;d=-d; } if( d<1-EPSILON ){ float om=acosf( d ); float si=sinf( om ); a=sinf( a*om )/si; b=sinf( b*om )/si; } return *this*b + t*a; } Vector i()const{ float xz=v.x*v.z,wy=w*v.y; float xy=v.x*v.y,wz=w*v.z; float yy=v.y*v.y,zz=v.z*v.z; return Vector( 1-2*(yy+zz),2*(xy-wz),2*(xz+wy) ); } Vector j()const{ float yz=v.y*v.z,wx=w*v.x; float xy=v.x*v.y,wz=w*v.z; float xx=v.x*v.x,zz=v.z*v.z; return Vector( 2*(xy+wz),1-2*(xx+zz),2*(yz-wx) ); } Vector k()const{ float xz=v.x*v.z,wy=w*v.y; float yz=v.y*v.z,wx=w*v.x; float xx=v.x*v.x,yy=v.y*v.y; return Vector( 2*(xz-wy),2*(yz+wx),1-2*(xx+yy) ); } }; class Matrix{ static Matrix tmps[64]; static Matrix &alloc_tmp(){ static int tmp=0;return tmps[tmp++&63]; } friend class Transform; public: Vector i,j,k; Matrix():i(Vector(1,0,0)),j(Vector(0,1,0)),k(Vector(0,0,1)){ } Matrix( const Vector &i,const Vector &j,const Vector &k ):i(i),j(j),k(k){ } Matrix( const Quat &q ){ float xx=q.v.x*q.v.x,yy=q.v.y*q.v.y,zz=q.v.z*q.v.z; float xy=q.v.x*q.v.y,xz=q.v.x*q.v.z,yz=q.v.y*q.v.z; float wx=q.w*q.v.x,wy=q.w*q.v.y,wz=q.w*q.v.z; i=Vector( 1-2*(yy+zz),2*(xy-wz),2*(xz+wy) ), j=Vector( 2*(xy+wz),1-2*(xx+zz),2*(yz-wx) ), k=Vector( 2*(xz-wy),2*(yz+wx),1-2*(xx+yy) ); } Matrix( float angle,const Vector &axis ){ const Vector &u=axis; float c=cosf(angle),s=sinf(angle); float x2=axis.x*axis.x,y2=axis.y*axis.y,z2=axis.z*axis.z; i=Vector( x2+c*(1-x2),u.x*u.y*(1-c)-u.z*s,u.z*u.x*(1-c)+u.y*s ); j=Vector( u.x*u.y*(1-c)+u.z*s,y2+c*(1-y2),u.y*u.z*(1-c)-u.x*s ); k=Vector( u.z*u.x*(1-c)-u.y*s,u.y*u.z*(1-c)+u.x*s,z2+c*(1-z2) ); } Vector &operator[]( int n ){ return (&i)[n]; } const Vector &operator[]( int n )const{ return (&i)[n]; } Matrix &operator~()const{ Matrix &m=alloc_tmp(); m.i.x=i.x;m.i.y=j.x;m.i.z=k.x; m.j.x=i.y;m.j.y=j.y;m.j.z=k.y; m.k.x=i.z;m.k.y=j.z;m.k.z=k.z; return m; } float determinant()const{ return i.x*(j.y*k.z-j.z*k.y )-i.y*(j.x*k.z-j.z*k.x )+i.z*(j.x*k.y-j.y*k.x ); } Matrix &operator-()const{ Matrix &m=alloc_tmp(); float t=1.0f/determinant(); m.i.x= t*(j.y*k.z-j.z*k.y);m.i.y=-t*(i.y*k.z-i.z*k.y);m.i.z= t*(i.y*j.z-i.z*j.y); m.j.x=-t*(j.x*k.z-j.z*k.x);m.j.y= t*(i.x*k.z-i.z*k.x);m.j.z=-t*(i.x*j.z-i.z*j.x); m.k.x= t*(j.x*k.y-j.y*k.x);m.k.y=-t*(i.x*k.y-i.y*k.x);m.k.z= t*(i.x*j.y-i.y*j.x); return m; } Matrix &cofactor()const{ Matrix &m=alloc_tmp(); m.i.x= (j.y*k.z-j.z*k.y);m.i.y=-(j.x*k.z-j.z*k.x);m.i.z= (j.x*k.y-j.y*k.x); m.j.x=-(i.y*k.z-i.z*k.y);m.j.y= (i.x*k.z-i.z*k.x);m.j.z=-(i.x*k.y-i.y*k.x); m.k.x= (i.y*j.z-i.z*j.y);m.k.y=-(i.x*j.z-i.z*j.x);m.k.z= (i.x*j.y-i.y*j.x); return m; } bool operator==( const Matrix &q )const{ return i==q.i && j==q.j && k==q.k; } bool operator!=( const Matrix &q )const{ return i!=q.i || j!=q.j || k!=q.k; } Vector operator*( const Vector &q )const{ return Vector( i.x*q.x+j.x*q.y+k.x*q.z,i.y*q.x+j.y*q.y+k.y*q.z,i.z*q.x+j.z*q.y+k.z*q.z ); } Matrix &operator*( const Matrix &q )const{ Matrix &m=alloc_tmp(); m.i.x=i.x*q.i.x+j.x*q.i.y+k.x*q.i.z;m.i.y=i.y*q.i.x+j.y*q.i.y+k.y*q.i.z;m.i.z=i.z*q.i.x+j.z*q.i.y+k.z*q.i.z; m.j.x=i.x*q.j.x+j.x*q.j.y+k.x*q.j.z;m.j.y=i.y*q.j.x+j.y*q.j.y+k.y*q.j.z;m.j.z=i.z*q.j.x+j.z*q.j.y+k.z*q.j.z; m.k.x=i.x*q.k.x+j.x*q.k.y+k.x*q.k.z;m.k.y=i.y*q.k.x+j.y*q.k.y+k.y*q.k.z;m.k.z=i.z*q.k.x+j.z*q.k.y+k.z*q.k.z; return m; } void orthogonalize(){ k.normalize(); i=j.cross( k ).normalized(); j=k.cross( i ); } Matrix &orthogonalized()const{ Matrix &m=alloc_tmp(); m=*this;m.orthogonalize(); return m; } }; class Box{ public: Vector a,b; Box():a( Vector(INFINITY,INFINITY,INFINITY) ),b( Vector(-INFINITY,-INFINITY,-INFINITY) ){ } Box( const Vector &q ):a(q),b(q){ } Box( const Vector &a,const Vector &b ):a(a),b(b){ } Box( const Line &l ):a(l.o),b(l.o){ update( l.o+l.d ); } void clear(){ a.x=a.y=a.z=INFINITY; b.x=b.y=b.z=-INFINITY; } bool empty()const{ return b.x<a.x || b.y<a.y || b.z<a.z; } Vector centre()const{ return Vector( (a.x+b.x)*.5f,(a.y+b.y)*.5f,(a.z+b.z)*.5f ); } Vector corner( int n )const{ return Vector( ((n&1)?b:a).x,((n&2)?b:a).y,((n&4)?b:a).z ); } void update( const Vector &q ){ if( q.x<a.x ) a.x=q.x;if( q.y<a.y ) a.y=q.y;if( q.z<a.z ) a.z=q.z; if( q.x>b.x ) b.x=q.x;if( q.y>b.y ) b.y=q.y;if( q.z>b.z ) b.z=q.z; } void update( const Box &q ){ if( q.a.x<a.x ) a.x=q.a.x;if( q.a.y<a.y ) a.y=q.a.y;if( q.a.z<a.z ) a.z=q.a.z; if( q.b.x>b.x ) b.x=q.b.x;if( q.b.y>b.y ) b.y=q.b.y;if( q.b.z>b.z ) b.z=q.b.z; } bool overlaps( const Box &q )const{ return (b.x<q.b.x?b.x:q.b.x)>=(a.x>q.a.x?a.x:q.a.x) && (b.y<q.b.y?b.y:q.b.y)>=(a.y>q.a.y?a.y:q.a.y) && (b.z<q.b.z?b.z:q.b.z)>=(a.z>q.a.z?a.z:q.a.z); } void expand( float n ){ a.x-=n;a.y-=n;a.z-=n;b.x+=n;b.y+=n;b.z+=n; } float width()const{ return b.x-a.x; } float height()const{ return b.y-a.y; } float depth()const{ return b.z-a.z; } bool contains( const Vector &q ){ return q.x>=a.x && q.x<=b.x && q.y>=a.y && q.y<=b.y && q.z>=a.z && q.z<=b.z; } }; class Transform{ static Transform tmps[64]; static Transform &alloc_tmp(){ static int tmp=0;return tmps[tmp++&63]; } public: Matrix m; Vector v; Transform(){ } Transform( const Matrix &m ):m(m){ } Transform( const Vector &v ):v(v){ } Transform( const Matrix &m,const Vector &v ):m(m),v(v){ } Transform &operator-()const{ Transform &t=alloc_tmp(); t.m=-m;t.v=t.m*-v; return t; } Transform &operator~()const{ Transform &t=alloc_tmp(); t.m=~m;t.v=t.m*-v; return t; } Vector operator*( const Vector &q )const{ return m*q+v; } Line operator*( const Line &q )const{ Vector t=(*this)*q.o; return Line( t,(*this)*(q.o+q.d)-t ); } Box operator*( const Box &q )const{ Box t( (*this*q.corner(0) ) ); for( int k=1;k<8;++k ) t.update( *this*q.corner(k) ); return t; } Transform &operator*( const Transform &q )const{ Transform &t=alloc_tmp(); t.m=m*q.m;t.v=m*q.v+v; return t; } bool operator==( const Transform &q )const{ return m==q.m && v==q.v; } bool operator!=( const Transform &q )const{ return !operator==( q ); } }; inline float transformRadius( float r,const Matrix &t ){ static const float sq_3=sqrtf(1.0f/3.0f); return (t * Vector( sq_3,sq_3,sq_3 )).length()*r; } inline Matrix pitchMatrix( float q ){ return Matrix( Vector(1,0,0),Vector(0,cosf(q),sinf(q)),Vector(0,-sinf(q),cosf(q)) ); } inline Matrix yawMatrix( float q ){ return Matrix( Vector(cosf(q),0,sinf(q)),Vector(0,1,0),Vector(-sinf(q),0,cosf(q)) ); } inline Matrix rollMatrix( float q ){ return Matrix( Vector(cosf(q),sinf(q),0),Vector(-sinf(q),cosf(q),0),Vector(0,0,1) ); } inline float matrixPitch( const Matrix &m ){ return m.k.pitch(); } inline float matrixYaw( const Matrix &m ){ return m.k.yaw(); } inline float matrixRoll( const Matrix &m ){ return atan2f( m.i.y,m.j.y ); } inline Matrix scaleMatrix( float x,float y,float z ){ return Matrix( Vector( x,0,0 ),Vector( 0,y,0 ),Vector( 0,0,z ) ); } inline Matrix scaleMatrix( const Vector &scale ){ return Matrix( Vector( scale.x,0,0 ),Vector( 0,scale.y,0 ),Vector( 0,0,scale.z ) ); } inline Quat pitchQuat( float p ){ return Quat( cosf(p/-2),Vector( sinf(p/-2),0,0 ) ); } inline Quat yawQuat( float y ){ return Quat( cosf(y/2),Vector( 0,sinf(y/2),0 ) ); } inline Quat rollQuat( float r ){ return Quat( cosf(r/-2),Vector( 0,0,sinf(r/-2) ) ); } inline Matrix rotationMatrix( float p,float y,float r ){ return yawMatrix(y)*pitchMatrix(p)*rollMatrix(r); } inline Matrix rotationMatrix( const Vector &rot ){ return yawMatrix(rot.y)*pitchMatrix(rot.x)*rollMatrix(rot.z); } inline float quatPitch( const Quat &q ){ return q.k().pitch(); } inline float quatYaw( const Quat &q ){ return q.k().yaw(); } inline float quatRoll( const Quat &q ){ return matrixRoll( q ); } inline Quat matrixQuat( const Matrix &p ){ Matrix m=p; m.orthogonalize(); float t=m.i.x+m.j.y+m.k.z,w,x,y,z; if( t>EPSILON ){ t=sqrtf( t+1 )*2; x=(m.k.y-m.j.z)/t; y=(m.i.z-m.k.x)/t; z=(m.j.x-m.i.y)/t; w=t/4; }else if( m.i.x>m.j.y && m.i.x>m.k.z ){ t=sqrtf( m.i.x-m.j.y-m.k.z+1 )*2; x=t/4; y=(m.j.x+m.i.y)/t; z=(m.i.z+m.k.x)/t; w=(m.k.y-m.j.z)/t; }else if( m.j.y>m.k.z ){ t=sqrtf( m.j.y-m.k.z-m.i.x+1 )*2; x=(m.j.x+m.i.y)/t; y=t/4; z=(m.k.y+m.j.z)/t; w=(m.i.z-m.k.x)/t; }else{ t=sqrtf( m.k.z-m.j.y-m.i.x+1 )*2; x=(m.i.z+m.k.x)/t; y=(m.k.y+m.j.z)/t; z=t/4; w=(m.j.x-m.i.y)/t; } return Quat( w,Vector( x,y,z ) ); } #endif |
| ||
Thank you very much! Tom p.s. More more more!!! :) |
| ||
Thank you! PS: I agree with Toms PS :) |
| ||
Wow, sweet. Does Blitz store 3x3 matrices? I've been storing Eulers, converting to quats, transforming the necessary mat elements, and converting back to eulers. It might be faster to store a 3x3 matrix, and use gl matrix commands instead of glRotatef(). But then, I finally got my transformations working (using Blitz3D results as a guide) so maybe I should leave it damn well alone. |
| ||
Lucky I never tried to make my own 3D engine, (looks a bit complicated!) |
| ||
Greetings Puppies, Nice job Mark. I can understand the code but have no idea what it actually means :0) Peace, Jes |
| ||
Now I remember why I'm quite happy to pay Mark Sibly whatever he charges, and just walk away with the result! Cheers, Mark. |
| ||
Thanks Mark I'm always very impressed by code that I can not understand :D |
| ||
Me too! :P |
| ||
It would be VERY useful if someone converted this to Blitz, for all the people doing OpenGL stuff. |
| ||
I'm kind of confused. I thought header files weren't really intended to contain the implementation (except for Inlines), but it appears that that's how Mark uses them. |
| ||
Awesome! Its a great beginning Mark, hopefully throughout the years you'll keep 'em coming. Nice to see the true faces of all those commands we use. Not trivial stuff. |
| ||
What is and ESPILON? |
| ||
It is the fifth letter of the Greek alphabet. Apparently first used by the Hungarian mathmetician Paul Erdos to denote a very small or insignificant quantity. In this case it is a very small value, that is still representable using the floating point numbering system. It is used to determine if two numbers are approximately equal, because floating point numbers usually accumulate small rounding errors which make exact comparisons unlikely to suceeed. So here Epsilon is just about significant, and anything less than Epsilon is deemed to be insignificant I guess all these Greek letters get used in maths because the Greeks were apparently rather good at it. So I am pretty sure I have no Greek ancestors. In any event If that is the only question you have about the above then you are a lot Greeker than me. |
| ||
Did he say Greeker or geekier? :) |
| ||
hehe :) Here's me being 'geek' <Sarge> scouse did you see the tutorial i sent <Scouse> no sir <Sarge> i will send it to you in a bit <Scouse> wow, what kind of compression is that? <Scouse> nerd joke, sorry :P Tom |
| ||
Very good. Try this. http://www.cs.bris.ac.uk/Research/QuantumComputing/compression.html "Although compression for sources of pure state is now quite well understood,..." Not by us non Greeks it isn't. :( |
| ||
Oh hell, you are a saint Mark :). Thanks a ton! |
| ||
LMAO @ Tom XD |
| ||
Out of curiosity, are you making this source public domain or is there a specific license you want people to adhere to? |
| ||
I don't think Mark has patented basic 3D maths. |
| ||
I don't think Mark has patented basic 3D maths. Yeah - someone else already tried that. :p |
| ||
I patented eye balls. Pay up or I cut them out ;) |
| ||
btw, blitz3d source code... i want a good compiler sdk for add more cool features in compiling |
| ||
Out of curiosity, are you making this source public domain or is there a specific license you want people to adhere to? This code is completely public domain - do whatever you want with it! |
| ||
Oh lord, now you've done it... Noel will surely defile it. |
| ||
sweet :) now if we could get you to release the rest of the blitz3d code :P |
| ||
"Right now I could stand to hug you. I won't. But you know what I mean." Futurama quotes are nice. |
| ||
I'm pleased to see the use of return *this. Nice and fast. You 'could' save a few nano seconds by converting your math labels to #DEFINE's eg. const float PI=3.14159265359f;//180 degrees #DEFINE PI=3.14159265359f;//180 degrees |
| ||
you know the old saying, take care of the nano seconds and the seconds will take care of themselves. |
| ||
I understood everything up until the green lettering. |
| ||
thx thx thx mark!!! |
| ||
As long as we're talking about Greek letters (like EPSILON), why not replace "INFINITY" with "OMEGA", the Greek letter normally used to represent Infinity? :) |
| ||
Small question. The Transform-class has a method called QuatRoll. This method calls the Matrixroll method passing a Quat as parameter, but the Matrixroll method is defined to only accept a Matrix. Is this wrong or is it just me that doesn't get it? |
| ||
I'd like to find out how to convert quat to euler using the above code. I will then impliment it in the ode wrapper. |
| ||
Flying Willy, See the matrix class. My guess is that this is the quat to euler rotation matrix conversion. (as below - the matrix itself is defined as the three vectors, i,j,k) Sweenie, I do not use C++ (seems I am going to have to make the effort - if only to make sense of this sort of stuff) but maybe the code is using this to implicitly cast a quat to a matrix? Matrix( const Quat &q ){ float xx=q.v.x*q.v.x,yy=q.v.y*q.v.y,zz=q.v.z*q.v.z; float xy=q.v.x*q.v.y,xz=q.v.x*q.v.z,yz=q.v.y*q.v.z; float wx=q.w*q.v.x,wy=q.w*q.v.y,wz=q.w*q.v.z; i=Vector( 1-2*(yy+zz),2*(xy-wz),2*(xz+wy) ), j=Vector( 2*(xy+wz),1-2*(xx+zz),2*(yz-wx) ), k=Vector( 2*(xz-wy),2*(yz+wx),1-2*(xx+yy) ); } There is also some stuff on the code archives dealing with quats. Not tested though, I have never used them directly. |
| ||
Aha, you mean that if a function "ask" for a reference to a matrix and you instead pass a quaternion as reference, the matrix constructor above will kick in and convert it for you. I never knew that could be done, but then again , my C++ knowledge is pretty limited as well. |
| ||
The above code looks like a version of the constructor for a Matrix object that initializes the i,j,k vectors of the Matrix object from the given Quat object. I'm guessing it is just computing the rotation matrix that corresponds to the quaternion... but I don't know enough about quaternions to verify that statement... ;-) Hope this helps... |
| ||
I really don't understand the math that's going on! |
| ||
yeah, that is one of the advantages (or disadvantages since it makes a temp var that may not be released at all.) of C++, since what that will compile to is basically this.MatrixRoll(Matrix(q)); ' which the compiler then changes to Matrix tmp = Matrix(q); MatrixRoll(tmp); which is why some programmers, make sure they do the conversion themselves, since then they can keep account of ALL vars that are created. |
| ||
Guess this is nice for the real "hardcore" 3d math kind of people. Don't get me wrong I like trigonometry (especially when using for game development), but I don't think I would be able to program it like Mark does here. My whole reason for using Blitz was to not have to worry about this type of thing (no offense intended). |
| ||
Its great that you are posting up source code from BB3D like that Mark, it would be greater if I could understand it, but thats a seperate issue... |
| ||
@Drago: You said it bruthah! I hate this aspect of C++, and this is the typical and accepted way people use the language all the time. I steer clear of big C++ class libraries because of this sort of nonsense. And, don't even get me started on C++ "templates" or the "let's try (and fail) to code our way around the fundamental shortcomings of C++" that is called "STL" (the Standard Templates Library). LOL! |
| ||
This is exactly what im doing in maths right now... neat! |
| ||
1) Epsilon is often used in mathematics to represent an arbitrary small number. Possibly the most commonly written sentence fragment in analysis is: "For every epsilon > 0, there exists delta such that..." (substitute the actual epsilon and delta characters, hastily scrawled in chalk, for additional realism). Paul Erdos did not invent this convention (which is far older than he) but is, apparently, known for referring to children as epsilons. 2) Omega is not used to represent infinity (not that I've seen, anyway). Usually infinity is represented by: Aleph (hebrew letter) with a numerical subscript. The infinity symbol (sideways 8), although this is almost always used to represent countable infinity (Aleph 0) The italic c (for continuum), representing the degree of infiniteness of the Real Numbers (which is at least Aleph 1). 3) Very elegant C++ -- I love it. |
| ||
He's a better programmer than me, thats for sure. I got lost at #ifndef GEOM_H :P Just kidding- but i never got much farther... |
| ||
Anyone had any luck getting this to compile? I tried to import it in Bmax, and got about a dozen parse errors.(MingW is set up.) |
| ||
It compiles fine in visual studio. |
| ||
Thank you to show us this part of code, it shows the IDE is very good coded. |
| ||
Yeah, Thanks! |
| ||
Huh, comming back and looking at this now I understand everything but the quats. I get them a little but require more study to make any use of them :). |
| ||
Same here: Apart from Quaternions the adventurous high school student can make sense of the code. I know 'of' them though..and their use in interpolating a coordinate through a spline. The imaginery side of maths is quite something. |
| ||
Quaternions in most Animation Files do not need the multi line code examples you usually find (and most of them do not function anyway, endless formulas and Codelines produce wrong results - at least when I wanted to convert *.wrl or *.LiA files to B3D) After some try and error tests I found this: For instance to convert a Quaternion of the animation keys from a VRML-File (extension .wrl) to use it on a *.b3d file, all you need is this: w#=w#*180/Pi pitch#=x#*w# yaw#=-y#*w# roll#=z#*w# or w#=w#*180/Pi RotateEntity bone,x#*w#,-y#*w#,z#*w# After years of research I'm convinced the Quaternion thing is just a Hoax ;-) . |
| ||
Am I the only one who doesn't understand all the code? |
| ||
You're about 8 months too slow with that "joke". |
| ||
You would be right if it actually WAS a joke. :) Although it's 8 months slow, it still is related to the other posts. |
| ||
So there! pwned |
| ||
I've just spent the last few hours scouring nigh on every math site on the net, and wouldn't you know it, the equation I was after could be found here all along. That'll teach me to go looking elsewhere without checking here first. Thanks for the code. |
| ||
Here's a BMax version:Const TWOPI:Float=Pi*2.0 '360 degrees Const HALFPI:Float=Pi*.5 '90 degrees Const QUARTERPI:Float=Pi*.25 '45 degrees Const EPSILON:Float=.000001 'small value Const INFINITY:Float=10000000.0 'big value Type TVec Field x:Float,y:Float,z:Float Method Copy:TVec() Local q:TVec=New TVec q.x=x; q.y=y; q.z=z Return q End Method Function Create0:TVec() Local q:TVec=New TVec q.x=0.0; q.y=0.0; q.z=0.0 Return q End Function Function Create:TVec(x#,y#,z#) Local q:TVec=New TVec q.x=x#; q.y=y#; q.z=z# Return q End Function Rem operator Float*() ' ? operator overload Return &x; } operator Const Float *() ' ? operator overload Return &x; } Float &operator[]( Int n ) ' ? operator overload Return (&x)[n]; } Float operator[]( Int n ) ' ? operator overload Return (&x)[n]; } End Rem Method Negate:TVec() ' - operator overload Return TVec.Create( -x,-y,-z ) End Method Method Multiply:TVec( scale:Float ) ' * operator overload Return TVec.Create( x*scale,y*scale,z*scale ) End Method Method MultiplyVector:TVec( q:TVec ) ' * operator overload Return TVec.Create( x*q.x,y*q.y,z*q.z ) End Method Method Divide:TVec( scale:Float ) ' / operator overload Return TVec.Create( x/scale,y/scale,z/scale ) End Method Method DivideVector:TVec( q:TVec ) ' / operator overload Return TVec.Create( x/q.x,y/q.y,z/q.z ) End Method Method Add:TVec( q:TVec ) ' + operator overload Return TVec.Create( x+q.x,y+q.y,z+q.z ) End Method Method Subtract:TVec( q:TVec ) ' - operator overload Return TVec.Create( x-q.x,y-q.y,z-q.z ) End Method Rem Vector &operator*=( Float scale ) ' *= operator overload x*=scale;y*=scale;z*=scale;Return *this; } Vector &operator*=( Const Vector &q ) ' *= operator overload x*=q.x;y*=q.y;z*=q.z;Return *this; } Vector &operator/=( Float scale ) ' /= operator overload x/=scale;y/=scale;z/=scale;Return *this; } Vector &operator/=( Const Vector &q ) ' /= operator overload x/=q.x;y/=q.y;z/=q.z;Return *this; } End Rem Method Inc( q:TVec ) ' += operator overload x:+q.x;y:+q.y;z:+q.z End Method Method Dec( q:TVec ) ' -= operator overload x:-q.x;y:-q.y;z:-q.z End Method Method LessThan:Int( q:TVec ) ' < operator overload If( Abs(x-q.x)>EPSILON ) If x<q.x Then Return True Else Return False EndIf If( Abs(y-q.y)>EPSILON ) If y<q.y Then Return True Else Return False EndIf Return Abs(z-q.z)>EPSILON And z<q.z End Method Method Equals:Int( q:TVec ) ' = operator overload Return Abs(x-q.x)<=EPSILON And Abs(y-q.y)<=EPSILON And Abs(z-q.z)<=EPSILON End Method Method Inequality:Int( q:TVec ) ' != operator overload Return Abs(x-q.x)>EPSILON Or Abs(y-q.y)>EPSILON Or Abs(z-q.z)>EPSILON End Method Method Dot:Float( q:TVec ) Return x*q.x+y*q.y+z*q.z End Method Method Cross:TVec( q:TVec ) Return TVec.Create( y*q.z-z*q.y,z*q.x-x*q.z,x*q.y-y*q.x ) End Method Method Length:Float() Return Sqr(x*x+y*y+z*z) End Method Method Distance:Float( q:TVec ) Local dx:Float=x-q.x; Local dy:Float=y-q.y; Local dz:Float=z-q.z; Return Sqr(dx*dx+dy*dy+dz*dz) End Method Method Normalized:TVec() Local l:Float=Length(); Return TVec.Create( x/l,y/l,z/l ) End Method Method Normalize() Local l:Float=Length(); x:/l; y:/l; z:/l End Method Method Yaw:Float() Return -ATan2( x,z ) End Method Method Pitch:Float() Return -ATan2( y,Sqr( x*x+z*z ) ) End Method Method Clear() x=0;y=0;z=0 End Method End Type Type TLine Field o:TVec,d:TVec Function Create0:TLine() Local line:TLine=New Tline line.o=TVec.Create(0.0,0.0,0.0) line.d=TVec.Create(0.0,0.0,0.0) Return line End Function Function Create:TLine(o:TVec,d:TVec) Local line:TLine=New Tline line.o=TVec.Create(o.x,o.y,o.z) line.d=TVec.Create(d.x,d.y,d.z) Return line End Function Method Add:TLine( q:TVec ) ' + operator overload Return Create( o.Add(q),d ); End Method Method Subtract:TLine( q:TVec ) ' - operator overload Return Create( o.Subtract(q),d ); End Method Method Multiply:TVec( q:Float ) ' * operator overload Return o.Add(d.Multiply(q)) End Method Method Nearest:TVec( q:TVec ) Return o.Add( d.Multiply( ( d.Dot(q.Subtract(o)) / d.Dot(d) ) ) ) End Method End Type Type TPlane Field n:TVec Field d:Float Method Copy:TPlane() Local plane:TPlane=New TPlane plane.n=TVec.Create(n.x,n.y,n.z) plane.d=d Return plane End Method Function Create0:TPlane() Local plane:TPlane=New TPlane plane.n=TVec.Create(0.0,0.0,0.0) plane.d=0.0 Return plane End Function ' normal/offset form Function Create:TPlane(n:TVec,d:Float) Local plane:TPlane=New TPlane plane.n=TVec.Create(n.x,n.y,n.z) plane.d=d Return plane End Function ' point/normal form Function Create1:TPlane(p:TVec,n:TVec) Local plane:TPlane=New TPlane plane.n=TVec.Create(n.x,n.y,n.z) plane.d=n.Negate().Dot(p) Return plane End Function ' create plane from tri Function CreateFromTri:TPlane(v0:TVec,v1:TVec,v2:TVec) Local plane:TPlane=New TPlane plane.n=(v1.Subtract(v0)).Cross(v2.Subtract(v0)).normalized() plane.d=plane.n.Negate().Dot(v0) Return plane End Function Method Negate:TPlane() ' - operator overload Return TPlane.Create( n.Negate(),-d ) End Method Method t_intersect:Float( q:TLine ) Return -Distance(q.o)/n.Dot(q.d) End Method Method IntersectLine:TVec( q:TLine ) Return q.Multiply(t_intersect(q)) End Method Method IntersectPlane:TLine( q:TPlane ) Local lv:TVec=n.Cross( q.n ).Normalized() Return TLine.Create( q.IntersectLine( TLine.Create( Nearest( n.Multiply(-d) ),n.Cross(lv) ) ),lv ) End Method Method Nearest:TVec( q:TVec ) Return q.Subtract(n.Multiply(Distance(q))) End Method Method Negate2() n=n.Negate();d=-d End Method Method Distance:Float(q:TVec) Return n.Dot(q)+d End Method End Type Type TQuat Field w:Float Field v:TVec Function Create0:TQuat() Local q:TQuat=New TQuat q.w=1.0 Return q End Function Function Create:TQuat( w:Float,v:TVec ) Local q:TQuat=New TQuat q.w=1.0 q.v.x=v.x q.v.y=v.y q.v.z=v.z Return q End Function Method Negate:TQuat() ' - operator overload Return TQuat.Create( w,v.Negate() ) End Method Method Add:TQuat( q:TQuat ) ' + operator overload Return TQuat.Create( w+q.w,v.Add(q.v) ) End Method Method Subtract:TQuat( q:TQuat ) ' - operator overload Return TQuat.Create( w-q.w,v.Subtract(q.v) ) End Method Method Multiply:TQuat( q:TQuat ) ' * operator overload Return TQuat.Create( w*q.w-v.dot(q.v),(q.v.cross(v)).Add(q.v.Multiply(w)).Add(v.Multiply(q.w)) ) End Method Method MultiplyVector:TVec( q:TVec ) ' * operator overload Return ( Self.Multiply(TQuat.Create(0,q)).Multiply(Self.Negate()) ).v End Method Method MultiplyFloat:TQuat( q:Float ) ' * operator overload Return TQuat.Create( w*q,v.Multiply(q) ) End Method Method Divide:TQuat( q:Float ) ' / operator overload Return TQuat.Create( w/q,v.Divide(q) ) End Method Method Dot:Float( q:TQuat ) Return v.x*q.v.x+v.y*q.v.y+v.z*q.v.z+w*q.w End Method Method Length:Float() Return Sqr( w*w+v.x*v.x+v.y*v.y+v.z*v.z ) End Method Method Normalize() w=w/Length() v.x=v.x/Length() v.y=v.y/Length() v.z=v.z/Length() End Method Method Normalized:TQuat() Local q:TQuat=New TQuat q.w=q.w/Length() q.v.x=q.v.x/Length() q.v.y=q.v.y/Length() q.v.z=q.v.z/Length() Return q End Method Method SlerpTo:TQuat( q:TQuat,a:Float ) Local t:TQuat=q Local d:Float=dot(q),b:Float=1-a If( d<0 ) t.w=-t.w; t.v=t.v.Negate(); d=-d If( d<1-EPSILON ) Local om:Float=ACos( d ) Local si:Float=Sin( om ) a=Sin( a*om )/si b=Sin( b*om )/si EndIf Return (Self.MultiplyFloat(b)).Add(t.MultiplyFloat(a)) End Method Method i:TVec() Local xz:Float=v.x*v.z,wy:Float=w*v.y Local xy:Float=v.x*v.y,wz:Float=w*v.z Local yy:Float=v.y*v.y,zz:Float=v.z*v.z Return TVec.Create( 1-2*(yy+zz),2*(xy-wz),2*(xz+wy) ) End Method Method j:TVec() Local yz:Float=v.y*v.z,wx:Float=w*v.x Local xy:Float=v.x*v.y,wz:Float=w*v.z Local xx:Float=v.x*v.x,zz:Float=v.z*v.z Return TVec.Create( 2*(xy+wz),1-2*(xx+zz),2*(yz-wx) ) End Method Method k:TVec() Local xz:Float=v.x*v.z,wy:Float=w*v.y Local yz:Float=v.y*v.z,wx:Float=w*v.x Local xx:Float=v.x*v.x,yy:Float=v.y*v.y Return TVec.Create( 2*(xz-wy),2*(yz+wx),1-2*(xx+yy) ) End Method End Type Type TMat Field i:TVec,j:TVec,k:TVec Method Copy:TMat() Local m:TMat=New TMat m.i=TVec.Create(i.x,i.y,i.z) m.j=TVec.Create(j.x,j.y,j.z) m.k=TVec.Create(k.x,k.y,k.z) Return m End Method Function Create0:TMat() Local m:TMat=New TMat m.i=TVec.Create(1,0,0); m.j=TVec.Create(0,1,0); m.k=TVec.Create(0,0,1) Return m End Function Function Create:TMat( i:TVec,j:TVec,k:TVec ) Local m:TMat=New TMat m.i=i; m.j=j; m.k=k Return m End Function Function CreateFromQuat:TMat( q:TQuat ) Local m:TMat=New TMat Local xx:Float=q.v.x*q.v.x,yy:Float=q.v.y*q.v.y,zz:Float=q.v.z*q.v.z Local xy:Float=q.v.x*q.v.y,xz:Float=q.v.x*q.v.z,yz:Float=q.v.y*q.v.z Local wx:Float=q.w*q.v.x,wy:Float=q.w*q.v.y,wz:Float=q.w*q.v.z m.i=TVec.Create( 1-2*(yy+zz),2*(xy-wz),2*(xz+wy) ) m.j=TVec.Create( 2*(xy+wz),1-2*(xx+zz),2*(yz-wx) ) m.k=TVec.Create( 2*(xz-wy),2*(yz+wx),1-2*(xx+yy) ) Return m End Function Function CreateFromAngle:TMat( angle:Float,axis:TVec ) Local m:TMat=New TMat Local u:TVec=axis Local c:Float=Cos(angle),s:Float=Sin(angle) Local x2:Float=axis.x*axis.x,y2:Float=axis.y*axis.y,z2:Float=axis.z*axis.z m.i=TVec.Create( x2+c*(1-x2),u.x*u.y*(1-c)-u.z*s,u.z*u.x*(1-c)+u.y*s ) m.j=TVec.Create( u.x*u.y*(1-c)+u.z*s,y2+c*(1-y2),u.y*u.z*(1-c)-u.x*s ) m.k=TVec.Create( u.z*u.x*(1-c)-u.y*s,u.y*u.z*(1-c)+u.x*s,z2+c*(1-z2) ) Return m End Function Rem Vector &operator[]( Int n ){ Return (&i)[n]; } Const Vector &operator[]( Int n )Const{ Return (&i)[n]; } End Rem Method Inverse:TMat() ' ~ operator overload - inverse? Local m:TMat=TMat.Create0() m.i.x=i.x;m.i.y=j.x;m.i.z=k.x m.j.x=i.y;m.j.y=j.y;m.j.z=k.y m.k.x=i.z;m.k.y=j.z;m.k.z=k.z Return m End Method Method Determinant:Float() Return i.x*(j.y*k.z-j.z*k.y )-i.y*(j.x*k.z-j.z*k.x )+i.z*(j.x*k.y-j.y*k.x ) End Method Method Negate:TMat() ' - operator overload Local m:TMat=TMat.Create0() Local t:Float=1.0/Determinant() m.i.x= t*(j.y*k.z-j.z*k.y);m.i.y=-t*(i.y*k.z-i.z*k.y);m.i.z= t*(i.y*j.z-i.z*j.y) m.j.x=-t*(j.x*k.z-j.z*k.x);m.j.y= t*(i.x*k.z-i.z*k.x);m.j.z=-t*(i.x*j.z-i.z*j.x) m.k.x= t*(j.x*k.y-j.y*k.x);m.k.y=-t*(i.x*k.y-i.y*k.x);m.k.z= t*(i.x*j.y-i.y*j.x) Return m End Method Method Cofactor:TMat() Local m:TMat=TMat.Create0() m.i.x= (j.y*k.z-j.z*k.y);m.i.y=-(j.x*k.z-j.z*k.x);m.i.z= (j.x*k.y-j.y*k.x) m.j.x=-(i.y*k.z-i.z*k.y);m.j.y= (i.x*k.z-i.z*k.x);m.j.z=-(i.x*k.y-i.y*k.x) m.k.x= (i.y*j.z-i.z*j.y);m.k.y=-(i.x*j.z-i.z*j.x);m.k.z= (i.x*j.y-i.y*j.x) Return m End Method Method Equals:Int( q:TMat ) ' == operator overload Return i=q.i And j=q.j And k=q.k End Method Method Inequality:Int( q:TMat ) ' != operator overload Return i<>q.i Or j<>q.j Or k<>q.k End Method Method MultiplyVector:TVec( q:TVec ) ' * operator overload Return TVec.Create( i.x*q.x+j.x*q.y+k.x*q.z,i.y*q.x+j.y*q.y+k.y*q.z,i.z*q.x+j.z*q.y+k.z*q.z ) End Method Method Multiply:TMat( q:TMat ) ' * operator overload Local m:TMat=TMat.Create0() m.i.x=i.x*q.i.x+j.x*q.i.y+k.x*q.i.z;m.i.y=i.y*q.i.x+j.y*q.i.y+k.y*q.i.z;m.i.z=i.z*q.i.x+j.z*q.i.y+k.z*q.i.z m.j.x=i.x*q.j.x+j.x*q.j.y+k.x*q.j.z;m.j.y=i.y*q.j.x+j.y*q.j.y+k.y*q.j.z;m.j.z=i.z*q.j.x+j.z*q.j.y+k.z*q.j.z m.k.x=i.x*q.k.x+j.x*q.k.y+k.x*q.k.z;m.k.y=i.y*q.k.x+j.y*q.k.y+k.y*q.k.z;m.k.z=i.z*q.k.x+j.z*q.k.y+k.z*q.k.z Return m End Method Method Orthogonalize() k.Normalize() i=j.Cross( k ).Normalized() j=k.Cross( i ) End Method Method Orthogonalized:TMat() Local m:TMat=TMat.Create0() m.Orthogonalize() Return m End Method End Type Type TBox Field a:TVec,b:TVec Function Create0:TBox() Local box:TBox=New TBox box.a=TVec.Create(INFINITY,INFINITY,INFINITY) box.b=TVec.Create(-INFINITY,-INFINITY,-INFINITY) Return box End Function Function CreateFromPoint:TBox( q:TVec ) Local box:TBox=New TBox box.a=TVec.Create(q.x,q.y,q.z) box.b=TVec.Create(q.x,q.y,q.z) Return box End Function Function Create:TBox( a:TVec,b:TVec ) Local box:TBox=New TBox box.a=TVec.Create(a.x,a.y,a.z) box.b=TVec.Create(b.x,b.y,b.z) Return box End Function Function CreateFromLine:TBox( l:TLine ) Local box:TBox=New TBox box.a=TVec.Create(l.o.x,l.o.y,l.o.z) box.b=TVec.Create(l.o.x,l.o.y,l.o.z) box.UpdateFromVector( l.o.Add(l.d) ) Return box End Function Method Clear() a.x=INFINITY;a.y=INFINITY;a.z=INFINITY b.x=-INFINITY;b.y=-INFINITY;b.z=-INFINITY End Method Method Empty:Int() Return b.x<a.x Or b.y<a.y Or b.z<a.z End Method Method Centre:TVec() Return TVec.Create( (a.x+b.x)*.5,(a.y+b.y)*.5,(a.z+b.z)*.5 ) End Method Method Corner:TVec( n:Int ) Local x#=n&1;If x Then x=b.x Else x=a.x Local y#=n&2;If y Then y=b.y Else y=a.y Local z#=n&4;If z Then z=b.z Else z=a.z Return TVec.Create( x,y,z ) End Method Method UpdateFromVector( q:TVec ) If q.x<a.x Then a.x=q.x If q.y<a.y Then a.y=q.y If q.z<a.z Then a.z=q.z If q.x>b.x Then b.x=q.x If q.y>b.y Then b.y=q.y If q.z>b.z Then b.z=q.z End Method Method UpdateFromBox( q:TBox ) If q.a.x<a.x Then a.x=q.a.x If q.a.y<a.y Then a.y=q.a.y If q.a.z<a.z Then a.z=q.a.z If q.b.x>b.x Then b.x=q.b.x If q.b.y>b.y Then b.y=q.b.y If q.b.z>b.z Then b.z=q.b.z End Method Method Overlaps:Int( q:TBox ) Local x#=b.x<q.b.x;If x Then x=b.x Else x=q.b.x Local y#=b.y<q.b.y;If y Then y=b.y Else y=q.b.y Local z#=b.z<q.b.z;If z Then z=b.z Else z=q.b.z Return x And y And z End Method Method Expand( n:Float ) a.x:-n;a.y:-n;a.z:-n;b.x:+n;b.y:+n;b.z:+n End Method Method Width:Int() Return b.x-a.x End Method Method Height:Int() Return b.y-a.y End Method Method Depth:Int() Return b.z-a.z End Method Method Contains:Int( q:TVec ) Return q.x>=a.x And q.x<=b.x And q.y>=a.y And q.y<=b.y And q.z>=a.z And q.z<=b.z End Method End Type Type TTransform Field m:TMat Field v:TVec Function Create0:TTransform() Local tform:TTransform=New TTransform tform.m:TMat=TMat.Create0() tform.v:TVec=TVec.Create0() Return tform End Function Function CreateFromMatrix:TTransform(m:TMat) Local tform:TTransform=New TTransform tform.m=m.Copy() Return tform End Function Function CreateFromVector:TTransform(v:TVec) Local tform:TTransform=New TTransform tform.v=TVec.Create(v.x,v.y,v.z) Return tform End Function Function Create:TTransform(m:TMat,v:TVec) Local tform:TTransform=New TTransform tform.m=m.Copy() tform.v=TVec.Create(v.x,v.y,v.z) Return tform End Function Method Negate:TTransform() ' - operator overload Local t:TTransform=New TTransform t.m=m.Negate();t.v=t.m.MultiplyVector(v.Negate()) Return t End Method Method Inverse:TTransform() ' ~ operator overload Local t:TTransform=New TTransform t.m=m.Inverse();t.v=t.m.MultiplyVector(v.Negate()) Return t End Method Method MultiplyVector:TVec( q:TVec ) ' * operator overload Return m.MultiplyVector(q).Add(v) End Method Method MultiplyLine:TLine( q:TLine ) ' * operator overload Local t:TVec=Self.MultiplyVector(q.o) Return TLine.Create( t,Self.MultiplyVector(q.o.Add(q.d)).Subtract(t) ) End Method Method MultiplyBox:TBox( q:TBox ) ' * operator overload Local t:TBox=TBox.CreateFromPoint(Self.MultiplyVector(q.corner(0))) For Local k:Int=1 To 8 t.UpdateFromVector( Self.MultiplyVector(q.corner(k)) ) Next Return t End Method Method MultiplyTransform:TTransform( q:TTransform ) ' operator overload Local t:TTransform=New TTransform t.m=m.Multiply(q.m);t.v=m.MultiplyVector(q.v.Add(v)) Return t End Method Method Equals:Int( q:TTransform ) ' == operator overload Return m.Equals(q.m) And v.Equals(q.v) End Method Method Inequality:Int( q:TTransform ) ' != operator overload Return Not Equals( q ) End Method End Type Function TransformRadius:Float( r:Float,t:TMat ) Local sq_3:Float=Sqr(1.0/3.0) Return t.MultiplyVector( TVec.Create(sq_3,sq_3,sq_3) ).length()*r End Function Function PitchMatrix:TMat( q:Float ) Return TMat.Create( TVec.Create(1,0,0),TVec.Create(0,Cos(q),Sin(q)),TVec.Create(0,-Sin(q),Cos(q)) ) End Function Function YawMatrix:TMat( q:Float ) Return TMat.Create( TVec.Create(Cos(q),0,Sin(q)),TVec.Create(0,1,0),TVec.Create(-Sin(q),0,Cos(q)) ) End Function Function RollMatrix:TMat( q:Float ) Return TMat.Create( TVec.Create(Cos(q),Sin(q),0),TVec.Create(-Sin(q),Cos(q),0),TVec.Create(0,0,1) ) End Function Function MatrixPitch:Float( m:TMat ) Return m.k.pitch() End Function Function MatrixYaw:Float( m:TMat ) Return m.k.yaw() End Function Function MatrixRoll:Float( m:TMat ) Return ATan2( m.i.y,m.j.y ) End Function Function ScaleMatrix:TMat( x:Float,y:Float,z:Float ) Return TMat.Create( TVec.Create( x,0,0 ),TVec.Create( 0,y,0 ),TVec.Create( 0,0,z ) ) End Function Function ScaleMatrix1:TMat( scale:TVec ) Return TMat.Create( TVec.Create( scale.x,0,0 ),TVec.Create( 0,scale.y,0 ),TVec.Create( 0,0,scale.z ) ) End Function Function PitchQuat:TQuat( p:Float ) Return TQuat.Create( Cos(p/-2),TVec.Create( Sin(p/-2),0,0 ) ) End Function Function YawQuat:TQuat( y:Float ) Return TQuat.Create( Cos(y/2),TVec.Create( 0,Sin(y/2),0 ) ) End Function Function RollQuat:TQuat( r:Float ) Return TQuat.Create( Cos(r/-2),TVec.Create( 0,0,Sin(r/-2) ) ) End Function Function RotationMatrix:TMat( p:Float,y:Float,r:Float ) Return YawMatrix(y).Multiply(PitchMatrix(p)).Multiply(RollMatrix(r)) End Function Function RotationMatrix1:TMat( rot:TVec ) Return YawMatrix(rot.y).Multiply(PitchMatrix(rot.x)).Multiply(RollMatrix(rot.z)) EndFunction Function QuatPitch:Float( q:TQuat ) Return q.k().Pitch() End Function Function QuatYaw:Float( q:TQuat ) Return q.k().Yaw() End Function Function QuatRoll:Float( q:TQuat ) Return MatrixRoll( TMat.CreateFromQuat(q) ) End Function Function MatrixQuat:TQuat( p:TMat ) Local m:TMat m=p m.Orthogonalize() Local t:Float=m.i.x+m.j.y+m.k.z,w:Float,x:Float,y:Float,z:Float If( t>EPSILON ) t=Sqr( t+1 )*2 x=(m.k.y-m.j.z)/t y=(m.i.z-m.k.x)/t z=(m.j.x-m.i.y)/t w=t/4 Else If( m.i.x>m.j.y And m.i.x>m.k.z ) t=Sqr( m.i.x-m.j.y-m.k.z+1 )*2 x=t/4 y=(m.j.x+m.i.y)/t z=(m.i.z+m.k.x)/t w=(m.k.y-m.j.z)/t Else If( m.j.y>m.k.z ) t=Sqr( m.j.y-m.k.z-m.i.x+1 )*2 x=(m.j.x+m.i.y)/t y=t/4 z=(m.k.y+m.j.z)/t w=(m.i.z-m.k.x)/t Else t=Sqr( m.k.z-m.j.y-m.i.x+1 )*2 x=(m.i.z+m.k.x)/t y=(m.k.y+m.j.z)/t z=t/4 w=(m.j.x-m.i.y)/t EndIf Return TQuat.Create( w,TVec.Create( x,y,z ) ) End Function Heavy useage of this is likely to be quite a bit slower than C++ due to the Bmax functions not being inlined and also due to the GC having to collect lots of vector objects. |
| ||
const float EPSILON=.000001f; //small value const float INFINITY=10000000.0f; //big valueHow come EPSILON uses 6 decimal places but INFINITY uses 8? |
| ||
@SimonH in "Type TQuat" You'd better store the lenght locally... Method Length:Float() Return Sqr( w*w+v.x*v.x+v.y*v.y+v.z*v.z ) End Method Method Normalize() local l_lenght:float=Lenght() w=w/l_lenght v.x=v.x/l_lenght v.y=v.y/l_lenght v.z=v.z/l_lenght End Method idem for Method Normalized:TQuat() @ Mark Sibly not sure, but it seems to be the same (i'm not easy with C++ programing ... so... ) I don't know how pointer "this" is archived, and don't know about redondant routines... void normalize(){ float l_lenght=length(); *this=*this/l_length; } Quat normalized()const{ float l_lenght=length(); return *this/l_length; } |
| ||
in the quat code ( bmax version )Method Normalized:TQuat() Local q:TQuat=New TQuat q.w=q.w/Length() q.v.x=q.v.x/Length() q.v.y=q.v.y/Length() q.v.z=q.v.z/Length() Return q End Method if we operand "/lentght()" to the new quat, the result is "0" => q is a "new" quat, so (as there is no "Method New()" to set w as "1"), all its value are 0,0,0,0 , instead of copying the callback quat you should add a New() method as the original C++ file and use the copy constructor instead of new Method New() w=1 v = TVec.Create(0,0,0) End Method Method Copy:TQuat() local q:TQuat = New TQuat q.w=w; q.v = v.copy() return q End Method Method Normalized:TQuat() Local q:TQuat=Copy() q.w=q.w/Length() q.v.x=q.v.x/Length() q.v.y=q.v.y/Length() q.v.z=q.v.z/Length() Return q End Method [EDIT 1] in Type TMat Method Orthogonalized:TMat() Local m:TMat=TMat.Create0() m.Orthogonalize() Return m End Method It does not copy the matrix, then ortogonalize... it only return a new "Identity + orthogonalized" should be : Method Orthogonalized:TMat() local m:TMat = Copy() m.Orthogonalize() return m End Method Last edited 2012 Last edited 2012 |
| ||
[double post, sorry for that] |
| ||
Mark, have you ever considered making a math website. Or a gsme; Mark Math (ages 2 and up)? |
| ||
Is there a tutorial or reference that shows how the b3d entity commands can be represented using these classes? ie: TranslateEntity,MoveEntity,RotateEntity,TurnEntity,PositionEntity, etc? I think I have it figured out but it'd be great if someone else could should more light on this. Thanks! |
| ||
My brain hurts. |
| ||
My brain hurts too. |
| ||
Something hurts here too... but much lower... ...my feet, what did you expect? Seriously now, you guys resurrected a 9 years old thread?! Holy necroposting Batman!!! |