OpenGL 学习 06 - 多边形偏移/裁剪/混合/抗锯齿

学习书籍: OpenGL 超级宝典(中文第五版) 密码:fu4w
书籍源码:OpenGL 超级宝典第五版源代码 密码:oyb4
环境搭建:OpenGL 学习 01 - Mac 搭建 OpenGL 环境

基本概念

多边形偏移

上一节在 OpenGL 学习 05 - 花托 中,我们通过深度测试实现真实视觉并提高性能,但会遇到一些麻烦,比如我们想将2个几何图形绘制在同一个位置,我们想要画一架大飞机,然后在飞机上绘制一个五角星图案,这叫做“贴花”。这 2 个图形的深度值 z 相同或者几乎相同,这种情况称为 深度值冲突

处理深度值冲突的方法:

  1. 手动调整 z 值进行一点点偏移,但可能会出现图形悬浮(不推荐)
  2. 利用 多边形偏移 调节片段的深度值,但实际不改变 3D 空间物理位置(推荐)

应用到片段上的总偏移方程式如下,其中 DZ 是深度值相对多边形屏幕区域的变化量,r 是使深度缓冲区值产生变化的最小值,这2个值都是 OpenGL 内部的值,我们不用关心,我们是通过控制 factor 和 units 达到效果:


// 设置多边形偏移
void glPolygonOffset(GLfloat factor, GLfloat units);

裁剪

除了深度测试,还有一种提高渲染性能的方法,那就是 只刷新屏幕上发生变化的部分,即裁剪。OpenGL 允许我们在将要进行渲染的窗口中指定一个裁剪框,只刷新裁剪框里面的变化。默认裁剪框和窗口大小一致,并不会进行裁剪测试。

//设置裁剪框位置和大小
void glScissor(GLint x, GLint y, GLsizei width, GLsizei height);

混合

通常情况下,OpenGL 渲染时会把颜色值放在颜色缓存区中,任何绘制操作都是完全覆盖原来的颜色值,比如我们在一个红色图形前面画一个蓝色图形,在重叠的部分,蓝色覆盖红色。但如果我们想在重叠区显示重叠颜色(比如红蓝混合色)怎么办?这时就需要使用到 OpenGL 的混合功能。

目标颜色:已经存储在颜色缓冲区中的颜色
源颜色:将要加入进行混合的颜色
混合方程式:目标颜色和源颜色的组合方式,用来生成混合后的颜色

其中 Cf 是最终产生颜色,Cs 为源颜色,Cd 为目标颜色,S 和 D 分别为源颜色和目标颜色的混合因子

// 我们通过控制 S 和 D 混合因子控制混合方程式输出,S 和 D 都是枚举值
void glBlendFunc(CLenum S, GLenum D);

看到上面的混合因子表,一开始是懵逼的,我们来简单计算一下,到底表示的意义是什么,下面是其中一种情况的计算过程,其他类推:

/*
Rs/Gs/Bs/As - 源颜色 RGBA 各个通道的混合因子
Rd/Gd/Bd/Ad - 目标颜色 RGBA 各个通道的混合因子
Rc/Gc/Bc/Ac - 常量颜色 RGBA 各个通道的混合因子
Cs = 源颜色 = { 0.0f, 0.0f, 1.0f, 0.6f } 
Cd = 目标颜色 = { 1.0f, 0.0f, 0.0f, 1.0f } 
As = 源颜色 alpha 值 = 0.6f
Ad = 目标颜色 alpha 值 = 1.0f
S = 源颜色混合因子 = GL_SRC_ALPHA = As = 0.6f
D = 目标颜色混合因子 = GL_ONE_MINUS_SRC_COLOR = 1.0f - As = 0.4f
Cf = 最终产生颜色 = Cs * 0.6f + Cd * 0.4f = {
   0.0f * 0.6f + 1.0f * 0.4f,
   0.0f * 0.6f + 0.0f * 0.4f,
   1.0f * 0.6f + 0.0f * 0.4f,
   0.6f * 0.6f + 1.0f * 0.4f
} = { 0.4f, 0.6f, 0.0f, 0.76f }
*/
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

