1. ## Relative positioning

I am writing a game where essentially a sphere moves around a 3 dimensional grid. I allow the user to rotate the grid around itself so he can get better views. The keys to move left and right, however, are mapped to increasing or decreasing the x value of this ball. Unfortunately, this means that in the grid, rotated 90 degrees around the y axis (y axis rotation is like that of a tornado), right and left (increase / decrease x value) instead mean away / toward. At 180, right means left and left means right. At 270, right means toward and left means away. I'm sorry if I confused anyone, but this is sort of hard to explain. Grab a tissue box and try it. Anyway, does anyone know how to turn the rotation amount (like amntxrot , amntyrot, amntzrot which are measured in degrees...in the above example the amntxrot is zero, amntyrot is 90, and amntzrot is zero) into some form of left and right? I can't rotate the universe around the user to solve it and I can't hard-wire it in for every value - things become very complicated when doing compound rotations (90x, 0y, 90z for example)

2. oh boy, you managed to rotate my head around!

hehe, i got no clue...

3. why not just have a function like displaySphere that will display the sphere for any orientation of the coordinates. Then, your left and right will be simply left and right without regards to orientation, and leave orientation up to the display function.

Does this help any?

4. although, you could probably use some semi-complicated trig.

lets say you have a coordinate vector Vx and Vy and they are parallel to the screens x and y axis. Then a shift 1 unit along Vx will equal a shift of i unit along x.

x = Vx(cosT) and y = Vx(sinT) where 'x' is the x axis of the screen and T is the angle between the Vx and the x axis. In this case T = 0, and cos(0) = 1, sin(0) = 0, so a translation of 1 unit along Vx equals a translation of 1 unit along x and a translation of 0 along the y axis.

now lets say the user rotated the axis counter-clockwise, say 30 deg. Then a translation of unit 1 along the Vx vector would equal to in x, y coordinates:
x = Vx(cosT) = Vx(cos(30)) = Vx(sqrt(3)/2)
y = Vx(cosQ) = Vx(sin(30)) = Vx(1/2)

the idea is to basically decompose one vector into its component vectors parallel and perpendicular to the target vector (look up the dot product of vectors)

Did this help any?

[pain]
What are you guys talking about
[/pain]

6. not sure if i understandyou so imma guess you could just put:

Code:
case VK_RIGHT:

