Help With Vector Math

Started by
3 comments, last by _goat 18 years ago
I'm writing up a camera class today and I'm having troubles. The mouse handles perfectly fine, but motion is not so good looking. I believe it may have to do with my vector math functions. Is there anything wrong here? SimStructs.h

typedef struct SimVector
{
    float x, y, z;

    void operator= (SimVector v)
    {
        x = v.x;
        y = v.y;
        z = v.z;
    }

    void operator+= (SimVector v)
    {
        x += v.x;
        y += v.y;
        z += v.z;
    }

    void operator-= (SimVector v)
    {
        x -= v.x;
        y -= v.y;
        z -= v.z;
    }

    void operator*= (float a)
    {
        x *= a;
        y *= a;
        z *= a;
    }

    void operator/= (float a)
    {
        x /= a;
        y /= a;
        z /= a;
    }

    SimVector operator+ (SimVector v)
    {
        SimVector ret;
        ret.x = x + v.x;
        ret.y = y + v.y;
        ret.z = z + v.z;
        return ret;
    }

    SimVector operator- (SimVector v)
    {
        SimVector ret;
        ret.x = x - v.x;
        ret.y = y - v.y;
        ret.z = z - v.z;
        return ret;
    }

    SimVector operator* (float a)
    {
        SimVector ret;
        ret.x = x * a;
        ret.y = y * a;
        ret.z = z * a;
    }

    SimVector operator/ (float a)
    {
        SimVector ret;
        ret.x = x / a;
        ret.y = y / a;
        ret.z = z / a;
        return ret;
    }

    float operator[] (int a)
    {
        if(a == 0)
            return x;
        if(a == 1)
            return y;
        if(a == 2)
            return z;
    }
};

namespace SimStructs
{
    float GetMagnitude(SimVector v);
    void Normalize(SimVector &v);
    float DotProduct(SimVector v1, SimVector v2);
    SimVector CrossProduct(SimVector v1, SimVector v2);
}


SimStructs.cpp

float SimStructs::GetMagnitude(SimVector v)
{
    return sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
}

void SimStructs::Normalize(SimVector &v)
{
    float mag = 1.0f / SimStructs::GetMagnitude(v);

    v *= mag;
}

float SimStructs::DotProduct(SimVector v1, SimVector v2)
{
    return (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z);
}

SimVector SimStructs::CrossProduct(SimVector v1, SimVector v2)
{
    SimVector ret;
    ret.x = (v1.y * v2.z - v1.z * v2.y);
    ret.y = (v1.z * v2.x - v1.x * v2.z);
    ret.z = (v1.x * v2.y - v1.y * v2.x);
    return ret;
}

Camera code:

void SimCamera::Move(float speed, float timestep)
{
    direction = target - position;
    SimStructs::Normalize(direction);

    position += (direction * speed * timestep);
    target += (direction * speed * timestep);
}

void SimCamera::Strafe(float speed, float timestep)
{
    direction = target - position;
    SimStructs::Normalize(direction);

    strafe = SimStructs::CrossProduct(direction, up);
    SimStructs::Normalize(strafe);

    position += (strafe * speed * timestep);
    target += (strafe * speed * timestep);
}

Usage:

    camera.MouseInput();

    if(globalInput.IsKeyDown(SDLK_w))
        camera.Move(1, frameInterval);
    if(globalInput.IsKeyDown(SDLK_s))
        camera.Move(-1, frameInterval);
    if(globalInput.IsKeyDown(SDLK_a))
        camera.Strafe(-1, frameInterval);
    if(globalInput.IsKeyDown(SDLK_d))
        camera.Strafe(1, frameInterval);

Advertisement
there's a return missing in your operator*
Thanks :). I feel kinda dumb now.
Haha. Don't! Happend at least a 100 times to me before. Strangly enough, MSVC doesn't complain or even warn about it.
Now that you've got your class working, it's time to clean it up and make it watertight. I'll take a Zahlman approach to this (that's right - it's official).

// "typedef" isn't required in C++. You can leave it out happily.struct SimVector{	float x, y, z;		// A constructor will make your life a trillion easier. That's	// right, a trillion. Note we initialise via the initialisation	// list.	SimVector(float x_, float y_, float z_) : x(x_), y(y_), z(z_)	{	}		// You don't need to write an assignment operator ( operator = ),	// because C++ will generate one for your automatically, with a 	// member-wise copy. That's what you've got, so delete it and watch	// it still work.		// You should pass by reference rather by value. this means that	// instead of making a new SimVector, we get given a reference to	// the original one. It is declared "const" so we can't change it.	//	// You should return a (non-const) reference so people can do things	// like:	//    SimVector v = SimVector(3, 4, 5);	//    if ( (v += 4).x == 7 ) go_crazy();	//	SimVector& operator += (const SimVector& v)	{		x += v.x; y += v.y; z += v.z;		return *this;	}		// ...		// it's good practice to make your addition, subtraction, division and 	// multiplication friend operators, because otherwise this:	//   SimVector r = 3.6f * my_simvector;	// won't work, as you have only define an operator * that -takes- a float,	// not a float that takes a SimVector for multiplication.	inline friend SimVector operator + (const SimVector& lhs, const SimVector& rhs)	{		// thanks, constructor!		return SimVector(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z);	}		// finally, -I- prefer to have my major functions as friend functions. it gives	// them the same scope as your class, and makes for a logical place to put them.	inline friend float Magnitude(const SimVector& v)	{		return sqrt(v.x * v.x + v.y * v.y + v.z * v.z);	}}


Hope that helps.
[ search: google ][ programming: msdn | boost | opengl ][ languages: nihongo ]

This topic is closed to new replies.

Advertisement