Retina 显示屏(以及类似的高 DPI 显示器)具有更高的像素密度,物理像素与逻辑像素的比例通常为 2:1 或更高。这会导致视口尺寸与窗口尺寸不一致。
问题原因
在 Retina 显示屏上:
- 窗口尺寸:以逻辑像素(点)为单位,例如 800×600
- 帧缓冲区尺寸:以物理像素为单位,可能是 1600×1200
glfwCreateWindow创建的窗口大小是逻辑尺寸glViewport需要的是帧缓冲区的物理尺寸
解决方案
方法一:使用 glfwGetFramebufferSize(推荐)
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
在窗口大小回调函数中也应使用此方法:
void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
glViewport(0, 0, width, height);
}
注意:对于 Retina 显示屏,应该使用 glfwSetFramebufferSizeCallback 而不是 glfwSetWindowSizeCallback,因为帧缓冲区尺寸变化才是真正需要处理的。
方法二:正确设置回调
// 使用帧缓冲区尺寸回调(而非窗口尺寸回调)
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
方法三:禁用高 DPI 缩放(不推荐)
如果确实需要禁用 Retina 缩放:
glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_FALSE);
这会使帧缓冲区尺寸与窗口尺寸一致,但会失去高分辨率渲染的优势。
完整示例
void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
glViewport(0, 0, width, height);
}
int main() {
// ... 初始化 GLFW ...
GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
if (window == NULL) {
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
// 注册帧缓冲区尺寸回调
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// 初始化 GLAD ...
// 初始设置视口
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
// 渲染循环 ...
}
要点总结
- 始终使用
glfwGetFramebufferSize获取实际渲染尺寸 - 使用
glfwSetFramebufferSizeCallback处理尺寸变化 - 这样代码可以自动适配 Retina 和普通显示器,无需针对特定平台编写特殊逻辑

274

被折叠的 条评论
为什么被折叠?



