OpenGL自定义相机与模型:GLFrame

GLFrame叫参考帧,其中存储了1个世界坐标点和2个世界坐标下的方向向量,也就是9个glFloat值,分别用来表示:当前位置点,向前方向向量,向上方向向量。

GLFrame可以表示世界坐标系中任意物体的位置与方向。无论是相机还是模型,都可以使用GLFrame来表示。对任意一个使用GLFrame来表示的物体而言,涉及到的坐标系有两个:永远不变的世界坐标系,针对于自身的物体坐标系(即绘图坐标系)。

 一般来说,针对于物体自身的物体坐标系有如下特点:X轴永远平行于视口的水平方向,+X的方向根据右手定则由+Y与+Z得出;Y轴永远平行于视口的竖直方向,竖直向上为+Y;Z轴永远平行于视口的垂直纸面向里方向,正前方为+Z。也就是说,在世界坐标系中,物体坐标系的Y轴看上去就是GLFrame的向上方向向量,Z轴看上去就是GLFrame的向前方向向量,而X轴由Y轴方向向量与Z轴方向向量根据右手定则可得出。

举例来说,比如相机,默认状态下,其物体坐标系为:+Y竖直向上;相机的视野中心轴即Z轴,+Z指向相机看到的方向,也就是垂直纸面向里;根据+Y与+Z可得出+X是水平向左。所以对于默认的相机,修改其vOrigin.y,若增大,则相机上移,看到的景物下移,减小同理;修改其vOrigin.z,若增大,则相机向前移动,看到的景物更加靠近,减小同理;修改其vOrigin.x,若增大,则相机向左移动,看到的景物右移,减小同理。

GLFrame默认构造函数会将物体初始化为:位置在(0,0,0)点,up为(0,1,0)朝向+Y,forward为(0,0,-1)朝向-Z。也就是说初始化后的物体坐标系与世界坐标系相比,X轴与Z轴方向相反,Y轴方向相同。该默认属性适合相机,但不适合模型。若建立模型,应该将模型的坐标系修改为与世界坐标系方向一致,即model.SetForwardVector(0.0f,0.0f,1.0f);

在相机坐标系下:相机位于原点(0,0,0),竖直向上为+Y,相机正对的方向为+Z,根据右手法则,可判断出+X为从相机坐标系原点向左。

特别注意相机一定要使用ApplyCameraTransform。若使用了ApplyActorTransform,得出的相机变换是反转的。相应地,模型一定要使用ApplyActorTransform

注意,OpenGL的世界中,Y才是指向天空方向(up),水平地面为XOZ平面,Z才是向前的方向(forward)。

实际上,GLFrame就是一系列的变换。由GLFrame可以导出变换矩阵,只要与该变换矩阵相乘,任何物体都可以进行GLFrame所指定的变换GLFrame会将物体坐标系(也就是当前绘图坐标系)做指定变换,在变换完成后我们就可以进行指定的绘制操作。比如有两个物体A与B,根据A的GLFrame导出变换矩阵Ma,然后令变换矩阵与B相乘。本来B的位置与方向都是相对于世界坐标系原点,经过变换后,B的位置与方向改变为相对于A的物体坐标系原点。

如下所示:

glPushMatrix();
model[i].ApplyActorTransform();//对坐标系做变换
glutSolidSphere(0.1f, 13, 26); //绘制球体
glPopMatrix();

首先要保存当前矩阵状态,然后应用变换。变换后绘图,绘图结束后恢复矩阵。这是因为ApplyActorTransform是应用GLFrame所指定的变换,若不进行恢复矩阵,那么之后的变换就会叠加在当前变换上。

但相机变换特殊,相机变换应该遵循如下流程:

glPushMatrix();//针对相机变换
camera.ApplyCameraTransform();
glPushMatrix();//针对模型变换
model[i].ApplyActorTransform();//对坐标系做变换
glutSolidSphere(0.1f, 13, 26); //绘制球体
glPopMatrix();//针对模型变换
glPopMatrix();//针对相机变换

也就是说,在相机变换结束时,要在此基础上进行模型变换。当一切变换结束后,才对相机变换所保存的矩阵进行恢复。相机变换只可以调用一次,但模型变换可以调用多次。

 

GLFrame类定义如下:

 

