Code archives/3D Graphics - Maths/3D Math Lib - BMax

This code has been declared by its author to be Public Domain code.

Download source code

3D Math Lib - BMax by Chroma2005
Easy to use 3d math lib for BMax. Can do complex equations on a single line. Very handy for converting complex maths from C/C++.
Each command has a description of what it does and examples of exactly how to use it.

Updated 02Dec05: Added some Quaternions
Updated 04Dec05: Added Matrices
' 3D Math Library v2.0
' BlitzMAX Edition
' by Chroma

' You can do some lengthy equations with this Math Lib
' Just remember it does the maths in order of parenthesis
' So you have to write the equation accordingly (in reverse?)
' For example the equation: v=v1+v2*v3+v4
' It doesn't automatically do the multiplication first
' You have to engineer the equation manually like so:
' v = v1.Add( v4.Add( v2.Mul( v3 ) ) )
' Just be aware of the order they are calc'ed in

' Here's a physics example:
' vAcceleration = vForces.DivS( Mass )
' vVelocity.AddTimeStep( vAcceleration, dt )
' vPosition.AddTimeStep( vVelocity, dt )

'Test
'Graphics 800,600,32,85
'a:Vector = Vector.Create()
'b:Vector = Vector.Create(1,2,3)
'While Not KeyHit(KEY_ESCAPE)
'Cls
'a.AddTimeStep( b, .015)
'a.Show(5,5,"Test")
'Flip
'Wend
'End


' Constants
Const Tol:Float = 0.0001

