OpenGL

基本概念

1.光栅化:实际绘制或填充每个顶点之间的像素形成线程

2.着色:沿着顶点之间改变颜色值 能够轻松创建光照到一个立方体的效果

3.纹理贴图:将纹理图片附着到你绘图的图像上

4.混合:颜色混合效果

着色器

图元:组成图片的基本单元

OpenGL 渲染管线;一系列有序的处理阶段的序列,用于把我们应用中的数据转化到OpenGL生成一个最终的图像的一个过程

glsl:专门为图形开发设计的编程语言

着色器的渲染流程

顶点数据->顶点着色器->细分着色器->几何着色器->图元设置->剪切->光栅化->片元着色器->效果

这里引用一个优秀的大牛画的流程图
OpenGL_第1张图片

在开发的时候 一般用到的是 顶点着色器 片元着色器

OpenGL渲染结构

使用七种基本图元

如何使用存储着色器

如何使用Uniform着色器

如何使用glbatch帮助类传递几何图形

.
基本图形管线
OpenGL中的图元知识顶点的几何以及预定义的方式结合在一起
管线分为2个部分,上半部分是客户端下半部分是服务器端
服务器端和客户端是功能和运行上都是异步他们是各自独立的软件块和硬件块
,
. OpenGL_第2张图片

Texture Data 纹理 

Uniform

通过设置U inform变量就紧接着发送一个图元批次处理命令,Uniform变量实际上可以无限次的使用,设置一个应用于整个表面的单个颜色值,还可以是一个时间值。

atttributes 不能直接传数据到 片元着色器

属性:就是对一个顶点要做出改变的元素,实际上顶点位置本身就是一个属性,属性可以是整型布尔型车浮点型等

vertex shader 顶点着色器

Fragment shader 片元着色器

渲染过程中必备两个着色器 顶点着色器和片元着色器

有三种方式向OpenGL 着色器传递渲染数据的方法

1.属性(atttributes)

2.Uniforms

3.纹理 (Texture)

坐标系

//笛卡尔坐标系

投影方式

1.正投影 (2d)

2.透视投影(3d)

使用存储着色器

存储着色器分类

1.单位着色器

2.平面着色器

3.上色着色器

4.默认光源着色器

5.点光源着色器

6.纹理替换矩阵

7.纹理调整着色器

8.纹理光源着色器

常用代码 

定义着色器

GLShaderManager shaderManager;

初始化着色器

shaderManager.initalizeStockShaders();

使用

shaderManager.userStockManager(参数列表)

OpenGL 组合图元

线

三角形

线带

线环

三角形金字塔

三角形带

三角形扇

缓冲区

 颜色缓冲区:(GPU上内存区间),场景所需要颜色存储写入缓冲区

深度缓冲区:深度值z值 深度缓冲区-->深度测试。确定遮挡关系,保证渲染正确。

双缓冲区:生产者 消费者

模版缓冲区

矩阵

在计算机图形学中,除了GLMatrixStack类,还有一些其他的矩阵类可以使用,例如:
 ● M3DMatrix44f:用于表示3D空间中的矩阵。
 ● GLFrame:用于表示帧相关的矩阵。
 ● GLFrustum:用于表示透视投影矩阵。
这些矩阵类都有不同的用途和特点,具体的使用场景和方法可能会因应用程序的需求而有所不同。

GLMatrixStack

GLMatrixStack 是一个用于存储和操作矩阵的类,通常在计算机图形学中使用。它的主要作用是在进行图形变换时,高效地管理和操作矩阵。
GLMatrixStack 类通常实现了以下几个基本功能:
 1. 矩阵入栈(push):将当前矩阵压入栈中,作为新的栈顶矩阵。
 2. 矩阵出栈(pop):弹出栈顶矩阵,并将其作为当前矩阵。
 3. 替换矩阵(load):将指定的矩阵替换为当前矩阵。
 4. 相乘矩阵(multiply):将当前矩阵与指定的矩阵相乘,得到新的矩阵。
 5. 转置矩阵(transpose):将当前矩阵进行转置操作。
 6. 逆矩阵(invert):计算当前矩阵的逆矩阵。
