15-预先计算透视矩阵
4.11.2 预先计算透视矩阵
可以减少display()函数开销的另一个优化是将透视矩阵的计算移动到init()函数中。我们在4.5节中提到了这种可能性(在脚注中)。虽然这很容易做到,但可能会有一点轻微的复杂情况。虽然通常并不需要重新计算透视矩阵,但是如果运行应用程序的用户调整窗口大小(例如通过拖动窗口角大小调整手柄),则重新计算就是必要的。
幸运的是,GLFW可以配置在调整窗口大小时自动回调指定的函数。在调用init()之前,我们将以下内容添加到main():
glfwSetWindowSizeCallback(window, window_reshape_callback);
第一个参数是GLFW窗口,第二个参数是GLFW在调整窗口大小时调用的函数的名称。然后,我们将计算透视矩阵的代码移动到init()中,同时将其复制到名为window_reshape_callback()的新函数中。
在程序4.1的例子中,如果我们重新组织代码,从display()中删除透视矩阵的计算,那么main()、init()、display()和新函数window_reshape_callback()修改后的版本将如下所示。
void init(GLFWwindow* window) {
. . .
// 和之前版本一样,再加上以下三行代码:
glfwGetFramebufferSize(window, &width, &height); aspect = (float)width / (float)height; pMat = glm::perspective(1.0472f, aspect, 0.1f, 1000.0f); // 1.0472 radians = 60 degrees
}
void display(GLFWwindow* window, double currentTime) {
. . .
// 和之前版本一样,再移除以下几行代码:
// build perspective matrix glfwGetFramebufferSize(window, &width, &height); aspect = (float)width / (float)height; pMat = glm::perspective(1.0472f, aspect, 0.1f, 1000.0f); // 函数余下部分没有变化
. . .
}
void window_reshape_callback(GLFWwindow* window, int newWidth, int newHeight) { aspect = (float)newWidth / (float)newHeight; // 回调提供的新的宽度、高度
glViewport(0, 0, newWidth, newHeight); // 设置和帧缓冲区相关的屏幕区域
pMat = glm::perspective(1.0472f, aspect, 0.1f, 1000.0f); }
int main(void) {
. . .
// 和之前版本一样,再加上以下调用:
glfwSetWindowSizeCallback(window, window_reshape_callback); init(window)
while (!glfwWindowShouldClose(window)) {
// 余下和以前一样
}
本书配套资源中的程序,与透视矩阵计算有关的实现都是以这种方式组织的,从程序4.1的颜色插值版本开始。