但是这会带来一个问题,当我们进行了颜色混合后,最终目标颜色分量 Alpha 通道同时也被改变了——原来 Alpha 是 0.6,混合后变成了 0.76。这时我们就需要另外一个函数 glBlendFuncSeparate

//允许分别为 RGB 通道和 Alpha 通道设置混合因子(OpenGL 2.0 开始支持)
void glBlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);

除了上面默认的混合方程式,也有其他混合方程式:

//改变混合方程式等式结构
void glBlendEquation(GLenum mode);
//修改常量颜色,即上面表中的 Rc、Gc、Bc、Ac
void glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);

抗锯齿

OpenGL 混合的另外一种用途就是抗锯齿。图形边缘会出现一些吸引眼睛的注意力而让人感觉图形不自然的像素点,称为锯齿。我们需要尽可能的逼真,尤其在游戏、模拟和艺术创造中。为了消除图元之间的锯齿,OpenGL 利用混合功能,把像素的目标颜色和周围像素的颜色进行混合。

抗锯齿功能开启条件:

  1. 开启混合功能
  2. 设置混合方程式为 GL_ADD
  3. 设置混合方程式因子为 S = GL_SRC_ALPHA, D = GL_ONE_MINUS_SRC_ALPHA
  4. 开启抗锯齿功能(点/线/多边形)

源码解析

多边形偏移

核心代码:

//设置多边形偏移的总偏移
glPolygonOffset(-1.0f, -1.0f);
//开启多边形偏移
glEnable(GL_POLYGON_OFFSET_POINT); // 点
glEnable(GL_POLYGON_OFFSET_LINE); // 线
glEnable(GL_POLYGON_OFFSET_UNITS); // 图形
//关闭多边形偏移
glDisable(GL_POLYGON_OFFSET_POINT); // 点
glDisable(GL_POLYGON_OFFSET_LINE); // 线
glDisable(GL_POLYGON_OFFSET_UNITS); // 图形

Demo 源码: 之前文章的 03-Primitives Demo 中的三角形带中有运用到,这里就不重复拷贝了。

裁剪

核心代码:

//开启裁剪
glEnable(GL_SCISSOR_TEST);
//设置颜色缓冲区背景为红色
glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
//裁剪出(x: 100, y: 100, w: 600, h: 400)区域
glScissor(100, 100, 600, 400);
//清空颜色缓存区,同步到后台缓冲区,注意这里会设置的是裁剪区域
glClear(GL_COLOR_BUFFER_BIT);
//关闭裁剪
glDisable(GL_SCISSOR_TEST);

Demo 源码: 05-Scissor

#include <GLTools.h>        // OpenGL toolkit
#include <glut/glut.h>

//渲染画面
void RenderScene(void) {
    
    //设置颜色缓冲区背景色为蓝色
    glClearColor(0.0f, 0.0f, 1.0f, 0.0f);
    //清空颜色缓存区,设置到后台缓存区,执行完这步才绘制了背景颜色
    glClear(GL_COLOR_BUFFER_BIT);
    //开启裁剪
    glEnable(GL_SCISSOR_TEST);
    
    //设置颜色缓冲区背景色为红色
    glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
    //裁剪出(x: 100, y: 100, w: 600, h: 400)区域
    glScissor(100, 100, 600, 400);
    //清空颜色缓存区,设置到后台缓冲区,注意这里会设置的是裁剪区域
    glClear(GL_COLOR_BUFFER_BIT);
    
    //设置颜色缓冲区背景色为绿色
    glClearColor(0.0f, 1.0f, 0.0f, 0.0f);
    //裁剪出(x: 200, y: 200, w: 400, h: 200)区域
    glScissor(200, 200, 400, 200);
    //清空颜色缓存区,设置到后台缓冲区,注意这里会设置的是裁剪区域
    glClear(GL_COLOR_BUFFER_BIT);
    
    //关闭裁剪
    glDisable(GL_SCISSOR_TEST);
    //将在后台缓冲区进行渲染,然后在结束时交换到前台
    glutSwapBuffers();
}

//窗口大小改变时接受新的宽度和高度
void ChangeSize(int w, int h) {
    //设置视图窗口位置
    glViewport(0, 0, w, h);
}

