OpenGL(2)-初探

了解了OpenGL的相關(guān)概念,我們?cè)偻ㄟ^兩個(gè)小示例來看看OpenGL的相關(guān)API以及圖形的繪制流程。

在實(shí)現(xiàn)示例之前,我們需要配置相關(guān)的環(huán)境:

  • 添加OpenGl.frameworkGLUT.framework系統(tǒng)庫,添加libGLTools.a靜態(tài)庫,
  • 引入CLTools、glew,并且在Build SettingsHeader Search Paths中添加CLTools的路徑,
  • 移除原來的main、AppDelegateViewController文件,創(chuàng)建一個(gè)main.cpp文件。

這樣,我們就可以在main.cpp實(shí)現(xiàn)相關(guān)功能了。

三角形

引入工具類

#include "GLTools.h"
#include <GLUT/GLUT.h>
#include "GLShaderManager.h"
  • GLTools.h:包含了?部分GLTools中類似C語言的獨(dú)立函數(shù)
  • GLUT/GLUT.h:使用glut
  • GLShaderManager.h:著?器管理器,允許我們使用并管理著色器,另外還提供了一組存儲(chǔ)著色器,能夠進(jìn)行一些基本的渲染操作

創(chuàng)建全局變量

著色管理器和GL批處理類:

GLShaderManager shaderManager;
GLBatch glBatch;

代碼實(shí)現(xiàn)

    1. 初始化、基礎(chǔ)設(shè)置操作
    1. 注冊(cè)窗口調(diào)整和渲染的回調(diào)函數(shù)
    1. 配置三角形的頂點(diǎn)數(shù)據(jù)
int main(int argc,char* argv[]) {
    
    // 設(shè)置當(dāng)前工作目錄,針對(duì)MAC OS X
    gltSetWorkingDirectory(argv[0]);
    
    // 初始化GLUT庫
    glutInit(&argc, argv);
    
    // 初始化雙緩沖窗口
    // GLUT_DOUBLE表示雙緩沖窗口、GLUT_RGBA表示RGBA顏色模式、GLUT_DEPTH表示深度測(cè)試、GLUT_STENCIL表示模板緩沖區(qū)
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
    
    // 設(shè)置GLUT窗口大小、標(biāo)題
    glutInitWindowSize(800, 800);
    glutCreateWindow("Triangle");
    
    // 注冊(cè)回調(diào)函數(shù)
    // 窗口調(diào)整
    glutReshapeFunc(reshapeAction);
    // 渲染操作
    glutDisplayFunc(renderAction);
    
    // 驅(qū)動(dòng)程序的初始化中容錯(cuò)判斷
    GLenum error = glewInit();
    if(GLEW_OK != error) {
        fprintf(stderr,"glew error:%s\n",glewGetErrorString(error));
        return 1;
    }
    
    // 初始化設(shè)置
    setupTriangle();
    
    glutMainLoop();
    
    return 0;
}

void setupTriangle() {
    // 設(shè)置窗口背景顏色
    glClearColor(1, 1, 1, 1);
    
    // 初始化著色管理器
    shaderManager.InitializeStockShaders();
    
    // 設(shè)置三角形的頂點(diǎn)坐標(biāo) x y z
    GLfloat vertCoordinates[] = {
        -0.5f, 0.0f, 0.0f,
         0.5f, 0.0f, 0.0f,
         0.0f, 0.5f, 0.0f,
    };
    
    // 批次處理
    glBatch.Begin(GL_TRIANGLES, 3);
    glBatch.CopyVertexData3f(vertCoordinates);
    glBatch.End();
}

// 窗口調(diào)整
void reshapeAction(int width, int height) {
    // glViewport (GLint x, GLint y, GLsizei width, GLsizei height)
    // x,y 以像素為單位,指定了窗口的左下角位置。width,height表示視口矩形的寬度和高度,根據(jù)窗口的實(shí)時(shí)變化重繪窗口。
    glViewport(0, 0, width, height);
}

