先讲下OpenGL的坐标系。OpenGL的坐标系和Windows窗口默认的坐标系是不同的。WindowsGDi的默认原点在左上角,X向右递增,Y向下递增,而OpenGL的原点在窗口的左下角,X向右递增,Y向上递增。
OpenGL里面所谓的窗口就是我们创建出来的窗口,也叫做屏幕窗口,我们可以在这整个窗口里面绘图。而视口则是窗口的一个子区域,通过设置视口就可以把绘图区域限定为窗口的一个子区域,而这个子区域的别名就叫做视口。这个函数是glViewport。该函数原型为
void glViewport(GLint x,
GLint y,
GLsizei width,
GLsizei height)
第一个参数和第二个参数是左下角的坐标,第三个参数和第四个参数则分别是视口的宽度和高度。记住一点,OpenGL用的是笛卡尔坐标系,而我一直习惯了WindowsGDI的坐标系设置。
现在来讲解最关键的东西—-世界窗口(裁剪区)。
这个东西理解了,我们就可以通过一些设置做出一些漂亮的图形裁剪啊之类的,总之能达到一些很爽的效果。以计算机图形学OpenGL版3.2节的例子来说明,世界窗口即是能容纳sinc(x) = sin(PIx) / (PI x)的定义域和值域的二维矩阵。比如说,这个例子里面绘画函数的时候x的范围是[-4.0,4.0],该函数最大值不会超过1.0,在该范围内最小值也会大于-0.3,那么我们可以设置世界窗口为[-4.0,4.0,-0.3,1.0],四个值分别是描述了现实世界中的一个与坐标轴平行的矩形。如果把世界窗口设置为[-5.0,5.0,-0.3,1.0],该函数的显示效果可能会更好一点,因为可以看到边界外面的部分。
现在很明显的看到,世界窗口和视口大小基本上是不一致的,那么我们要显示的图形肯定会被拉伸。这个拉伸也是很简单的按照比例尺计算出来的。可以很形象的想象下,把一个人放小显示在一个窗口里面,或者把一只蚂蚁放大显示在一个窗口里面。
附3.2节sinc源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| #include <windows.h> #include <math.h> #include <gl/gl.h> #include <gl/glu.h> #include <gl/glut.h> #pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
const float PI = atan(1.0) * 4; const int WINDOW_WIDTH = 640; const int WINDOW_HEIGHT = 480; const int WINDOW_POS_X = 300; const int WINDOW_POS_Y = 150;
void SetWindow(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(left, right, bottom, top); }
void SetViewport(GLint left, GLint right, GLint bottom, GLint top) { glViewport(left, bottom, right - left, top - bottom); }
void myInit() { glClearColor(1.0, 1.0, 1.0, 0.0); glColor3f(0.0, 0.0, 1.0); glLineWidth(2.0); }
void myDisplay() { glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity();
SetViewport(0, WINDOW_WIDTH / 2, 0, WINDOW_HEIGHT); glBegin(GL_LINE_STRIP); for (float x = -4.0; x <= 4.0; x += 0.1) { if (fabs(x) < 1e-8) { glVertex2f(0.0, 1.0); } else { glVertex2f(x, sin(PI * x) / (PI* x)); } } glEnd();
glFlush(); }
int main(int argc, char** argv) { glutInit(argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT); glutInitWindowPosition(WINDOW_POS_X, WINDOW_POS_Y); glutCreateWindow("The Famous Sinc Function"); glutDisplayFunc(myDisplay); myInit(); SetWindow(-5.0, 5.0, -0.3, 1.0); glutMainLoop();
return 0; }
|
显示效果如图,
由于我设置了视口为左半窗口,可以明显的看到,函数曲线挤压在左边了。注意,在主函数里面设置视口一直没有效果,我也不知道为什么。