opengl构造一个灵活的camera

dx龙书有一章的题目就构建一个灵活的camera.

看了 opengl 以后,对视口变换,投影变换,模型视图变换 的顺序,关系,理解得更清晰了。

其中,视图变换相当于模型变换的逆向变换, glLookAt() 这类直接操作camera的函数,只是封装了一些逆向移动的各种 translate,rotate,scale而已。

于是自己写了一个 camera 类。

其中不足是暂时不会用 opengl 的 api 来直接计算。比如一个 vector 乘以 一个matrix,结果再保存到这个vector中,dx是有 api 的 ,我猜 opengl 可能也有。

只是自己暂时没有找到。 我也没有自己动手写这样一个函数 ,免得将来找到了,发现自己犯傻做了太多的无用功。

 

这个例子,纯属是为了更进一步理解 model-view 变换而写的,重点在 camera.h 和 camera.cpp,

用 camera类的 work() 函数,来取代 glLookAt() 函数。

 

贴出来做个笔记。

 

main.cpp

#include "GLFrame.h"
#include <string>
using namespace std;

const int WINDOW_POS_X = 100;
const int WINDOW_POS_Y = 100;
const int WINDOW_SIZE_X	= 800;
const int WINDOW_SIZE_Y = 600;

const string WINDOW_NAME = "solar";

int main(int arc,char** argv)
{
	glutInit( &arc,argv);
	glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);

	glutInitWindowPosition( WINDOW_POS_X,WINDOW_POS_Y);
	glutInitWindowSize(WINDOW_SIZE_X,WINDOW_SIZE_Y);
	glutCreateWindow( WINDOW_NAME.c_str() );

	glutDisplayFunc( onPaintGL);
	glutReshapeFunc( onReshapeGL);
	//glutTimerFunc(200,onTimerGL,200);
	glutMouseFunc( onMouseGL);
	glutKeyboardFunc( onKeyboard );

	init();
	glutMainLoop();

	return 0;
}


glFrame.h

#include <GL\glut.h>


void init();
void onPaintGL();
void onReshapeGL(int width,int height);
void onMouseGL(int button,int state,int x,int y);
void onTimerGL(int value);
void onKeyboard(unsigned char key,int x,int y);


logic.cpp

#include "GLFrame.h"

#include <iostream>
using namespace std;

#include "camera.h"

int window_width = 0;
int window_height = 0;


void paintSolar();
void paintUI();

float cur_revolution_angle = 0.0f;
float cur_autobiography_angle = 0.0f;
void revolution_earth();
void autobiography_earth();

//	camera logic
static OGL_CAMERA::Camera g_camera;
enum ECameraWorkType
{
	ECWT_OGL_LOOKAT,
	ECWT_CUSTOM_CAMERA,
};
ECameraWorkType g_cwt = ECWT_CUSTOM_CAMERA;

void init()
{
	glClearColor( 0.0,0.0,0.0,0.0);
	glShadeModel( GL_FLAT );

}


void onPaintGL()
{
	glClear( GL_COLOR_BUFFER_BIT );

	glViewport(0,0,window_width,window_height);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(60.0f,(GLfloat)window_width/(GLfloat)window_height,0.1,100);
	
	glMatrixMode(GL_MODELVIEW);
	if( g_cwt == ECWT_OGL_LOOKAT )
	{
		glLoadIdentity();
		gluLookAt(0.0f,0.0f,20.0f,0.0f,0.0f,0.0f,0.0f,1.0f,0.0f);	
	}
	else if( g_cwt == ECWT_CUSTOM_CAMERA)
	{
		g_camera.work();
	}


	paintSolar();

	glFlush();
}

void onReshapeGL(int width,int height)
{
	window_width = width;
	window_height = height;
}

void onMouseGL(int button,int state,int x,int y)
{
	

	//glutPostRedisplay();
}

void onKeyboard(unsigned char key,int x,int y)
{
	switch(key)
	{
	case 'c':
	case 'C':
		cout << "camera work type changed" << endl;	
		g_cwt==ECWT_OGL_LOOKAT ? g_cwt = ECWT_CUSTOM_CAMERA : g_cwt = ECWT_OGL_LOOKAT; 
		glutPostRedisplay();
		break;
	}

	
	if( g_cwt == ECWT_CUSTOM_CAMERA )
	{
		g_camera.processInput( key );
		glutPostRedisplay();
	}

}

void paintSolar()
{	
	glColor3f( 1.0f,0.0f,0.0f);
	glPushMatrix();
	{
		glRotatef(cur_autobiography_angle,0,1,0);
		glRotatef(90,1,0,0);
		glutWireSphere(5.0f,10,10);	
	}
	glPopMatrix();

	
	glColor3f( 0.0f,0.0f,1.0f);
	glPushMatrix();
	{
		glRotatef(cur_revolution_angle,0,1,0);
		glTranslatef(10.0f,0.0f,0.0f);
		glRotatef(cur_autobiography_angle,0,1,0);
		glRotatef(90,1,0,0);
		glutWireSphere(1.0f,10,10);	
	}
	glPopMatrix();
	
}

void revolution_earth()
{
	cur_revolution_angle += 1;
	cur_revolution_angle = cur_revolution_angle > 360 ? 0 : cur_revolution_angle;	
}

void autobiography_earth()
{
	cur_autobiography_angle += 1.0f;
	cur_autobiography_angle = cur_autobiography_angle > 360 ? 0 : cur_autobiography_angle;	
}


void onTimerGL(int value)
{
	revolution_earth();
	autobiography_earth();	
	
	glutPostRedisplay();


	glutTimerFunc(100,onTimerGL,value);
}


 

 camera.h

#ifndef	OGL_CAMERA_H
#define	OGL_CAMERA_H

#include <GL\glut.h>

namespace OGL_CAMERA
{
class Camera
{
protected:
	GLdouble _pos[3];
	GLdouble _pitch;
	GLdouble _roll;
	GLdouble _yaw;

	//GLdouble _up[3];
	//GLdouble _right[3];
	//GLdouble _look[3];	
protected:
	void doPitch( GLdouble angle );
	void doRoll( GLdouble angle );
	void doYaw( GLdouble angle );

	void doWalk( GLdouble dis );
	void doStrafe( GLdouble dis );
	void doFly( GLdouble dis );

public:
	Camera();
	~Camera();
	void work();
	void processInput(unsigned char key);

};

}		//	namespace OGL_CAMERA



#endif	//OGL_CAMERA_H

 

camera.cpp

 

#include "camera.h"

using namespace OGL_CAMERA;

Camera::Camera()
{
	_pos[0] = 0;		_pos[1] = 0;		_pos[2] = 20;
	//_up[3] = 0;			_up[1] = 1;			_up[2] = 0;
	//_right[0] = 1.0;	_right[1] = 0;			_right[2] = 0;
	//_look[0];			_look[1] = 0;			_look[2] = -1;
	
	_pitch = 0;
	_yaw = 0;
	_roll = 0;

}


Camera::~Camera()
{

}

void Camera::processInput(unsigned char key)
{
	static GLdouble angle = 5.0;
	static GLdouble dis = 0.1;

	switch(key)
	{
		//	pitch
	case 'w':
	case 'W':
		doPitch(angle);
		break;
	case 's':
	case 'S':
		doPitch(-angle);
		break;

		//	yaw	
	case 'a':
	case 'A':
		doYaw(angle);
		break;
	case 'd':
	case 'D':
		doYaw(-angle);
		break;

		//	roll
	case 'q':
	case 'Q':
		doRoll(angle);
		break;
	case 'e':
	case 'E':
		doRoll(-angle);
		break;

		//	walk
	case 'i':
	case 'I':
		doWalk(-dis);
		break;
	case 'k':
	case 'K':
		doWalk(dis);
		break;
		//	strafe
	case 'j':
	case 'J':
		doStrafe(-dis);
		break;
	case 'l':
	case 'L':
		doStrafe(dis);
		break;
		//	fly
	case 'u':
	case 'U':
		doFly(dis);
		break;
	case 'o':
	case 'O':
		doFly(-dis);
		break;
	}
}

void Camera::doPitch( GLdouble angle )
{
	_pitch += angle;
}

void Camera::doRoll( GLdouble angle )
{
	_roll += angle;
}

void Camera::doYaw( GLdouble angle )
{
	_yaw += angle;
}

void Camera::doWalk( GLdouble dis )
{
	_pos[2] += dis;
}

void Camera::doStrafe( GLdouble dis )
{
	_pos[0] += dis;
}

void Camera::doFly( GLdouble dis )
{
	_pos[1] += dis;
}

void Camera::work()
{
	glLoadIdentity();
	//gluLookAt(0.0f,0.0f,10.0f,0.0f,0.0f,0.0f,0.0f,1.0f,0.0f);
	glRotatef( -_pitch,1.0,0.0,0.0);
	glRotatef( -_yaw,0.0,1.0,0.0);
	glRotatef( -_roll,0.0,0.0,1.0);
	glTranslatef(-_pos[0],-_pos[1],-_pos[2]);
	


	
}



 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值