OpenGl入门基础知识-叩开3D的心扉

OpenGl入门基础知识-叩开3D的心扉_第1张图片

OpenGL简介

是在SGI等多家世界闻名的计算机公司的倡导下,以SGI的GL三维图形库为基础制定的一个通用共享的开放式三维图形标准。是图形硬件的一个软件接口。

OpenGL特点

OpenGL是一个开放的三维图形软件包,它独立于窗口系统和操作系统,以它为基础开发的应用程序可以十分方便地在各种平台间移植。
OpenGL可以与Visual C++紧密接口,便于实现有关计算和图形算法,可保证算法的正确性和可靠性。
OpenGL使用简便,效率高。

vs环境下OpenGL函数库配置

加载glut库
把过glut32.lib拷贝到VC的安装目录下的lib文件夹中:如D:\Program Files\Microsoft Visual Studio\VC98\Lib
把glut.h拷贝到VC的安装目录下的Include\GL文件夹中:如:D:\Program Files\Microsoft Visual Studio\VC98\Include\GL
把glut32.dll拷贝到C:\WINDOWS\system32

OpenGL函数的命名规则

一般的函数命名如下:
<前缀><根函数><参数数目><参数类型>

前缀有gl、glu、aux、glut、wgl、glx、agl等等,分别表示该函数属于OpenGL那个开发库等。所谓开发库,要知道原生的OpenGL是跨平台的,跨平台意味着很多功能是无法实现的,比如说Windows和X-Window的窗口实现机制是不同的,OpenGL并不关心这些东西,只管画图。所以,OpenGL并没有窗口函数,比如无法创建窗口,无法获得输入……这些东西都需要其他的函数库来实现。用OpenGL常用的工具函数库来实现。

我们主要使用两种,一个是GLU库,它提供了比较基础的命令的封装,可以很简单的实现比较多的复杂功能;而另外一个就是GLUT,glut是不依赖于窗口平台的OpenGL工具包,目的是隐藏不同窗口平台API的复杂度,提供更为复杂的绘制功能,我们会大量的使用它。

OpenGL内部数据都是以float的形式存放的,如果使用double会对性能有一定的影响。


初始化窗口

glutInit() 是用glut来初始化OpenGL的,所有的问题都交给这个函数吧,基本不用管,虽说可以接受参数的,基本无用。

glutInitDisplayMode(MODE) 非常重要,这里告诉系统我们需要一个怎样显示模式。至于其参数GLUT_RGBA就是使用(red, green, blue)的颜色系统。有没有写错?这里有个A啊,不应该是(red, green, blue, alpha)么?大概是历史原因,GLUT_RGBA和GLUT_RGB是其实是等价的(坑爹啊),要想实现Alpha还得用其他的参数。而GLUT_SINGLE意味着所有的绘图操作都直接在显示的窗口执行,相对的,我们还有一个双缓冲的窗口,对于动画来说非常合适。

glutInitWindowSize(400, 400) 这个函数很容易理解,设置出现的窗口的大小。实际上还有个glutInitWindowPosition()也很常用,用来设置窗口出现的位置。

glutCreateWindow(“First”) ,一旦调用了,就出现一个窗口了,参数就是窗口的标题。

glutDisplayFunc(func) 是glut非常讨人喜欢的一个功能,它注册了一个函数,用来绘制OpenGL窗口,这个函数里就写着很多OpenGL的绘图操作等命令,也就是我们主要要学习的东西。

glutMainLoop() ,主循环,一旦调用了,我们的OpenGL就一直运行下去了。和很多程序中的主循环一样,不停的运行,画出即时的图像,处理输入等。


绘图

看看drawFunc里的几句话,这里是实际绘图的函数。

glClear(GL_COLOR_BUFFER_BIT) 是把先前的画面给清除,这基本是定律,每次重绘之前都要把原来的画面擦除,否则叠加起来什么都看不出了。glClear一看就知道是OpenGL原生的命令,而参数就是指明要清除的buffer。大家一定会有疑问,我们清除,不就是清除屏幕上的画面么,为什么还要指定?OpenGL的博大精深这里就体现出来了,buffer不仅仅有我们看到的那个GL_COLOR_BUFFER_BIT,OpenGL中还有其他的buffer类型,我们会在后面的章节讲到。

glutWireTeapot(0.5) 是glut提供的绘制犹他茶壶的工具函数,茶壶还是相当复杂的一个几何体,用这个函数一下子就画出来了,不过基本也就演示用用。这里是用的线模型,因为没有说光照和材质,如果glutSolidTeapot()画出来就成纸片儿了。

