参考资料: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;
}

Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