// 渲染
void renderAction() {
    
    // 清除一個(gè)或一組特定的緩沖區(qū)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    // 設(shè)置顏色
    GLfloat vRed[] = {1.0, 0.0, 0.0, 1.0};

    // 著色管理器使用存儲(chǔ)著色器進(jìn)行渲染
    shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
    
    glBatch.Draw();
    
    // 雙緩沖處理,交換緩沖區(qū)指針
    glutSwapBuffers();
}

固定管線存儲(chǔ)著色器

  1. GLT_SHADER_IDENTITY:?jiǎn)挝恢?單元著色器

使用默認(rèn)笛卡爾坐標(biāo)系,坐標(biāo)范圍為(-1.0,1.0),所有片段都應(yīng)用同一種顏色。使用方法:

shaderManager.UserStockShader(GLT_SHADER_IDENTITY, GLfloat vColor[4]);
  • 參數(shù)1:著色器類型
  • 參數(shù)2:顏色參數(shù)
  1. GLT_SHADER_FLAT:平面著色器

用以模型/投影變化。可以為幾何圖形變化指定一個(gè)4*4變換矩陣,該矩陣被稱為“模型視圖投影矩陣”。使用方法:

shaderManager.UserStockShader(GLT_SHADER_FLAT,GLfloat mvp[16],GLfloat vColor[4]);
  • 參數(shù)1:著色器類型
  • 參數(shù)2:4*4變換矩陣
  • 參數(shù)3:顏色參數(shù)
  1. GLT_SHADER_SHADED:上色著色器

用以將顏色平滑的插入到頂點(diǎn)之間,進(jìn)行平滑著色。使用方法:

shaderManager.UserStockShader(GLT_SHADER_SHADED,GLfloat vColor[4]);
  • 參數(shù)1:著色器類型
  • 參數(shù)2:顏色參數(shù)
  1. GLT_SHADER_DEFAULT_LIGHT:默認(rèn)光源著色器

用來為圖形產(chǎn)生陰影和光照效果。使用方法:

shaderManager.UserStockShader(GLT_SHADER_DEFAULT_LIGHT,GLfloat mvMatrix[16],GLfloat pMatrix[16],GLfloat vColor[4]);
  • 參數(shù)1:著色器類型
  • 參數(shù)2:模型視圖矩陣
  • 參數(shù)3:投影矩陣
  • 參數(shù)4:顏色參數(shù)
  1. GLT_SHADER_POINT_LIGHT_DIFF:點(diǎn)光源著色器

用來為圖形產(chǎn)生陰影和光照效果。與默認(rèn)光源著色器非常類似,區(qū)別在與點(diǎn)光源著色器可以指定光源位置。使用方法:

shaderManager.UserStockShader(GLT_SHADER_DEFAULT_LIGHT,GLfloat mvMatrix[16],GLfloat pMatrix[16],GLfloat vColor[4]);
  • 參數(shù)1:著色器類型
  • 參數(shù)2:模型視圖矩陣
  • 參數(shù)3:投影矩陣
  • 參數(shù)4:視點(diǎn)坐標(biāo)光源位置
  • 參數(shù)5:顏色參數(shù)
  1. GLT_SHADER_TEXTURE_REPLACE:紋理替換矩陣著色器

通過給定的模型視圖投影矩陣,使用紋理單元來進(jìn)行填充,其每個(gè)像素點(diǎn)的顏色是從紋理中獲取。使用方法:

shaderManager.UserStockShader(GLT_SHADER_TEXTURE_REPLACE,GLfloat mvMatrix[16],GLint nTextureUnit);
  • 參數(shù)1:著色器類型
  • 參數(shù)2:模型視圖矩陣
  • 參數(shù)3:紋理單元
  1. GLT_SHADER_TEXTURE_MODULATE:紋理調(diào)整著色器

通過給定的模型視圖投影矩陣,將一個(gè)基本色乘以一個(gè)取自紋理單元nTextureUnit的紋理,將顏色與紋理進(jìn)行混合后填充到片段中。使用方法:

