1 问题描述
在游戏引擎中实现人物模型和相机的绑定是非常简单的事情,但是openGL中自己的camera对象和导入的人物模型如何实现游戏引擎中的相机绑定的效果呢?
2 问题分析
首先将游戏引擎中人物模型和相机绑定的效果的动作进行分解;
主要有两个动作,转动和走动;
要满足的效果:
- 相机转动和移动的时候人物模型的的脸始终面向前方,也就是和相机的forward向量要保持一致;
- 转动和移动的时候人物始终要在相机的forward向量的方向上,如果在正前方就一直在正前方;如果在正后方就一直在正后方;
3 解决方案
1 分析
以下的解决方案都是基于人物模型的位置和相机位置先绑定的基础上进行的;
效果1实现思路:
人物模型的转动的角度和相机转动的角度保持同步;同步包括角度的大小和方向;
效果2实现思路:
人物模型的位置肯定不是固定在相机的位置;相机的forward的向量来保证这个效果;如下这个代码就是保证效果2的代码;这个是将人物模型放在了相机的后面;
glm::vec3 pos_avator = glm::vec3(camera.position.x - camera.forward.x, 0.1, camera.position.z- camera.forward.z);
2 代码实现
在cpu中的代码:
glm::vec3 pos_avator = glm::vec3(camera.position.x - camera.forward.x, 0.1, camera.position.z- camera.forward.z);
odel_avator = glm::translate(model_avator, pos_avator);
// translate it down so it's at the center of the scene
model_avator = glm::scale(model_avator, glm::vec3(0.006f, 0.006f, 0.006f));
// it's a bit too big for our scene, so scale it down
glm::mat4 trans_ava = glm::translate(glm::mat4(1.0f), glm::vec3(-pos_avator.x, -pos_avator.y, -pos_avator.z));
glm::mat4 trans_ava_inver = glm::translate(glm::mat4(1.0f), pos_avator);
shaderAvator.use();
shaderAvator.setMat4("projection", projection);
shaderAvator.setMat4("view", view);
shaderAvator.setMat4("model", model_avator);
shaderAvator.setMat4("trans_ava", trans_ava);
shaderAvator.setMat4("trans_ava_inver", trans_ava_inver);
glm::vec3 forward = camera.forward;
shaderAvator.setVec3("camera_forward", forward.x, forward.y, forward.z);
shaderAvator.setVec3("camera_position", camera.position.x, camera.position.y, camera.position.z);
objArrow.draw(shaderAvator);
shader:
- avator.vert:
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;
out vec2 TexCoords;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform mat4 trans_ava_inver;
uniform mat4 trans_ava;
uniform vec3 camera_forward;//相机camera的forward向量
uniform vec3 camera_position;
mat4 getRotationMatrix(float angle, vec3 axis)
{
mat4 rmatrix;
vec3 a = normalize(axis);
float s = sin(angle);
float c = cos(angle);
rmatrix[0][0] = a.x*a.x + (1.0 - a.x*a.x)*c;
rmatrix[0][1] = a.x * a.y * (1.0 - c) - a.z * s;
rmatrix[0][2] = a.x * a.z * (1.0 - c) + a.y * s;
rmatrix[0][3] = 0.0;
rmatrix[1][0] = a.x * a.y * (1.0 -c) + a.z *s;
rmatrix[1][1] = a.y * a.y + (1.0 - a.y * a.y)*c;
rmatrix[1][2] = a.y * a.z * (1.0 -c) -a.x * s;
rmatrix[1][3] = 0.0;
rmatrix[2][0] = a.x * a.z *(1.0 -c) - a.y *s;
rmatrix[2][1] = a.y * a.z *(1.0 -c) + a.x * s;
rmatrix[2][2] = a.z * a.z + (1.0 - a.z * a.z) *c;
rmatrix[2][3] = 0.0;
rmatrix[3][0] = 0.0;
rmatrix[3][1] = 0.0;
rmatrix[3][2] = 0.0;
rmatrix[3][3] = 1.0;
return rmatrix;
}
void main()
{
TexCoords = aTexCoords;
//1.让人物模型旋转
vec3 axis_y=vec3(0.0,1.0,0.0);
vec3 n=-axis_y;
vec3 axis_x=vec3(1.0,0.0,0.0);
//计算相机的forward的向量和x正半轴之间的夹角
float forwardX_cos=dot(camera_forward,axis_x);//cos值
float forwardX_theta=acos(forwardX_cos);//角度值
mat4 rotateMatrix_flower_camera;
if(camera_forward.z<0)
{
rotateMatrix_flower_camera = getRotationMatrix(forwardX_theta, n);//绕y轴旋转一定的角度
}
else
{
rotateMatrix_flower_camera = getRotationMatrix(-forwardX_theta, n);//绕y轴旋转一定的角度
}
vec4 pos = vec4(aPos, 1.0f);
//先移动到原点,然后再进行其他的操作;
pos=trans_ava*pos;
pos=rotateMatrix_flower_camera*pos;
pos=trans_ava_inver*pos;
gl_Position = projection * view * model *pos;
}
- avator.frag:
#version 330 core
out vec4 FragColor;
in vec2 TexCoords;
uniform sampler2D texture_diffuse1;
void main()
{
FragColor = texture(texture_diffuse1, TexCoords);
}
4 效果纠正
前面部分实现的效果有问题,不是自己想要的效果:本来人物模型是原地转动,但是现在人物模型是绕着相机的位置做单位圆的转动;
需要做以下的修改:
Camera camera_avator(glm::vec3(-4.0f, 2.0f, 0.0f));
Camera camera(glm::vec3(-4.0f, 2.0f, 0.0f));
在while帧循环中添加了:
glm::vec3 pos_avator = glm::vec3(camera_avator.position.x, 0.1, camera_avator.position.z);
camera.position= glm::vec3(camera_avator.position.x-camera_avator.forward.x, camera_avator.position.y,camera_avator.position.z- camera_avator.forward.z);
现在效果就是正确的,整个效果是自己可以实现的效果;