Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4233093
  • 博文数量: 176
  • 博客积分: 10059
  • 博客等级: 上将
  • 技术积分: 4681
  • 用 户 组: 普通用户
  • 注册时间: 2006-03-24 12:27
文章分类

全部博文(176)

文章存档

2012年(1)

2011年(4)

2010年(14)

2009年(71)

2008年(103)

分类: C/C++

2009-10-07 20:54:14

本文主要讲OpenGL中的几何变换。
 
我们生活在一个三维的世界——如果要观察一个物体,我们可以:
1、从不同的位置去观察它。(视点变换/视图变换,gluLookAt)
2、移动或者旋转它,当然了,如果它只是计算机里面的物体,我们还可以放大或缩小它。(模型变换)
3、如果把物体画下来,我们可以选择:是否需要一种“近大远小”的透视效果。另外,我们可能只希望看到物体的一部分,而不是全部(剪裁)。(投影变换)
4、我们可能希望把整个看到的图形画下来,但它只占据纸张的一部分,而不是全部。(视口变换)
这些,都可以在OpenGL中实现。
 
1、模型变换和视图变换
从“相对移动”的观点来看,改变观察点的位置与方向和改变物体本身的位置与方向具有等效性。在OpenGL中,实现这两种功能甚至使用的是同样的函数。
由于模型和视图的变换都通过矩阵运算来实现,在进行变换前,应先设置当前操作的矩阵为“模型视图矩阵”。设置的方法是以GL_MODELVIEW为参数调用glMatrixMode函数,像这样:
glMatrixMode(GL_MODELVIEW);
通常,我们需要在进行变换前把当前矩阵设置为单位矩阵。这也只需要一行代码:
glLoadIdentity();
然后,就可以进行模型变换和视图变换了。进行模型和视图变换,主要涉及到三个函数:
glTranslate*,把当前矩阵和一个表示移动物体的矩阵相乘。三个参数分别表示了在三个坐标上的位移值。
glRotate*,把当前矩阵和一个表示旋转物体的矩阵相乘。物体将绕着(0,0,0)到(x,y,z)的直线以逆时针旋转,参数angle表示旋转的角度。
glScale*,把当前矩阵和一个表示缩放物体的矩阵相乘。x,y,z分别表示在该方向上的缩放比例。
 
注意我都是说“与XX相乘”,而不是直接说“这个函数就是旋转”或者“这个函数就是移动”,这是有原因的,马上就会讲到。
假设当前矩阵为单位矩阵,然后先乘以一个表示旋转的矩阵R,再乘以一个表示移动的矩阵T,最后得到的矩阵再乘上每一个顶点的坐标矩阵v。所以,经过变换得到的顶点坐标就是((RT)v)。由于矩阵乘法的结合率,((RT)v) = (R(Tv)),换句话说,实际上是先进行移动,然后进行旋转。即:实际变换的顺序与代码中写的顺序是相反的。由于“先移动后旋转”和“先旋转后移动”得到的结果很可能不同,初学的时候需要特别注意这一点。
OpenGL之所以这样设计,是为了得到更高的效率。但在绘制复杂的三维图形时,如果每次都去考虑如何把变换倒过来,也是很痛苦的事情。这里介绍另一种思路,可以让代码看起来更自然(写出的代码其实完全一样,只是考虑问题时用的方法不同了)。
让我们想象,坐标并不是固定不变的。旋转的时候,坐标系统随着物体旋转。移动的时候,坐标系统随着物体移动。如此一来,就不需要考虑代码的顺序反转的问题了。


运行结果:


#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>

#include <stdio.h>

#pragma comment(lib, "OpenGL32.lib")
#pragma comment(lib, "glu32.lib")
#pragma comment(lib, "glut32.lib")

void init()
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glShadeModel(GL_FLAT);
}

void drawsquare( int width )
{
    glRecti( -width/2, -width/2, width/2, width/2 );
}