shaderManager.UserStockShader(GLT_SHADER_TEXTURE_MODULATE,GLfloat mvMatrix[16],GLfloat vColor[4],GLint nTextureUnit);
  • 參數(shù)1:著色器類型
  • 參數(shù)2:模型視圖矩陣
  • 參數(shù)3:顏色參數(shù)
  • 參數(shù)4:紋理單元
  1. GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF:紋理光源著色器

通過給定的模型視圖投影矩陣,將一個(gè)紋理通過漫反射照明計(jì)算進(jìn)行調(diào)整(相乘)。使用方法:

shaderManager.UserStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIEF,GLfloat mvMatrix[16],GLfloat pMatrix[16],GLfloat vLightPos[3],GLfloat vBaseColor[4],GLint nTextureUnit);
  • 參數(shù)1:著色器類型
  • 參數(shù)2:模型視圖矩陣
  • 參數(shù)3:視覺空間中的光源位置
  • 參數(shù)4:幾何圖形的基本色
  • 參數(shù)5:需要處理的紋理單元

設(shè)置初始顯示模式

對(duì)應(yīng)宏定義 含義
GLUT_RGB 0x0000 指定 RGB 顏色模式的窗口
GLUT_RGBA 0x0000 指定 RGBA 顏色模式的窗口
GLUT_INDEX 0x0001 指定顏色索引模式的窗口
GLUT_SINGLE 0x0000 指定單緩存窗口
GLUT_DOUBLE 0x0002 指定雙緩存窗口
GLUT_ACCUM 0x0004 窗口使用累加緩存
GLUT_ALPHA 0x0008 窗口的顏色分量包含 alpha 值
GLUT_DEPTH 0x0010 窗口使用深度緩存
GLUT_STENCIL 0x0020 窗口使用模板緩存
GLUT_MULTISAMPLE 0x0080 指定支持多樣本功能的窗口
GLUT_STEREO 0x0100 指定立體窗口
GLUT_LUMINANCE 0x0200 窗口使用亮度顏色模型

幾何圖元

  • GL_POINTS:點(diǎn)
  • GL_LINES:線段,二個(gè)點(diǎn)確定線段
  • GL_LINE_STRIP:第一個(gè)點(diǎn)依次連接的線段
  • GL_LINE_LOOP:和GL_LINE_STRIP相同,但首尾連接,形成環(huán)狀
  • GL_POLYGON:多邊形
  • GL_QUADS:由四個(gè)點(diǎn)組成一個(gè)四邊形
  • GL_QUADS_STRIP:四邊形帶
  • GL_TRIANGLES:三角形,三個(gè)點(diǎn)確定
  • GL_TRIANGLE_STRIP:共用一個(gè)條帶上的頂點(diǎn)的一組三角形
  • GL_TRIANGLE_FAN:以一個(gè)原點(diǎn)為中心呈扇形排列,公共相鄰頂點(diǎn)的一組三角形
幾何圖元.png

可移動(dòng)的正方形

渲染矩形和渲染三角形在初始化設(shè)置上基本一樣。實(shí)現(xiàn)矩形可以通過修改幾何圖元的類型即可,下面我們提供兩種思路,一種是使用批處理類渲染三角形的方式(GL_TRIANGLES),將兩個(gè)三角形拼接成矩形,這樣需要6個(gè)頂點(diǎn);另一種是直接使用批處理類渲染矩形的方式(GL_QUADS或者GL_TRIANGLE_FAN),需要4個(gè)頂點(diǎn)。

GLfloat squareEdge = 0.1;
// 給定初始坐標(biāo)
GLfloat vVerts[] = {
        -squareEdge, -squareEdge, 0.0,
        squareEdge,  -squareEdge, 0.0,
        squareEdge,  squareEdge,  0.0,
        -squareEdge, squareEdge,  0.0
};

// 偏移量
GLfloat xPos = 0.0;
GLfloat yPos = 0.0;

void setupSquare() {
    glClearColor(1, 1, 1, 1);
    
    // 初始化著色管理器
    shaderManager.InitializeStockShaders();
    
    // 批次類處理設(shè)置為矩形
    glBatch.Begin(GL_TRIANGLE_FAN, 4);
    glBatch.CopyVertexData3f(vVerts);
    glBatch.End();
}