//程序入口
int main(int argc, char* argv[]) {
    //设置当前工作目录,针对MAC OS X
    gltSetWorkingDirectory(argv[0]);
    
    //初始化GLUT库
    glutInit(&argc, argv);
    
    /*初始化渲染模式,其中标志GLUT_DOUBLE、GLUT_RGBA、GLUT_DEPTH、GLUT_STENCIL分别指
     双缓冲窗口、RGBA颜色模式、深度测试、模板缓冲区*/
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
    
    //初始化窗口大小
    glutInitWindowSize(800, 600);
    //创建窗口
    glutCreateWindow("OpenGL Scissor");
    
    //注册回调函数
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);
    
    //确保驱动程序的初始化中没有出现任何问题。
    GLenum err = glewInit();
    if(GLEW_OK != err) {
        fprintf(stderr, "glew error:%s\n", glewGetErrorString(err));
        return 1;
    }

    //进入调用循环
    glutMainLoop();
    return 0;
}

混合

核心源码:

//开启颜色混合
glEnable(GL_BLEND);
//配置混合方程式,默认为 GL_FUNC_ADD 方程
glBlendEquation(GL_FUNC_ADD);
//配置混合方程式混合因子
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//分别设置 RGB 通道和 Alpha 通道混合因子
glBlendFuncSeparate(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//改变常量颜色
glBlendColor(1.0f, 0.0f, 0.0f, 1.0f);
//关闭颜色混合
glDisable(GL_BLEND);

Demo 源码: 06-Blending

#include <GLTools.h>    // OpenGL toolkit
#include <GLShaderManager.h>
#include <glut/glut.h>

GLBatch squareBatch;
GLBatch greenBatch;
GLBatch redBatch;
GLBatch blueBatch;
GLBatch blackBatch;

GLShaderManager shaderManager;

GLfloat blockSize = 0.2f;
GLfloat vVerts[] = {
    -blockSize, -blockSize, 0.0f,
    blockSize, -blockSize, 0.0f,
    blockSize,  blockSize, 0.0f,
    -blockSize,  blockSize, 0.0f
};

//程序一次性初始化
void SetupRC() {
    //设置窗口背景为黑色
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f );
    
    //初始化着色器管理者
    shaderManager.InitializeStockShaders();
    
    //创建移动矩形批次
    squareBatch.Begin(GL_TRIANGLE_FAN, 4);
    squareBatch.CopyVertexData3f(vVerts);
    squareBatch.End();
    
    //绿色矩形批次
    GLfloat vBlock[] = {
        0.25f, 0.25f, 0.0f,
        0.75f, 0.25f, 0.0f,
        0.75f, 0.75f, 0.0f,
        0.25f, 0.75f, 0.0f
    };
    greenBatch.Begin(GL_TRIANGLE_FAN, 4);
    greenBatch.CopyVertexData3f(vBlock);
    greenBatch.End();
    
    //红色矩形批次
    GLfloat vBlock2[] = {
        -0.75f, 0.25f, 0.0f,
        -0.25f, 0.25f, 0.0f,
        -0.25f, 0.75f, 0.0f,
        -0.75f, 0.75f, 0.0f
    };
    redBatch.Begin(GL_TRIANGLE_FAN, 4);
    redBatch.CopyVertexData3f(vBlock2);
    redBatch.End();
    
    //蓝色矩形批次
    GLfloat vBlock3[] = {
        -0.75f, -0.75f, 0.0f,
        -0.25f, -0.75f, 0.0f,
        -0.25f, -0.25f, 0.0f,
        -0.75f, -0.25f, 0.0f
    };
    blueBatch.Begin(GL_TRIANGLE_FAN, 4);
    blueBatch.CopyVertexData3f(vBlock3);
    blueBatch.End();
    
    //黑色矩形批次
    GLfloat vBlock4[] = {
        0.25f, -0.75f, 0.0f,
        0.75f, -0.75f, 0.0f,
        0.75f, -0.25f, 0.0f,
        0.25f, -0.25f, 0.0f
    };
    blackBatch.Begin(GL_TRIANGLE_FAN, 4);
    blackBatch.CopyVertexData3f(vBlock4);
    blackBatch.End();
}

