Qt opengl fps相机

参考文章:https://blog.csdn.net/ziyuanxiazai123/article/details/51586007

想写个相机就先要对MVP矩阵有一定了解,相机本质上其实就是一个view矩阵和一个projection矩阵。对相机的操作全都体现在

这两个矩阵上,projection矩阵可以通过QMatrix4x4的perspective函数得到

:projectionMatrix.perspective(viewAngle, aspect, Near, Far);

参数意义为:视角,宽高比例,近平面,远平面。

projection矩阵只需要进行一次计算,若之后又需要可以再进行更改。

相机的重点是view矩阵的计算。

此时可以使用QMatrix4x4的lookat函数进行计算。

viewMatrix.lookAt(location, location + forward, up);

其意义为:相机位置,目标位置,上矢量。

有个坑是 每次使用都要把view矩阵初始化,不然看到的内容就是模型在脸上飞来飞去。。

能显示了之后就要对相机的动态进行处理了。

作为一个fps相机,鼠标和键盘的协作是不可少的。鼠标能控制相机的朝向,也就是改变相机的forward前向量,而且由于fps是不会进行翻转(滚转角旋转)的所以up向量始终为(0,1,0)。

所以最终目的就是通过鼠标的移动计算新的forward向量并改变view矩阵。

鼠标的移动:

采用Qt的void mouseMoveEvent(QMouseEvent *event)函数可以轻松做到这一点。首先将鼠标锁在界面中心即:

QCursor::setPos(QPoint(width / 2, height / 2));

每次移动鼠标计算移动距离

	float dx = event->x() - width/2;
	float dy = event->y() - height/2;

在相机中设置两个数:Yaw和Pitch,分别为俯仰角和偏航角,由于fps不用滚转角,这里先不做考虑。

        camera->SetPitch(camera->GetPitch() - dy);
	if (camera->GetPitch() > 89.0)
		camera->SetPitch(89.0);
	if (camera->GetPitch() < -89.0)
		camera->SetPitch(-89.0);
	camera->SetYaw(camera->GetYaw()- dx );
	if (camera->GetYaw() < 0.0f)
		camera->SetYaw(camera->GetYaw() + 360.0f);
	if (camera->GetYaw() > 360.0f)
		camera->SetYaw(camera->GetYaw() - 360.0f);

并对Yaw和Pitch进行限制Pitch的范围是(-89,89)以防产生万向锁问题,Yaw的范围为(0,360)

每一帧相机的Yaw和Pitch角都会产生变化,再要做的就是对这两个数据进行操作了。

通过这两个数据就可以计算出forward向量了:

	forward.setX(-sin(qDegreesToRadians(yawAngle))*cos(qDegreesToRadians(pitchAngle)));
	forward.setY(sin(qDegreesToRadians(pitchAngle)));
	forward.setZ(-cos(qDegreesToRadians(yawAngle))*cos(qDegreesToRadians(pitchAngle)));
	forward.normalize();

qDegreesToRadians将角度转为弧度。并将向量归一化。

此时,viewMatrix.lookAt(location, location + forward, up);中的三个参数都已知晓,将产生的view矩阵传入shader

即可产生效果。最后隐藏鼠标    setMouseTracking(true) 如果觉得太快可以加入灵敏度设定改变dx,dy的大小实现转动的快慢。

鼠标搞定后是键盘。

采用void keyPressEvent(QKeyEvent *e)和void keyReleaseEvent(QKeyEvent *e)。

每次按下按键,改变相机的location,即可达成目标。

需要注意的是如果是单纯的在按下(keyPressEvent)改变相机位置,在开始按下的时候会出现一次卡顿然后才会一直移动。

这时采用一个bool数组bool keyAry[100]

按下时使对应的keyAry元素置为true,放开按键时 keyReleaseEvent中将对应元素置为false。

然后在paintGL函数中放入函数Translation即可。

void Translation(float speed)
{
	if (keyArr[Direction::up])
		location += up * speed;
	if (keyArr[Direction::down])
		location -= up * speed;
	if (keyArr[Direction::left])
		location -= side * speed;
	if (keyArr[Direction::right])
		location += side * speed;
	if (keyArr[Direction::forward])
		location += forward * speed;
	if (keyArr[Direction::back])
		location -= forward * speed;

}

side变量可以通过公式求得:

	side.setX(cos(qDegreesToRadians(yawAngle)));
	side.setY(0);
	side.setZ(-sin(qDegreesToRadians(yawAngle)));
	side.normalize();

fps相机最后效果

猜你喜欢

转载自blog.csdn.net/qq_38105943/article/details/87457073