通过使用 GLMatrixStack,你可以在进行图形变换时,将一系列矩阵操作组合在一起,形成一个矩阵链。这样可以方便地进行复杂的图形变换,并且可以在需要时还原之前的变换状态。

GLFrame

GLFrame是OpenGL中用于表示物体或观察者的坐标的类。GLFrame类中存储了一个世界坐标点和两个世界坐标下的方向向量,分别用来表示当前位置点、向前方向向量和向上方向向量。
通过GLFrame类提供的旋转、移动的函数(如MoveForward、MoveUp、MoveRight)以及RotateWorld形式的旋转函数,可以快速完成平移以及旋转操作。此外,GLFrame可以用来产生模型视图矩阵,从而实现位置的移动。

GLFrame类可以通过调用GetCameraMatrix函数来产生模型视图矩阵,该函数会先产生一个旋转矩阵,然后再产生一个平移矩阵,最后将两个矩阵做叉乘得到模型视图矩阵。
你可以使用GLFrame类的相关函数来设置观察者的位置和方向,从而得到一个变换后的矩阵。这个矩阵可以用于产生位置的移动,实现物体的旋转和移动。
 

你可以使用GLFrame类提供的函数来设置观察者的位置和方向,其中常用的函数包括:
 ● MoveForward(): 默认的朝向是-z轴,所以向屏幕里面移动传正数值,向屏幕外即+z轴,需要传负数值。
 ● MoveUp(): 设置向上移动的距离。
 ● MoveRight(): 设置向右移动的距离。
 ● RotateWorld(): 按照世界坐标系进行旋转。
在设置观察者的位置和方向时,需要注意坐标系的选择和转换,以确保结果的准确性。此外,还可以结合其他OpenGL类和函数来实现更复杂的变换和渲染效果。

GLFrustum

GLFrustum是OpenGL类库中的函数,用于定义一个平截头体,并计算一个用于实现透视投影的矩阵。其函数原型为glFrustum(left,right,bottom,top,near,far),各个参数含义如下:
 ● left和right:指明相对于垂直平面的左右坐标位置。
 ● bottom和top:指明相对于水平剪切面的下上位置。
 ● near和far:指明相对于深度剪切面的远近的距离,两个必须为正数。
通过调用glFrustum函数,可以确定视角边界的各个点,进而确定红色的可视区域,这在OpenGL ES版本中常被用于视角设定。

在OpenGL ES版本中,使用glFrustum函数来设定视角的方法如下:
public void glFrustumf(float left,float right,float bottom,float top,float near,float far)
参数用来确定视角边界的各个点。具体来说,left和right表示相对于垂直平面的左右坐标位置,bottom和top表示相对于水平剪切面的下上位置,near和far表示相对于深度剪切面的远近的距离。
调用glFrustum函数后,会根据视角边界的各个点来确定视角,从而实现透视投影的效果,使图形呈现出“近大远小”的特点。

GLBatch

GLBatch 是一个用于管理和批量提交 OpenGL 命令的类,它可以将一系列的 OpenGL 命令组织在一起,并一次性提交给图形渲染硬件,从而提高渲染效率。
GLBatch 类通常包含以下几个基本功能:
 1. 命令存储:可以将各种OpenGL 命令(如顶点绘制、纹理绑定、矩阵变换等)存储在一个批处理中。
 2. 批量提交:可以一次性将批处理中的所有命令提交给图形渲染硬件,避免了多次单独提交命令所带来的性能开销。
 3. 状态管理:可以自动管理OpenGL 状态,确保在批处理中的命令能够正确执行,并且不会受到其他命令的影响。
 4. 数据优化:可以对批处理中的数据进行优化,例如合并相同的顶点数据、减少数据传输等,从而提高渲染效率。
通过使用 GLBatch,你可以将多个OpenGL 命令组合在一起,形成一个批处理,并一次性提交给图形渲染硬件,从而提高渲染效率和性能。这对于处理大量的图形数据和进行复杂的渲染操作非常有用。