由于我們需要通過鍵盤控制所繪制矩形的位置,所以我們需要監(jiān)聽鍵盤的輸入,并且修改矩形的位置重新渲染。

// 注冊(cè)鍵盤的回調(diào)
glutSpecialFunc(squareSpecialKey);

此處,我們使用鍵盤的上下左右鍵來移動(dòng)矩形。這里需要做個(gè)特殊處理,當(dāng)矩形移動(dòng)到窗口的邊界時(shí),就需要停止繼續(xù)移動(dòng)。注意,這里每次只響應(yīng)一個(gè)鍵。

void squareSpecialKey(int key, int x, int y) {
    // 每次移動(dòng)的步長(zhǎng)(距離)
    GLfloat stepSize = 0.025;

    // 只響應(yīng)上下左右鍵
    if (key == GLUT_KEY_UP || key == GLUT_KEY_DOWN || key == GLUT_KEY_LEFT || key == GLUT_KEY_RIGHT) {
        switch (key) {
            case GLUT_KEY_UP:
                yPos += stepSize;
                break;
            case GLUT_KEY_DOWN:
                yPos -= stepSize;
                break;
            case GLUT_KEY_LEFT:
                xPos -= stepSize;
                break;
            case GLUT_KEY_RIGHT:
                xPos += stepSize;
                break;
            default:
                break;
        }
        
        // 邊界檢測(cè)
        // -x
        if (xPos < -1.0 + squareEdge) {
            xPos = -1.0 + squareEdge;
        }
        // x
        if (xPos > 1.0 - squareEdge) {
            xPos = 1.0 - squareEdge;
        }
        // -y
        if (yPos < -1.0 + squareEdge) {
            yPos = -1.0 + squareEdge;
        }
        // y
        if (yPos > 1.0 - squareEdge) {
            yPos = 1.0 - squareEdge;
        }
        
        glutPostRedisplay();
    }
}

下面就是渲染過程了,考慮到每次移動(dòng)都需要修改矩陣的坐標(biāo),我們可以使用平面著色器,將新的坐標(biāo)矩陣通過變換之后,直接傳給著色器管理器即可。

void squareRender() {
    
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    // 設(shè)置顏色
    GLfloat vRed[] = {1.0, 0.0, 0.0, 1.0};
    
    // 矩陣變化 對(duì)原來矩形的頂點(diǎn)數(shù)組進(jìn)行變換 將變換之后的結(jié)果存入mTransfromMatrix
    M3DMatrix44f mTransfromMatrix;
    m3dTranslationMatrix44(mTransfromMatrix, xPos, yPos, 0.0);
    
    shaderManager.UseStockShader(GLT_SHADER_FLAT, mTransfromMatrix, vRed);
    glBatch.Draw();
    glutSwapBuffers();
}

渲染一個(gè)圓形,我們可以使用幾何圖元GL_POLYGON,也就是從圓周上選定無限多個(gè)點(diǎn)作為頂點(diǎn),把這些頂點(diǎn)連接起來,即可組成一個(gè)圓。下面示例中,我們選定了10000個(gè)頂點(diǎn)。

int n = 10000;
GLfloat PI = 3.1415926;
// 半徑
GLfloat r = 0.5;

void setupCircle() {
    // 設(shè)置窗口背景顏色
    glClearColor(1, 1, 1, 1);
    
    // 初始化著色管理器
    shaderManager.InitializeStockShaders();
    
    GLfloat vVerts[30000] = {0};
    
    // 計(jì)算頂點(diǎn)
    for (int i = 0; i < n; i++) {
        vVerts[i*3] = r * cos(2 * PI * i / n);
        vVerts[i*3+1] = r * sin(2 * PI * i / n);
        vVerts[i*3+2] = 0;
    }
    
    // 批次處理
    glBatch.Begin(GL_POLYGON, n);
    glBatch.CopyVertexData3f(vVerts);
    glBatch.End();
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容