'-------------------------------------------
'---- Vector Type and Functions/Methods ----
'-------------------------------------------
Type Vector

	Field x:Float
	Field y:Float
	Field z:Float
	
	' Purpose: Create a New Vector
	' Returns: Vector
	' Example1: v1:Vector = New Vector
	' Example2: v1:Vector = Vector.Create()
	' Example3: v1:Vector = Vector.Create(1,2,3)
	Function Create:Vector( x:Float = 0, y:Float = 0, z:Float = 0 )
		Local v:Vector = New Vector
		v.x = x
		v.y = y
		v.z = z
		Return v
	End Function
	
	' Purpose: Set a Vector with New XYZ Components
	' Returns: Nothing
	' Example: v1.Set(1,2,3)
	' Example: v1.Set() will set a vector to (0,0,0)
	Method Set( newx:Float = 0, newy:Float = 0, newz:Float = 0 )
		x = newx
		y = newy
		z = newz
	End Method
	
	' Purpose: Add Two Vectors
	' Returns: Vector
	' Example1: v1=v1+v2 would be written v1 = v1.Add( v2 )
	' Example2: v1=v2+v3 would be written v1 = v2.Add( v3 )
	Method Add:Vector( v:Vector )
		Local res:Vector = New Vector
		res.x = x + v.x 
		res.y = y + v.y
		res.z = z + v.z
		Return res
	End Method

	' Purpose: Subtract Two Vectors
	' Returns: Vector
	' Example1: v1=v1-v2 would be written v1 = v1.Sub( v2 ) 
	' Example2: v1=v2-v3 would be written v1 = v2.Sub( v3 ) 
	Method Sub:Vector( v:Vector )
		Local res:Vector = New Vector
		res.x = x - v.x
		res.y = y - v.y
		res.z = z - v.z
		Return res
	End Method
	
	' Purpose: Multiply Two Vectors
	' Returns: Vector
	' Example1: v1=v1*v2 would be written v1 = v1.Mul( v2 ) 
	' Example2: v1=v2*v3 would be written v1 = v2.Mul( v3 )
	Method Mul:Vector( v:Vector )
		Local res:Vector = New Vector
		res.x = x * v.x
		res.y = y * v.y
		res.z = z * v.z
		Return res
	End Method
	
	' Purpose: Divide One Vector By Another
	' Returns: Vector
	' Example1: v1=v1/v2 would be written v1 = v1.Div( v2 )
	' Example2: v1=v2/v3 would be written v1 = v2.Div( v3 )
	Method Div:Vector( v:Vector )
		Local res:Vector = New Vector
		res.x = x / v.x
		res.y = y / v.y
		res.z = z / v.z
		Return res
	End Method
	
	' Purpose: Add a Scalar to a Vector
	' Returns: Vector
	' Example1: v1=v1+1 would be written v1 = v1.AddS( 1 )
	' Example2: v1=v2+1 would be written v1 = v2.AddS( 1 )
	Method AddS:Vector( s:Float )
		Local res:Vector = New Vector
		res.x = x + s
		res.y = y + s
		res.z = z + s
		Return res
	End Method
	
	' Purpose: Subtract a Scalar from a Vector
	' Returns: Vector
	' Example1: v1=v1-1 would be written v1 = v1.SubS( 1 )
	' Example2: v1=v2-1 would be written v1 = v2.SubS( 1 )
	Method SubS:Vector( s:Float )
		Local res:Vector = New Vector
		res.x = x - s
		res.y = y - s
		res.z = z - s
		Return res
	End Method

	' Purpose: Multiply a Vector by a Scalar
	' Returns: Vector
	' Example1: v1=v1*2 would be written v1 = v1.MulS( 2 )
	' Example2: v1=v2*2 would be written v1 = v2.MulS( 2 )
	Method MulS:Vector( s:Float )
		Local res:Vector = New Vector
		res.x = x * s
		res.y = y * s
		res.z = z * s
		Return res
	End Method
	
	' Purpose: Divide a Vector by a Scalar
	' Returns: Vector
	' Example1: v1=v1/2 would be written v1 = v1.DivS( 2 )
	' Example2: v1=v2/2 would be written v1 = v2.DivS( 2 )
	Method DivS:Vector( s:Float )
		Local res:Vector = New Vector
		res.x = x / s
		res.y = y / s
		res.z = z / s
		Return res
	End Method
	
	' Purpose: Multiply a Vector by a Quaternion
	' Returns: Quaternion
	' Example: q1=v1*q1 would be written q1 = v1.MulQ ( q1 )	
	Method MulQ:Quaternion( q:Quaternion )
		Local res:Quaternion = New Quaternion
		res.n = -(q.v.x*x + q.v.y*y + q.v.z*z)
		res.v.x = q.n*x + q.v.z*y - q.v.y*z
		res.v.y = q.n*y + q.v.x*z - q.v.z*x
		res.v.z = q.n*z + q.v.y*x - q.v.x*y
		Return res
	End Method

	' Purpose: Multiply a Vector by a Matrix
	' Returns: Vector
	' Example: v1=v1*m1 would be written v1 = v1.MulM( m1 )	
	Method MulM:Vector ( m:Matrix )
		Local res:Vector = New Vector	
		res.x = x*m.e11 + y*m.e21 + z*m.e31
		res.y = x*m.e12 + y*m.e22 + z*m.e32
		res.z = x*m.e13 + y*m.e23 + z*m.e33
		Return res
	End Method

	' Purpose: Calculate the Magnitude of a Vector
	' Returns: Float
	' Example: Local a:Float = v1.Magnitude()
	Method Magnitude:Float()
		Return Sqr(x * x + y * y + z * z)
	End Method

	' Purpose: Normalize a Vector
	' Returns: Nothing - Directly Normalizes Target Vector
	' Example: v1.Normalize()
	Method Normalize()
		Local mag:Float = Magnitude()
		If mag = 0.0 Then Set();Return
		x :/ mag
		y :/ mag
		z :/ mag
		If Abs( x ) < Tol x = 0.0
		If Abs( y ) < Tol y = 0.0
		If Abs( z ) < Tol z = 0.0
	End Method
	
	' Purpose: Calculate the Cross Product of Two Vectors
	' Returns: Vector
	' Example1: v1 = v1.CrossP( v2 )
	' Example2: v1 = v2.CrossP( v3 )
	Method CrossP:Vector( v:Vector )
		Local res:Vector = New Vector
		res.x =  y * v.z  -  z * v.y 
		res.y = -x * v.z  +  z * v.x 
		res.z =  x * v.y  -  y * v.x
		Return res
	EndMethod
	
	' Purpose: Calculate the Dot Product Between Two Vectors
	' Returns: Float
	' Example: Local mydot:float = v1.DotP( v2 )
	Method DotP:Float( v:Vector )
		Return x * v.x + y * v.y + z * v.z
	EndMethod
	
	Method Inverse:Vector()
		Return Vector.Create( -x, -y, -z )
	End Method
	
	' Purpose: Add Two Vectors and Multiply by a DeltaTime
	' Returns: Nothing - Directly Changes the Target Vector
	' Example: vPos=vPos+vVel*dt would be vPos.AddTimeStep( vVel, dt )
	Method AddTimeStep( v:Vector, time_step:Float )
		x :+ v.x * time_step
		y :+ v.y * time_step
		z :+ v.z * time_step
	End Method
	
	' Purpose: Show Vector Values for Debug Purposes
	' Returns: Nothing
	' Note: Graphics mode must be set for this command to work
	' Example: v1.Show( 5, 5, "vPosition" )
	Method Show( xpos:Int = 5, ypos:Int = 5, label:String = "", vspc:Int = 12 )
		DrawText label + "_X: " + x, xpos, ypos
		DrawText label + "_Y: " + y, xpos, ypos + vspc
		DrawText label + "_Z: " + z, xpos, ypos + vspc * 2
	End Method
	