除了 GLBatch,还有以下几种方法可以提高 OpenGL 的渲染效率:
 1. 减少状态切换:OpenGL 中的状态切换(如切换渲染目标、纹理、矩阵等)会导致性能开销。尽量减少不必要的状态切换,将相关的操作组合在一起,以减少状态切换的次数。
 2. 使用顶点缓存对象(Vertex Buffer Object,VBO):将顶点数据存储在 VBO 中,可以减少 CPU 与 GPU 之间的数据传输次数,提高渲染效率。VBO 可以一次性将大量顶点数据传递给 GPU,避免了每次绘制时都传输顶点数据的开销。
 3. 合理使用纹理:使用纹理可以减少三角形的绘制数量,提高渲染效率。尽量使用较小的纹理,避免使用过大的纹理,并且可以使用纹理压缩技术来减少纹理的大小。
 4. 利用片段着色器(Fragment Shader)的效率:片段着色器可以进行大量的计算,但要注意避免在片段着色器中进行复杂的计算或循环。尽量使用向量操作和常量折叠等优化技巧来提高片段着色器的效率。
 5. 多线程渲染:利用多线程技术可以在多个核心上并行执行渲染任务,提高渲染效率。可以使用 OpenGL 的多线程扩展(如 OpenGL 4.0 及以上版本的GL_ARB_parallel_shader_compile和GL_ARB_shader_multithread等)来实现多线程渲染。
 6. 合理使用帧缓冲区对象(Framebuffer Object,FBO):FBO 可以用于渲染到离屏缓冲区,进行后期处理或多重渲染。合理使用 FBO 可以避免不必要的渲染目标切换和缓冲区拷贝,提高渲染效率。
 7. 缓存和重用资源:对于经常使用的资源(如纹理、模型等),可以进行缓存并在需要时重用,避免重复加载和创建资源。
 8. 优化几何数据:尽量减少三角形的数量,优化模型的拓扑结构,使用合适的索引缓冲区等,可以减少 GPU 的工作负载,提高渲染效率。
这些方法可以帮助提高 OpenGL 的渲染效率。根据具体应用场景和硬件环境,选择合适的优化策略可以显著提高图形渲染的性能。

GLGeometryTransform

GLGeometryTransform是OpenGL中用于管理管线的一个类,用于管理模型矩阵和投影矩阵。在使用GLGeometryTransform时,可以通过SetMatrixStacks函数将模型视图矩阵和投影矩阵分别放入对应的矩阵堆栈中。然后,在绘制图形时,可以通过GetModelViewProjectionMatrix函数获取模型视图投影矩阵,并将其传递给着色器,以便根据不同的模型视图投影矩阵选择不同的着色器进行绘制。
GLGeometryTransform可以提高OpenGL的渲染效率,因为它可以减少对模型视图投影矩阵的重复计算,从而提高渲染速度。此外,它还可以方便地管理多个矩阵,使代码更加清晰和易于维护。

使用GLGeometryTransform类可以通过以下步骤来管理模型视图投影矩阵:
 1. 定义modelViewMatrix和projectionMatrix分别为模型视图矩阵堆栈和投影矩阵堆栈。
 2. 在ChangeSize时初始化投影矩阵,并将其放入LoadMatrix进入投影矩阵堆栈。
 3. 将模型视图矩阵堆栈和投影矩阵堆栈放入transformPipeline几何变换管线对象中进行管理。
 4. 通过transformPipeline.GetModelViewProjectionMatrix()获取模型视图投影矩阵,并传递给UseStockShader使用。
 5. 渲染完成后,使用PopMatrix出栈恢复模型视图矩阵堆栈。
通过使用GLGeometryTransform类,可以更方便地管理多个矩阵,从而提高OpenGL的渲染效率。

来个demo

//
//  main.cpp
//  01 OpenGL 环境搭建
//
//  Created by KING on 2023/12/24.
//
#include "GLTools.h"
/// 矩阵
#include "GLMatrixStack.h"
#include "GLFrame.h"
#include "GLFrustum.h"
#include "GLBatch.h"
#include "GLGeometryTransform.h"

#include 
#ifdef __APPLE__
#include 
#else
#include 
#endif
/*
 GLMatrixStack 变化管线使用矩阵堆栈
 
 GLMatrixStack 构造函数允许指定堆栈的最大深度、默认深度为64 这个矩阵堆在初始化时已经在堆栈中包含了单位矩阵
 GLMatrixStack::GLMatrixStack(int iStackDepth = 64)
 //通过调用顶部载入这个单位矩阵
 void GLMatrixStack::LoadIndentiy(void)
 //在堆栈顶部载入任何矩阵
 void GLMatrixStack::LoadMatrix(const M3DMatrix44f m)
 */
