Archived

This topic is now archived and is closed to further replies.

Getting this Camera code to give X, Y, Z coords that are CORRECT

This topic is 5272 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

The code below is giving me some troubles because I want to make a GUI on the screen, but since I don''t quite understand the math to camera''s quite yet I need help trying to get this code to give the X,Y,Z coords, so that I can make make GUI on screen. cameraGL.h
#ifndef CAMERAGL_INCLUDED
#define CAMERAGL_INCLUDED

/*
All the Win/OpenGL stuff.. 
if youre not using Windows you most likely know what goes here
*/
#ifdef _WIN32
#define  WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <GL/gl.h>
#include <GL/glu.h>
#pragma comment (lib, "opengl32.lib")
#pragma comment (lib, "glu32.lib")
#endif

#include <math.h>

/*
Usage:
You can access the Right/Up/Forward vectors like a float[3] array,
but cannot write to them, because that would screw up the matrix.
Same goes for Position, except its safe to write to it.

setView() has to be called before you draw anything.
Just call it instead of gluLookAt (which most are using)

move and rotate come in two versions. Loc means the transformation
is in local coords, so rotating around (1,0,0) means youre rotating
around your current Right-vector while Glob would rotate around the
global x-axis.

Most likely you will use Loc for controlling the camera, though Glob
can be usefull if you need to apply physics. Also walking characters
will usually rotate around the global rather than around their local Up,
while flying objects will always use local axes.

If talking about objects when this is a camera confuses you: if you drop
the setView() method you can use this for objects in your world too. Just
rename the class to Object3D or something and derive a camera class from it.
*/
class CameraGL {
public:
	float const *Right, *Up, *Forward;
	float *Position;
private:
	float Transform[16];
	float FOV;
	float Aspect;
	float NearP, FarP;
	float xFac, yFac;

public:
	CameraGL(float x=0.0f, float y=0.0f, float z=0.0f);

	void setView();
	void moveLoc(float x, float y, float z, float distance=1);
	void moveGlob(float x, float y, float z, float distance=1);
	void rotateLoc(float deg, float x, float y, float z);
	void rotateGlob(float deg, float x, float y, float z);

	/*Call this at least once before using the Visible functions*/
	void setPerspective(float fov, float aspect, float nearp, float farp);
	/*pos points to a float[3]*/
	int SphereVisible(float* pos, float radius);
	/*bbox points to a float[3*8] (8 corners)*/
	bool BoxVisible(float* bbox);
	bool AABBVisible(float* bbox);
};

#endif
cameraGL.cpp
#include "cameraGL.h"

/*
The constructor will set the matrix to identity, except the inverted z-axis.
I cant get used to "forward" being negative, but if this bothers you feel free
to change the marked parts.

Also, if you dont like to access the vectors like float-arrays you can always
use vector-pointers, as long as they only contain three floats like this:
struct vector{float x,y,z;};
and replace the float* with vector* in the header file.
*/
CameraGL::CameraGL(float x, float y, float z) {
	memset(Transform, 0, 16*sizeof(float));
	Transform[0] = 1.0f;
	Transform[5] = 1.0f;
	Transform[10] = -1.0f;
	Transform[15] = 1.0f;
	Transform[12] = x; Transform[13] = y; Transform[14] = z;

	Right=&Transform[0];
	Up=&Transform[4];
	Forward=&Transform[8];
	Position=&Transform[12];
}

/*
This one does pretty much the same as gluLookAt, just that it doesnt require
to extract the vectors for gluLookAt and have it rebuild the matrix we already
got.
*/
void CameraGL::setView() {
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	float viewmatrix[16]={//Remove the three - for non-inverted z-axis

						  Transform[0], Transform[4], -Transform[8], 0,
						  Transform[1], Transform[5], -Transform[9], 0,
						  Transform[2], Transform[6], -Transform[10], 0,

						  -(Transform[0]*Transform[12] +
						  Transform[1]*Transform[13] +
						  Transform[2]*Transform[14]),

						  -(Transform[4]*Transform[12] +
						  Transform[5]*Transform[13] +
						  Transform[6]*Transform[14]),

						  //add a - like above for non-inverted z-axis

						  (Transform[8]*Transform[12] +
						  Transform[9]*Transform[13] +
						  Transform[10]*Transform[14]), 1};
	glLoadMatrixf(viewmatrix);
}

void CameraGL::moveLoc(float x, float y, float z, float distance) {
	float dx=x*Transform[0] + y*Transform[4] + z*Transform[8];
	float dy=x*Transform[1] + y*Transform[5] + z*Transform[9];
	float dz=x*Transform[2] + y*Transform[6] + z*Transform[10];
	Transform[12] += dx * distance;
	Transform[13] += dy * distance;
	Transform[14] += dz * distance;
}

void CameraGL::moveGlob(float x, float y, float z, float distance) {
	Transform[12] += x * distance;
	Transform[13] += y * distance;
	Transform[14] += z * distance;
}

/*
Here we let OpenGls (most likely quite optimized) functions do the work.
Note that its transformations already are in local coords.
*/
void CameraGL::rotateLoc(float deg, float x, float y, float z) {
	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glLoadMatrixf(Transform);
	glRotatef(deg, x,y,z);
	glGetFloatv(GL_MODELVIEW_MATRIX, Transform);
	glPopMatrix();
}