End Type

' Degrees To Radians Conversion
Function DegreesToRadians:Float(deg:Float)
	Return deg * Pi / 180.0
End Function

' Radians To Degrees Conversion
Function RadiansToDegrees:Float(rad:Float)
	Return rad * 180.0 / Pi
End Function


'-------------------------------------------
'-- Quaternion Type and Functions/Methods --
'-------------------------------------------
Type Quaternion
	
	Field n:Float
	Field v:Vector = New Vector
	
	' Purpose: Create a New Quaternion
	' Returns: Quaternion
	' Example1: q1:Quaternion = New Quaternion
	' Example2: q1:Quaternion = Quaternion.Create( 1, 2, 3, 4 )
	' Example3: q1:Quaternion = Quaternion.Create()
	Function Create:Quaternion( n:Float = 0, x:Float = 0, y:Float = 0, z:Float = 0 )
		Local q:Quaternion = New Quaternion
		q.n = n
		q.v.x = x
		q.v.y = y
		q.v.z = z
		Return q
	End Function
	
	' Purpose: Add Two Quaternions
	' Returns: Quaternion
	' Example1: q1=q1+q2 would be q1 = q1.Add( q2 )
	' Example2: q1=q2+q3 would be q1 = q2.Add( q3 )
	Method Add:Quaternion( q:Quaternion )
		Local res:Quaternion = New Quaternion
		res.n = n + q.n
		res.v.x = v.x + q.v.x
		res.v.y = v.y + q.v.y
		res.v.z = v.z + q.v.z
		Return res
	End Method
	
	' Purpose: Subtract Two Quaternions
	' Returns: Quaternion
	' Example1: q1=q1-q2 would be q1 = q1.Sub( q2 )
	' Example2: q1=q2-q3 would be q1 = q2.Sub( q3 )
	Method Sub:Quaternion( q:Quaternion )
		Local res:Quaternion = New Quaternion
		res.n = n - q.n
		res.v.x = v.x - q.v.x
		res.v.y = v.y - q.v.y
		res.v.z = v.z - q.v.z
		Return res
	End Method
	
	' Purpose: Multiply Two Quaternions
	' Returns: Quaternion
	' Example1: q1=q1*q2 would be q1 = q1.Mul( q2 )
	' Example2: q1=q2*q3 would be q1 = q2.Mul( q3 )
	Method Mul:Quaternion( q:Quaternion )
		Local res:Quaternion = New Quaternion
		res.n = n*q.n - v.x*q.v.x - v.y*q.v.y - v.z*q.v.z
		res.v.x = n*q.v.x + v.x*q.n + v.y*q.v.z - v.z*q.v.y
		res.v.y = n*q.v.y + v.y*q.n + v.z*q.v.x - v.x*q.v.z
		res.v.z = n*q.v.y + v.y*q.n + v.z*q.v.x - v.x*q.v.z
		Return res
	End Method
	
	' Purpose: Multiply a Quaternion by a Scalar
	' Returns: Quaternion
	' Example1: q1=q1*2 would be q1 = q1.MulS( 2 )
	' Example2: q1=q2*2 would be q1 = q2.MulS( 2 )
	Method MulS:Quaternion( s:Float )
		Local res:Quaternion = New Quaternion
		res.n = n * s
		res.v.x = v.x * s
		res.v.y = v.y * s
		res.v.z = v.z * s
		Return res
	End Method

	' Purpose: Divide a Quaternion by a Scalar
	' Returns: Quaternion
	' Example1: q1=q1/2 would be q1 = q1.DivS( 2 )
	' Example2: q1=q2/2 would be q1 = q2.DivS( 2 )
	Method DivS:Quaternion( s:Float )
		Local res:Quaternion = New Quaternion
		res.n = n / s
		res.v.x = v.x / s
		res.v.y = v.y / s
		res.v.z = v.z / s
		Return res
	End Method
	
	' Purpose: Multiply a Quaternion by a Vector
	' Returns: Quaternion
	' Example1: q1=q1*v1 would be written q1 = q1.MulV( v1 )
	Method MulV:Quaternion( v:Vector )
		res:Quaternion = New Quaternion
		res.n = -(self.v.x*v.x + self.v.y*v.y + self.v.z*v.z)
		res.v.x = self.n*v.x + self.v.y*v.z - self.v.z*v.y
		res.v.y = self.n*v.y + self.v.z*v.x - self.v.x*v.z
		res.v.z = self.n*v.z + self.v.x*v.y - self.v.y*v.x
		Return res
	End Method
	
	' Purpose: Calculate the Magnitude of a Quaternion
	' Returns: Float
	' Example: Local qmag:float = q1.Magnitude()
	Method Magnitude:Float( q:Quaternion )
		Return Float Sqr( n * n + v.x * v.x + v.y * v.y + v.z * v.z )
	End Method

	' Purpose: Gets the XYZ Component of a Quaternion
	' Returns: Vector
	' Example: v1 = q1.GetVector()
	Method GetVector:Vector()
		Return Vector.Create(v.x, v.y, v.z)
	End Method
	
	' Purpose: Inverse a Quaternion
	' Returns: Quaternion
	' Example1: q1=~q1 would be q1 = q1.Inverse()
	' Example2: q1=~q2 would be q1 = q2.Inverse() 
	Method Inverse:Quaternion()
		Return Quaternion.Create(n, -v.x, -v.y, -v.z)
	End Method
	
	' Purpose: Show Quaternion Values for Debug Purposes
	' Returns: Nothing
	' Note: Graphics mode must be set for this command to work
	' Example: q1.Show( 5, 5, "qAngularVelocity" )
	Method Show( xpos:Int, ypos:Int, label:String = "", vspc:Int = 12 )
		DrawText n, xpos, ypos
		DrawText v.x, xpos, ypos + vspc
		DrawText v.y, xpos, ypos + vspc * 2
		DrawText v.z, xpos, ypos + vspc * 3
	End Method

	' Purpose: Used in Physics
	' Returns: Quaternion
	' Example: q1 = q1.QRotate( q2 )
	Method QRotate:Quaternion( q:Quaternion )
		' q1*q2*(~q1)
		Local t:Quaternion = New Quaternion
		t = self.Mul( q )
		Return t.Mul( self.Inverse() )
	End Method

	' Purpose: Used in Physics
	' Returns: Vector
	' Example: v1 = q1.QVRotate( v2 )
	Method QVRotate:Vector( v )
		Local t:Quaternion = New Quaternion
		' t = q*v*(~q);
		t = self.MulV( v )
		t = t.Mul( self.Inverse() )
		Return t.GetVector()
	End Method