GLShaderManager shaderManager;
GLMatrixStack   modelViewMatrix;
GLMatrixStack   projectionMatrix;
GLFrame cameraFrame;
GLFrame objectFrame;
// 投影矩阵
GLFrustum viewFrustum;
/// 容器类(7种不同的图元对应7种容器对象)
GLBatch pointBatch;
GLBatch lineBatch;
GLBatch lineStripBatch;
GLBatch lineLoopBatch;
GLBatch triangleBatch;
GLBatch triangleStringBatch;
GLBatch tringleFanBatch;
// 几何变换的管道
GLGeometryTransform transformPipline;
M3DMatrix44f shadowMatrix;


GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f };
GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };


// 跟踪效果步骤
int nStep = 0;

// 此函数在呈现上下文中进行任何必要的初始化。.
// 这是第一次做任何与opengl相关的任务。
void SetupRC()
{
   //定义一些点,类似佛罗里达州的形状。
    GLfloat vCoast[24][3] = {
        {2.80, 1.20, 0.0 }, {2.0,  1.20, 0.0 },
        {2.0,  1.08, 0.0 },  {2.0,  1.08, 0.0 },
        {0.0,  0.80, 0.0 },  {-.32, 0.40, 0.0 },
        {-.48, 0.2, 0.0 },   {-.40, 0.0, 0.0 },
        {-.60, -.40, 0.0 },  {-.80, -.80, 0.0 },
        {-.80, -1.4, 0.0 },  {-.40, -1.60, 0.0 },
        {0.0, -1.20, 0.0 },  { .2, -.80, 0.0 },
        {.48, -.40, 0.0 },   {.52, -.20, 0.0 },
        {.48,  .20, 0.0 },   {.80,  .40, 0.0 },
        {1.20, .80, 0.0 },   {1.60, .60, 0.0 },
        {2.0, .60, 0.0 },    {2.2, .80, 0.0 },
        {2.40, 1.0, 0.0 },   {2.80, 1.0, 0.0 }};
    
    
    //通过三角形创建金字塔
    GLfloat vPyramid[12][3] = {
        -2.0f, 0.0f, -2.0f,
        2.0f, 0.0f, -2.0f,
        0.0f, 4.0f, 0.0f,
        
        2.0f, 0.0f, -2.0f,
        2.0f, 0.0f, 2.0f,
        0.0f, 4.0f, 0.0f,
        
        2.0f, 0.0f, 2.0f,
        -2.0f, 0.0f, 2.0f,
        0.0f, 4.0f, 0.0f,
        
        -2.0f, 0.0f, 2.0f,
        -2.0f, 0.0f, -2.0f,
        0.0f, 4.0f, 0.0f};
    //1.设置背景
    glClearColor(0.7f, 0.7f,0.7f, 1.0f);
    shaderManager.InitializeStockShaders();
    glEnable(GL_DEPTH_TEST);
    /// 设置变换管线
    transformPipline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
    cameraFrame.MoveForward(-15.0f);
    
    
    /// 画图形 GLBatch
    /// GLenum 模式
    /// nVerts 点的个数
    pointBatch.Begin(GL_POINTS, 24);
    pointBatch.CopyVertexData3f(vCoast);
    pointBatch.End();
    
    /// 线的方式
    lineBatch.Begin(GL_LINES, 24);
    lineBatch.CopyVertexData3f(vCoast);
    lineBatch.End();
    
    /// 线段
    lineStripBatch.Begin(GL_LINE_STRIP, 24);
    lineStripBatch.CopyVertexData3f(vCoast);
    lineStripBatch.End();
    
    /// 线环
    lineLoopBatch.Begin(GL_LINE_LOOP, 24);
    lineLoopBatch.CopyVertexData3f(vCoast);
    lineLoopBatch.End();
    
    /// 金字塔
    triangleBatch.Begin(GL_TRIANGLES, 12);
    triangleBatch.CopyVertexData3f(vPyramid);
    triangleBatch.End();
    
    /// 三角形扇子
    GLfloat vpoints[100][3];
    int nVerts = 0;
    //半径
    GLfloat r = 3.0f;
    
    //原点
    vpoints[nVerts] [0] = 0.0f;
    vpoints[nVerts] [1]=0.0f;
    vpoints[nVerts] [2]= 0.0f;
    for (GLfloat angle = 0; angle < M3D_2PI; angle += M3D_2PI / 6.0f) {
        nVerts++;
        vpoints[nVerts][0] = float(cos(angle)) * r;
        vpoints[nVerts][1] = float(sin(angle)) * r;
        vpoints[nVerts][2] = -0.5f;
    }
    nVerts++;
    vpoints[nVerts][0] = r;
    vpoints[nVerts][1] = 0;
    vpoints[nVerts][2] = 0;

    tringleFanBatch.Begin(GL_TRIANGLE_FAN, 8);
    tringleFanBatch.CopyVertexData3f(vpoints);
    tringleFanBatch.End();
    
    
    //三角形条带,一个小环或圆柱段
    int iCount = 0;
    GLfloat radius = 3.0f;
    
    for (GLfloat angle = 0.0f;  angle <= (2 * M3D_2PI); angle += 0.3f) {
            /// 圆形顶点的xy
        GLfloat x = radius * sin(angle);
        GLfloat y = radius * cos(angle);
        
        vpoints[iCount][0] = x;
        vpoints[iCount][1] = y;
        vpoints[iCount][2] = -0.5f;
        iCount++;
        
        vpoints[iCount][0] = x;
        vpoints[iCount][1] = y;
        vpoints[iCount][2] = 0.5f;
        iCount++;
    }
    // 关闭循环
    //结束循环,在循环位置生成2个三角形
    vpoints[iCount][0] = vpoints[0][0];;
    vpoints[iCount][1] = vpoints[0][1];
    vpoints[iCount][2] = 0.5f;
    iCount++;
    
    vpoints[iCount][0] = vpoints[1][0];
    vpoints[iCount][1] = vpoints[1][1];
    vpoints[iCount][2] = 0.5;
    iCount++;
    triangleStringBatch.Begin(GL_TRIANGLE_STRIP, iCount);
    triangleStringBatch.CopyVertexData3f(vpoints);
    triangleStringBatch.End();
}

