Jump to content
  • Advertisement
Sign in to follow this  
MrLloyd1981

Camera in Open GL help

This topic is 3271 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

Hey! I've created a camera class following an exercise in a book. However, I have a function called slide that 'slides' the camera in one of three axis, analogous to the x, y or z axis. However when I have the slide function move in the z axis there is some unexplained rotation visible on screen! The Camera class also utilises a custom 3D point and 3D vector class. Please see the following code: custom point class
//interface for point3 class
#ifndef _POINT3_H
#define _POINT3_H
#include "Vector3.h"

class Point3{
	public:
		Point3();
		Point3(float,float,float);
		Point3(const Point3&);
		~Point3();
		void set(const Point3&);
		void set(float,float,float);
		void setX(float);
		void setY(float);
		void setZ(float);
		float getX() const;
		float getY() const;
		float getZ() const;
		Vector3 operator-(const Point3&);
	private:
		float x;
		float y;
		float z;
};

#endif

//Point3.cpp - implementation of Point3 class
#include "Point3.h"

Point3::Point3(){
	x = 0.0;
	y = 0.0;
	z = 0.0;
}

Point3::Point3(float x, float y, float z){
	this->x = x;
	this->y = y;
	this->z = z;
}

Point3::Point3(const Point3& rhs){
	this->x = rhs.getX();
	this->y = rhs.getY();
	this->z = rhs.getZ();
}

Point3::~Point3(){
}



void Point3::set(const Point3& point){
	x = point.getX();
	y = point.getY();
	z = point.getZ();
}

void Point3::set(float x,float y,float z){
	this->x = x;
	this->y = y;
	this->z = z;
}

void Point3::setX(float x){
	this->x = x;
}

void Point3::setY(float y){
	this->y = y;
}

void Point3::setZ(float z){
	this->z = z;
}

float Point3::getX()const{
	return x;
}

float Point3::getY()const{
	return y;
}

float Point3::getZ()const{
	return z;
}

Vector3 Point3::operator-(const Point3& rhs){
	float delX = x - rhs.getX();
	float delY = y - rhs.getY();
	float delZ = z - rhs.getZ();
	Vector3 vec(delX,delY,delZ);
	return vec;
}

custom Vector class
[source lang = "cpp"]//Vector3.h - interface for Vector3 class
#ifndef _VECTOR3_H
#define _VECTOR3_H

class Vector3{
	public:
		Vector3();
		Vector3(float,float,float);
		Vector3(const Vector3&);
		~Vector3();
		void set(const Vector3&);
		void set(float,float,float);
		void setX(float);
		void setY(float);
		void setZ(float);
		float getX()const;
		float getY()const;
		float getZ()const;
		float dotProd(const Vector3&)const;
		Vector3 crossProd(const Vector3&)const;
		void normalize();

	private:
		float x;
		float y;
		float z;
};

#endif

//vector.cpp - implementation of vector class
#include <cmath>
#include "Vector3.h"

//constructors/copy constructors/destructors

Vector3::Vector3(){
	x = 0.0;
	y = 0.0;
	z = 0.0;
}

Vector3::Vector3(float x,float y,float z){
	this->x = x;
	this->y = y;
	this->z = z;
}

Vector3::Vector3(const Vector3& rhs){
	this->x = rhs.getX();
	this->y = rhs.getY();
	this->z = rhs.getZ();
}

Vector3::~Vector3(){

}

//setter functions
void Vector3::set(const Vector3& rhs){
	this->x = rhs.getX();
	this->y = rhs.getY();
	this->z = rhs.getZ();
}

void Vector3::set(float x,float y,float z){
	this->x = x;
	this->y = y;
	this->z = z;
}

void Vector3::setX(float x){
	this->x = x;
}

void Vector3::setY(float y){
	this->y = y;
}

void Vector3::setZ(float z){
	this->z = z;
}


//getter functions
float Vector3::getX()const{
	return x;
}

float Vector3::getY()const{
	return y;
}

float Vector3::getZ()const{
	return z;
}

//calculates dot product of two vectors
float Vector3::dotProd(const Vector3& rhs)const{
	float dot = (this->x * rhs.getX()) + (this->y * rhs.getY()) +
				(this->z * rhs.getZ());
	return dot;
}

//calculates cross product of two vectors
Vector3 Vector3::crossProd(const Vector3& rhs)const{
	//calculate components
	float i = (this->y * rhs.getZ()) - (this->z * rhs.getY());
	float j = (this->x * rhs.getZ()) - (this->z * rhs.getX());
	float k = (this->x * rhs.getY()) - (this->y * rhs.getX());

	//create new vector based on components
	Vector3 cross(i,-j,k);
	return cross;
}

