OpenGL 入门基础教程 —— 键盘和鼠标响应
参考资料:http://www.opengl-tutorial.org/cn/beginners-tutorials/tutorial-6-keyboard-and-mouse/知识点1:主要思想:实现键鼠操作对画面的影响,实际上是通过每一帧都变化的MVP矩阵来实现的,那么我们只需要对键鼠操作返回不同的MVP组成矩阵即可,然后在主循环中更新MVP矩阵,最终实现画面的切换。do{
参考资料:http://www.opengl-tutorial.org/cn/beginners-tutorials/tutorial-6-keyboard-and-mouse/
知识点1:主要思想:实现键鼠操作对画面的影响,实际上是通过每一帧都变化的MVP矩阵来实现的,那么我们只需要对键鼠操作返回不同的MVP组成矩阵即可,然后在主循环中更新MVP矩阵,最终实现画面的切换。
do{
// ...
// Compute the MVP matrix from keyboard and mouse input
computeMatricesFromInputs();
glm::mat4 ProjectionMatrix = getProjectionMatrix();
glm::mat4 ViewMatrix = getViewMatrix();
glm::mat4 ModelMatrix = glm::mat4(1.0);
glm::mat4 MVP = ProjectionMatrix * ViewMatrix * ModelMatrix;
// ...
}
这段代码需要3个新函数:
computeMatricesFromInputs()读键盘和鼠标操作,然后计算投影观察矩阵。这一步正是精华所在。
getProjectionMatrix()返回计算好的投影矩阵。
getViewMatrix()返回计算好的观察矩阵。
// Include GLFW
#include <glfw3.h>
extern GLFWwindow* window; // The "extern" keyword here is to access the variable "window" declared in tutorialXXX.cpp. This is a hack to keep the tutorials simple. Please avoid this.
// Include GLM
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
using namespace glm;
#include "controls.hpp"
glm::mat4 ViewMatrix;
glm::mat4 ProjectionMatrix;
glm::mat4 getViewMatrix(){
return ViewMatrix;
}
glm::mat4 getProjectionMatrix(){
return ProjectionMatrix;
}
//初始位置的设置
// Initial position : on +Z
glm::vec3 position = glm::vec3( 0, 0, 5 );
// Initial horizontal angle : toward -Z
float horizontalAngle = 3.14f;
// Initial vertical angle : none
float verticalAngle = 0.0f;
// Initial Field of View
float initialFoV = 45.0f;
//鼠标属性的设定,速度,再乘以帧差时间,就可以得到移动距离
float speed = 3.0f; // 3 units / second
float mouseSpeed = 0.005f;
//计算MVP矩阵的各分量
void computeMatricesFromInputs(){
// glfwGetTime is called only once, the first time this function is called
static double lastTime = glfwGetTime();
// Compute time difference between current and last frame
double currentTime = glfwGetTime();
float deltaTime = float(currentTime - lastTime);
// Get mouse position 鼠标位置获取
double xpos, ypos;
glfwGetCursorPos(window, &xpos, &ypos);
// Reset mouse position for next frame 下一帧鼠标位置设定在屏幕中央
glfwSetCursorPos(window, 1024/2, 768/2);
// Compute new orientation 新视角的变化
horizontalAngle += mouseSpeed * float(1024/2 - xpos );
verticalAngle += mouseSpeed * float( 768/2 - ypos );
// Direction : Spherical coordinates to Cartesian coordinates conversion 视线方向的向量
glm::vec3 direction(
cos(verticalAngle) * sin(horizontalAngle),
sin(verticalAngle),
cos(verticalAngle) * cos(horizontalAngle)
);
// Right vector
glm::vec3 right = glm::vec3(
sin(horizontalAngle - 3.14f/2.0f),
0,
cos(horizontalAngle - 3.14f/2.0f)
);
// Up vector
glm::vec3 up = glm::cross( right, direction );
// Move forward
if (glfwGetKey( window, GLFW_KEY_UP ) == GLFW_PRESS){
position += direction * deltaTime * speed;
}
// Move backward
if (glfwGetKey( window, GLFW_KEY_DOWN ) == GLFW_PRESS){
position -= direction * deltaTime * speed;
}
// Strafe right
if (glfwGetKey( window, GLFW_KEY_RIGHT ) == GLFW_PRESS){
position += right * deltaTime * speed;
}
// Strafe left
if (glfwGetKey( window, GLFW_KEY_LEFT ) == GLFW_PRESS){
position -= right * deltaTime * speed;
}
float FoV = initialFoV;// - 5 * glfwGetMouseWheel(); // Now GLFW 3 requires setting up a callback for this. It's a bit too complicated for this beginner's tutorial, so it's disabled instead.
// Projection matrix : 45?Field of View, 4:3 ratio, display range : 0.1 unit <-> 100 units
ProjectionMatrix = glm::perspective(FoV, 4.0f / 3.0f, 0.1f, 100.0f);
// Camera matrix
ViewMatrix = glm::lookAt(
position, // Camera is here
position+direction, // and looks here : at the same position, plus "direction"
up // Head is up (set to 0,-1,0 to look upside-down)
);
// For the next frame, the "last time" will be "now"
lastTime = currentTime;
}
知识点2:背面剔除
自由移动鼠标,您会观察到:如果移动到立方体内部,多边形仍然会显示。这看起来理所当然,实则大有优化的余地。实际上在常见应用中您绝不会身处立方体内部。
有一种思路是让GPU检查摄像机与三角形前后位置关系。如果摄像机在三角形前面则显示该三角形;如果摄像机在三角形后面,且不在网格(mesh)(网格必须是封闭的)内部,那么必有三角形位于摄像机前面。您一定会察觉到速度变快了:三角形数量平均减少了一半!
最可喜的是这种检查十分简单。GPU计算出三角形的法线(用叉乘,还记得吗?),然后检查这个法线是否朝向摄像机。
不过这种方法是有代价的:三角形的方向是隐含的。这意味着如果在缓冲中翻转两个顶点,可能会产生孔洞。但一般来说,这一点额外工作是值得的。一般在3D建模软件中只需点击”反转法线”(实际是翻转两个顶点,从而翻转法线)就大功告成了。
开启背面剔除十分简单:
// Cull triangles which normal is not towards the camera
glEnable(GL_CULL_FACE);
C++代码特殊之处:
1:替换了纹理
2:实现模型的自动变化(未实现绕行),具体方法是将相机的position设置为随时间变化的参量
// Include GLFW
#include <glfw3.h>
extern GLFWwindow* window; // The "extern" keyword here is to access the variable "window" declared in tutorialXXX.cpp. This is a hack to keep the tutorials simple. Please avoid this.
// Include GLM
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
using namespace glm;
#include "controls.hpp"
glm::mat4 ViewMatrix;
glm::mat4 ProjectionMatrix;
glm::mat4 getViewMatrix(){
return ViewMatrix;
}
glm::mat4 getProjectionMatrix(){
return ProjectionMatrix;
}
//初始位置的设置
// Initial position : on +Z
glm::vec3 position = glm::vec3( 0, 0, 5 );
// Initial horizontal angle : toward -Z
float horizontalAngle = 5.0f;
// Initial vertical angle : none
float verticalAngle = 0.0f;
// Initial Field of View
float initialFoV = 45.0f;
//鼠标属性的设定
float speed = 3.0f; // 3 units / second
float mouseSpeed = 0.005f;
//计算MVP矩阵的各分量
void computeMatricesFromInputs(){
// glfwGetTime is called only once, the first time this function is called
static double lastTime = glfwGetTime();
// Compute time difference between current and last frame
double currentTime = glfwGetTime();
float deltaTime = float(currentTime - lastTime);
// Get mouse position
double xpos, ypos;
glfwGetCursorPos(window, &xpos, &ypos);
// Reset mouse position for next frame
glfwSetCursorPos(window, 1024/2, 768/2);
// Compute new orientation 新视角的变化
horizontalAngle += mouseSpeed * float(1024/2 - xpos );
verticalAngle += mouseSpeed * float( 768/2 - ypos );
//verticalAngle += 0.0f ; 可限制verticalAngle
// Direction : Spherical coordinates to Cartesian coordinates conversion 视线方向的向量
glm::vec3 direction(
cos(verticalAngle) * sin(horizontalAngle),
sin(verticalAngle),
cos(verticalAngle) * cos(horizontalAngle)
);
// Right vector
glm::vec3 right = glm::vec3(
sin(horizontalAngle - 3.14f/2.0f),
0,
cos(horizontalAngle - 3.14f/2.0f)
);
// Up vector
glm::vec3 up = glm::cross( right, direction );
// Move forward
// if (glfwGetKey( window, GLFW_KEY_UP ) == GLFW_PRESS){
// position += direction * deltaTime * speed;
// }
// Move backward
// if (glfwGetKey( window, GLFW_KEY_DOWN ) == GLFW_PRESS){
// position -= direction * deltaTime * speed;
// }
// Strafe right
// if (glfwGetKey( window, GLFW_KEY_RIGHT ) == GLFW_PRESS){
// position += right * deltaTime * speed;
// }
// Strafe left
// if (glfwGetKey( window, GLFW_KEY_LEFT ) == GLFW_PRESS){
// position -= right * deltaTime * speed;
// }
position = glm::vec3(0.0f,0.0f,10.0f) + (5 * cos(float(currentTime)), 0, 5 * sin(float(currentTime)));
float FoV = initialFoV; //- 5 * glfwGetMouseWheel(); // Now GLFW 3 requires setting up a callback for this. It's a bit too complicated for this beginner's tutorial, so it's disabled instead.
// Projection matrix : 45?Field of View, 4:3 ratio, display range : 0.1 unit <-> 100 units
ProjectionMatrix = glm::perspective(FoV, 4.0f / 3.0f, 0.1f, 100.0f);
// Camera matrix
ViewMatrix = glm::lookAt(
position, // Camera is here
/*position+direction*/glm::vec3(0,2,0), // and looks here : at the same position, plus "direction"
glm::vec3(0,1,0) // Head is up (set to 0,-1,0 to look upside-down)
);
// For the next frame, the "last time" will be "now"
lastTime = currentTime;
}
更多推荐



所有评论(0)