if (amntxrot <= 360) {
amntxrot += 1.0f; //assuming you have floats and this is for increasing degrees

break;

//and repeat
again, this probably isnt what you want, but i didnt understand what you wanted either ..

7. The easiest way to do rotations is through the use of matrices. I'm not sure I understand your problem.

Code:
//***********************************************
//** Matrix header for use with 1.0 object file *
//***********************************************

#ifndef _MATRIX_1_0
#define _MATRIX_1_0

#define PI 3.14159

//Defines a point in 2D space
struct point2D
{
int x;
int y;
point2D operator = (point2D newpoint)
{
x=newpoint.x;
y=newpoint.y;
return *this;
}
};

//Defines a point in 2D texture space
struct Texel
{
int u;
int v;
Texel operator =(Texel nt)
{
u=nt.u;
v=nt.v;
return *this;
}
};

//Defines a point in 3D space
struct point3D
{
double x;
double y;
double z;
point3D operator =(point3D np)
{
x=np.x;
y=np.y;
z=np.z;
return *this;
}
};

//Defines a vertex in 3D space
struct Vertex
{
point3D Local;
point3D World;
point3D View;
point2D Screen;
Texel	  Texture;
Vertex operator =(Vertex vt)
{
Local=vt.Local;
World=vt.World;
View=vt.View;
Screen=vt.Screen;
Texture=vt.Texture;
return *this;
}
};

//Pipeline modes
enum plMode {WORLD,VIEW,SCREEN};

//Structure to store state of pipeline
struct plPipeLine
{
int plProjDist;
point2D plCenters;
point3D plTranslate_Local;
point3D plScale_Local;
point3D plRotate_Local;
point3D plTranslate_World;
point3D plRotate_World;
int NumVertexes;
Vertex *Vertexes;
};

class MatrixPackage
{
double master[4][4];
const double COS[360];
const double SIN[360];
point2D Centers;
int ProjDist;

//Master concatenation function
void MatrixMult(const double mat1[4][4],
const double mat2[4][4],
double result[4][4]);

void Copy(const double source[4][4],const double target[4][4]);

//Setup translation matrix
void Translate(const double dx,const double dy,
const double dz);

void Translate(point3D tr);

//Setup scale matrix
void Scale(const double sx,const double sy,const double sz);
void Scale(point3D sc);

//Setup rotation matrix
void Rotate(const int ax=0,const int ay=0,const int az=0);
void Rotate(point3D rt);

//Transform from local to world space
void WorldTransform(Vertex *Vertexes,const int NumVertexes);

//Transform from world to view space
void ViewTransform(Vertex *Vertexes,const int NumVertexes);

//Project from 3D to 2D - view space to screen space
void Project(Vertex *Vertexes,const int NumVertexes);

//Runs pipeline from local space to world space
void ToWorld(plPipeLine &plState);

//Runs pipeline from world space to view space
void ToView(plPipeLine &plState);

//Runs full pipeline, local to screen space
void ToScreen(plPipeLine &plState);

public:
MatrixPackage1(void);
void InitMaster(void);
void SetProjectionDist(const int newdistance)
{ProjDist=newdistance;};
void SetCenterScreen(const int cx,const int cy)
{Centers.x=cx;Centers.y=cy;};
void SetCenterScreen(point2D nc) {Centers=nc;};

//Execute pipeline according to plMode
double *Execute(plMode pm);

};

#endif  //end of _MATRIX_ define block

//**************************
//* 3D Matrix package      *
//* Source code file       *
//* Compiled to matrix.obj *
//* Version 1.0            *
//**************************

#include <math.h>
#include "c:\tc\matrix.h"

#ifndef _MATRIX_1_0
#error Object file version does not match header version
#endif

MatrixPackage::MatrixPackage(void)
{
InitMaster();
for (int i=0;i<360;i++)
{
const COS[i]=cos((double)i*PI/(double)180.0);
const SIN[i]=sin((double)i*PI/(double)180.0);
}
CenterX=160;CenterY=100;ProjDist=320;
}

void MatrixPackage::InitMaster(void)
{
//Sets matrix to identity matrix
master[0][0]=1.0;
master[0][1]=0.0;
master[0][2]=0.0;
master[0][3]=0.0;

master[1][0]=0.0;
master[1][1]=1.0;
master[1][2]=0.0;
master[1][3]=0.0;

master[2][0]=0.0;
master[2][1]=0.0;
master[2][2]=1.0;
master[2][3]=0.0;

master[3][0]=0.0;
master[3][1]=0.0;
master[3][2]=0.0;
master[3][3]=1.0;
}

void MatrixPackage::Copy(const double source[4][4],
const double target[4][4])
{
target[0][0]=source[0][0];
target[0][1]=source[0][1];
target[0][2]=source[0][2];
target[0][3]=source[0][3];

target[1][0]=source[1][0];
target[1][1]=source[1][1];
target[1][2]=source[1][2];
target[1][3]=source[1][3];

target[2][0]=source[2][0];
target[2][1]=source[2][1];
target[2][2]=source[2][2];
target[2][3]=source[2][3];

target[3][0]=source[3][0];
target[3][1]=source[3][1];
target[3][2]=source[3][2];
target[3][3]=source[3][3];
}

void MatrixPackage::MatrixMult(const double mat1[4][4],
const double mat2[4][4],
double result[4][4])
{
for (int i=0;i<4;i++)
{
for (int j=0;j<4;j++)
{
result[i][j]+=((mat1[i][0]*mat2[0][j])+
(mat1[i][1]*mat2[1][j])+
(mat1[i][2]*mat2[2][j])+
(mat1[i][3]*mat2[3][j]));
}
}
}

void MatrixPackage::Translate(const double dx,
const double dy,
const double dz)
{
double temp[4][4];
double result[4][4];

temp[0][0]=1.0;
temp[0][1]=0.0;
temp[0][2]=0.0;
temp[0][3]=0.0;

temp[1][0]=0.0;
temp[1][1]=1.0;
temp[1][2]=0.0;
temp[1][3]=0.0;

temp[2][0]=0.0;
temp[2][1]=0.0;
temp[2][2]=1.0;
temp[2][3]=0.0;

temp[3][0]=dx;
temp[3][1]=dy;
temp[3][2]=dz;
temp[3][3]=1.0;

MatrixMult(temp,master,result);
Copy(result,master);
}

MatrixPackage::Scale(const double sx,
const double sy,
const double sz)
{
double temp[4][4];
double result[4][4];

temp[0][0]=sx;
temp[0][1]=0.0;
temp[0][2]=0.0;
temp[0][3]=0.0;

temp[1][0]=0.0;
temp[1][1]=sy;
temp[1][2]=0.0;
temp[1][3]=0.0;

temp[2][0]=0.0;
temp[2][1]=0.0;
temp[2][2]=sz;
temp[2][3]=0.0;

temp[3][0]=0.0;
temp[3][1]=0.0;
temp[3][2]=0.0;
temp[3][3]=1.0;

MatrixMult(temp,master,result);
Copy(result,master);
}

void MatrixPackage::Rotate(const int ax,const int ay,const int az)
{
const double xmat[4][4];
const double ymat[4][4];
const double zmat[4][4];
double mat1[4][4];
double mat2[4][4];
//************************************************************************
//X rotation

xmat[0][0]=1.0;
xmat[0][1]=0.0;
xmat[0][2]=0.0;
xmat[0][3]=0.0;

xmat[1][0]=0.0;
xmat[1][1]=COS[ax];
xmat[1][2]=SIN[ax];
xmat[1][3]=0.0;

xmat[2][0]=0.0;
xmat[2][1]=-SIN[ax];
xmat[2][2]=COS[ax];
xmat[2][3]=0.0;

xmat[3][0]=0.0;
xmat[3][1]=0.0;
xmat[3][2]=0.0;
xmat[3][3]=1.0;

//Multiply - store result in mat1
MatrixMult(xmat,master,mat1);
//**************************************************  **********************
//**************************************************  **********************
//Y rotation

ymat[0][0]=COS[ay];
ymat[0][1]=0.0;
ymat[0][2]=-SIN[ay];
ymat[0][3]=0.0;

ymat[1][0]=0;
ymat[1][1]=1;
ymat[1][2]=0;
ymat[1][3]=0;

ymat[2][0]=SIN[ay];
ymat[2][1]=0;
ymat[2][2]=COS[ay];
ymat[2][3]=0;

ymat[3][0]=0.0;
ymat[3][1]=0.0;
ymat[3][2]=0.0;
ymat[3][3]=1.0;

//Multiply - store result in mat2
MatrixMult(ymat,mat1,mat2);
//**************************************************  **********************

//**************************************************  **********************
//Z rotation

zmat[0][0]=COS[az];
zmat[0][1]=SIN[az];
zmat[0][2]=0.0;
zmat[0][3]=0.0;

zmat[1][0]=-SIN[az];
zmat[1][1]=COS[az];
zmat[1][2]=0.0;
zmat[1][3]=0.0;

zmat[2][0]=0.0;
zmat[2][1]=0.0;
zmat[2][2]=1.0;
zmat[2][3]=0.0;

zmat[3][0]=0.0;
zmat[3][1]=0.0;
zmat[3][2]=0.0;
zmat[3][3]=1.0;

//Multiply - store result in master
MatrixMult(zmat,mat2,master);
//**************************************************  **********************
}

void MatrixPackage::WorldTransform(Vertex *Vertexes,
const int NumVertexes)
{

for (int i=0;i<NumVertexes;i++)
{
double lx=Vertexes->Local.x;
double ly=Vertexes->Local.y;
double lz=Vertexes->Local.z;

Vertexes->World.x=lx*master[0][0]+ly*master[1][0]+
lz*master[2][0]+master[3][0];
Vertexes->World.y=lx*master[0][1]+ly*master[1][1]+
lz*master[2][1]+master[3][1];
Vertexes->World.z=lx*master[0][2]+lz*master[1][2]+
lz*master[2][2]+master[3][2];
}
}

void MatrixPackage::ViewTransform(Vertex *Vertexes,
const int NumVertexes)
{

for (int i=0;i<NumVertexes;i++)
{
double wx=Vertexes->World.x;
double wy=Vertexes->World.y;
double wz=Vertexes->World.z;
Vertexes->View.x=wx*master[0][0]+wy*master[1][0]+
wz*master[2][0]+master[3][0];
Vertexes->View.y=wx*master[0][1]+wy*master[1][1]+
wz*master[2][1]+master[3][1];
Vertexes->View.z=wx*master[0][2]+wz*master[1][2]+
wz*master[2][2]+master[3][2];
}
}

void MatrixPackage::Project(Vertex *Vertexes,
const int NumVertexes)
{
for (int i=0;i<NumVertexes;i++)
{
double vx=Vertexes->View.x;
double vy=Vertexes->View.y;
double vz=Vertexes->View.z;
Vertexes->Screen.x=(int)((vx*(double)ProjDist)/vz);
Vertexes->Screen.y=(int)((vy*(double)ProjDist)/vz);
Vertexes->Screen.x+=Centers.x;
Vertexes->Screen.y+=Centers.y;
}
}

void MatrixPackage::ToWorld(plPipeLine &plState)
{
SetProjectionDist(plState.plProjDist);
SetCenterScreen(plState.plCenters);
Translate(plState.plTranslate_Local);
Scale(plState.plScale_Local);
Rotate(plState.plRotate_Local);
Transform(plState.Vertexes,plState.NumVertexes);
}

void MatrixPackage::ToView(plPipeLine &plState)
{
SetProjectionDist(plState.plProjDist);
SetCenterScreen(plState.plCenters);
Translate(plState.plTranslate_Local);
Scale(plState.plScale_Local);
Rotate(plState.plRotate_Local);
Transform(plState.Vertexes,plState.NumVertexes);
InitMaster();
Translate(plState.plTranslate2);
Rotate(plState.plRotate2);
ViewTransform(plState.Vertexes,plState.NumVertexes);
}

void MatrixPackage::ToScreen(plPipeLine &plState)
{
SetProjectionDist(plState.plProjDist);
SetCenterScreen(plState.plCenters);
Translate(plState.plTranslate_Local);
Scale(plState.plScale_Local);
Rotate(plState.plRotate_Local);
Transform(plState.Vertexes,plState.NumVertexes);
InitMaster();
Translate(plState.plTranslate2);
Rotate(plState.plRotate2);
ViewTransform(plState.Vertexes,plState.NumVertexes);
Project(plState.Vertexes,plState.NumVertexes);
}

double *MatrixPackage1::Execute(plMode pm)
{
switch (pm)
{
case WORLD:  ToWorld(plState);break;
case VIEW:	 ToView(plState);break;
case SCREEN: ToScreen(plState);break;
}
return &master;
}

void MatrixPackage::Translate(const point3D &pt)
{
Translate(pt.x,pt.y,pt.z);
}

void MatrixPackage::Rotate(const point3D &pt)
{
Rotate(pt.x,pt.y,pt.z);
}

void MatrixPackage::Scale(const point3D &pt)
{
Scale(pt.x,pt.y,pt.z);
}
This code will handle rotation, scaling, translation, etc.,etc.
It also handles transformation, projection, and allows you to specify how far along the pipeline you wish to go.

All functions have not been tested so there might be a few minor errors. Sorry its so long, but I could not get my winzip to work.
I normally dont post code snippets this long but had no choice.

Perhaps I need to re-install WinZip.

Any questions PM me.

This assumes:

• Local space coords are centered in object - otherwise you will get an off balance local rotation.
• Z coords have been properly clipped prior to transformation and backface culling has already been done.
• Vertexes that are not visible (as well as polies/triangles) have been properly removed from the vertex list.
• The view matrix is setup after using this class and then concatenated with the final master matrix - returned from the Execute function.
• Z coordinates move into the screen, X is left and right, and Y is up (right handed coord system I believe)

8. To use this class:

MatrixPackage1 constructor is incorrect. Should just be
MatrixPackage. MatrixP..1 is from a prev template version of this class.

• Create an instance of MatrixPackage.
• Setup translation, scaling, and rotation with calls to these functions. The reason there are two versions of these functions is so that I can change the underlying code later on, but the public interface will remain the same.
• After you set all of these up, simply pass your vertex list to the WorldTransform function when calling it. This will convert from Local to World space.
• Reset the master matrix
• Perform any rotation,scaling,translation. This is done now in World space.
• Call ViewTransform and pass your vertexes to the function. Note that you do not have to explicity pass the World vertexes to the function since these are members of the Vertex struct. The View Transform function will automatically use these members.
• (optional and not implemented) Retrieve a pointer to the master matrix - concatenate with self-made view matrix (must be double data type)
• Call Project (after setting the desired projection distance and center of the screen) to convert View vertexes into Screen space (3D to 2D).
• Draw the objects from the vertex list. (not handled by this class). Vertexes must be taken from each object (thus each poly in the object) and placed into a master list - this way all vertexes for all visible objects can be transformed with one master multiply.

Note that this class is not done since it does not support the view matrix. But it should give you an idea of how to do it.

I've worked very hard on this code for some time and it is the result of reading several books and many hours of headaches. Most of this is not needed within environments like OpenGL (though you do have to setup the matrices) or DirectX.

If you have suggestions about this code, PM me. If we could test this code completely (through several users) I would be interested in placing it on the FAQ board. We have lots of questions regarding matrices on these boards and this might help a bit.