作业要求:
- 对第 3 题读入的模型使用鼠标进行旋转、缩放操作;
- 利用光照模型实现简单光照效果,使用物体材质和环境光、漫反射、镜面反射结合
产生光照效果; - 光照参考效果见附件“模型光照效果.jpg”。
鼠标操作
与之前通过捕捉光标而使鼠标移动时自动确定视角方位不同,此题要求鼠标来控制旋转和缩放操作。
因此不能捕捉光标,而是设计为鼠标左键控制平移,右键控制旋转,中键(滚轮)控制缩放。
平移
用一个bool变量MOUSE_LEFT_ON
来记录鼠标被按下的事件发生之前,处于被按下还是松开的状态。如果之前是松开的,则记录下当前的光标位置并存储到lastX
和lastY
,以便后续再次松开时能通过光标移动的相对距离xoffset
和yoffset
来更改摄像机的平移位置。
void processInput(GLFWwindow *window) {
... ...
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS) {//正在被按下
if (MOUSE_LEFT_ON == false) {//之前没被按下
MOUSE_LEFT_ON = true;
//保存下来lastX和lastY
double xpos, ypos;
glfwGetCursorPos(window, &xpos, &ypos);
lastX = xpos;
lastY = ypos;
} else {//之前一直被按着
//重新获得当前的位置
double xpos, ypos;
glfwGetCursorPos(window, &xpos, &ypos);
float xoffset = xpos - lastX;
float yoffset = lastY - ypos;
lastX = xpos;
lastY = ypos;
camera.ProcessMouseMovement(-xoffset, -yoffset);//更改摄像机位置
}
} else {//被松开
MOUSE_LEFT_ON = false;
}
... ...
}
摄像机的平移操作可以由助教给的Camera类里的ProcessMouseMovement()
函数完成。
// processes input received from a mouse input system. Expects the offset value in both the x and y direction.
void ProcessMouseMovement(float xoffset, float yoffset, GLboolean constrainPitch = true)
{
xoffset *= MouseSensitivity;
yoffset *= MouseSensitivity;
Yaw += xoffset;
Pitch += yoffset;
// make sure that when pitch is out of bounds, screen doesn't get flipped
if (constrainPitch)
{
if (Pitch > 89.0f)
Pitch = 89.0f;
if (Pitch < -89.0f)
Pitch = -89.0f;
}
// update Front, Right and Up Vectors using the updated Euler angles
updateCameraVectors();
}
旋转
用一个bool变量MOUSE_RIGHT_ON
来记录鼠标被按下的事件发生之前,处于被按下还是松开的状态。如果之前是松开的,则记录下当前的光标位置并存储到lastX
和lastY
,以便后续再次松开时能通过光标移动的相对距离xoffset
和yoffset
来更改摄像机的旋转角度。
void processInput(GLFWwindow *window) {
... ...
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS) {//正在被按下
if (MOUSE_RIGHT_ON == false) {//之前没被按下
MOUSE_RIGHT_ON = true;
//保存下来lastX和lastY
double xpos, ypos;
glfwGetCursorPos(window, &xpos, &ypos);
lastX = xpos;
lastY = ypos;
} else {//之前一直被按着
//重新获得当前的位置
double xpos, ypos;
glfwGetCursorPos(window, &xpos, &ypos);
float sensitivity = 3e-3;
float xoffset = (xpos - lastX)*sensitivity;
float yoffset = (lastY - ypos)*sensitivity;
lastX = xpos;
lastY = ypos;
camera.ProcessKeyboard(RIGHT, -xoffset);
camera.ProcessKeyboard(UP , -yoffset);
}
} else {//被松开
MOUSE_RIGHT_ON = false;
}
... ...
}
注意为了使光标移动一小段距离时不至于产生过大的旋转,需要降低灵敏度,将相对位移乘以一个系数后传入Camera类的ProcessKeyBoard()
函数进行处理。
// processes input received from any keyboard-like input system.
// Accepts input parameter in the form of camera defined ENUM (to abstract it from windowing systems)
void ProcessKeyboard(Camera_Movement direction, float deltaTime)
{
float velocity = MovementSpeed * deltaTime;
if (direction == FORWARD)
Position += Front * velocity;
if (direction == BACKWARD)
Position -= Front * velocity;
if (direction == LEFT)
Position -= Right * velocity;
if (direction == RIGHT)
Position += Right * velocity;
if (direction == UP)
Position += Up * velocity;
if (direction == DOWN)
Position -= Up * velocity;
}
缩放
首先通过回调函数scroll_callback()
将鼠标事件的变化值传给Camera类。
// glfw: whenever the mouse scroll wheel scrolls, this callback is called
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) {
camera.ProcessMouseScroll(yoffset);
}
再通过Camera类中的ProcessMouseScroll()
函数完成对相机zoom
参数的修改。
// processes input received from a mouse scroll-wheel event. Only requires input on the vertical wheel-axis
void ProcessMouseScroll(float yoffset)
{
Zoom -= (float)yoffset;
if (Zoom < 1.0f)
Zoom = 1.0f;
if (Zoom > 45.0f)
Zoom = 45.0f;
}
通过修改相机的zoom
参数,每次在获取投影矩阵projection
并设置着色器参数时,就能使渲染的图像得到缩放。
......
glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
......
ourShader.setMat4("projection", projection);
......
光照
此题的光照效果与C-4作业的要求完全一样,因此不再赘述。直接使用C-4的实现即可。
效果图
最后的显示效果如下图所示。
![]() |
![]() |
![]() |
![]() |