c++ - 在保持纵横比的 openGL 中调整圆圈的大小

标签 c++ opengl reshape orthographic

我写了这段打印圆圈的代码。当我尝试调整窗口大小时,问题就来了。不保持纵横比,圆变成椭圆形。

#include<GL/glut.h>
#include<GL/glu.h>
#include<GL/gl.h>
#include<string.h>
#include<stdio.h> 
#include <math.h>
#define PI 3.1415

const float DEG2RAD = 3.14159 / 180;
// Keep track of windows changing width and height
GLfloat windowWidth;
GLfloat windowHeight;

void drawCircle(float radius)
{
    glBegin(GL_LINE_LOOP);
    for (int i = 0; i <= 300; i++) {
        double angle = 2 * PI * i / 300;
        double x = radius * cos(angle);
        double y = radius * sin(angle);
        glVertex2d(x, y);
    }
    glEnd();
}

///////////////////////////////////////////////////////////
// Called to draw scene
void RenderScene(void)
{
    // Clear the window with current clearing color
    glClear(GL_COLOR_BUFFER_BIT );

    // Save the matrix state and do the rotations
    glMatrixMode(GL_MODELVIEW);
    //glPushMatrix();
    glColor3d(1, 0, 0);


    drawCircle(100);

    glutSwapBuffers();
}





///////////////////////////////////////////////////////////
// This function does any needed initialization on the 
// rendering context. 
void SetupRC()
{
    // Light values and coordinates
    //glEnable(GL_DEPTH_TEST);  // Hidden surface removal

    glClearColor(0,0,0,0);
}


void ChangeSize(int w, int h)
{
    GLfloat aspectRatio;
    GLfloat nRange = 200.0f;
    // Prevent a divide by zero
    if (h == 0)
        h = 1;

    // Set Viewport to window dimensions
    glViewport(0, 0, w, h);

    // Reset coordinate system
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    // Establish clipping volume (left, right, bottom, top, near, far)
    aspectRatio = (GLfloat)w / (GLfloat)h;
    if (w <= h)
    {
        glOrtho(-nRange, nRange, -nRange*aspectRatio, nRange*aspectRatio, -nRange*2, nRange * 2);
    }
    else
    {
        glOrtho(-nRange /aspectRatio, nRange /aspectRatio, -nRange, nRange, -nRange * 2, nRange * 2);
    }

    // Specify the orthographic (or perpendicular) projection, 
    // i.e., define the viewing box.

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}





///////////////////////////////////////////////////////////
// Entry point of the program
int main(int argc, char* argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glClear(GL_COLOR_BUFFER_BIT);
    glutInitWindowSize(800, 800);
    glutCreateWindow("Circle");
    glutReshapeFunc(ChangeSize);

    glutDisplayFunc(RenderScene);
    SetupRC();
    glutMainLoop();

    return 0;
}

这就是代码。我认为问题出在 ChangeSize() 函数中。有人能帮我吗?我尝试通过定义为宽度/高度的纵横比划分和多重播放范围,问题仍然存在。

最佳答案

投影矩阵描述了从场景的 3D 点到视口(viewport)的 2D 点的映射。投影矩阵从 View 空间变换到裁剪空间。 通过用 w 组件划分,将剪辑空间中的坐标转换为 (-1, -1, -1) 到 (1, 1, 1) 范围内的归一化设备坐标 (NDC)剪辑坐标。

在正交投影中,眼睛空间中的坐标线性映射到归一化设备坐标,剪辑空间坐标等于归一化设备坐标,因为 w 组件为 1(对于笛卡尔坐标) .

enter image description here

正交投影矩阵:

r = right, l = left, b = bottom, t = top, n = near, f = far 

2/(r-l)         0               0               0
0               2/(t-b)         0               0
0               0               -2/(f-n)        0
-(r+l)/(r-l)    -(t+b)/(t-b)    -(f+n)/(f-n)    1


假设您有一个全高清窗口:

w = 1920.0;
h = 1080.0;

窗口的纵横比为 1.77778

aspectRatio = w / h = 1.77778

如果您设置这样的正交投影矩阵:

glOrtho(-nRange*aspectRatio, nRange*aspectRatio, -nRange, nRange, -nRange*2, nRange*2 );   

这将导致以下正交投影矩阵 (1.0/1.77778 == 0.5625):

0.5625/nRange   0            0.0          0.0
0.0             1.0/nRange   0.0          0.0
0.0             0.0          0.5/nRange   0.0
0.0             0.0          0.0          1.0   

绘制几何图形时,几何图形的每个点都会通过投影矩阵进行变换。如果在视口(viewport)的 XY 平面中绘制了一个圆, 然后 X 坐标0.5625/nRange 缩放:

X' = X * prjMat[0][0] = X * 0.5625/nRange

Y 坐标1.0/nRange缩放

Y' = Y * prjMat[1][1] = Y * 1.0/nRange

这意味着,当几何体从 View 空间转换到标准化设备空间时,正交投影矩阵将视口(viewport)的纵横比倒数应用于几何体。 这导致完美的圆在规范化的设备空间中变形为椭圆,看起来像这样:

enter image description here

如果将这个椭圆拉伸(stretch)回矩形视口(viewport),您可以在窗口或屏幕上看到完美的圆:

enter image description here

关于c++ - 在保持纵横比的 openGL 中调整圆圈的大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48411444/

相关文章:

c++ - OpenGL 子窗口不会同时响应

opengl - 使用 GL_TEXTURE_RECTANGLE 时 glTexImage2D 不工作

r - 聚合数据帧后,如何获取行名列表作为值?

python - numpy 数组 reshape 添加维度

c++ - 在 Eclipse 中安装插件

c++ - 是否可以在 C/C++ 中声明全局二维数组?

c++ - 可变参数模板模板

c++ - 帮忙解决这个选角问题

opengl - GL_TEXTURE_3D - mipmap 尺寸

r - 在 R 中拆分列名并将数据从宽格式转换为长格式