Thread: should I build my own vector and matrix classes?

  1. #1
    Shadow12345
    Guest

    should I build my own vector and matrix classes?

    as you know I'm starting game programming. I've seen the same vector math done over and over, and the same basic matrix operations done over and over (some matrices are way too complicated for me to understand). Do you think I should go ahead and build my own vector and matrix classes anyway? It will take some time (finding out what to do, making sure it works, etc) so I only want to do the things that are most important.

    Thanks

  2. #2
    Programming Sex-God Polymorphic OOP's Avatar
    Join Date
    Nov 2002
    Posts
    1,078
    Yes.

    Even if you end up not using them, you should understand them extremely well. Making your own is really the best way to get an understanding for the math, and also let's you see some optimizations that you may not have recognized if you didn't fully understand the math. It's a great place to not only learn the math, but also to get experience in programming. Anything that you can do yourself, do do yourself, or at least attempt to. While you shouldn't have to understand the inner workings of all libraries you use 100%, you should still have a strong understanding of a general implementation of them. While a lot of people recommend working with a "magical box" that you take for granted, it really should be more of a "opaque glass box" that you can somewhat see inside of, but don't really see its exact implementation.
    Last edited by Polymorphic OOP; 01-04-2003 at 10:18 AM.

  3. #3
    Shadow12345
    Guest
    While a lot of people recommend working with a "magical box" that you take for granted, it really should be more of a "opaque glass box" that you can somewhat see inside of, but don't really see its exact implementation.
    That's an excellent way of putting it, Poly.

    I'm going to just write down everything that a vector class should have, I'll try building that first. Just correct me or add stuff if you don't mind. I'll add the math portions that I know, then I'll look through some books to see if i have the math written down

    each vector should have methods for:
    adding, subtracting, multiplying and dividing vectors (using overloaded operatorx methods) just add, subtract, multiply or divide the x,y,z components

    cross product (perpendicular vector)
    A x B = ((Ay * Bz) - (Az * By), (Ax * Bz) - (Az * Bx), (Ax * By) - (Ay * Bx)) I hope that one is right, I just remember you never use the x when determining the x component of the cross vector, same for the y and z


    dot product (angles between vectors, I think) I have no clue how this is done but I can look it up later

    normalize vectors (just make the length one so it's a unit normal)
    just divide its length by itself

    getscalar value of vector (just find the length , divide by itself to get normal vector)
    scalar = sqrt(x^2 - y^2 - z^2)

    Is there anything else I should need? that would make a great start to a vector class. I might also need a 2d vector class, for screen coordinates. Now that I mention it I'm reading about how to move the camera using the mouse, it's harder than I thought because each scene you have to find the cross product between the view vector and the up vector to get the vector that you move the camera up and down with.

    Ok, talk to you later

  4. #4
    Programming Sex-God Polymorphic OOP's Avatar
    Join Date
    Nov 2002
    Posts
    1,078
    Originally posted by Shadow12345
    dividing vectors
    There is no such operation as dividing by vectors.

    Originally posted by Shadow12345
    cross product (perpendicular vector)
    A x B = ((Ay * Bz) - (Az * By), (Ax * Bz) - (Az * Bx), (Ax * By) - (Ay * Bx)) I hope that one is right, I just remember you never use the x when determining the x component of the cross vector, same for the y and z
    That's usually how I remember it, but you did miss something. The middle component should be Az * Bx - Ax * Bz

    Originally posted by Shadow12345
    dot product (angles between vectors, I think) I have no clue how this is done but I can look it up later
    It's actually the simplest of them all in terms of calculation. It's a straight multiplication of the components and then all added up.

    ax * bx + ay * by + az * bz

    Originally posted by Shadow12345
    scalar = sqrt(x^2 - y^2 - z^2)
    it's sqrt(x*x + y*y + z*z)

    It's addition not subtraction -- it's the pythagorean thereom!

    Originally posted by Shadow12345
    Is there anything else I should need? that would make a great start to a vector class.
    Multiplication by a scalar, matrix times vector, addition to a point, etc. There're quite a few. You'll see them as you go along.
    Which brings me to a very important object -- points. Points and vectors are very different and you should have point classes (quite different from vectors). A vector plus a vector is a vector, a vector plus a point is a point (its the result of the original point translated by the vector), point plus point is not a valid operation, point minus point is the vector which you need to get from the second point to the first, a point has no magnitude while a vector does, etc. a lot of it is just common sense. You need to differentiate between vectors and points if you want a geometrically meaningful library.

    Originally posted by Shadow12345
    I might also need a 2d vector class, for screen coordinates.
    A very good idea. When I made my library I made 3D, 2D, 1D, and (yes) 0D vectors. The 0D vector was only important for aspecial way I was doing calculations through polymorphism as an optimization for speed (which I started writing an article for gamedev about but never finished), but it is uneccissary in most other places. I even differentiated between xyVectors, yzVectors, and xzVectors, and xVectors, yVectors, and zVectors, which can sometimes be very important (for instance an xVector in 3-space implicitly has 0 for y and z, etc. an x vector plus a y vector is an xyVector. Mostly they're just for if you want to optimize but are very necissary in that polymorphism optimization).

    Good luck!
    Last edited by Polymorphic OOP; 01-04-2003 at 11:14 AM.

  5. #5
    Shadow12345
    Guest
    it's sqrt(x*x + y*y + z*z)
    I feel smart...

    Points and vectors are very different and you should have point classes
    I don't think I'll end up building a separate point class because they generally just use them interchangably and you know whether it's a point or a vector by context (that's how I've always seen it. For example in a camera class the view is an up vector represented by an object of the vector3d class, the up vector is a vector represented by the vector3d class, but the position is a point but is also represented by the same vector3d class).

    There is no such operation as dividing by vectors.
    Are you sure? I thought you did dividing by vectors to represent things like forces and stuff, i.e you take a whole bunch of vectors divide them by each other and you get a single composite vector. I guess I really need to touch up on all this math crap

    thanks again poly

  6. #6
    Programming Sex-God Polymorphic OOP's Avatar
    Join Date
    Nov 2002
    Posts
    1,078
    Originally posted by Shadow12345
    I don't think I'll end up building a separate point class because they generally just use them interchangably and you know whether it's a point or a vector by context (that's how I've always seen it. For example in a camera class the view is an up vector represented by an object of the vector3d class, the up vector is a vector represented by the vector3d class, but the position is a point but is also represented by the same vector3d class).
    If you want a type-safe math library that makes any geometric sense, then you really do have to differentiate between the two.

    There are also things like rotating a vector or a point about some arbitrary axis in space. When dealing with a vector, you only have to be concerned about the rotation and the angle of the axis (because a vector has no location), while when dealing with a point, you have to take into account the location of the axis as well.

    Really try to make a different set of point classes. It's a very important difference that should be represented in code as such.

    Originally posted by Shadow12345
    Are you sure? I thought you did dividing by vectors to represent things like forces and stuff, i.e you take a whole bunch of vectors divide them by each other and you get a single composite vector. I guess I really need to touch up on all this math crap
    Yup, I'm positive. Dividing a vector by a vector is an undefined operation.

  7. #7
    Shadow12345
    Guest
    Okay well I'll post what I have when I've got rough draft. There shouldn't be any problems with the math (BUT IF THERE IS PLEASE POINT IT OUT) I'll probably post in like 15 mins or so.

    EDIT: I actually have another question. I'd like to keep this thread alive and keep posting questions that might not be described in tutorials. Anyway I know the conversion between radians and degrees (degrees = 360 around circle, radians = 2piR around circle) but why would you want to use one over the other? I think you have to be in degree mode to properly calculate the lenghts of sides using trigonomic ratios (well this is how it is on my ti 83 anyways) but I can't think of any other situations where one would be particular better than the other (and knowing my luck there are hundres).
    Last edited by Shadow12345; 01-04-2003 at 11:53 AM.

  8. #8
    Programming Sex-God Polymorphic OOP's Avatar
    Join Date
    Nov 2002
    Posts
    1,078
    You can use either in all situations, it's just a different way of describing the same exact things. The only reason you'd want to use one over the other is because of different libraries using radians over degrees or the other way around, which really gets annoying. Personally, if it there were any good libraries for it, I'd use rotations in all situations. IE 1.0f is a complete rotation. It just makes things very clear. 0.25 is a quarter of a rotation -- you don't even have to think about it. Unfortunately, as I said, good luck at finding a math library which works with rotations instead of radians or degrees, heh.

  9. #9
    Shadow12345
    Guest
    IE 1.0f is a complete rotation. It just makes things very clear. 0.25 is a quarter of a rotation -- you don't even have to think about it. Unfortunately, as I said, good luck at finding a math library which works with rotations instead of radians or degrees, heh.
    ohhhh, I was wondering what in the hell that meant, I was reading a tutorial from www.gametutorials.com and they must be using 1.0f as a full rotation because it checks if the current rotation is 1 or -1.0f and doesn't let it go above 1 or under -1.0f

    sweet

    here's the code that has that :
    Code:
    	if(currentRotX > 1.0f)
    		currentRotX = 1.0f;
    	// Check if the rotation is below -1.0, if so we want to make sure it doesn't continue
    	else if(currentRotX < -1.0f)
    		currentRotX = -1.0f;
    	// Otherwise, we can rotate the view around our position
    	else
    	{
    		// To find the axis we need to rotate around for up and down
    		// movements, we need to get a perpendicular vector from the
    		// camera's view vector and up vector.  This will be the axis.
    		// Before using the axis, it's a good idea to normalize it first.
    		CVector3 vAxis = Cross(m_vView - m_vPosition, m_vUpVector);
    		vAxis = Normalize(vAxis);
    
    		// Rotate around our perpendicular axis and along the y-axis
    		RotateView(angleZ, vAxis.x, vAxis.y, vAxis.z);
    		RotateView(angleY, 0, 1, 0);
    	}

  10. #10
    Shadow12345
    Guest
    well this is what I have so far, just my implementation file

    Code:
    #include "Vector.h"
    #include "Main.h"
    
    //DEFAULT CONSTRUCTOR
    Vector3D::Vector3D() { x = 0; y = 0; z = 0; }
    
    //CREATES A NEW VECTOR WITH THE NEW X,Y,Z VALUES PASSED IN
    Vector3D::Vector3D(float x1, float y1, float z1): x(x1), y(y1), z(z1){}
    
    Vector3D Vector3D::operator+(Vector3D v) {
    	Vector3D	temp;
    	temp.x = x + v.x;
    	temp.y = y + v.y;
    	temp.z = z + v.z;
    	return temp;
    }
    
    Vector3D Vector3D::operator-(Vector3D v) {
    	Vector3D	temp;
    	temp.x = x - v.x;
    	temp.y = y - v.y;
    	temp.z = z - v.z;
    	return temp;
    }
    
    //DIVIDE THE COMPONENTS OF THE CALLING VECTOR BY THE SCALAR
    Vector3D Vector3D::operator/(float scalar) {
    	return Vector3D(x / scalar, y / scalar, z / scalar);
    }
    
    //MULTIPLY EACH VECTOR COMPONENT BY SCALAR AND RETURN NEW VECTOR
    Vector3D Vector3D::operator*(float scalar) {
    	return Vector3D(x * scalar, y * scalar, z * scalar);
    }
    
    //FIND THE CROSS PRODUCT BETWEEN TWO VECTORS
    Vector3D Vector3D::CrossProduct(Vector3D v, Vector3D v1) {
    
    return Vector3D( (v.y * v1.z) - (v.z - v1.y), (v.x * v1.z) - (v.z * v1.x), (v.x * v1.y) - (v.y - v1.x) );
    }
    
    float	Vector3D::Magnitude(Vector3D v) {
    	return sqrt( (v.x * v.x) + (v.y * v.y) + (v.z * v.z) );
    }
    
    void	Vector3D::Normalize(Vector3D v) {
    	if(v.magnitude == 1)	//IF IT'S ALREADY NORMALIZE WE GET THE HELL OUTTA HERE!
    		return;
    	else{ 
    		float magnitude = v.Magnitude(v);	//MAKE SURE YOU HAVE THE PROPER CURRENT MAGNITUDE
    		v.magnitude = magnitude / magnitude;
    	}
    
    }
    
    //MULTIPLY COMPONENTS AND ADD, RETURNS THE NUMBER OF DEGREES BETWEEN TWO VECTORS
    float Vector3D::DotProduct(Vector3D v, Vector3D v1) {
    return float(v.x * v1.x + v.y * v1.y + v.z * v1.z);
    }

  11. #11
    Programming Sex-God Polymorphic OOP's Avatar
    Join Date
    Nov 2002
    Posts
    1,078
    Why do you make your dot product, and cross product, member functions take two parameters!? They should only take one. It should operate on the object you are calling the member function on and the single parameter as the other operand. Also why do your magnitude and normalize functions take parameters!? They should have none. They operate on the object you call the member function on.

    Also, you might want to overload operator* to do dot product because it obeys just about all of the same rules as multiplication of 2 scalars, however it was a good idea not to overload operator* for cross product as its presedence isn't clear and its not commutative or associative.

    EDIT: After further looking through, you have a lot more problems with your design.

    The normalize function has a few problems.

    For one, it's really not too good of an idea to have magnitude as a data member. That's just another variable to keep updating that you usually only need to check in certain situations (which you'd check by using the magnitude function and saving to a temporary variable if you needed to use it several times in a short period of time).

    Also, you are performing the normalization wrong

    v.magnitude = magnitude / magnitude;

    Firstly -- as I said, a magnitude member isn't a good idea, and in that particular line of code, the right side of that equation is always 1. It's an uneccisary computation. v.magnitude = 1.0f would have the same outcome but no computation needed. Again, you don't want to do that, you want to divide each component by the magnitude to normalize it. Keep direction and magnitude solely via the components and not a magnitude datamember, otherwise you are completely missing the "point" in using vectors. If you just use the vector for direction and not magnitude, then your operations would not work properly as they are.
    Last edited by Polymorphic OOP; 01-04-2003 at 12:37 PM.

  12. #12
    Shadow12345
    Guest
    Why do you make your dot product, and cross product, member functions take two parameters!? They should only take one
    I think it might make more sense for me to not build this as a class

    I like this:
    Vector3D perpendicular = Cross(v1, v2)
    as opposed to this:
    Vector3D perpendicular = v1.cross(v2)

    EDIT: Yeah im going to keep the overloaded members where they are but I'm not going to have cross/dot product and other stuff that uses two vectors as a member function

  13. #13
    Programming Sex-God Polymorphic OOP's Avatar
    Join Date
    Nov 2002
    Posts
    1,078
    Originally posted by Shadow12345
    Vector3D perpendicular = Cross(v1, v2)

    EDIT: Yeah im going to keep the overloaded members where they are but I'm not going to have cross/dot product and other stuff that uses two vectors as a member function
    Yeah, that's fine. I recommend you make it static member function if you do that instead though.

    Also, I'm not sure if you noticed my edit on the other post. You had a lot of other problems with your design and your normalize function.

  14. #14
    Shadow12345
    Guest
    yeah i just changed that im having a really hard time thinking, but dammit im gonna get this stuff workin! heh

    EDIT:
    If you just find the magnitude of the vector, and then divide the vector object by magnitude that should be the same as dividing each component by magnitude.

    Code:
    CVector3 Normalize(CVector3 vVector)
    {
    	// What's this function for you might ask?  Well, since we are using the cross
    	// product formula, we need to make sure our view vector is normalized.  
    	// For a vector to be normalized, it means that it has a length of 1.
    	// For instance, a vector (2, 0, 0) would be (1, 0, 0) once normalized.
    	// Most equations work well with normalized vectors.  If in doubt, normalize.
    
    	// Get the magnitude of our normal
    	float magnitude = Magnitude(vVector);				
    
    	// Now that we have the magnitude, we can divide our vector by that magnitude.
    	// That will make our vector a total length of 1.  
    	// This makes it easier to work with too.
    	vVector = vVector / magnitude;		
    	
    	// Finally, return our normalized vector
    	return vVector;										
    }
    that's not my code

    EDIT1: I'm gonna stop for a while I really can't do any programming today
    Last edited by Shadow12345; 01-04-2003 at 12:56 PM.

  15. #15
    Programming Sex-God Polymorphic OOP's Avatar
    Join Date
    Nov 2002
    Posts
    1,078
    If you just find the magnitude of the vector, and then divide the vector object by magnitude that should be the same as dividing each component by magnitude.
    Yup, correct.

Popular pages Recent additions subscribe to a feed