End Type


'-------------------------------------------
'---- Matrix Type and Functions/Methods ----
'-------------------------------------------

Type Matrix

	Field e11:Float = 0, e12:Float = 0, e13:Float = 0
	Field e21:Float = 0, e22:Float = 0, e23:Float = 0
	Field e31:Float = 0, e32:Float = 0, e33:Float = 0

	Function Create:Matrix(e11#=0,e12#=0,e13#=0,e21#=0,e22#=0,e23#=0,e31#=0,e32#=0,e33#=0)
		Local m:Matrix = New Matrix
		m.e11 = e11
		m.e12 = e12
		m.e13 = e13
		m.e21 = e21
		m.e22 = e22
		m.e23 = e23
		m.e31 = e31
		m.e32 = e32
		m.e33 = e33
		Return m
	End Function

	Method Det:Float()
		Return e11*e22*e33-e11*e32*e23+e21*e32*e13-e21*e12*e33+e31*e12*e23-e31*e22*e13
	End Method

	Method Transpose:Matrix()
		Return Matrix.Create(e11,e21,e31,e12,e22,e32,e13,e23,e33)
	End Method
		
	Method 	Inverse:Matrix()
		Local dd:Float = e11*e22*e33-e11*e32*e23+e21*e32*e13-e21*e12*e33+e31*e12*e23-e31*e22*e13
		If dd = 0 Then dd = 1
		Local a:Float = (e22*e33-e23*e32)/dd
		Local b:Float = -(e12*e33-e13*e32)/dd
		Local c:Float = (e12*e23-e13*e22)/dd
		Local d:Float = -(e21*e33-e23*e31)/dd
		Local e:Float = (e11*e33-e13*e31)/dd
		Local f:Float = -(e11*e23-e13*e21)/dd
		Local g:Float = (e21*e32-e22*e31)/dd
		Local h:Float = -(e11*e32-e12*e31)/dd
		Local i:Float = (e11*e22-e12*e21)/dd
		Return Matrix.Create(a,b,c,d,e,f,g,h,i)
	End Method
		
	Method Add:Matrix( m:Matrix )
		Local res:Matrix = New Matrix
		res.e11 = e11 + m.e11
		res.e12 = e12 + m.e12
		res.e13 = e13 + m.e13
		res.e21 = e21 + m.e21
		res.e22 = e22 + m.e22
		res.e23 = e23 + m.e23
		res.e31 = e31 + m.e31
		res.e32 = e32 + m.e32
		res.e33 = e33 + m.e33
		Return res
	End Method

	Method Sub:Matrix( m:Matrix )
		Local res:Matrix = New Matrix
		res.e11 = e11 - m.e11
		res.e12 = e12 - m.e12
		res.e13 = e13 - m.e13
		res.e21 = e21 - m.e21
		res.e22 = e22 - m.e22
		res.e23 = e23 - m.e23
		res.e31 = e31 - m.e31
		res.e32 = e32 - m.e32
		res.e33 = e33 - m.e33
		Return res
	End Method

	Method Mul:Matrix( m:Matrix )
		Local res:Matrix = New Matrix
		res.e11 = e11*m.e11 + e12*m.e21 + e13*m.e31
		res.e12 = e11*m.e12 + e12*m.e22 + e13*m.e32
		res.e13 = e11*m.e13 + e12*m.e23 + e13*m.e33
		res.e21 = e21*m.e11 + e22*m.e21 + e23*m.e31
		res.e22 = e21*m.e12 + e22*m.e22 + e23*m.e32
		res.e23 = e21*m.e13 + e22*m.e23 + e23*m.e33
		res.e31 = e31*m.e11 + e32*m.e21 + e33*m.e31
		res.e32 = e31*m.e12 + e32*m.e22 + e33*m.e32
		res.e33 = e31*m.e13 + e32*m.e23 + e33*m.e33
		Return res
	End Method

	Method MulS:Matrix( s:Float )
		Local res:Matrix = New Matrix
		res.e11 = e11 * s
		res.e12 = e12 * s
		res.e13 = e13 * s
		res.e21 = e21 * s
		res.e22 = e22 * s
		res.e23 = e23 * s
		res.e31 = e31 * s
		res.e32 = e32 * s
		res.e33 = e33 * s
		Return res
	End Method

	Method DivS:Matrix( s:Float )
		Local res:Matrix = New Matrix
		res.e11 = e11 * s
		res.e12 = e12 * s
		res.e13 = e13 * s
		res.e21 = e21 * s
		res.e22 = e22 * s
		res.e23 = e23 * s
		res.e31 = e31 * s
		res.e32 = e32 * s
		res.e33 = e33 * s
		Return res
	End Method

	' Purpose: Multiply a Matrix by a Vector and Return a Vector Result
	' Example: v1=m1*v1 would be v1=m1.MulV( v1 )
	Method MulV:Vector( v:Vector )
		Local res:Vector = New Vector
		res.x = e11*v.x + e12*v.y + e13*v.z
		res.y = e21*v.x + e22*v.y + e23*v.z
		res.z = e31*v.x + e32*v.y + e33*v.z
		Return res
	End Method

End Type

Comments

Arowx2006
Just what I needed to move my project up to the next level. Thank You


Pineapple2006
Very nice indeed! :)

