OpenGL投影缩放

Posted

技术标签:

【中文标题】OpenGL投影缩放【英文标题】:OpenGL projection scaling 【发布时间】:2013-02-27 08:58:40 【问题描述】:

我有一个代表简单 3D 场景的学习项目。 我正在修改模型视图矩阵以使用gluLookAt() 将视点移动到某个非原点,然后我将线球放置在原点。最后,我正在修改投影矩阵以使用glOrtho() 接收带有一些参数的正交投影。但是当调整窗口大小时,球体会变形。我想我应该修改reshape()glOrtho() 函数,但是如何修改?

void display(void)
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3b(197, 96, 63);
    glLoadIdentity();    
    gluLookAt(2, 0.5 ,2, 0, 0, 0, 0, 1, 0);
    glutWireSphere(0.2, 20, 10);  
    glFlush();


void reshape(int w, int h)
    glViewport(0, 0, (GLsizei) w, (GLsizei) h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-1, 1, -1, 1, 0.8 , 100);
    glMatrixMode(GL_MODELVIEW);

【问题讨论】:

希望您的内容如何扩展?信箱?放大窗口? 您需要更改您的glOrtho 命令以尊重屏幕的AspectRatio。目前,您正在告诉它制作一个完美的正方形。如果您调整窗口大小但不更改函数调用的 (-1, 1, -1, 1, ...) 部分,glOrtho 将设置您的坐标系以使事物以完美的正方形投影到屏幕上,即使视口(w 和 h)不代表正方形。 【参考方案1】:

正如我在评论中所说,您需要设置正交投影以适合您的窗口。假设您的 OpenGL 窗口在调整大小之前以正方形开始,(-1, 1, -1, 1, ...) 假设为正方形坐标系。如果您更改它以更好地反映窗口的纵横比,您应该会得到更好的外观。请尝试以下操作:

glOrtho ((float)w/(float)h, (float)-w/(float)h, -1, 1, 0.8, 100);

这应该保持您设置的坐标系,但尊重纵横比(按宽度)。

【讨论】:

@vard,请记住,这是在窗口的纵横比偏向宽度大于高度的情况下使用的。在其他情况下,您需要将 (float) 内容移至其他 2 个参数并执行 (float)h/(float)w 以保持纵横比与高度大于宽度一致。【参考方案2】:

首先,与您的问题完全无关:将您现在拥有的所有内容移至 reshape 以显示。是的,我知道很多教程都采用您的方式,但请相信我,如果不采用这种方式,事情会变得更加清晰。


现在关于您的问题:Ortho 在视图空间中设置体积,将其映射到视口坐标。 glOrtho 的 (bottom,left) 角映射到 glViewport 的 (x,y) 并且 (top,right) 映射到 glViewport 的 (x,y)+(width,height)。

因此您必须将 glOrtho 参数调整为视口的纵横比。很简单:

void display(void)

    int const win_width  = glutGet(GLUT_WINDOW_WIDTH);
    int const win_height = glutGet(GLUT_WINDOW_HEIGHT);
    float const win_aspect = (float)win_width / (float)win_height;

    glClear(GL_COLOR_BUFFER_BIT);
    glViewport(0, 0, win_width, win_height);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-win_aspect, win_aspect, -1, 1, 0.8 , 100);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();    
    gluLookAt(2, 0.5 ,2, 0, 0, 0, 0, 1, 0);

    glColor3b(197, 96, 63);
    glutWireSphere(0.2, 20, 10);  
    glFlush();

【讨论】:

datenwold,感谢您的建议。是不是说显示函数的调用频率足够看不到window reshape 发生的变化,所以我们可以把reshape 函数的工作全部移到显示函数上? @vard:显示函数将始终在窗口调整大小后调用,因为窗口调整大小会损坏窗口的内容,需要刷新显示。专用重塑处理程序的主要用途是处理仅在发生窗口大小调整时才应该发生的事情,例如重新初始化后处理中间缓冲区等。然而,在任何严肃的应用程序中,设置投影矩阵是在整个渲染帧(想想 HUD、小地图、右上视图等)过程中多次发生的事情,因此无论如何代码最终都会显示。【参考方案3】:

此时您将窗口投影到带有glOrtho(-1, 1, -1, 1, 0.8 , 100); 的二次输出,因为宽度和高度相等。您应该将前四个参数更改为窗口的当前纵横比,以防止失真。喜欢

glOrtho(-w/2f, w/2f, -h/2f, h/2f, 0.8 , 100);

(在我的示例中,您必须使球体更大,因为投影平面会比您的更大。)

【讨论】:

嗯,使用你的代码我在屏幕上什么也看不到((也许在这个投影中我的球体太小了? 是的,正如我所写的,您应该将球体的大小调整为至少 w 或 h 倍,以获得与以前相同的输出。

以上是关于OpenGL投影缩放的主要内容,如果未能解决你的问题,请参考以下文章

在 openGL 绘图调用之后会发生啥?

OpenGL-坐标系

没有 OpenGL 的重复 OpenGL 正交投影行为

opengl两种投影类型

OPENGL若干重要基础概念

OpenGL:光照模型视图投影变换