void changeSize(int width, int height) {
    glViewport(0, 0,width,height);
    /// 创建投影矩阵并将它载入投影矩阵堆栈中
    viewFrustum.SetPerspective(35.0f, float(width)/float(height), 1.0f, 500.f);
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    modelViewMatrix.LoadIdentity();
}

void keyPressFunc(unsigned char key, int x, int y) {
    if (key == 32) {
        nStep++;
        if (nStep > 6) {
            nStep = 0;
        }
    }
    switch(nStep)
    {
        case 0:
            glutSetWindowTitle("GL_POINTS");
            break;
        case 1:
            glutSetWindowTitle("GL_LINES");
            break;
        case 2:
            glutSetWindowTitle("GL_LINE_STRIP");
            break;
        case 3:
            glutSetWindowTitle("GL_LINE_LOOP");
            break;
        case 4:
            glutSetWindowTitle("GL_TRIANGLES");
            break;
        case 5:
            glutSetWindowTitle("GL_TRIANGLE_STRIP");
            break;
        case 6:
            glutSetWindowTitle("GL_TRIANGLE_FAN");
            break;
    }
    
    glutPostRedisplay();

    
}

void SpecialKeys(int key, int x, int y) {
    ///移动物体方式
    ///1. 修改物体坐标系
    ///2. 修改世界坐标系
    if (key == GLUT_KEY_UP) {
        objectFrame.RotateWorld(m3dDegToRad(-5.f), 1.0f, 0.0f,0.0f);
    }
    if (key == GLUT_KEY_DOWN) {
        objectFrame.RotateWorld(m3dDegToRad(5.f), 1.0f, 0.0f, 0.0f);
    }

    if (key == GLUT_KEY_RIGHT) {
        objectFrame.RotateWorld(m3dDegToRad(5.f), 0.0f, 1.0f, 0.0f);
    }
    if (key == GLUT_KEY_LEFT) {
        objectFrame.RotateWorld(m3dDegToRad(-5.f), 0.0f, 1.0f, 0.0f);
    }
    glutPostRedisplay();
    
}
void DrawWireFrameBatch(GLBatch* pBatch) {
    /// 画颜色的部分
    shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipline.GetModelViewProjectionMatrix(),vGreen);
    pBatch->Draw();
    
    //边框
    glPolygonOffset(-1.0f, -1.0f); //偏移深度 在同一位置要绘制填充和边线 会产生z轴冲突 所以需要偏移
    glEnable(GL_POLYGON_OFFSET_LINE);
    
    glEnable(GL_LINE_SMOOTH);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA,   GL_ONE_MINUS_SRC_ALPHA);
    
    //通过调用glPolygonMode 将多边形正面或者背面设为线框模式 实现线框渲染
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    glLineWidth(2.5f);
    
    shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipline.GetModelViewProjectionMatrix(),vBlack);
    pBatch->Draw();
    
    // 复原原本的设置
    通过调用glPolygonMode将多边形正面或者背面设为全部填充模式
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    glDisable(GL_POLYGON_OFFSET_LINE);
    glLineWidth(1.0f);
    glDisable(GL_BLEND);
    glDisable(GL_LINE_SMOOTH);
}



