opengl的3个自由度旋转和3个自由度移动

这个东西写出来,基本上从程序的效果上看应该没有问题,可以实现一个有6个自由度的相机,对地面拍摄的程序。但是里面的素材很渣,没有光线所以谨慎观看。

先说为什么写这个,很久以前当我发现写程序其实跟写作文没区别的时候,我发现我自己错了,后来学一些计算机图形学,至少用到了一些线性代数的知识,这个立刻与写作文区别开了。这里的6个自由度的相机其实只是把线性代数的乘法应用了一下,只是简单的应用一下乘法。

先说一下,下面的公式我参考了这个思密达,好像是一个挺不错的哥们。可以看他关于旋转矩阵的解说 http://www.songho.ca/opengl/gl_anglestoaxes.html

但是他只给出了关于绕X,Y,Z旋转轴旋转的变化矩阵,而且如果旋转的顺序不同,得到的结果也不同,这个大家可以考虑一个相机镜头先绕X轴旋转90度,再绕Y轴旋转90度的所看到的景观与先绕Y轴旋转90度,再绕X轴旋转90度的看到景观不同。理论上的解释是,如果A,B,C,D四个坐标系,A经过M1转换到B,B进过M2到C,C进过M3到D,那么一个A坐标的点P1需要进过M1,M2,M3这3个坐标系转换到达D坐标系P2,所以:

P2=P1*M1*M2*M3
由于矩阵乘法不具备交换交换律,(其实很好证明,大家随便拿两个矩阵算一下就可以得到一个反例)所以当你想先绕X轴转动60度,再绕Y轴转动90,又绕Z轴转动30度可以利用下面的方法来做。


一共6种排序组合。所以当你已知转动顺序和转动角度的时候完全可以用这种方法。


但是在现实中,转动的顺序你提前并不知道,所以只能通过增量的方法来实现对绕任意轴任意角度进行变化。那这个方法其实也很简单,如下介绍,

比如我举个例子,用户首先绕Z转动90度,用户再绕Y转动90度。


用户输入 先绕Z转动90度

由于程序不知道用户行为,所以先转Z轴90度的,当前栈顶矩阵变为:

0 -1 0 0
1  0 0 0
0  0 1 0
0  0 0 0
1. 利用这个矩阵进行视模转换,渲染必要的场景

2. 保存这个当前的旋转矩阵。(关键在这里)


用户再绕Y转动90度

1. 导入上一步保存的选择矩阵,当前视图模型矩阵为:

0 -1 0 0
1  0 0 0
0  0 1 0
0  0 0 0
2. 绕Y轴90度的,当前栈顶矩阵变为:

0 -1  0  0
0  0 -1  0
1  0  0  0
0  0  0  1

3. 利用这个矩阵进行视模转换,渲染必要的场景

4. 再次保存这个当前的旋转矩阵。


上面的方法核心就是通过保存上一次的旋转矩阵,来进行下一次的视图模型转换。下面有两个代码,一个是一开始说的 http://www.songho.ca/opengl/gl_anglestoaxes.html视图模型转换代码,还有是刚刚说的这个代码。

///
// convert Euler angles(x,y,z) to axes(left, up, forward)
// Each column of the rotation matrix represents left, up and forward axis.
// The order of rotation is Roll->Yaw->Pitch (Rx*Ry*Rz)
// Rx: rotation about X-axis, pitch
// Ry: rotation about Y-axis, yaw(heading)
// Rz: rotation about Z-axis, roll
//    Rx           Ry          Rz
// |1  0   0| | Cy  0 Sy| |Cz -Sz 0|   | CyCz        -CySz         Sy  |
// |0 Cx -Sx|*|  0  1  0|*|Sz  Cz 0| = | SxSyCz+CxSz -SxSySz+CxCz -SxCy|
// |0 Sx  Cx| |-Sy  0 Cy| | 0   0 1|   |-CxSyCz+SxSz  CxSySz+SxCz  CxCy|
///</span>
void anglesToAxes2(const Vector3 angles, Vector3& left, Vector3& up, Vector3& forward)
{
	
	float sx, sy, sz, cx, cy, cz, theta;

	theta = angles.x * DEG2RAD;
	sx = sinf(theta);
	cx = cosf(theta);

	theta = angles.y * DEG2RAD;
	sy = sinf(theta);
	cy = cosf(theta);

	theta = angles.z * DEG2RAD;
	sz = sinf(theta);
	cz = cosf(theta);

	left.x = cy*cz;
	left.y = sx*sy*cz + cx*sz;
	left.z = -cx*sy*cz + sx*sz;


	up.x = -cy*sz;
	up.y = -sx*sy*sz + cx*cz;
	up.z = cx*sy*sz + sx*cz;

	forward.x = sy;
	forward.y = -sx*cy;
	forward.z = cx*cy;
}


/************************************************************************/
/* the increment version method                                        */
/************************************************************************/
void anglesToAxes(Vector3& angles,Vector3& left, Vector3& up, Vector3& forward){

	//save the current gl_modelview_matrix
	
	
	//calculate the rotate matrix by using the opengl
	glPushMatrix();

	glLoadMatrixf(mat);
	
	log("the increment process ");
	printCurrentMatrix(GL_MODELVIEW_MATRIX);

	if ((angles.x>0)||(angles.x<0))
	{

		glRotated(angles.x,1,0,0);

	}else if((angles.y>0)||(angles.y<0)){

		glRotated(angles.y,0,1,0);

	}else if((angles.z>0)||(angles.z<0)){

		glRotated(angles.z,0,0,1);
	}else{}
	angles.x=0;
	angles.y=0;
	angles.z=0;

	glGetFloatv(GL_MODELVIEW_MATRIX, mat);

	log("the increment process ");
	printCurrentMatrix(GL_MODELVIEW_MATRIX);

	glPopMatrix();

	//update the An
	left.x=mat[0];
	left.y=mat[1];
	left.z=mat[2];

	up.x=mat[4];
	up.y=mat[5];
	up.z=mat[6];

	forward.x=mat[8];
	forward.y=mat[9];
	forward.z=mat[10];

}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值