⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 glcamera.cpp

📁 RBF平台
💻 CPP
字号:
/*Szymon RusinkiewiczPrinceton UniversityGLCamera.ccManages OpenGL camera and trackball/arcball interaction*/#include <GL/glut.h>#include "GLCamera.h"#ifndef M_PI# define M_PI 3.14159265358979323846#endif#define DOF 10.0f#define MAXDOF 10000.0f#define SPIN_TIME 0.1f#define SPIN_SPEED 0.05f#define TRACKBALL_R 0.8f#define DEPTH_FUDGE (1.0f + 0.2f * field_of_view)#define MOVEZ_MULT 5.0f#define WHEEL_MOVE 0.2f#define MAX_LIGHT M_PI// Read back the framebuffer at the given pixel, and determine// the 3D point there.  If there's nothing there, reads back a// number of pixels farther and farther away.bool GLCamera::read_depth(int x, int y, point &p) const{	GLdouble M[16], P[16]; GLint V[4];	glGetDoublev(GL_MODELVIEW_MATRIX, M);	glGetDoublev(GL_PROJECTION_MATRIX, P);	glGetIntegerv(GL_VIEWPORT, V);	static const float dx[] =		{ 0, 1,-1,-1, 1, 3,-3, 0, 0, 6,-6,-6, 6, 25,-25,  0,  0 };	static const float dy[] =		{ 0, 1, 1,-1,-1, 0, 0, 3,-3, 6, 6,-6,-6,  0,  0, 25,-25 };	const float scale = 0.01f;	const int displacements = sizeof(dx) / sizeof(float);	int xmin = V[0], xmax = V[0]+V[2]-1, ymin = V[1], ymax = V[1]+V[3]-1;	for (int i = 0 ; i < displacements; i++) {		int xx = min(max(x + int(dx[i]*scale*V[2]), xmin), xmax);		int yy = min(max(y + int(dy[i]*scale*V[3]), ymin), ymax);		float d;		glReadPixels(xx, yy, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &d);		static float maxd = 0.0f;		if (!maxd) {			glScissor(xx, yy, 1, 1);			glEnable(GL_SCISSOR_TEST);			glClearDepth(1);			glClear(GL_DEPTH_BUFFER_BIT);			glReadPixels(xx, yy, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &maxd);			if (maxd) {				glClearDepth(d / maxd);				glClear(GL_DEPTH_BUFFER_BIT);			}			glDisable(GL_SCISSOR_TEST);			glClearDepth(1);			if (!maxd)				return false;		}		d /= maxd;		if (d > 0.0001f && d < 0.9999f) {			GLdouble X, Y, Z;			gluUnProject(xx, yy, d, M, P, V, &X, &Y, &Z);			p = point(X, Y, Z);			return true;		}	}	return false;}// Mouse helper - decide whether to start auto-spinvoid GLCamera::startspin(){	float dt = now() - last_time;	if (dt < SPIN_TIME && fabs(spinspeed) > SPIN_SPEED)		dospin = true;}// Mouse rotation helper - compute trackball position from mouse posvec GLCamera::mouse2tb(float x, float y){	float r2 = x*x + y*y;	float t = 0.5 * sqr(TRACKBALL_R);	vec pos(x, y, 0);	if (r2 < t)		pos[2] = sqrt(2*t - r2);	else		pos[2] = t / sqrt(r2);	return pos;}// Mouse helper - rotatevoid GLCamera::rotate(int mousex, int mousey, xform &xf){	float ox = (lastmousex - tb_screen_x) / tb_screen_size;	float oy = (lastmousey - tb_screen_y) / tb_screen_size;	float nx = (    mousex - tb_screen_x) / tb_screen_size;	float ny = (    mousey - tb_screen_y) / tb_screen_size;	vec pos1 = mouse2tb(ox, oy);	vec pos2 = mouse2tb(nx, ny);	spinaxis = pos1 CROSS pos2;	float spinamount = sqrt(sqr(nx-ox)+sqr(ny-oy));	xf = xform::trans(spincenter) * xform::rot(spinamount, spinaxis) *	     xform::trans(-spincenter) * xf;	float dt = now() - last_time;	if (dt > SPIN_TIME)		spinspeed = spinamount / SPIN_TIME;	else		spinspeed = (spinamount / SPIN_TIME) +			    (1.0f-dt/SPIN_TIME)*spinspeed;}// Mouse helper - translatevoid GLCamera::movexy(int mousex, int mousey, xform &xf){	float dx = pixscale * click_depth * (mousex - lastmousex);	float dy = pixscale * click_depth * (mousey - lastmousey);	xf = xform::trans(dx, dy, 0) * xf;}// Mouse helper - translate in Z// In order to be extra-clever, though, this actually translates along the// direction of the center of the trackballvoid GLCamera::movez(int mousex, int mousey, xform &xf){	float delta = MOVEZ_MULT / field_of_view * pixscale *		      ((mousex-lastmousex) - (mousey-lastmousey));	float dz = click_depth * (exp(-delta) - 1.0f);	//xf = xform::trans(0, 0, -dz) * xf;	xf = xform::trans(dz * spincenter / len(spincenter)) * xf;	surface_depth += dz;	if (surface_depth < 0)		surface_depth = 0;	click_depth += dz;	if (click_depth < 0)		click_depth = 0;}// Mouse helper - wheel motionvoid GLCamera::wheel(Mouse::button updown, xform &xf){	float dz = click_depth * WHEEL_MOVE;	if (updown == Mouse::WHEELUP)		dz = -dz;	xf = xform::trans(0, 0, dz) * xf;	surface_depth -= dz;	if (surface_depth < 0)		surface_depth = 0;	click_depth -= dz;	if (click_depth < 0)		click_depth = 0;}// Mouse helper - change lighting directionvoid GLCamera::relight(int mousex, int mousey){	GLint V[4];	glGetIntegerv(GL_VIEWPORT, V);	float x = 2.0f * float(mousex - V[0]) / float(V[2]) - 1.0f;	float y = 2.0f * float(mousey - V[1]) / float(V[3]) - 1.0f;	float theta = MAX_LIGHT * min(sqrt(x*x+y*y), 1.0f);	float phi = atan2(y, x);	lightdir[0] = sin(theta)*cos(phi);	lightdir[1] = sin(theta)*sin(phi);	lightdir[2] = cos(theta);}// Handle a mouse click - sets up rotation center, pixscale, and click_depthvoid GLCamera::mouse_click(int mousex, int mousey,			   const point &scene_center, float scene_size){	GLdouble M[16], P[16]; GLint V[4];#if 0	glGetDoublev(GL_MODELVIEW_MATRIX, M);#else	M[0] = M[5] = M[10] = M[15] = 1.0;	M[1] = M[2] = M[3] = M[4] =	M[6] = M[7] = M[8] = M[9] =	M[11] = M[12] = M[13] = M[14] = 0;#endif	glGetDoublev(GL_PROJECTION_MATRIX, P);	glGetIntegerv(GL_VIEWPORT, V);	// Assume glFrustum only...	pixscale = 2.0f / max(P[0]*V[2], P[5]*V[3]);	point surface_point;	if (read_depth(mousex, mousey, surface_point))		click_depth = -surface_point[2];	else		click_depth = surface_depth;	GLdouble cx, cy, cz;	gluProject(scene_center[0], scene_center[1], scene_center[2],		   M, P, V,		   &cx, &cy, &cz);	double csize = max(V[2], V[3]);	int xmin = V[0], xmax = V[0]+V[2], ymin = V[1], ymax = V[1]+V[3];	if (scene_center[2] < 0 && len(scene_center) > scene_size) {		csize = -scene_size / scene_center[2] / pixscale;		xmin = min(max((GLint) (cx - csize), V[0]), V[0]+V[2]);		xmax = min(max((GLint) (cx + csize), V[0]), V[0]+V[2]);		ymin = min(max((GLint) (cy - csize), V[1]), V[1]+V[3]);		ymax = min(max((GLint) (cy + csize), V[1]), V[1]+V[3]);	}	GLdouble s[3];	gluUnProject((xmin+xmax)/2, (ymin+ymax)/2, 1,		     M, P, V,		     &s[0], &s[1], &s[2]);	spincenter = vec(s);	normalize(spincenter);	if (read_depth((xmin+xmax)/2, (ymin+ymax)/2, surface_point))		spincenter *=  DEPTH_FUDGE * surface_point[2] / spincenter[2];	else		spincenter *= -DEPTH_FUDGE * click_depth / spincenter[2];	float f = csize / max(V[2], V[3]);	f = min(max(2.0f * f - 1.0f, 0.0f), 1.0f);	spincenter = f * spincenter + (1.0f - f) * scene_center;	gluProject(spincenter[0], spincenter[1], spincenter[2],		   M, P, V,		   &cx, &cy, &cz);	tb_screen_x = cx;	tb_screen_y = cy;	tb_screen_size = csize;	tb_screen_size = min(tb_screen_size, 0.7f * min(V[2], V[3]));	tb_screen_size = max(tb_screen_size, 0.3f * min(V[2], V[3]));}// Handle a mouse event void GLCamera::mouse(int mousex, int mousey, Mouse::button b,		     const point &scene_center, float scene_size,		     xform &xf){	if (b == Mouse::NONE && lastb == Mouse::NONE)		return;	GLint V[4];	glGetIntegerv(GL_VIEWPORT, V);	mousey = V[1] + V[3] - 1 - mousey;	dospin = false;	if ((b != lastb) && (b != Mouse::NONE))		mouse_click(mousex, mousey, scene_center, scene_size);	// Handle rotation	if ((b == Mouse::ROTATE) && (lastb == Mouse::NONE))		spinspeed = 0;	if ((b == Mouse::ROTATE) && (lastb == Mouse::ROTATE))		rotate(mousex, mousey, xf);	if ((b == Mouse::NONE) && (lastb == Mouse::ROTATE))		startspin();	// Handle translation	if ((b == Mouse::MOVEXY) && (lastb == Mouse::MOVEXY))		movexy(mousex, mousey, xf);	if ((b == Mouse::MOVEZ) && (lastb == Mouse::MOVEZ))		movez(mousex, mousey, xf);	if (b == Mouse::WHEELUP || b == Mouse::WHEELDOWN)		wheel(b, xf);	// Handle lighting	if (b == Mouse::LIGHT)		relight(mousex, mousey);	lastmousex = mousex;  lastmousey = mousey;  lastb = b;	last_time = now();}// Idle loop - handles auto-rotate.  Returns true iff auto-rotatingbool GLCamera::autospin(xform &xf){	if (!dospin)		return false;	float dt = now() - last_time;	float spinamount = spinspeed * dt;	xf = xform::trans(spincenter) * xform::rot(spinamount, spinaxis) *	     xform::trans(-spincenter) * xf;	last_time = now();	return true;}// Set up the OpenGL camera for renderingvoid GLCamera::setupGL(const point &scene_center, float scene_size) const{	GLint V[4];	glGetIntegerv(GL_VIEWPORT, V);	int width = V[2], height = V[3];	point surface_point;	if (read_depth(width/2, height/2, surface_point))		surface_depth = -surface_point[2];	float fardist  = max(-(scene_center[2] - scene_size),			     scene_size / DOF);	float neardist = max(-(scene_center[2] + scene_size),			     scene_size / MAXDOF);	surface_depth = min(surface_depth, fardist);	surface_depth = max(surface_depth, neardist);	surface_depth = max(surface_depth, fardist / MAXDOF);	neardist = max(neardist, surface_depth / DOF);	float diag = sqrt(float(sqr(width) + sqr(height)));	float top = (float) height/diag * 0.5f*field_of_view * neardist;	float bottom = -top;	float right = (float) width/diag * 0.5f*field_of_view * neardist;	float left = -right;	glMatrixMode(GL_PROJECTION);	glLoadIdentity();	glFrustum(left, right, bottom, top, neardist, fardist);	glMatrixMode(GL_MODELVIEW);	glLoadIdentity();	GLfloat light0_position[] = { lightdir[0], lightdir[1], lightdir[2], 0 };	GLfloat light1_position[] = { -lightdir[0], -lightdir[1], -lightdir[2], 0 };	GLfloat light2_position[] = { lightdir[2], 0, -lightdir[0], 0 };	GLfloat light3_position[] = { -lightdir[2], 0, lightdir[0], 0 };	GLfloat light4_position[] = { 0, lightdir[2], -lightdir[1], 0 };	GLfloat light5_position[] = { 0, -lightdir[2], lightdir[1], 0 };	glLightfv(GL_LIGHT0, GL_POSITION, light0_position);	glLightfv(GL_LIGHT1, GL_POSITION, light1_position);	glLightfv(GL_LIGHT2, GL_POSITION, light2_position);	glLightfv(GL_LIGHT3, GL_POSITION, light3_position);	glLightfv(GL_LIGHT4, GL_POSITION, light4_position);	glLightfv(GL_LIGHT5, GL_POSITION, light5_position);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -