首先强调一个看似废话的概念:
OpenGL中无论是平行投影还是透视投影,只有位于视景体中的物体才能被看到,即显示到窗口显示区。
这个概念很基础同样很重要,网上几乎没有人愿意解释此概念。但是初学者的程序出现“黑屏”往往是由于对此概念没有理解。
OpenGL提供了两种基本类型的投影,1、透视投影:远大近小;2、正投影(平行投影):不影响相对大小,一般用于建筑和CAD应用程序中。
(一)glOrtho平行投影下,如何将物体显示在窗口区域上?
glOrtho是创建一个正交平行的视景体。一般用于物体不会因为离屏幕的远近而产生大小的变换的情况。比如,常用的工程中的制图等。这里不讲glOrtho的函数详细说明,用实例说话!不懂的读者请参考我的博客其他文章或自己Google。
1. glOrtho平行投影下,二维物体的显示情况
结论:①平行投影下,要将物体现实在屏幕上只要将物体放置在glOrtho创建的视景体中即可。
②glutInitWindowSize窗口中所现实的仅仅是该平行视景体的成比例缩放的像。也就是说不可能通过改变glutInitWindowSize的尺寸而看到原来看不到的物体。
OpenGL中世界窗口以当前显示窗口中心为原点,水平向右为+x轴,竖直向上为+y轴,垂直于屏幕指向我们为+z轴。长度单位这样来定:平面窗口范围按此单位恰好是左下角(-1,-1) 到右上角(1,1)。OpenGL默认的glOrtho创建的平行视景体就是这种情况。
1)First 程序及运行结果
将下面代码中的橙色部分代码加上对显示结果没有影响,证明OpenGL glut中的默认平行投影视景体是个(-1,-1,-1)到(1,1,1)的立方体。
#include <GL/glut.h>
void display(void)
{
glClear (GL_COLOR_BUFFER_BIT); /* clear all pixels */
glColor3f (1.0, 1.0, 1.0); //设置当前绘制颜色
//glTranslated(0,0,-1.1); // 物体位于视景体之外,黑屏
glTranslated(0,0,-1.0); // 可以看到右上角的白色正方形
//glTranslated(0,0,1.0); // 可以看到右上角的白色正方形
//glTranslated(0,0,1.1); //物体位于视景体之外,黑屏
glRectf(0.25f, 0.25f, 0.75f, 0.75f); //可以看出位于视景体内
//glRectf(1.25f, 1.25f, 1.75f, 1.75f); // 位于视景体外,所以显示不出来
glFlush (); //don't wait! start processing buffered OpenGL routines
}
void init (void)
{
glClearColor (0.0, 0.0, 0.0, 0.0); /* select clearing olor */
// glMatrixMode(GL_PROJECTION); /* initialize viewing values */
// glLoadIdentity();
// glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); //注意该视景体的范围和几何中心
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize (500, 500); //改为glutInitWindowSize (250, 250); 可以看出变换的仅仅是物体按比例大小的变换
glutInitWindowPosition (100, 100);
glutCreateWindow ("First");
init ();
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
2)Second 程序及运行结果
#include <GL/glut.h>
void init(void)
{
glClearColor (0.0, 0.0, 0.0, 0.0); /* select clearing color */
glMatrixMode(GL_PROJECTION); /* initialize viewing values */
glLoadIdentity();
glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0); //与上面1)的First的glOrtho 对比可以看出视景体的范围和几何中心对绘图结果的影响
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glRectf(0.25f, 0.25f, 0.75f, 0.75f); //注意正方形的几何中心在(0.5,0.5)
glFlush();
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(250, 250); //glutInitWindowSize (500, 500); //可以看出物体的比例没变,仅仅是大小的改变
glutInitWindowPosition(100, 100);
glutCreateWindow(argv[0]);
init();
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
2. glOrtho平行投影下,三维物体的显示情况
1) 半径为1的球体默认的显示
将下面代码中的橙色部分代码加上对显示结果没有影响,证明OpenGL glut中的默认投影是个平行投影,并且平行投影视景体是个(-1,-1,-1)到(1,1,1)的立方体。
#include <GL/glut.h>
void init(void)
{
glClearColor(0.0, 0.0, 0.0, 0.0);
// glMatrixMode(GL_PROJECTION); /* initialize viewing values */
// glLoadIdentity();
// glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); //注意该视景体的范围和几何中心
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//glTranslatef(0,0,-1.0); //向-z方向移动1个单位后,球显示的尺寸没变,因球心移到视景体的后平面
//我在自己实验的时候 发现并不是出现了一个球,它只是一闪而过,此后窗口中并没有图像
//glTranslatef(0,0,-1.5); // 为什么球变小了,球心移动到视景体之外,看到的是被视景体后平面截取的部分
//同样,我在自己实验的时候,发现是一个相对于刚才要小的球一闪而过
//glTranslatef(0,0,-2); //黑屏,此时球与平行视景体的后面相切
//glTranslatef(0,0,1); //此时球心位于平行视景体的"前面"
//glTranslatef(0,0,1.5); //此时球心位于平行视景体的"前面",结果与glTranslatef(0,0,-1.5)相同
//此时我的结果也是黑屏
//glTranslatef(0,0,2); //黑屏,此时球与平行视景体的前面相切
//此时我的结果也是黑屏
glutSolidSphere(1.0, 20, 16); //半径为1的球体
glFlush();
}
//由上图物体的显示可以看出,视景体的大小和中心位置。
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(500, 500); //换成glutInitWindowSize(300, 300);对比下结果
//相对于500 来说,感觉在300 的窗口中绘制球体的速度要慢一点,因为我在300的窗口看见了一闪而过的白色物体,但在500的窗口里面是没有的。
glutInitWindowPosition(100, 100);
glutCreateWindow("a 3D Shpere with radius = 1");
init();
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
2) glOrtho设置平行视景体的范围和大小对物体显示的影响-----视景体的范围在(-1,-1,-1)~(1,1,1)
#include <GL/glut.h>
void init(void)
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glMatrixMode(GL_PROJECTION); /* initialize viewing values */
glLoadIdentity();
//注意该视景体的范围和几何中心
glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0); // in the first quadrant
glOrtho(-1.0, 0.0, 0.0, 1.0, -1.0, 1.0); // in the second quadrant
glOrtho(-1.0, 0.0, -1.0, 0.0, -1.0, 1.0); // in the third quadrant
glOrtho(0.0, 1.0, -1.0, 0.0, -1.0, 1.0); // in the fourth quadrant
glOrtho(0.0, 1.0, 0.0, -1.0, -1.0, 1.0); //注意y的范围应该是bottom < top,这里说明bottom和top都用的绝对值
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glutSolidSphere(1.0, 20, 16); //
glFlush();
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(500, 500);
glutInitWindowPosition(100, 100);
glutCreateWindow("a 3D Shpere with radius = 1");
init();
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
//综上,可以看出,如果你要放置一个一个二维的物体在里面,那你哪怕边边角角都必须在里面,虽然该转载日志说是可以显示三维物体的边界,但在ubuntu下证实不可以的,也许和编译的环境有关系,关于top 和bottom的绝对值取值,验证时可以的。这在课本上以及相关的书籍上是没有的。我应该牢记把,诸位。。。。
此处留一个疑问还没解决:就是在上面的正交投影的函数里面,为什么near==-1 far==1???在我看到一个对函数的解释里面是说,所有的near 和far都是同时是正或者负,当near是负值时在默认的gluLookAt函数中,是在视点的前面,那么正值是在视点的后面,同理可知。那这是在默认的条件下,如果当视点的位置大于far所表示的位置时,那么远裁面不就变成了近裁面了么?????求大神能在这里面解释一下~~或者 我找到答案再贴上来。
//另外关于如何调用glOrtho();首先必须使用相应的函数进行指示,然后用loadidentity 进行作用域指示。可能说法不是很准确,但是 还是暂时可以这样等价思考的吧。。。????
3)视景体的范围对物体显示的影响---------视景体的范围超出(-1,-1,-1)~(1,1,1)
#include <GL/glut.h>
void init(void)
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glMatrixMode(GL_PROJECTION); /* initialize viewing values */
glLoadIdentity();
glOrtho(-2.0, 2.0, -2.0, 2.0, -1.0, 1.0); //注意该视景体的范围和几何中心
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glutSolidSphere(1.0, 20, 16); //半径为1的球体
glFlush();
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(500, 500); //换成glutInitWindowSize(300, 300);对比下结果
glutInitWindowPosition(100, 100);
glutCreateWindow("a 3D Shpere with radius = 1");
init();
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
(二)glutInitWindowSize对物体显示的影响
实际上glutInitWindowSize的大小对物体在显示区域中显示的大小是有影响的,如下代码中所示。前边说OpenGL中显示物体仅仅需要将物体放在视景体中是为了让大家抓住主要矛盾。其实物体的最终形状还与显示屏中窗口区域的大小有关。要在一个非正方形的窗口内现实出“正球”此时就涉及到一个纵横比锁定的问题。
1) 纵横比不等于1的窗口下“单位球”的显示
#include <GL/glut.h>
void init(void)
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glMatrixMode(GL_PROJECTION); /* initialize viewing values */
glLoadIdentity();
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); //注意该视景体的范围和几何中心
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glutSolidSphere(1.0, 20, 16); //
glFlush();
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(500, 200);
glutInitWindowPosition(100, 100);
glutCreateWindow("a 3D Shpere with radius = 1");
init();
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
2)通过将平行投影视景体的纵横比设置为显示窗口的纵横比来校正窗口的纵横比不为一所带来的影响
#include <GL/glut.h>
void init(void)
{
int aspectRatio;
aspectRatio = 500/200;
glClearColor(0.0, 0.0, 0.0, 0.0);
glMatrixMode(GL_PROJECTION); /* initialize viewing values */
glLoadIdentity();
// glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); //注意该视景体的范围和几何中心
glOrtho(-1.0*aspectRatio, 1.0*aspectRatio, -1.0, 1.0, -1.0, 1.0); // w > h
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glutSolidSphere(1.0, 20, 16); //半径为1的球体
glFlush();
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(500, 200);
glutInitWindowPosition(100, 100);
glutCreateWindow("aspect ration not equal to 1");
init();
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
最后感谢原作者~~