//特殊按钮监听
void SpecialKeys(int key, int x, int y) {
    GLfloat stepSize = 0.025f;
    
    //左上角的 X 坐标和右下角的 Y 坐标
    GLfloat blockX = vVerts[0];
    GLfloat blockY = vVerts[7];
    
    //根据移动方向移动位置
    switch (key) {
        case GLUT_KEY_UP: blockY += stepSize; break;
        case GLUT_KEY_DOWN: blockY -= stepSize; break;
        case GLUT_KEY_LEFT: blockX -= stepSize; break;
        case GLUT_KEY_RIGHT: blockX += stepSize; break;
        default: break;
    }
    
    //移动边界处理
    if(blockX < -1.0f) blockX = -1.0f;
    if(blockX > (1.0f - blockSize * 2)) blockX = 1.0f - blockSize * 2;;
    if(blockY < -1.0f + blockSize * 2)  blockY = -1.0f + blockSize * 2;
    if(blockY > 1.0f) blockY = 1.0f;
    
    //矩形四个顶点位置
    vVerts[0] = blockX;
    vVerts[1] = blockY - blockSize*2;
    vVerts[3] = blockX + blockSize*2;
    vVerts[4] = blockY - blockSize*2;
    vVerts[6] = blockX + blockSize*2;
    vVerts[7] = blockY;
    vVerts[9] = blockX;
    vVerts[10] = blockY;
    
    //批次顶点数据编号
    squareBatch.CopyVertexData3f(vVerts);
    
    //触发渲染
    glutPostRedisplay();
}

//渲染画面
void RenderScene(void) {
    //清理各个缓存区
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    
    //定义4种颜色
    GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 1.0f };
    GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f };
    GLfloat vBlue[] = { 0.0f, 0.0f, 1.0f, 0.6f };
    GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
    
    //画绿色矩形
    shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vGreen);
    greenBatch.Draw();
    
    //画红色矩形
    shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
    redBatch.Draw();
    
    //画蓝色矩形
    shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vBlue);
    blueBatch.Draw();
    
    //画黑色矩形
    shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vBlack);
    blackBatch.Draw();
    
    //开启颜色混合
    glEnable(GL_BLEND);
    //配置混合方程式
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    //画移动矩形,本身半透明蓝色
    shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vBlue);
    squareBatch.Draw();
    //关闭颜色混合
    glDisable(GL_BLEND);
    
    //将在后台缓冲区进行渲染,然后在结束时交换到前台
    glutSwapBuffers();
}

//窗口大小改变时接受新的宽度和高度
void ChangeSize(int w, int h) {
    
    //设置视图窗口位置
    glViewport(0, 0, w, h);
}

//程序入口
int main(int argc, char* argv[]) {
    //设置当前工作目录,针对MAC OS X
    gltSetWorkingDirectory(argv[0]);
    
    //初始化GLUT库
    glutInit(&argc, argv);
    
    /*初始化渲染模式,其中标志GLUT_DOUBLE、GLUT_RGBA、GLUT_DEPTH、GLUT_STENCIL分别指
     双缓冲窗口、RGBA颜色模式、深度测试、模板缓冲区*/
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
    
    //初始化窗口大小
    glutInitWindowSize(800, 600);
    //创建窗口
    glutCreateWindow("Move Block with Arrow Keys to see blending");
    
    //注册回调函数
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);
    glutSpecialFunc(SpecialKeys);
    
    //确保驱动程序的初始化中没有出现任何问题。
    GLenum err = glewInit();
    if(GLEW_OK != err) {
        fprintf(stderr, "glew error:%s\n", glewGetErrorString(err));
        return 1;
    }
    
    //初始化设置
    SetupRC();
    
    //进入调用循环
    glutMainLoop();
    return 0;
}

抗锯齿

核心代码:

//开启抗锯齿处理,必须先开启颜色混合模式
glBlendEquation(GL_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
//抗锯齿开启
glEnable(GL_POINT_SMOOTH);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_POLYGON_SMOOTH);
//设置抗锯齿处理达到效果最好(另外一个是效果最快)
glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
//关闭抗锯齿处理
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
glDisable(GL_POINT_SMOOTH);
glDisable(GL_POLYGON_SMOOTH);