// 召唤场景

void RenderScene() {
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
    /// 压栈
    modelViewMatrix.PushMatrix();
    M3DMatrix44f mCamera;
    cameraFrame.GetCameraMatrix(mCamera);
    
    /// 矩阵乘以矩阵堆栈的顶部矩阵 相乘的结果随后存储在堆栈的顶部
    modelViewMatrix.MultMatrix(mCamera);
    
    M3DMatrix44f mObjecyFrame;
    ///只要使用 GetMatrix 函数就可以获取矩阵堆栈顶部的值 这个函数可以进行2次重载用来GLSHADERMANAGER的使用 或者是获取顶部矩阵的顶点副本数据
    objectFrame.GetMatrix(mObjecyFrame);
    /// 矩阵乘以矩阵堆栈的顶部矩阵 相乘的结果存在堆栈的 顶部
    modelViewMatrix.MultMatrix(mObjecyFrame);
    
    
    shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipline.GetModelViewProjectionMatrix(),vBlack);
    
    
    switch (nStep) {
        case 0:
                //设置点的大小
            glPointSize(4.0f);
            pointBatch.Draw();
            glPointSize(1.0f);
            break;
        case 1:
              // 设置线的宽度
            glLineWidth(2.0f);
            lineBatch.Draw();
            glLineWidth(1.0f);
            break;
        case 2:
            glLineWidth(2.0f);
            lineStripBatch.Draw();
            glLineWidth(1.0f);
            break;
        case 3:
            glLineWidth(2.0f);
            lineLoopBatch.Draw();
            glLineWidth(1.0f);

            break;
        case 4:
            DrawWireFrameBatch(&triangleBatch);
            break;
        case 5:
            DrawWireFrameBatch(&tringleFanBatch);

            break;
        case 6:
            DrawWireFrameBatch(&triangleStringBatch);

            break;
        default:
            break;
    }
    //还原到以前的模型视图矩阵(单位矩阵)
    modelViewMatrix.PopMatrix();
    // 进行缓冲区交换
    glutSwapBuffers();

}



int main(int argc, char* argv[]){
    gltSetWorkingDirectory(argv[0]);
    glutInit(&argc, argv);
    /// 申请一个颜色缓存区深度缓存区 双缓存区 模版缓存区
    glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
    ///  设置window尺寸
    glutInitWindowSize(800,600);
    /// 创建window标题
    glutCreateWindow("GL_POINTS");
    /// 注册窗口改变大小的回调函数
    glutReshapeFunc(changeSize);
    /// 点击空格键的回调函数
    glutKeyboardFunc(keyPressFunc);
    /// 特殊键位函数
    glutSpecialFunc(SpecialKeys);

    /// 显示函数
    glutDisplayFunc(RenderScene);
    /// 判断下是否哦能初始化glew库 确保项目能正常使用OpenGL 框架
    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW ERROR %s\n",glewGetErrorString(err));
        return 1;
    }
    
    //绘制
    SetupRC();

    glutMainLoop();
    
    return 0;
}

你可能感兴趣的:(算法)