glFlush() 似乎不用多说,画了那么多,自然要刷新一下显示。不过,这里的刷新不仅仅是屏幕上的更新,实际上,它是处理OpenGL的渲染流水线,让所有排队中的命令得到执行。OpenGL的渲染流水线是一个很重要的概念,不过这里暂时还不打算多说明,否则对初学者来说,未免有些麻烦了。
glutSwapBuffers(); 交换缓冲区(使用双缓存GLUT_DOUBLE,必须交换缓存才能显示)


小惊喜

glutIdleFunc(Func) 又是一个激动人心的函数,可以让OpenGL在闲暇之余,调用一下注册的函数,这是是产生动画的绝好方法
gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
//定义一个视图矩阵,并与当前矩阵相乘(实现漫游)

 void gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez, GLdouble centerx, GLdouble centery, GLdouble centerz, GLdouble upx, GLdouble upy, GLdouble upz);
该 函数定义一个视图 矩阵,并与当前矩阵相乘。
第一组eyex, eyey, eyez 相机在世界坐标的位置
第二组centerx, centery, centerz 相机镜头对准的物体在世界坐标的位置
第三组upx, upy, upz 相机向上的方向在世界坐标中的方向
你把相机想象成为你自己的脑袋:
第一组数据就是脑袋的位置
第二组数据就是眼睛看的物体的位置
第三组就是头顶朝向的方向(因为你可以歪着头看同一个物体)
OpenGL中维持着两套矩阵,一个是模型视图矩阵(model view matrix),另一个是投影矩阵(projection matrix)。
通过对OpenGL这两套矩阵的变换,我们可以得到各种投影效果

一些常用函数

glColor3f(1.0, 0.0, 0.0); //画笔红色
glutReshapeFunc(reshape); //窗口发生改变再渲染
glutMouseFunc(mouse);
glutMotionFunc(motion);
//处理当鼠标键摁下时,鼠标拖动的事件。当鼠标拖动时,将每一帧都调用一次这个函数 glLoadIdentity();
//重置当前模型观察矩阵

glPushMatrix();
//把刚刚的那个位置和角度保存进栈中(主要用于平移,旋转,缩放等)保存当前模型视图 glPopMatrix();
//根据保存的值恢复出位置,角度等 glRotatef(anglex, 1.0, 0.0, 0.0);
//以(x,y,z)向量为旋转轴旋转angle度 glScalef(1.0,1.0,1.0);
//每一点坐标分别乘以x,y,z倍(缩放)