Demo 源码: 07-Smoother

#include <GLTools.h>    // OpenGL toolkit
#include <GLFrustum.h>
#include <glut/glut.h>

GLShaderManager shaderManager;
GLFrustum viewFrustum;
GLBatch smallStarBatch;
GLBatch mediumStarBatch;
GLBatch largeStarBatch;
GLBatch mountainRangeBatch;
GLBatch moonBatch;

//常量宏
#define SMALL_STARS     100
#define MEDIUM_STARS     40
#define LARGE_STARS      15

#define SCREEN_X        800
#define SCREEN_Y        600

//点击菜单选项触发的回调方法
void ProcessMenu(int value) {
    switch(value) {
        case 1:
            //开启抗锯齿处理,必须先开启颜色混合模式
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
            glEnable(GL_BLEND);
            //点抗锯齿
            glEnable(GL_POINT_SMOOTH);
            glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
            //线抗锯齿
            glEnable(GL_LINE_SMOOTH);
            glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
            //多边形抗锯齿
            glEnable(GL_POLYGON_SMOOTH);
            glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
            break;
        case 2:
            //关闭抗锯齿处理
            glDisable(GL_BLEND);
            glDisable(GL_LINE_SMOOTH);
            glDisable(GL_POINT_SMOOTH);
            glDisable(GL_POLYGON_SMOOTH);
            break;
        default:
            break;
    }
    
    //触发渲染
    glutPostRedisplay();
}

//渲染画面
void RenderScene(void) {
    //清除缓存区
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    //设置着色器为单位黑色
    GLfloat vWhite [] = { 1.0f, 1.0f, 1.0f, 1.0f };
    shaderManager.UseStockShader(GLT_SHADER_FLAT, viewFrustum.GetProjectionMatrix(), vWhite);
    
    //画小点
    glPointSize(1.0f);
    smallStarBatch.Draw();
    
    //画大点
    glPointSize(4.0f);
    mediumStarBatch.Draw();
    
    //画超大点
    glPointSize(8.0f);
    largeStarBatch.Draw();
    
    //画月亮
    moonBatch.Draw();
    
    //画山的轮廓
    glLineWidth(3.5);
    mountainRangeBatch.Draw();
    
    //将在后台缓冲区进行渲染,然后在结束时交换到前台
    glutSwapBuffers();
}

//初始化小点批次
void SetupSmallStarBatch() {
    M3DVector3f vVerts[SMALL_STARS];
    for(int i = 0; i < SMALL_STARS; i++) {
        vVerts[i][0] = (GLfloat)(rand() % SCREEN_X);
        vVerts[i][1] = (GLfloat)(rand() % (SCREEN_Y - 100)) + 100.0f;
        vVerts[i][2] = 0.0f;
    }
    smallStarBatch.Begin(GL_POINTS, SMALL_STARS);
    smallStarBatch.CopyVertexData3f(vVerts);
    smallStarBatch.End();
}

//初始化大点批次
void SetupMeiumStarBatch() {
    M3DVector3f vVerts[MEDIUM_STARS];
    for(int i = 0; i < MEDIUM_STARS; i++) {
        vVerts[i][0] = (GLfloat)(rand() % SCREEN_X);
        vVerts[i][1] = (GLfloat)(rand() % (SCREEN_Y - 100)) + 100.0f;
        vVerts[i][2] = 0.0f;
    }

    mediumStarBatch.Begin(GL_POINTS, MEDIUM_STARS);
    mediumStarBatch.CopyVertexData3f(vVerts);
    mediumStarBatch.End();
}

//初始化超大点批次
void SetupLargeStarBatch() {
    M3DVector3f vVerts[LARGE_STARS];
    for(int i = 0; i < LARGE_STARS; i++) {
        vVerts[i][0] = (GLfloat)(rand() % SCREEN_X);
        vVerts[i][1] = (GLfloat)(rand() % (SCREEN_Y - 100)) + 100.0f;
        vVerts[i][2] = 0.0f;
    }
    
    largeStarBatch.Begin(GL_POINTS, LARGE_STARS);
    largeStarBatch.CopyVertexData3f(vVerts);
    largeStarBatch.End();
}