Great work me auld fruit

Dabz


Vertex2006
Hmm I think, this isn't the best way.

Global A : Vector
Global B : Vector
Global R : Vector

A = New Vector
A.Set(1.0, 2.0, 3.0)

B = New Vector
B.Set(3.0, 2.0, 1.0)

R = A.Add(B)
R = R.MulS(3.0)


R is firstly created by A.Add(B) than is R deleted by R.MulS (3.0) and is new created. This slowing the speed because the internel ressourcehandling.

Better:
	Method Add( a:Vector, b:Vector )
		Self.x = a.x + b.x 
		Self.y = a.y + b.y
		Self.z = a.z + b.z
	End Method


In practise:
R.Add(A, B) ' R = A + B

Also I miss some methods like Slerp(Quanternion), this is a very important function to interpolate between to rotations and completly a plane type.

Sorry, but there are certainly better libs :(

cu olli


Chroma2006
Hi Vertex...I'll check out the proposed changes. Thanks.


Gabriel2007
Just checked this out because I was checking my maths on multiplying a vector by a quaternion. Your method returns a quaternion, which I don't understand. If you multiply a vector by a quaternion, surely you get a vector result? You are, after all, effectively rotating a vector. A rotated vector is still a vector. No?


Chroma2007
No.


Bobysait2008
	' Purpose: Multiply Two Quaternions
	' Returns: Quaternion
	' Example1: q1=q1*q2 would be q1 = q1.Mul( q2 )
	' Example2: q1=q2*q3 would be q1 = q2.Mul( q3 )
	Method Mul:Quaternion( q:Quaternion )
		Local res:Quaternion = New Quaternion
		res.n = n*q.n - v.x*q.v.x - v.y*q.v.y - v.z*q.v.z
		res.v.x = n*q.v.x + v.x*q.n + v.y*q.v.z - v.z*q.v.y
		res.v.y = n*q.v.y + v.y*q.n + v.z*q.v.x - v.x*q.v.z
		res.v.z = n*q.v.y + v.y*q.n + v.z*q.v.x - v.x*q.v.z
		Return res
	End Method


Maybe I'm wrong, but it seems res.v.z is false
here, v.y=v.z ...

it should be something like
res.n   = n*q.n   - v.x*q.v.x - v.y*q.v.y - v.z*q.v.z
res.v.x = n*q.v.x + v.x*q.n   + v.y*q.v.z - v.z*q.v.y
res.v.y = n*q.v.y + v.x*q.v.z - v.y*q.n   + v.z*q.v.x
res.v.z = n*q.v.z - v.x*q.v.y + v.y*q.v.x + v.z*q.n

It's what I find when I developp Sibly's quaternion from its C++ lib
	'+> Original TQuat.Create( w*q.w-v.dot(q.v) , (q.v.cross(v)).Add(q.v.Multiply(w)).Add(v.Multiply(q.w)) )
	' According v:{ x,y,z }
	QF:tquat=New tquat

	v0:tvector=(q.v.cross(v))
	v0.x = q.y*z-q.z*y;
	v0.y = q.z*x-q.x*z;
	v0.z = q.x*y-q.y*x;

	v1:tvector=q.v.Multiply(w)		v1 = q.x*w
									q.y*w
									q.z*w

	v2:tvector=v0.Add(v1)			v2 = q.y*z - q.z*y + q.x*w
									q.z*x - q.x*z + q.y*w
									q.x*y - q.y*x + q.z*w

	v3:tvector=v.Multiply(q.w)		v3 = x*q.w
									y*q.w
									z*q.w

	v4:tvector=v2.Add(v3)			v4 = q.y*z - q.z*y + q.x*w + x*q.w
									q.z*x - q.x*z + q.y*w + y*q.w
									q.x*y - q.y*x + q.z*w + z*q.w


	QF.w = w*q.w - x*q.x - y*q.y - z*q.z
	QF.x = w*q.x + x*q.w - y*q.z + z*q.y
	QF.y = w*q.y + x*q.z + y*q.w - z*q.x
	QF.z = w*q.z - x*q.y + y*q.x + z*q.w



Of course, I have maybe made a mistake...


Chroma2009
Geez, you probably just nailed why I could never get my flight sim working 3 years ago...


Code Archives Forum