glViewport(0, 0, (GLsizei)w, (GLsizei)h);
//负责把视景体截取的图像按照怎样的高和宽显示到屏幕上 glMatrixMode(GL_PROJECTION);
//设置当前矩阵模式:对投影矩阵应用随后的矩阵操作 与glLoadIdentity()一同使用
glLoadIdentity();
//重置当前模型观察矩阵:将当前的用户坐标系的原点移到了屏幕中心 >>gluPerspective(60.0, (GLfloat)w /(GLfloat)h, 1.0, 20.0);
//创建一个投影矩阵并且与当前矩阵相乘,得到的矩阵设定为当前变换,但要先通过glMatrixMode设定成投影矩阵才会得到想要的投影矩阵变换
glMatrixMode(GL_MODELVIEW);
//设置当前矩阵模式:对模型视景矩阵堆栈应用随后的矩阵操作 另GL_TEXTURE参数,是对纹理矩阵堆栈应用随后的矩阵操作
glLoadIdentity();
//重置当前模型观察矩阵:将当前的用户坐标系的原点移到了屏幕中心
gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0,0.0, 0.0, 1.0, 0.0);`
//定义一个视图 与当阵相乘()


用OpenGL编写程序的模板基本模板

//主函数
int main(int argc, char* argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);        //设置显示模式(颜色、缓冲区等)
    glutCreateWindow(“A Simple Example”); //创建窗口
    SetupRC();                      //初始化渲染环境
    glutDisplayFunc(RenderScene);  //调用场景渲染函数
    glutReshapeFunc(ChangeSize);   //窗口发生变化
    glutMainLo();                  //程序开始事件处理
    }

几何图元的绘制

glBegin(GL_TRIANGLES);      //三角形
glVertex3f(0.0f,1.0f,0.0f);
glVertex3f(-1.0f,-1.0f,0.0f);
glVertex3f(1.0f,-1.0f,0.0f);
glEnd();
glBegin(GL_QUADS);           //四边形
glVertex3f(-1.0f,1.0f,0.0f);
glVertex3f(1.0f,1.0f,0.0f);
glVertex3f(1.0f,-1.0f,0.0f);
glVertex3f(-1.0f,-1.0f,0.0f);
glEnd();

下面是一个完整例子:

3D场景绘制2D透明缩放矩阵信息面板

#include 
#include 
#include 

//输出模式,0-单缓存模式;非0双缓存模式
#define OUTPUT_MODE 1

float scale = 0.0;
bool add = true;

unsigned char axle = 'x';

void init(void)
{
    //glClearColor函数设置好清除颜色,glClear利用glClearColor函数设置好的当前清除颜色设置窗口颜色
    glClearColor(1.0, 1.0, 0.8, 1.0);
}

void display(void)
{
    printf("scale=%f, axle=%c\n", scale, axle);
    glClear(GL_COLOR_BUFFER_BIT);

    //配置缩放比例大小scale
    scale = (add ? scale + 0.1 : scale - 0.1);
    if (scale >= 2.0)
    {
        add = false;
    }
    else if (scale <= 0.0) {
        add = true;
    }
    //开始绘画
    glPushMatrix();
    {
        if (axle == 'x') {
            glScalef(scale, 1, 1);
        }
        else if (axle == 'y') {
            glScalef(1, scale, 1);
        }
        else if (axle == 'z') {
            glScalef(1, 1, scale);
        }
        else {
            glScalef(scale, scale, scale);
        }
        glColor3f(1.0, 0.0, 1.0); //画笔梅红色
        glBegin(GL_POLYGON);
        glVertex2f(-0.2, -0.2);
        glVertex2f(-0.2, 0.2);
        glVertex2f(0.2, 0.2);
        glVertex2f(0.2, -0.2);
        glEnd();
    }
    glPopMatrix();

    glLoadIdentity();  //加载单位矩阵
    glColor3f(0.0, 0.0, 1.0); //画笔蓝色
                              //--------画直线START--------
                              //画直线
    glBegin(GL_LINES);
    glVertex2f(-0.5, 0);
    glVertex2f(0.5, 0);
    glVertex2f(0, 0.5);
    glVertex2f(0, -0.5);
    glEnd();
    //--------画直线E N D--------

    if (OUTPUT_MODE == 0) {
        glFlush();//单缓存GLUT_SINGLE时使用
    }
    else {
        glutSwapBuffers();//因为使用的是双缓存GLUT_DOUBLE,所以这里必须要交换缓存才会显示
    }

    Sleep(50);
}

void reshape(int w, int h)
{
    int offset = 50;
    int dis = (w > h ? h : w) - offset * 2;

    //配置显示物体屏幕的大小
    glViewport(offset, offset, (GLsizei)dis, (GLsizei)dis);
    printf("reshape: w=%d, h=%d, dis=%d\n", w, h, dis);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glOrtho(-1.5, 1.5, -1.5, 1.5, 0, 10);
    //gluOrtho2D(-1.5, 1.5, -1.5, 1.5);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void keyboard(unsigned char key, int x, int y)
{
    switch (key) {
    case 'x':
    case 'X':
        axle = 'x';
        glutPostRedisplay();
        break;
    case 'y':
    case 'Y':
        axle = 'y';
        glutPostRedisplay();
        break;
    case 'z':
    case 'Z':
        axle = 'z';
        glutPostRedisplay();
        break;
    case 'a':
    case 'A':
        axle = 'a';
        glutPostRedisplay();
        break;
    default:
        break;
    }
    printf("按键%c\n", key);
}

int main(int argc, char *argv[])
{
    printf("可通过按键xyza控制图形按哪一轴缩放\n");
    glutInit(&argc, argv);

    glutInitDisplayMode(GLUT_RGB | (OUTPUT_MODE == 0 ? GLUT_SINGLE : GLUT_DOUBLE));
    glutInitWindowPosition(100, 100);
    glutInitWindowSize(400, 400);
    glutCreateWindow("第一个 OpenGL 程序");

    init();
    glutDisplayFunc(&display);
    glutIdleFunc(display);       //程序空闲的时候调用display(设置不断调用显示函数)
    glutReshapeFunc(reshape);
    //  glutKeyboardFunc(keyboard);
    glutMainLoop();
    return 0;
}

运行截图
OpenGl入门基础知识-叩开3D的心扉_第2张图片

你可能感兴趣的:(OpenGl,3D)