//normalizes the vector
void Vector3::normalize(){
	//calculate magnitude of vector
	float length = sqrt((x*x)+(y*y)+(z*z));

	//normalize components;
	x /= length;
	y /= length;
	z /= length;
}

Custom camera class
[source lang = "cpp"]//Camera.h interface for the camera class

#ifndef _CAMERA_H
#define _CAMERA_H
#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>
#include <cmath>
#include "Point3.h"
#include "Vector3.h"


class Camera{
	public:
		Camera();
		~Camera();
		void set(Point3,Point3,Vector3);
		void roll(float);
		void pitch(float);
		void yaw(float);
		void slide(float,float,float);
		void setShape(float,float,float,float);
	private:
		Point3 eye, look;
		Vector3 u, v, n, up;
		double viewAngle, aspect, nearDist, farDist;
		void setModelViewMatrix();
};

#endif

//Camera.cpp - implementation for camera class
#include "Camera.h"

Camera::Camera(){
	eye.set(2.0,2.0,-2.0);
	look.set(0.0,0.0,0.0);
	up.set(0.0,1.0,0.0);
	set(eye,look,up);
}

Camera::~Camera(){
}

void Camera::set(Point3 Eye,Point3 lookAt,Vector3 up){
	//set eye values
	eye.set(Eye);
	//create vector n
	n.set(eye.getX() - lookAt.getX(), eye.getY() - lookAt.getY(), eye.getZ() - lookAt.getZ());
	//make u = up X n
	u.set(up.crossProd(n));
	
	//normalize vectors
	n.normalize(); u.normalize();

	//make v = nXu
	v.set(n.crossProd(u));
	setModelViewMatrix();
}

//rotates camera around its z axis
void Camera::roll(float angle){
	float cs = cos(3.14159265/180 * angle);
	float sn = sin(3.14159265/180 * angle);
	Vector3 t(u);
	u.set(cs*t.getX() - sn*v.getX(), cs*t.getY() - sn*v.getY(), cs*t.getZ() - sn*v.getZ());
	v.set(sn*t.getX() + cs*v.getX(), sn*t.getY() + cs*v.getY(), sn*v.getZ() + cs*v.getZ());
	setModelViewMatrix();
}

//rotates camera around its x axis
void Camera::pitch(float angle){
	float cs = cos(3.14159265/180 * angle);
	float sn = sin(3.14159265/180 * angle);
	Vector3 t(u);
	u.set(cs*t.getX() - sn*n.getX(),cs*t.getY() - sn*n.getY(),cs*t.getZ() - sn*n.getZ());
	n.set(cs*n.getX() + sn*t.getX(),cs*n.getY() + sn*t.getY(),cs*n.getZ() + sn*t.getZ());
	setModelViewMatrix();
}

//rotates camera around its y axis
void Camera::yaw(float angle){
	float cs = cos(3.14159265/180 * angle);
	float sn = sin(3.14159265/180 * angle);
	Vector3 t(v);
	v.set(cs*t.getX()+sn*n.getX(),cs*t.getY()+sn*n.getY(),cs*t.getZ()+sn*n.getZ());
	n.set(-sn*t.getX()+cs*n.getX(),-sn*t.getY()+cs*n.getY(),-sn*t.getZ()+cs*n.getZ());
	setModelViewMatrix();
}

void Camera::slide(float delU,float delV, float delN){

	//get the values of the different components of the
	//eye point, look point
	float eyeX = eye.getX();
	float eyeY = eye.getY();
	float eyeZ = eye.getZ();
	float lookX = look.getX();
	float lookY = look.getY();
	float lookZ = look.getZ();

	//now set the new values for eye and look based on old values
	//and the changes, e.g delU is a change in the u vector/x axis pos of the camera
	//del V is change in v vector/y axis pos and del v is change in normal from camera / z axis pos

	eye.setX(eyeX += delU* u.getX() + delV * v.getX() + delN * n.getX());

	eye.setY(eyeY += delU* u.getY() + delV * v.getY() + delN * n.getY());

	eye.setZ(eyeZ += (delU* u.getZ()) + (delV * v.getZ()) + (delN * n.getZ()));

	look.setX(lookX += delU* u.getX() + delV * v.getX() + delN * n.getX());

	look.setY(lookY += delU* u.getY() + delV * v.getY() + delN * n.getY());

	look.setZ(lookZ += (delU* u.getZ()) + (delV * v.getZ()) + (delN * n.getZ()));
	//now set modelview matrix of world
	setModelViewMatrix();
}