//初始化山轮廓批次
void SetupMountainRangeBatch() {
    M3DVector3f vMountains[12] = {
        0.0f, 25.0f, 0.0f,
        50.0f, 100.0f, 0.0f,
        100.0f, 25.0f, 0.0f,
        225.0f, 125.0f, 0.0f,
        300.0f, 50.0f, 0.0f,
        375.0f, 100.0f, 0.0f,
        460.0f, 25.0f, 0.0f,
        525.0f, 100.0f, 0.0f,
        600.0f, 20.0f, 0.0f,
        675.0f, 70.0f, 0.0f,
        750.0f, 25.0f, 0.0f,
        800.0f, 90.0f, 0.0f
    };
    
    mountainRangeBatch.Begin(GL_LINE_STRIP, 12);
    mountainRangeBatch.CopyVertexData3f(vMountains);
    mountainRangeBatch.End();
}

//初始化月亮批次
void SetupMoonBatch() {
    GLfloat x = 700.0f;
    GLfloat y = 500.0f;
    GLfloat r = 50.0f;
    M3DVector3f vVerts[SMALL_STARS];
    int nVerts = 0;
    vVerts[nVerts][0] = x;
    vVerts[nVerts][1] = y;
    vVerts[nVerts][2] = 0.0f;
    for(GLfloat angle = 0; angle < M3D_2PI; angle += 0.2f) {
        nVerts++;
        vVerts[nVerts][0] = x + float(cos(angle)) * r;
        vVerts[nVerts][1] = y + float(sin(angle)) * r;
        vVerts[nVerts][2] = 0.0f;
    }
    nVerts++;
    vVerts[nVerts][0] = x + r;;
    vVerts[nVerts][1] = y;
    vVerts[nVerts][2] = 0.0f;
    
    moonBatch.Begin(GL_TRIANGLE_FAN, 34);
    moonBatch.CopyVertexData3f(vVerts);
    moonBatch.End();
}

//程序化一次性初始化
void SetupRC() {
    //设置背景色为黑色
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f );
    
    //初始化着色器
    shaderManager.InitializeStockShaders();
    
    //初始化各个图元批次
    SetupSmallStarBatch();
    SetupMeiumStarBatch();
    SetupLargeStarBatch();
    SetupMountainRangeBatch();
    SetupMoonBatch();
}

//窗口大小改变时接受新的宽度和高度
void ChangeSize(int w, int h) {
    glViewport(0, 0, w, h);
    
    //正投影
    viewFrustum.SetOrthographic(0.0f, SCREEN_X, 0.0f, SCREEN_Y, -1.0f, 1.0f);
}

//程序入口
int main(int argc, char* argv[]) {
    //设置当前工作目录,针对MAC OS X
    gltSetWorkingDirectory(argv[0]);
    
    //GLUT初始化
    glutInit(&argc, argv);
    
    /*初始化渲染模式,其中标志GLUT_DOUBLE、GLUT_RGBA、GLUT_DEPTH、GLUT_STENCIL分别指
     双缓冲窗口、RGBA颜色模式、深度测试、模板缓冲区*/
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    
    //创建窗口大小、标题
    glutInitWindowSize(800, 600);
    glutCreateWindow("Smoothing Out The Jaggies");
    
    //创建菜单并绑定回调函数,添加选项,确定右键触发
    glutCreateMenu(ProcessMenu);
    glutAddMenuEntry("Antialiased Rendering",1);
    glutAddMenuEntry("Normal Rendering",2);
    glutAttachMenu(GLUT_RIGHT_BUTTON);
    
    //注册回调函数
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);
    
    //判断驱动是否正常
    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
        return 1;
    }
    
    //初始化
    SetupRC();
    
    //运行循环
    glutMainLoop();
    return 0;
}
开启抗锯齿前效果
开启抗锯齿后效果

上面的 Demo 源码全部都放在我的 github/OpenGLDemo 上,大家可以去下载和调试。

有什么问题可以在下方评论区提出,写得不好可以提出你的意见,我会合理采纳的,O(∩_∩)O哈哈~,求关注求赞

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容