class GLFrame
{
protected:
	M3DVector3f vOrigin;	// Where am I?
	M3DVector3f vForward;	// Where am I going?
	M3DVector3f vUp;		// Which way is up?

public:
	//默认构造函数(世界坐标系,位置在(0,0,0)点,up为(0,1,0)朝向+Y,forward为(0,0,-1)朝向-Z)
	GLFrame(void)

		//设置/获取世界坐标系下模型/相机的位置
		inline void SetOrigin(const M3DVector3f vPoint)
		inline void SetOrigin(float x, float y, float z)
		inline void GetOrigin(M3DVector3f vPoint)
		//获取世界坐标系下模型/相机位置的X/Y/Z分量
		inline float GetOriginX(void)
		inline float GetOriginY(void)
		inline float GetOriginZ(void)

		//设置/获取世界坐标系下模型/相机向前的方向向量
		inline void SetForwardVector(const M3DVector3f vDirection)
		inline void SetForwardVector(float x, float y, float z)
		inline void GetForwardVector(M3DVector3f vVector)

		//设置/获取世界坐标系下模型/相机向上的方向向量
		inline void SetUpVector(const M3DVector3f vDirection)
		inline void SetUpVector(float x, float y, float z)
		inline void GetUpVector(M3DVector3f vVector)

		//获取世界坐标系下模型/相机X/Y/Z轴方向向量
		inline void GetZAxis(M3DVector3f vVector) { GetForwardVector(vVector); }
	inline void GetYAxis(M3DVector3f vVector) { GetUpVector(vVector); }
	inline void GetXAxis(M3DVector3f vVector) { m3dCrossProduct(vVector, vUp, vForward); }

	// 以世界坐标系下(x,y,z)偏移量移动模型/相机
	inline void TranslateWorld(float x, float y, float z)
		// 以物体坐标系下(x,y,z)偏移量移动模型/相机
		inline void TranslateLocal(float x, float y, float z)
		// 沿物体坐标系下Z轴以指定偏移fDelta量移动模型/相机
		inline void MoveForward(float fDelta)
		// 沿物体坐标系下Y轴以指定偏移fDelta移动物体/相机
		inline void MoveUp(float fDelta)
		// 沿物体坐标系下X轴以指定偏移fDelta移动物体/相机
		inline void MoveRight(float fDelta)

		// 获取一个用于描述模型属性的4×4的矩阵
		void GetMatrix(M3DMatrix44f	matrix, bool bRotationOnly = false)
		// 获取一个用于描述相机属性的4×4的矩阵
		inline void GetCameraOrientation(M3DMatrix44f m)

		// 应用所有的相机变换。该函数仅用于相机
		inline void ApplyCameraTransform(bool bRotOnly = false)
		// 应用所有的物体变换。该函数仅用于除相机外的物体
		void ApplyActorTransform(bool bRotationOnly = false)

		// 令物体/相机以自身位置为中心,绕X/Y/Z轴旋转。其角度以PI为单位
		void RotateLocalX(float fAngle)
		void RotateLocalY(float fAngle)
		void RotateLocalZ(float fAngle)

		// Reset axes to make sure they are orthonormal. This should be called on occasion
		// if the matrix is long-lived and frequently transformed.
		// 规范化
		void Normalize(void)

		// 模型/相机绕世界坐标系下的指定轴(x,y,z)旋转fAngle度
		void RotateWorld(float fAngle, float x, float y, float z)

		// 模型/相机绕当前物体坐标系下的指定轴(x,y,z)旋转fAngle度
		void RotateLocal(float fAngle, float x, float y, float z)

		// 将点/向量vLocal从当前物体坐标系转换为世界坐标系
		void LocalToWorld(const M3DVector3f vLocal, M3DVector3f vWorld)

		// 将点/向量vLocal从世界坐标系转换为当前物体坐标系
		void WorldToLocal(const M3DVector3f vWorld, M3DVector3f vLocal)

		// 通过当前frame矩阵将vPointSrc点变换为vPointDst点
		void TransformPoint(M3DVector3f vPointSrc, M3DVector3f vPointDst)

		//通过当前frame矩阵将vVectorSrc向量旋转为vVectorDst向量
		void RotateVector(M3DVector3f vVectorSrc, M3DVector3f vVectorDst)
};

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值