void Camera::setShape(float viewAngle,float asp,float nearD,float farD){
	//sets shape of the camera, with viewangle asp = aspect ratio,
	//nearD being the pos of the near plane and farD being pos of far plane

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(viewAngle,asp,nearD,farD);
}

void Camera::setModelViewMatrix(){
	//create a matrix
	float m[16];

	//create a vector version of eye point
	Vector3 eVec(eye.getX(),eye.getY(),eye.getZ());

	//now set all the elements of the matrix accordingly
	m[0] = u.getX(); m[4] = u.getY(); m[8] = u.getZ(); m[12] = -eVec.dotProd(u);
	m[1] = v.getX(); m[5] = v.getY(); m[9] = v.getZ(); m[13] = -eVec.dotProd(v);
	m[2] = n.getX(); m[6] = n.getY(); m[10]= n.getZ(); m[14] = -eVec.dotProd(n);
	m[3] = 0       ; m[7] = 0;        m[11] = 0;       m[15] = 1.0;

	//now load into modelview matrix
	glMatrixMode(GL_MODELVIEW);
	glLoadMatrixf(m);
}

now the main client code, it's the keys function that uses a switch statement to call the slide function for the appropriate axis
[source lang = "cpp"]
#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>
#include "Camera.h"
#include "Point3.h"
#include "Vector3.h"
#include "Mesh.h"

void display();
void keys(unsigned char,int,int);
void myInit();

//global variables
Camera cam;
Mesh newMesh;
string name;
Point3 EYE(2.0,3.0,-2.0);
Point3 LOOK(0,0,0);
Vector3 UP(0,1,0);

void main(int argc,char** argv){
	glutInit(&argc,argv);
	glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB |GLUT_DEPTH);
	glutInitWindowSize(640,480);
	glutInitWindowPosition(0,0);
	glutCreateWindow("cam");
	glutDisplayFunc(display);
	glutKeyboardFunc(keys);
	myInit();
	glutMainLoop();
}


void myInit(){
	newMesh.readFile("barn.dat");
	glClearColor(1.0,1.0,1.0,0.0);
	glEnable(GL_DEPTH_TEST);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(-3.0,3.0,-3.0,3.0,-1.0,10.0);
	cam.set(EYE,LOOK,UP);
	cam.setShape(90,1.3,0.1,50);
}