void display()
{
    glClear(GL_COLOR_BUFFER_BIT);

    //draw axis

    {
        const float axislen = 300.0f;
        const float axislenh = axislen/2;
        glBegin(GL_LINES);
        glColor3f( 0.0f, 1.0f, 0.0f );//指定线的颜色,绿色

        // x-axis

        glVertex2f( -axislenh, 0.0f);
        glVertex2f( axislenh, 0.0f);

        // x-axis arrow

        glVertex2f( axislenh, 0.0f);
        glVertex2f( axislenh-7, 3.0f);
        glVertex2f( axislenh, 0.0f);
        glVertex2f( axislenh-7,-3.0f);


        glColor3f( 1.0f, 0.0f, 0.0f );//指定线的颜色,红色

        // y-axis

        glVertex2f( 0.0f, -axislenh);
        glVertex2f( 0.0f, axislenh);
        glVertex2f( 0.0f, axislenh);
        glVertex2f( 3.0f, axislenh-7);
        glVertex2f( 0.0f, axislenh);
        glVertex2f( -3.0f, axislenh-7);
        glEnd();
    }

    glMatrixMode( GL_MODELVIEW );
    glPushMatrix();


    /* 一个白色的正方形,先平移再旋转 */
    glLoadIdentity();
    glColor3f(1.0, 1.0, 1.0);
    glTranslatef( 100.0f, 0.0f, 0.0f );//沿着x轴移动

    glRotatef( 45, 0.0f, 0.0f, 1.0f );//沿着z轴旋转

    drawsquare(50);


    /* 一个红色的正方形,先旋转再平移 */
    glLoadIdentity();
    glColor3f(1.0, 0.0, 0.0);
    glRotatef( 45, 0.0f, 0.0f, 1.0f );//沿着z轴旋转

    glTranslatef( 100.0f, 0.0f, 0.0f );//沿着x轴移动

    drawsquare(50);

    glPopMatrix();
    glFlush();
}

void reshape( int w, int h )
{
    glViewport(0, 0, (GLsizei) w, (GLsizei) h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(-(GLdouble) w/2, (GLdouble) w/2, -(GLdouble) h/2, (GLdouble) h/2);
};

int main( int argc, char* argv[] )
{
    glutInit( &argc, argv );
    glutInitDisplayMode( GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH );
    glutInitWindowSize( 800, 800 );
    glutInitWindowPosition( 100, 100 );
    glutCreateWindow( "Chapter2" );
    init();
    glutDisplayFunc( &display );
    glutReshapeFunc( &reshape );
    glutMainLoop();

    return 0;
}





 
2、绘制一个球体(太阳)
 

// Purpose: To show how to draw the solar system
// Author: zieckey

// Date: 2009/10/7

#include "GL/glut.h"
#include <math.h>

// Rotation amounts
static GLfloat xRot = 0.0f;
static GLfloat yRot = 0.0f;

void SpecialKeys(int key, int x, int y);
void ChangeSize( GLsizei w, GLsizei h );
void DrawAxis();
void SetupRC();

void RenderScene()
{
    //清空颜色缓冲区,填充的颜色由 glClearColor( 0, 0.0, 0.0, 1 ); 指定为黑色
    glClear( GL_COLOR_BUFFER_BIT );

    // Save matrix state and do the rotation
    glPushMatrix();
    glRotatef(xRot, 1.0f, 0.0f, 0.0f);
    glRotatef(yRot, 0.0f, 1.0f, 0.0f);

    DrawAxis();

    //绘制太阳
    glColor3f( 1.0f, 1.0f, 1.0f );
    glutSolidSphere( 50.f, 15, 15 );

    // Restore transformations
    glPopMatrix();

    glutSwapBuffers();
}

int main(int argc, char* argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize (800, 600);
    glutInitWindowPosition (100, 100);
    glutCreateWindow( "Triangles Example" );
    glutDisplayFunc( RenderScene );
    glutReshapeFunc( ChangeSize );
    glutSpecialFunc( SpecialKeys );
    SetupRC();
    glutMainLoop();

    return 1;
}


void SetupRC()
{
    glClearColor( 0, 0.0, 0.0, 1 );
    glShadeModel( GL_SMOOTH );
}

void ChangeSize( GLsizei w, GLsizei h )
{
    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 projection matrix stack

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    // Establish clipping volume (left, right, bottom, top, near, far)

    if (w <= h)
        glOrtho (-nRange, nRange, -nRange*h/w, nRange*h/w, -nRange, nRange);
    else
        glOrtho (-nRange*w/h, nRange*w/h, -nRange, nRange, -nRange, nRange);

    // Reset Model view matrix stack

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void SpecialKeys(int key, int x, int y)
{
    if(key == GLUT_KEY_UP)
        xRot -= 5.0f;

    if(key == GLUT_KEY_DOWN)
        xRot += 5.0f;

    if(key == GLUT_KEY_LEFT)
        yRot -= 5.0f;

    if(key == GLUT_KEY_RIGHT)
        yRot += 5.0f;

    if(xRot > 356.0f)
        xRot = 0.0f;

    if(xRot < -1.0f)
        xRot = 355.0f;

    if(yRot > 356.0f)
        yRot = 0.0f;

    if(yRot < -1.0f)
        yRot = 355.0f;

    // Refresh the Window

    glutPostRedisplay();// this will refresh the window, so, it works the same to call RenderScene() directly

}


void DrawAxis()
{
    //绘制x、y、z坐标轴

    {
        glColor3f( 0.0f, 0.0f, 1.0f );//指定线的颜色,蓝色

        glBegin( GL_LINES );
        {
            // x-axis

            glVertex3f( 0.0f, 0.0f, 0.0f);
            glVertex3f( 200.0f, 0.0f, 0.0f);

            // x-axis arrow

            glVertex3f( 200.0f, 0.0f, 0.0f);
            glVertex3f( 193.0f, 3.0f, 0.0f);
            glVertex3f( 200.0f, 0.0f, 0.0f);
            glVertex3f( 193.0f,-3.0f, 0.0f);
        }
        glEnd();

        glColor3f( 0.0f, 1.0f, 0.0f );//指定线的颜色,绿色

        glBegin( GL_LINES );
        {
            // y-axis

            glVertex3f( 0.0f, 0.0f, 0.0f);
            glVertex3f( 0.0f, 200.0f, 0.0f);
            glVertex3f( 0.0f, 200.0f, 0.0f);
            glVertex3f( 3.0f, 193.0f, 0.0f);
            glVertex3f( 0.0f, 200.0f, 0.0f);
            glVertex3f( -3.0f, 193.0f, 0.0f);
        }
        glEnd();


        glColor3f( 1.0f, 0.0f, 0.0f );//指定线的颜色,红色

        glBegin( GL_LINES );
        {
            // z-axis

            glVertex3f( 0.0f, 0.0f, 0.0f );
            glVertex3f( 0.0f, 0.0f, 200.0f );
            glVertex3f( 0.0f, 0.0f, 200.0f );
            glVertex3f( 0.0f, 3.0f, 193.0f );
            glVertex3f( 0.0f, 0.0f, 200.0f );
            glVertex3f( 0.0f, -3.0f, 193.0f);
        }
        glEnd();
    }
}

运行效果图:

如果,转换一下坐标,例如将上面的 RenderScene 函数修改为下面的样子,


 


void RenderScene()
{
    //清空颜色缓冲区,填充的颜色由 glClearColor( 0, 0.0, 0.0, 1 ); 指定为黑色

    glClear( GL_COLOR_BUFFER_BIT );

    // Save matrix state and do the rotation

    glPushMatrix();
    glRotatef(xRot, 1.0f, 0.0f, 0.0f);
    glRotatef(yRot, 0.0f, 1.0f, 0.0f);

    DrawAxis();


    //绘制太阳

    glColor3f( 1.0f, 1.0f, 1.0f );
    glRotatef(45, 0.0f, 0.0f, 1.0f);    //沿着z轴旋转45‘

    glTranslatef( 100, 0, 0 );            //向x轴平移100个单位

    glutSolidSphere( 50.f, 15, 15 );

    // Restore transformations

    glPopMatrix();

    glutSwapBuffers();
}


那么效果图如下:

 
3、添加绕太阳旋转的地球以及绕地球转的月亮
 
只需添加另一个球体,然后想办法让这个球体在每一帧动画中在不同的地方出现,给人的感觉就像这个地球在绕太阳旋转。
需要增加另一函数
 glutIdleFunc (RenderScene);
该函数 glutIdleFunc 表示在CPU空闲的时间调用RenderScene来重新绘制窗体。
整体程序如下:
 

// Purpose: To show how to draw the solar system

// Author: zieckey

// Date: 2009/10/7


#include "GL/glut.h"
#include <math.h>
#include <stdio.h>

// Rotation amounts

static GLfloat xRot = 0.0f;
static GLfloat yRot = 0.0f;

void SpecialKeys(int key, int x, int y);
void ChangeSize( GLsizei w, GLsizei h );
void DrawAxis();
void SetupRC();

void RenderScene()
{
    //清空颜色缓冲区,填充的颜色由 glClearColor( 0, 0.0, 0.0, 1 ); 指定为黑色

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Save matrix state and do the rotation

    glPushMatrix();
    glRotatef(xRot, 1.0f, 0.0f, 0.0f);
    glRotatef(yRot, 0.0f, 1.0f, 0.0f);

    DrawAxis();


    //绘制太阳

    glColor3f( 1.0f, 1.0f, 1.0f );//白色

    glutSolidSphere( 50.f, 15, 15 );

    //绘制地球

    static GLfloat earthAngle = 0;
    const GLfloat RADIUS = 100.f;
    glRotatef( earthAngle, 0, 0, 1 );
    glTranslatef( RADIUS, RADIUS, 0 );
    glColor3f( 0.0f, 1.0f, 0.0f );//绿色

    glutSolidSphere( 20.f, 15, 15 );

    // 绘制黄色的“月亮”

    glColor3f(1.0f, 1.0f, 0.0f);
    glRotatef(earthAngle/30.0*360.0 - earthAngle/360.0*360.0, 0.0f, 0.0f, -1.0f);
    glTranslatef(RADIUS/2, 0.0f, 0.0f);
    glutSolidSphere(7, 20, 20);

    earthAngle += 1;
    if ( earthAngle >= 360 )
    {
        earthAngle -= 360;
    }

    printf( "Angle:%f\n", earthAngle );
    
    // Restore transformations

    glPopMatrix();

    glutSwapBuffers();
}

int main(int argc, char* argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize (800, 600);
    glutInitWindowPosition (100, 100);
    glutCreateWindow( "Triangles Example" );
    glutDisplayFunc( RenderScene );
    glutIdleFunc (RenderScene); //glutIdleFunc 表示在CPU空闲的时间调用某一函数

    glutReshapeFunc( ChangeSize );
    glutSpecialFunc( SpecialKeys );
    SetupRC();
    glutMainLoop();

    return 1;
}


void SetupRC()
{
    glClearColor( 0, 0.0, 0.0, 1 );
    glShadeModel( GL_SMOOTH );
    glEnable(GL_DEPTH_TEST);//被遮住的部分不绘制

}


void ChangeSize( GLsizei w, GLsizei h )
{
    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 projection matrix stack

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    // Establish clipping volume (left, right, bottom, top, near, far)

    if (w <= h)
        glOrtho (-nRange, nRange, -nRange*h/w, nRange*h/w, -nRange, nRange);
    else
        glOrtho (-nRange*w/h, nRange*w/h, -nRange, nRange, -nRange, nRange);

    // Reset Model view matrix stack

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void SpecialKeys(int key, int x, int y)
{
    if(key == GLUT_KEY_UP)
        xRot -= 5.0f;

    if(key == GLUT_KEY_DOWN)
        xRot += 5.0f;

    if(key == GLUT_KEY_LEFT)
        yRot -= 5.0f;

    if(key == GLUT_KEY_RIGHT)
        yRot += 5.0f;

    if(xRot > 356.0f)
        xRot = 0.0f;

    if(xRot < -1.0f)
        xRot = 355.0f;

    if(yRot > 356.0f)
        yRot = 0.0f;

    if(yRot < -1.0f)
        yRot = 355.0f;

    // Refresh the Window

    glutPostRedisplay();// this will refresh the window, so, it works the same to call RenderScene() directly

}


void DrawAxis()
{
    //绘制x、y、z坐标轴

    {
        glColor3f( 0.0f, 0.0f, 1.0f );//指定线的颜色,蓝色

        glBegin( GL_LINES );
        {
            // x-axis

            glVertex3f( 0.0f, 0.0f, 0.0f);
            glVertex3f( 200.0f, 0.0f, 0.0f);

            // x-axis arrow

            glVertex3f( 200.0f, 0.0f, 0.0f);
            glVertex3f( 193.0f, 3.0f, 0.0f);
            glVertex3f( 200.0f, 0.0f, 0.0f);
            glVertex3f( 193.0f,-3.0f, 0.0f);
        }
        glEnd();

        glColor3f( 0.0f, 1.0f, 0.0f );//指定线的颜色,绿色

        glBegin( GL_LINES );
        {
            // y-axis

            glVertex3f( 0.0f, 0.0f, 0.0f);
            glVertex3f( 0.0f, 200.0f, 0.0f);
            glVertex3f( 0.0f, 200.0f, 0.0f);
            glVertex3f( 3.0f, 193.0f, 0.0f);
            glVertex3f( 0.0f, 200.0f, 0.0f);
            glVertex3f( -3.0f, 193.0f, 0.0f);
        }
        glEnd();


        glColor3f( 1.0f, 0.0f, 0.0f );//指定线的颜色,红色

        glBegin( GL_LINES );
        {
            // z-axis

            glVertex3f( 0.0f, 0.0f, 0.0f );
            glVertex3f( 0.0f, 0.0f, 200.0f );
            glVertex3f( 0.0f, 0.0f, 200.0f );
            glVertex3f( 0.0f, 3.0f, 193.0f );
            glVertex3f( 0.0f, 0.0f, 200.0f );
            glVertex3f( 0.0f, -3.0f, 193.0f);
        }
        glEnd();
    }
}

程序运行效果图:

4、投影变换
投影变换就是定义一个可视空间,可视空间以外的物体不会被绘制到屏幕上。(注意,从现在起,坐标可以不再是-1.0到1.0了!)
OpenGL支持两种类型的投影变换,即透视投影和正投影。投影也是使用矩阵来实现的。如果需要操作投影矩阵,需要以GL_PROJECTION为参数调用glMatrixMode函数。
glMatrixMode(GL_PROJECTION);
通常,我们需要在进行变换前把当前矩阵设置为单位矩阵。
glLoadIdentity();
透视投影所产生的结果类似于照片,有近大远小的效果,比如在火车头内向前照一个铁轨的照片,两条铁轨似乎在远处相交了。
使用glFrustum函数可以将当前的可视空间设置为透视投影空间。
也可以使用更常用的gluPerspective函数。
正投影相当于在无限远处观察得到的结果,它只是一种理想状态。但对于计算机来说,使用正投影有可能获得更好的运行速度。
使用glOrtho函数可以将当前的可视空间设置为正投影空间
如果绘制的图形空间本身就是二维的,可以使用gluOrtho2D。他的使用类似于glOrgho。

5、视口变换
当一切工作已经就绪,只需要把像素绘制到屏幕上了。这时候还剩最后一个问题:应该把像素绘制到窗口的哪个区域呢?通常情况下,默认是完整的填充整个窗口,但我们完全可以只填充一半。(即:把整个图象填充到一半的窗口内)
使用glViewport来定义视口。其中前两个参数定义了视口的左下脚(0,0表示最左下方),后两个参数分别是宽度和高度。

6、加上光源

// Purpose: To show how to draw the solar system

// Author: zieckey

// Date: 2009/10/7


#include "GL/glut.h"
#include <math.h>
#include <stdio.h>

// Rotation amounts

static GLfloat xRot = 0.0f;
static GLfloat yRot = 0.0f;

void SpecialKeys(int key, int x, int y);
void ChangeSize( GLsizei w, GLsizei h );
void DrawAxis();
void SetupRC();

void RenderScene()
{
    //清空颜色缓冲区,填充的颜色由 glClearColor( 0, 0.0, 0.0, 1 ); 指定为黑色

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Save matrix state and do the rotation

    glPushMatrix();
    glRotatef(xRot, 1.0f, 0.0f, 0.0f);
    glRotatef(yRot, 0.0f, 1.0f, 0.0f);

    //glTranslatef( 0, 0, -200 );//将整个场景移动到视野中


    DrawAxis();


    //绘制太阳

    glColor3f( 1.0f, 1.0f, 0.0f );//黄色

    glDisable( GL_LIGHTING );
    glutSolidSphere( 50.f, 15, 15 );

    //启动0号光源(模拟太阳的光芒)

    glEnable( GL_LIGHTING );
    GLfloat lightPos[] = { 0, 0, 0 };
    glLightfv( GL_LIGHT0, GL_POSITION, lightPos );
    

    //绘制地球

    static GLfloat earthAngle = 0;
    const GLfloat RADIUS = 100.f;
    glRotatef( earthAngle, 0, 0, 1 );
    glTranslatef( RADIUS, RADIUS, 0 );
    glColor3f( 0.0f, 1.0f, 0.0f );//绿色

    glutSolidSphere( 20.f, 15, 15 );

    //启动1号光源,模拟地球的散射光

    glLightfv( GL_LIGHT1, GL_POSITION, lightPos );
    GLfloat whiteDiffuseLight[] = {0.1, 0.1, 0.1}; //set the diffuse light to white

    glLightfv( GL_LIGHT1, GL_DIFFUSE, whiteDiffuseLight );

    // 绘制黄色的“月亮”

    glColor3f(1.0f, 1.0f, 0.0f);
    glRotatef(earthAngle/30.0*360.0 - earthAngle/360.0*360.0, 0.0f, 0.0f, -1.0f);
    glTranslatef(RADIUS/3, 0.0f, 0.0f);
    glutSolidSphere(7, 20, 20);


    //启动2号光源,模拟月球的反射光

    glLightfv( GL_LIGHT2, GL_POSITION, lightPos );
    GLfloat graySpecularLight[] = {0.2, 0.2, 0.2}; //set the Specular light to gray white

    glLightfv( GL_LIGHT2, GL_DIFFUSE, graySpecularLight );

    earthAngle += 0.1;
    if ( earthAngle >= 360 )
    {
        earthAngle -= 360;
    }

    printf( "Angle:%f\n", earthAngle );
    
    // Restore transformations

    glPopMatrix();

    glutSwapBuffers();
}

int main(int argc, char* argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize (800, 600);
    glutInitWindowPosition (100, 100);
    glutCreateWindow( "Triangles Example" );
    glutDisplayFunc( RenderScene );
    glutIdleFunc (RenderScene); //glutIdleFunc 表示在CPU空闲的时间调用某一函数

    glutReshapeFunc( ChangeSize );
    glutSpecialFunc( SpecialKeys );
    SetupRC();
    glutMainLoop();

    return 1;
}


void SetupRC()
{
    glClearColor( 0, 0.0, 0.0, 1 );
    glShadeModel( GL_SMOOTH );
    glEnable(GL_DEPTH_TEST);//被遮住的部分不绘制

    glEnable(GL_LIGHT0);
    glEnable(GL_LIGHT1);
    glEnable(GL_LIGHT2);
}


void ChangeSize( GLsizei w, GLsizei h )
{
    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 projection matrix stack

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

     // Establish clipping volume (left, right, bottom, top, near, far)

     if (w <= h)
         glOrtho (-nRange, nRange, -nRange*h/w, nRange*h/w, -nRange, nRange);
     else
         glOrtho (-nRange*w/h, nRange*w/h, -nRange, nRange, -nRange, nRange);

    //45度视野,近、远平面分别为1和200

    //gluPerspective( 45.f, (GLfloat)w/(GLfloat)h, 1, 200 );


    // Reset Model view matrix stack

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void SpecialKeys(int key, int x, int y)
{
    if(key == GLUT_KEY_UP)
        xRot -= 5.0f;

    if(key == GLUT_KEY_DOWN)
        xRot += 5.0f;

    if(key == GLUT_KEY_LEFT)
        yRot -= 5.0f;

    if(key == GLUT_KEY_RIGHT)
        yRot += 5.0f;

    if(xRot > 356.0f)
        xRot = 0.0f;

    if(xRot < -1.0f)
        xRot = 355.0f;

    if(yRot > 356.0f)
        yRot = 0.0f;

    if(yRot < -1.0f)
        yRot = 355.0f;

    // Refresh the Window

    glutPostRedisplay();// this will refresh the window, so, it works the same to call RenderScene() directly

}


void DrawAxis()
{
    //绘制x、y、z坐标轴

    {
        glColor3f( 0.0f, 0.0f, 1.0f );//指定线的颜色,蓝色

        glBegin( GL_LINES );
        {
            // x-axis

            glVertex3f( 0.0f, 0.0f, 0.0f);
            glVertex3f( 200.0f, 0.0f, 0.0f);

            // x-axis arrow

            glVertex3f( 200.0f, 0.0f, 0.0f);
            glVertex3f( 193.0f, 3.0f, 0.0f);
            glVertex3f( 200.0f, 0.0f, 0.0f);
            glVertex3f( 193.0f,-3.0f, 0.0f);
        }
        glEnd();

        glColor3f( 0.0f, 1.0f, 0.0f );//指定线的颜色,绿色

        glBegin( GL_LINES );
        {
            // y-axis

            glVertex3f( 0.0f, 0.0f, 0.0f);
            glVertex3f( 0.0f, 200.0f, 0.0f);
            glVertex3f( 0.0f, 200.0f, 0.0f);
            glVertex3f( 3.0f, 193.0f, 0.0f);
            glVertex3f( 0.0f, 200.0f, 0.0f);
            glVertex3f( -3.0f, 193.0f, 0.0f);
        }
        glEnd();


        glColor3f( 1.0f, 0.0f, 0.0f );//指定线的颜色,红色

        glBegin( GL_LINES );
        {
            // z-axis

            glVertex3f( 0.0f, 0.0f, 0.0f );
            glVertex3f( 0.0f, 0.0f, 200.0f );
            glVertex3f( 0.0f, 0.0f, 200.0f );
            glVertex3f( 0.0f, 3.0f, 193.0f );
            glVertex3f( 0.0f, 0.0f, 200.0f );
            glVertex3f( 0.0f, -3.0f, 193.0f);
        }
        glEnd();
    }
}

运行效果图:


同系列其他文章:

OpenGL系列教程(1)——Create A Window using GLUT http://blog.chinaunix.net/u/16292/showart.php?id=2063233

OpenGL系列教程(2)——从点到线,绘制我们自己的绚丽曲线 http://blog.chinaunix.net/u/16292/showart_2065128.html

 
OpenGL系列教程(3)——由简单的三角形到美丽的圆锥体http://blog.chinaunix.net/u/16292/showart.php?id=2065202


 



阅读(15291) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~