/*
We have to invert the rotations to get the global axes in local coords.
Luckily thats just the transposed in this case.
*/
void CameraGL::rotateGlob(float deg, float x, float y, float z) {
	float dx=x*Transform[0] + y*Transform[1] + z*Transform[2];
	float dy=x*Transform[4] + y*Transform[5] + z*Transform[6];
	float dz=x*Transform[8] + y*Transform[9] + z*Transform[10];
	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glLoadMatrixf(Transform);
	glRotatef(deg, dx,dy,dz);
	glGetFloatv(GL_MODELVIEW_MATRIX, Transform);
	glPopMatrix();
}

int CameraGL::SphereVisible(float* pos, float radius) {
	float d[3]={pos[0]-Position[0], pos[1]-Position[1], pos[2]-Position[2]};

	float camZ=Forward[0]*d[0] + Forward[1]*d[1] + Forward[2]*d[2];
	if (camZ+radius < NearP || camZ-radius > FarP) return 0;
	
	float camX=Right[0]*d[0] + Right[1]*d[1] + Right[2]*d[2];
	float xLimit=(camZ+radius)*xFac + radius;
	if (camX<-xLimit || camX>xLimit) return 0;

	float camY=Up[0]*d[0] + Up[1]*d[1] + Up[2]*d[2];	
	float yLimit=(camZ+radius)*yFac + radius;
	if (camY<-yLimit || camY>yLimit) return 0;

	xLimit=(camZ-radius)*xFac - radius;
	yLimit=(camZ-radius)*yFac - radius;
	if (camZ-radius>NearP && camZ+radius<FarP && camX>-xLimit &&
		camX<xLimit && camY>-yLimit && camY<yLimit) return 1;

	else return -1;
}

bool CameraGL::BoxVisible(float* bbox) {
	float d[3];
	int l=0, r=0, f=0, n=0, t=0, b=0;
	bool inX, inY, inZ;
	float camX, camY, camZ;

	for (int i=0; i<8; ++i) {
		inX=inY=inZ=false;		
		d[0]=bbox[(i*3)]-Position[0];
		d[1]=bbox[(i*3)+1]-Position[1];
		d[2]=bbox[(i*3)+2]-Position[2];

		camX=Right[0]*d[0] + Right[1]*d[1] + Right[2]*d[2];
		camY=Up[0]*d[0] + Up[1]*d[1] + Up[2]*d[2];
		camZ=Forward[0]*d[0] + Forward[1]*d[1] + Forward[2]*d[2];

		if (camX < -xFac*camZ) ++l;
		else if (camX > xFac*camZ) ++r;
		else inX=true;
		
		if (camY < -yFac*camZ) b++;
		else if (camY > yFac*camZ) t++;
		else inY=true;

		if (camZ < NearP) ++n;		
		else if (camZ > FarP) ++f;
		else inZ=true;

		if (inX && inY && inZ) return true;
	}

	if (l==8 || r==8 || f==8 || n==8 || b==8 || t==8) return false;
	return true;
}

bool CameraGL::AABBVisible(float* bbox) {
	float d[3];
	int l=0, r=0, f=0, n=0, t=0, b=0;
	bool inX, inY, inZ;
	float camX, camY, camZ;

	float tmpcorners[2][3];
	tmpcorners[0][0]=bbox[0]-Position[0];
	tmpcorners[0][1]=bbox[1]-Position[1];
	tmpcorners[0][2]=bbox[2]-Position[2];
	tmpcorners[1][0]=bbox[3]-Position[0];
	tmpcorners[1][1]=bbox[4]-Position[1];
	tmpcorners[1][2]=bbox[5]-Position[2];

	for (int i=0; i<8; ++i) {
		inX=inY=inZ=false;
		d[0]=tmpcorners[i&1][0];
		d[1]=tmpcorners[(i>>2)&1][1];
		d[2]=tmpcorners[(i>>1)&1][2];

		camX=Right[0]*d[0] + Right[1]*d[1] + Right[2]*d[2];
		camY=Up[0]*d[0] + Up[1]*d[1] + Up[2]*d[2];
		camZ=Forward[0]*d[0] + Forward[1]*d[1] + Forward[2]*d[2];

		if (camX < -xFac*camZ) ++l;
		else if (camX > xFac*camZ) ++r;
		else inX=true;
		
		if (camY < -yFac*camZ) b++;
		else if (camY > yFac*camZ) t++;
		else inY=true;

		if (camZ < NearP) ++n;		
		else if (camZ > FarP) ++f;
		else inZ=true;

		if (inX && inY && inZ) return true;
	}

	if (l==8 || r==8 || f==8 || n==8 || b==8 || t==8) return false;
	return true;
}

void CameraGL::setPerspective(float fov, float aspect, float nearp, float farp) {
	FOV = fov; Aspect = aspect;	
	NearP=nearp; FarP=farp;
	yFac = tanf(FOV * 3.14f/360);
	xFac = yFac*Aspect;
	
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(FOV, Aspect, NearP, FarP);
	glMatrixMode(GL_MODELVIEW);
}
Higher Forces

Share this post


Link to post
Share on other sites
hmm...

look up gluOrtho2D in msdn and maybe that will enlighten you...
(you can also try glOrtho which is actually my favourite)


attn spoilers ahead :

glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0,0,resx,resy,-1,1);
glMatrixMode(GL_MODELVIEW);

//Draw 2dStuff here

glBegin(GL_TRIANGLE_STRIP);
glVertex2i(0,0);
glVertex2i(0,10);
glVertex2i(10,10);
glVertex2i(10,0);
glEnd();
//this should draw a quad from top left

//to 10 pixels below/right (not tested though)


glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
//voila you can continue to render 3dstuff

//(even the matrix was saved...)



also you might be playin with glDepthRange and the like...


well if that doesnt help...

mfg Phreak
--
"Input... need input!" - Johnny Five, Short Circuit.

Share this post


Link to post
Share on other sites