OpenGL 學習 06 - 多邊形偏移/裁剪/混合/抗鋸齒

學習書籍: OpenGL 超級寶典(中文第五版) 密碼:fu4w
書籍源碼:OpenGL 超級寶典第五版源代碼 密碼:oyb4
環(huán)境搭建:OpenGL 學習 01 - Mac 搭建 OpenGL 環(huán)境

基本概念

多邊形偏移

上一節(jié)在 OpenGL 學習 05 - 花托 中,我們通過深度測試實現(xiàn)真實視覺并提高性能牲证,但會遇到一些麻煩胶滋,比如我們想將2個幾何圖形繪制在同一個位置量瓜,我們想要畫一架大飛機,然后在飛機上繪制一個五角星圖案妇汗,這叫做“貼花”孩革。這 2 個圖形的深度值 z 相同或者幾乎相同,這種情況稱為 深度值沖突 惶翻。

處理深度值沖突的方法:

  1. 手動調整 z 值進行一點點偏移姑蓝,但可能會出現(xiàn)圖形懸浮(不推薦)
  2. 利用 多邊形偏移 調節(jié)片段的深度值,但實際不改變 3D 空間物理位置(推薦)

應用到片段上的總偏移方程式如下吕粗,其中 DZ 是深度值相對多邊形屏幕區(qū)域的變化量纺荧,r 是使深度緩沖區(qū)值產生變化的最小值,這2個值都是 OpenGL 內部的值颅筋,我們不用關心宙暇,我們是通過控制 factor 和 units 達到效果:


// 設置多邊形偏移
void glPolygonOffset(GLfloat factor, GLfloat units);

裁剪

除了深度測試,還有一種提高渲染性能的方法议泵,那就是 只刷新屏幕上發(fā)生變化的部分占贫,即裁剪。OpenGL 允許我們在將要進行渲染的窗口中指定一個裁剪框先口,只刷新裁剪框里面的變化型奥。默認裁剪框和窗口大小一致,并不會進行裁剪測試碉京。

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

混合

通常情況下厢汹,OpenGL 渲染時會把顏色值放在顏色緩存區(qū)中,任何繪制操作都是完全覆蓋原來的顏色值谐宙,比如我們在一個紅色圖形前面畫一個藍色圖形烫葬,在重疊的部分,藍色覆蓋紅色卧惜。但如果我們想在重疊區(qū)顯示重疊顏色(比如紅藍混合色)怎么辦厘灼?這時就需要使用到 OpenGL 的混合功能。

目標顏色:已經(jīng)存儲在顏色緩沖區(qū)中的顏色
源顏色:將要加入進行混合的顏色
混合方程式:目標顏色和源顏色的組合方式咽瓷,用來生成混合后的顏色

其中 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寓免。這時我們就需要另外一個函數(shù) 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 混合的另外一種用途就是抗鋸齒蜈首。圖形邊緣會出現(xiàn)一些吸引眼睛的注意力而讓人感覺圖形不自然的像素點实抡,稱為鋸齒。我們需要盡可能的逼真欢策,尤其在游戲吆寨、模擬和藝術創(chuàng)造中。為了消除圖元之間的鋸齒猬腰,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);
//設置顏色緩沖區(qū)背景為紅色
glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
//裁剪出(x: 100, y: 100, w: 600, h: 400)區(qū)域
glScissor(100, 100, 600, 400);
//清空顏色緩存區(qū)缩擂,同步到后臺緩沖區(qū)鼠冕,注意這里會設置的是裁剪區(qū)域
glClear(GL_COLOR_BUFFER_BIT);
//關閉裁剪
glDisable(GL_SCISSOR_TEST);

Demo 源碼: 05-Scissor

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

//渲染畫面
void RenderScene(void) {
    
    //設置顏色緩沖區(qū)背景色為藍色
    glClearColor(0.0f, 0.0f, 1.0f, 0.0f);
    //清空顏色緩存區(qū),設置到后臺緩存區(qū)胯盯,執(zhí)行完這步才繪制了背景顏色
    glClear(GL_COLOR_BUFFER_BIT);
    //開啟裁剪
    glEnable(GL_SCISSOR_TEST);
    
    //設置顏色緩沖區(qū)背景色為紅色
    glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
    //裁剪出(x: 100, y: 100, w: 600, h: 400)區(qū)域
    glScissor(100, 100, 600, 400);
    //清空顏色緩存區(qū)懈费,設置到后臺緩沖區(qū),注意這里會設置的是裁剪區(qū)域
    glClear(GL_COLOR_BUFFER_BIT);
    
    //設置顏色緩沖區(qū)背景色為綠色
    glClearColor(0.0f, 1.0f, 0.0f, 0.0f);
    //裁剪出(x: 200, y: 200, w: 400, h: 200)區(qū)域
    glScissor(200, 200, 400, 200);
    //清空顏色緩存區(qū)博脑,設置到后臺緩沖區(qū)憎乙,注意這里會設置的是裁剪區(qū)域
    glClear(GL_COLOR_BUFFER_BIT);
    
    //關閉裁剪
    glDisable(GL_SCISSOR_TEST);
    //將在后臺緩沖區(qū)進行渲染,然后在結束時交換到前臺
    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顏色模式、深度測試梢什、模板緩沖區(qū)*/
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
    
    //初始化窗口大小
    glutInitWindowSize(800, 600);
    //創(chuàng)建窗口
    glutCreateWindow("OpenGL Scissor");
    
    //注冊回調函數(shù)
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);
    
    //確保驅動程序的初始化中沒有出現(xiàn)任何問題奠蹬。
    GLenum err = glewInit();
    if(GLEW_OK != err) {
        fprintf(stderr, "glew error:%s\n", glewGetErrorString(err));
        return 1;
    }

    //進入調用循環(huán)
    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();
    
    //創(chuàng)建移動矩形批次
    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();
}

//特殊按鈕監(jiān)聽
void SpecialKeys(int key, int x, int y) {
    GLfloat stepSize = 0.025f;
    
    //左上角的 X 坐標和右下角的 Y 坐標
    GLfloat blockX = vVerts[0];
    GLfloat blockY = vVerts[7];
    
    //根據(jù)移動方向移動位置
    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;
    
    //批次頂點數(shù)據(jù)編號
    squareBatch.CopyVertexData3f(vVerts);
    
    //觸發(fā)渲染
    glutPostRedisplay();
}

//渲染畫面
void RenderScene(void) {
    //清理各個緩存區(qū)
    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);
    
    //將在后臺緩沖區(qū)進行渲染囤躁,然后在結束時交換到前臺
    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顏色模式、深度測試中姜、模板緩沖區(qū)*/
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
    
    //初始化窗口大小
    glutInitWindowSize(800, 600);
    //創(chuàng)建窗口
    glutCreateWindow("Move Block with Arrow Keys to see blending");
    
    //注冊回調函數(shù)
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);
    glutSpecialFunc(SpecialKeys);
    
    //確保驅動程序的初始化中沒有出現(xiàn)任何問題消玄。
    GLenum err = glewInit();
    if(GLEW_OK != err) {
        fprintf(stderr, "glew error:%s\n", glewGetErrorString(err));
        return 1;
    }
    
    //初始化設置
    SetupRC();
    
    //進入調用循環(huán)
    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

//點擊菜單選項觸發(fā)的回調方法
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;
    }
    
    //觸發(fā)渲染
    glutPostRedisplay();
}

//渲染畫面
void RenderScene(void) {
    //清除緩存區(qū)
    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();
    
    //將在后臺緩沖區(qū)進行渲染翩瓜,然后在結束時交換到前臺
    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顏色模式、深度測試蕊蝗、模板緩沖區(qū)*/
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    
    //創(chuàng)建窗口大小仅乓、標題
    glutInitWindowSize(800, 600);
    glutCreateWindow("Smoothing Out The Jaggies");
    
    //創(chuàng)建菜單并綁定回調函數(shù),添加選項蓬戚,確定右鍵觸發(fā)
    glutCreateMenu(ProcessMenu);
    glutAddMenuEntry("Antialiased Rendering",1);
    glutAddMenuEntry("Normal Rendering",2);
    glutAttachMenu(GLUT_RIGHT_BUTTON);
    
    //注冊回調函數(shù)
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);
    
    //判斷驅動是否正常
    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
        return 1;
    }
    
    //初始化
    SetupRC();
    
    //運行循環(huán)
    glutMainLoop();
    return 0;
}
開啟抗鋸齒前效果
開啟抗鋸齒后效果

上面的 Demo 源碼全部都放在我的 github/OpenGLDemo 上夸楣,大家可以去下載和調試。

有什么問題可以在下方評論區(qū)提出子漩,寫得不好可以提出你的意見豫喧,我會合理采納的,O(∩_∩)O哈哈~幢泼,求關注求贊

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末紧显,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子旭绒,更是在濱河造成了極大的恐慌鸟妙,老刑警劉巖焦人,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異重父,居然都是意外死亡花椭,警方通過查閱死者的電腦和手機伐债,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門补君,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蹄殃,你說我怎么就攤上這事郭厌〈螅” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵折柠,是天一觀的道長宾娜。 經(jīng)常有香客問我,道長扇售,這世上最難降的妖魔是什么前塔? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮承冰,結果婚禮上华弓,老公的妹妹穿的比我還像新娘。我一直安慰自己困乒,他們只是感情好寂屏,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著娜搂,像睡著了一般迁霎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上涌攻,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天欧引,我揣著相機與錄音频伤,去河邊找鬼恳谎。 笑死,一個胖子當著我的面吹牛憋肖,可吹牛的內容都是我干的因痛。 我是一名探鬼主播,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼岸更,長吁一口氣:“原來是場噩夢啊……” “哼鸵膏!你這毒婦竟也來了?” 一聲冷哼從身側響起怎炊,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤谭企,失蹤者是張志新(化名)和其女友劉穎廓译,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體债查,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡非区,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了盹廷。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片征绸。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖俄占,靈堂內的尸體忽然破棺而出管怠,到底是詐尸還是另有隱情,我是刑警寧澤缸榄,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布渤弛,位于F島的核電站,受9級特大地震影響甚带,放射性物質發(fā)生泄漏暮芭。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一欲低、第九天 我趴在偏房一處隱蔽的房頂上張望辕宏。 院中可真熱鬧,春花似錦砾莱、人聲如沸瑞筐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽聚假。三九已至,卻和暖如春闰非,著一層夾襖步出監(jiān)牢的瞬間膘格,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工财松, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留瘪贱,地道東北人。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓辆毡,卻偏偏與公主長得像菜秦,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子舶掖,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內容