在保持纵横比的 openGL 中调整圆圈的大小
Resize a circle in openGL keeping the aspect ratio
我写了这段打印圆圈的代码。当我尝试调整 window 的大小时,问题就来了。不保持纵横比,圆变成椭圆形。
#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()
函数中。有人能帮我吗?我尝试按定义为 width/height 的宽高比划分和多重播放范围,但问题仍然存在。
投影矩阵描述了从场景的 3D 点到视口的 2D 点的映射。投影矩阵从视图 space 变换到剪辑 space。
剪辑 space 中的坐标通过除以 w
转换为 (-1, -1, -1) 到 (1, 1, 1) 范围内的标准化设备坐标 (NDC)剪辑坐标的分量。
在正交投影中,眼睛中的坐标 space 线性映射到归一化设备坐标,剪辑空间坐标等于归一化设备坐标,因为 w
分量为 1(对于笛卡尔坐标)。
正交投影矩阵:
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
假设您拥有全高清 window:
w = 1920.0;
h = 1080.0;
window 的纵横比为 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
绘制几何图形时,几何图形的每个点都会通过投影矩阵进行变换。如果在视口的 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
这意味着,当几何体从视图 space 转换到规范化设备 space 时,正交投影矩阵将视口的纵横比倒数应用于几何体。
这导致完美的圆被扭曲成椭圆,在标准化设备 space 中看起来像这样:
如果将此椭圆拉伸回矩形视口,您可以在 window 或屏幕上看到完美的圆:
我写了这段打印圆圈的代码。当我尝试调整 window 的大小时,问题就来了。不保持纵横比,圆变成椭圆形。
#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()
函数中。有人能帮我吗?我尝试按定义为 width/height 的宽高比划分和多重播放范围,但问题仍然存在。
投影矩阵描述了从场景的 3D 点到视口的 2D 点的映射。投影矩阵从视图 space 变换到剪辑 space。
剪辑 space 中的坐标通过除以 w
转换为 (-1, -1, -1) 到 (1, 1, 1) 范围内的标准化设备坐标 (NDC)剪辑坐标的分量。
在正交投影中,眼睛中的坐标 space 线性映射到归一化设备坐标,剪辑空间坐标等于归一化设备坐标,因为 w
分量为 1(对于笛卡尔坐标)。
正交投影矩阵:
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
假设您拥有全高清 window:
w = 1920.0;
h = 1080.0;
window 的纵横比为 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
绘制几何图形时,几何图形的每个点都会通过投影矩阵进行变换。如果在视口的 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
这意味着,当几何体从视图 space 转换到规范化设备 space 时,正交投影矩阵将视口的纵横比倒数应用于几何体。 这导致完美的圆被扭曲成椭圆,在标准化设备 space 中看起来像这样:
如果将此椭圆拉伸回矩形视口,您可以在 window 或屏幕上看到完美的圆: