OpenGL系列教程(2)——从点到线,绘制我们自己的绚丽曲线

23197阅读 0评论2009-10-07 zieckey
分类:C/C++

 
前面的一节, Create A Window using GLUT 已经给出了如何利用GLUT创建一个窗口,下面我们在这个窗口里面绘制我们的世界。当然,先从简单开始,绘制一个点。
OpenGL中描述一个顶点的方法是指定其坐标和属性,命令是:
glVertex*(Coordination);
该命令以参数指定的坐标和当前颜色、纹理坐标、法向等属性定义一个顶点。
OpenGL
中描述一个面(线、点)的方法是glBegin/glEnd命令组:
glBegin(
形状);
glVertex(
顶点1);
glVertex(
顶点2);
……
glEnd();

OpenGL
支持点(GL_POINTS)、线段(GL_LINES)、三角形(GL_TRIANGLES)、四边形(GL_QUADS)、多边形(GL_POLYGON)等等,请看下面程序绘制一个点。
 
1、绘制一个点

// Purpose: To show how to draw points and lines in a windows
// Author: zieckey
// Date: 2009/10/7


#include "GL/glut.h"

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

    glClear( GL_COLOR_BUFFER_BIT );
    glPointSize( 9 );//指定点的大小,9个像素单位
    glColor3f( 1.0f, 0.0f, 0.0f );//指定点的颜色
    glBegin( GL_POINTS );//开始画点
    {
        glVertex3f(0.0f, 0.0f, 0.0f); // 在坐标为(0,0,0)的地方绘制了一个点
    }
    glEnd();//结束画点
    glutSwapBuffers();
}

void SetupRC()
{
    glClearColor( 0.0f, 0.0f, 0.0f, 1 );//以RGB(0,0,0)即黑色来清空颜色缓冲区

    glColor3f( 1.0f, 0.0f, 0.0f );//以RGB(1,0,0)即红色来绘制图形

}


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();
}

int main(int argc, char* argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize (200, 200);
    glutInitWindowPosition (10, 10);
    glutCreateWindow( "Point examples" );
    glutDisplayFunc( RenderScene );
    SetupRC();
    glutMainLoop();

    return 1;
}

程序运行结果如下:

 
 
2、下面,我们来绘制一个点园

// Purpose: To show how to draw points and lines in a windows
// Author: zieckey
// Date: 2009/10/7

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

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

    glClear( GL_COLOR_BUFFER_BIT );

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

    glPointSize( 9 );//指定点的大小,9个像素单位

    glBegin( GL_POINTS );//开始画点

    {
        glVertex3f(0.0f, 0.0f, 0.0f); // 在坐标为(0,0,0)的地方绘制了一个点

    }
    glEnd();//结束画点



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

    glPointSize( 3 );//指定点的大小,3个像素单位

    glBegin( GL_POINTS );
    {
        #define PI 3.14159f
        #define RADIUS 50.f
        GLfloat x = 0, y = 0, angle = 0.0;
        for ( angle = 0; angle <= 2.0f * PI; angle += 0.1f )
        {
            x = RADIUS * sin( angle );
            y = RADIUS * cos( angle );
            glVertex3f( x, y, 0 );
        }
    }
    glEnd();

    glutSwapBuffers();
}

void SetupRC()
{
    glClearColor( 0, 0.0, 0.0, 1 );
    glColor3f( 1.0f, 0.0f, 0.0f );
}

void ChangeSize( GLsizei w, GLsizei h )
{
    GLfloat nRange = 100.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();
}

int main(int argc, char* argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize (400, 300);
    glutInitWindowPosition (100, 100);
    glutCreateWindow( "Point examples" );
    glutDisplayFunc( RenderScene );
    glutReshapeFunc( ChangeSize );
    SetupRC();
    glutMainLoop();

    return 1;
}


程序运行结果如下:

3、增加坐标轴

下面我们给上面的图形增加坐标轴,看看如何画线

// Purpose: To show how to draw points and lines in a windows

// Author: zieckey

// Date: 2009/10/7


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

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

    glClear( GL_COLOR_BUFFER_BIT );

    //绘制一个点

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

        glPointSize( 9 );//指定点的大小,9个像素单位

        glBegin( GL_POINTS );//开始画点

        {
            glVertex3f(0.0f, 0.0f, 0.0f); // 在坐标为(0,0,0)的地方绘制了一个点

        }
        glEnd();//结束画点

    }

    //绘制一个点圆

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

        glPointSize( 3 );//指定点的大小,3个像素单位

        glBegin( GL_POINTS );
        {
            #define PI 3.14159f
            #define RADIUS 50.f
            GLfloat x = 0, y = 0, angle = 0.0;
            for ( angle = 0; angle <= 2.0f * PI; angle += 0.1f )
            {
                x = RADIUS * sin( angle );
                y = RADIUS * cos( angle );
                glVertex3f( x, y, 0 );
            }
        }
        glEnd();
    }

    //绘制x、y坐标轴

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

        glBegin( GL_LINES );
        {
            // x-axis

            glVertex3f( -100.0f, 0.0f, 0.0f);
            glVertex3f( 100.0f, 0.0f, 0.0f);

            // x-axis arrow

            glVertex3f( 100.0f, 0.0f, 0.0f);
            glVertex3f( 93.0f, 3.0f, 0.0f);
            glVertex3f( 100.0f, 0.0f, 0.0f);
            glVertex3f( 93.0f,-3.0f, 0.0f);

            // y-axis

            glVertex3f( 0.0f, -100.0f, 0.0f);
            glVertex3f( 0.0f, 100.0f, 0.0f);
            glVertex3f( 0.0f, 100.0f, 0.0f);
            glVertex3f( 3.0f, 93.0f, 0.0f);
            glVertex3f( 0.0f, 100.0f, 0.0f);
            glVertex3f( -3.0f, 93.0f, 0.0f);
        }
        glEnd();
    }


    glutSwapBuffers();
}

void SetupRC()
{
    glClearColor( 0, 0.0, 0.0, 1 );
    glColor3f( 1.0f, 0.0f, 0.0f );
}

void ChangeSize( GLsizei w, GLsizei h )
{
    GLfloat nRange = 100.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();
}

int main(int argc, char* argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize (400, 300);
    glutInitWindowPosition (100, 100);
    glutCreateWindow( "Point examples" );
    glutDisplayFunc( RenderScene );
    glutReshapeFunc( ChangeSize );
    SetupRC();
    glutMainLoop();

    return 1;
}

程序运行结果如下:

 

4、绘制三维曲线和添加键盘响应
为了从不同的角度观察三维曲线,我们这里可以通过 glRotatef 来旋转OpenGL绘图坐标系,
同时通过 glutSpecialFunc( SpecialKeys ) 设置了方向键的响应
 

// Purpose: To show how to draw points and lines in a windows
// 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 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);


    //绘制一个点

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

        glPointSize( 9 );//指定点的大小,9个像素单位

        glBegin( GL_POINTS );//开始画点

        {
            glVertex3f(0.0f, 0.0f, 0.0f); // 在坐标为(0,0,0)的地方绘制了一个点

        }
        glEnd();//结束画点

    }

    //绘制一个点圆

    {
        glColor3f( 0.5f, 0.5f, 0.5f );//指定点的颜色,灰白色

        glPointSize( 3 );//指定点的大小,3个像素单位

        glBegin( GL_POINTS );
        {
            #define PI 3.14159f
            #define CIRCLE_NUM 5
            #define RADIUS 100.f
            #define STEP 0.5f
            GLfloat x = 0, y = 0, z = -RADIUS, angle = 0.0;
            for ( angle = 0; angle <= 2.0f * PI * CIRCLE_NUM; angle += 0.1f )
            {
                x = RADIUS * sin( angle );
                y = RADIUS * cos( angle );
                z += STEP;
                glVertex3f( x, y, z );
            }
        }
        glEnd();
    }

    //绘制x、y坐标轴

    {
        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();
    }

    // Restore transformations

    glPopMatrix();

    glutSwapBuffers();
}

void SetupRC()
{
    glClearColor( 0, 0.0, 0.0, 1 );
    glColor3f( 1.0f, 0.0f, 0.0f );
}

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

}

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

    return 1;
}


程序运行结果如下:

 
 
5、遇到的问题分析
程序运行的时候,如果图形出不来,可能是下面的几个原因
a) 双缓冲和单缓冲的设置问题,例如我们用的是双缓冲,那么就要用 glutSwapBuffers(); 来刷新图形
b) 我们设置了正交投影(glOrtho),请注意下它的参数是不是范围太小,不能全部容纳我们绘制的图形,导致只看到图形的一部分
c) 看看 glutDisplayFunc( RenderScene );  glutReshapeFunc( ChangeSize );  glutSpecialFunc( SpecialKeys ); 等回调函数的设置的是否漏掉是否正确
 
等等吧,呵呵
 
6、总结:
这里我们知道了如何画点、线等,也知道了如何旋转坐标系,如何捕获键盘信息、如何设置视角等。
 
 
上一篇:OpenGL教程 "Top Ten"
下一篇:OpenGL系列教程(3)——由简单的三角形到美丽的圆锥体