void display(){
	glClearColor(1.0,1.0,1.0,0.0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	newMesh.drawMesh();
	newMesh.drawEdges();
	glutSwapBuffers();
}

void keys(unsigned char ch,int x, int y){
	switch(ch){
		case 'a':
			cam.slide(-0.05,0.0,0.0);
			break;
		case 'd':
			cam.slide(0.05,0.0,0.0);
			break;
		case 'w':
			cam.slide(0.0,0.05,0.0);
			break;
		case 's':
			cam.slide(0.0,-0.05,0.0);
			break;
		case 'z':
			cam.slide(0.0,0.0,0.5);
			break;
		case 'x':
			cam.slide(0.0,0.0,-0.5);
		case 'r':
			cam.roll(-5.0);
			break;
		case 't':
			cam.roll(5.0);
			break;
		case 'f':
			cam.pitch(-5.0);
			break;
		case 'g':
			cam.pitch(5.0);
			break;
		case 'v':
			cam.yaw(-5.0);
			break;
		case 'b':
			cam.yaw(5.0);
			break;
			
	}

	glutPostRedisplay();
}

While I'm at it I best post up the mesh class in case you are curious about that too
[source lang = "cpp"]
//Mesh.h - interface for the mesh class
#ifndef _MESH_H
#define _MESH_H
#include <windows.h>
#include <string>
#include <gl/Gl.h>
#include <gl/Glu.h>
#include <gl/Glut.h>
using namespace std;


struct GLpoint3D{
	GLfloat x;
	GLfloat y;
	GLfloat z;
};

struct Vector3D{
	GLfloat x;
	GLfloat y;
	GLfloat z;
};

struct VertexID{
	int vertIndex;
	int normIndex;
};

struct Face{
	int nVerts;
	VertexID* vert;
};

class Mesh{
	public:
		Mesh();
		~Mesh();
		void readFile(string name);
		void drawMesh();
		void writeMesh(string name);
		void drawEdges();
	private:
		int numVerts;
		GLpoint3D* pt;
		int numNormals;
		Vector3D* norm;
		int numFaces;
		Face* face;
};

#endif

//mesh.cpp - implementation for the mesh class
#include <fstream>
#include "Mesh.h"
using namespace std;


Mesh::Mesh(){
	numVerts	= 0;
	pt			= NULL;
	numNormals	= 0;
	norm		= NULL;
	numFaces	= 0;
	face		= NULL;
}

Mesh::~Mesh(){
	delete [] pt;
	delete [] norm;
}

void Mesh::drawMesh(){

	GLfloat r,g,b;
	r = g = b = 0.0;

	for(int i = 0; i < numFaces; i++){
		glColor3f(r,g,b);
		glBegin(GL_POLYGON);
		for(int j = 0; j < face.nVerts; j++){
			int in = face.vert[j].normIndex;
			int iv = face.vert[j].vertIndex;
			glNormal3f(norm[in].x,norm[in].y, norm[in].z);
			glVertex3f(pt[iv].x,pt[iv].y,pt[iv].z);
		}
		glEnd();
		r += 0.15;
		g += 0.2;
		b += 0.05;
	}
}

void Mesh::drawEdges(){
	glColor3f(0.0f,0.0f,0.0f);
	for(int i = 0; i < numFaces; i++){
		glBegin(GL_LINE_LOOP);
		for(int j = 0; j < face.nVerts; j++){
			int iv = face.vert[j].vertIndex;
			glVertex3f(pt[iv].x,pt[iv].y,pt[iv].z);

		}
		glEnd();
	}
	
}

void Mesh::readFile(string name){
	ifstream inFile;
	inFile.open(name.c_str());
	inFile >> numVerts >> numNormals >> numFaces;
	pt		= new GLpoint3D[numVerts];
	norm	= new Vector3D[numNormals];
	face	= new Face[numFaces];

	//read vertices
	for (int i = 0; i < numVerts; i++){
		inFile >> pt.x >> pt.y >> pt.z;
	}

	for (int i = 0; i < numNormals ; i++){
		inFile >> norm.x >> norm.y >> norm.z;
	}

	for (int i = 0; i < numFaces; i++){
		inFile >> face.nVerts;
		face.vert = new VertexID[face.nVerts];
		for(int j = 0; j < face.nVerts; j++)
			inFile	>> face.vert[j].vertIndex;
		
		for(int j = 0; j < face.nVerts; j++)
			inFile	>> face.vert[j].normIndex;
		
	}

	inFile.close();
}

void Mesh::writeMesh(string name){
	ofstream outFile;
	outFile.open(name.c_str());
	outFile << numVerts <<" "<< numNormals <<" "<< numFaces<<endl;

	for (int i = 0; i < numVerts; i++){
		outFile << pt.x <<" "<< pt.y <<" "<< pt.z<<"\t";
	}

	outFile <<endl;

	for (int i = 0; i < numNormals ; i++){
		outFile << norm.x <<" "<< norm.y <<" "<< norm.z<<"\t";
	}

	outFile <<endl;

	for (int i = 0; i < numFaces; i++){
		outFile << face.nVerts<<"\t";

		for(int j = 0; j < face.nVerts; j++)
			outFile	<< face.vert[j].vertIndex<<" ";
		
		outFile <<"\t";

		for(int j = 0; j < face.nVerts; j++)
			outFile	<< face.vert[j].normIndex<<" ";

		outFile <<endl;
		
	}

	outFile.close();
}

Anyone thats able to help - Thanks in advance!

Share this post


Link to post
Share on other sites
Advertisement
In the switch statement in void keys(unsigned char ch,int x, int y), you are missing a break statement for case 'x', resulting in a roll in the camera as well as a translation when x is pressed.

Share this post


Link to post
Share on other sites
Ugh! What a silly oversight. Thanks very much! My eyes are quite tired from programming today, thats why I must have overlooked it.

However, I've noticed when I use the rotation functions there is some weird distortion present in my mesh. It's as if the mesh is being contorted or 'squashed'. If anyone could give me some pointers let me know please!

Share this post


Link to post
Share on other sites
Is the Y axis 'up' in this context? If so, it looks like you may be rotating the wrong vectors in your rotation functions.

In the Yaw function, for instance, which purports to rotate about the up vector, you are rotating your 'up' and 'lookDirection' vectors, instead of your 'right' and 'lookDirection' vectors. This results in the 'right' vector staying where it is and applying a weird transformation to your scene.

I would suggest using more meaningful variable names in your camera class. The usage of u, v, and n are very confusing, in my opinion.

Share this post


Link to post
Share on other sites
Cheers, thanks very much. I took another look at my code and found the mistakes I was making. It's now working a treat. U,V and N just happen to be the vector names used in the educational book I'm reading at the moment, "Computer Graphics using OpenGL 3rd edition" (Kelly/Hill)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!