OpenGL->圖元解析、深度測試、正背面剔除、裁剪、混合

網格狀甜甜圈

這種圖形是如何畫出來的呢?帶著這個疑問我們來研究一下子?

下面首下看下OpenGL的渲染流程來解答這個問題?


OpenGL渲染流程圖.001.jpeg

在上圖中屬性、uniform值、紋理、輸出是這個流程的關鍵因素我們先簡單了解下:

屬性:就是對每一個頂點都要作改變的數據元素。實際上,頂點位置本身就是一個屬性。屬性值可以是浮點數、整數、布爾數據。
屬性總是以四維向量的形式進行內部存儲的,即使我們不會使用所有的4個分量。一個頂點位置可能存儲(x,y,z),將占有4個分量中的3個。
實際上如果是在平面情況下:只要在xy平面上就能繪制,那么Z分量就會自動設置為0;
屬性還可以是:紋理坐標、顏色值、關照計算表面法線
在頂點程序(shader渲染)可以代表你想要的任何意義。因為都是你設定的。
屬性會從本地客戶機內存中復制存儲在圖形硬件中的一個緩沖區上。這些屬性只提供給頂點著色器使用,對于片元著色器木有太大意義。

注意:這些屬性對每個頂點都要做改變,但并不意味著它們的值不能重復。通常情況下,它們都是不一樣的,但有可能整個數組都是同一值的情況。

Uniform值

屬性是一種對整個批次屬性都取統一值的單一值。它是不變的。通過設置uniform變量就緊接著發送一個圖元批次命令,Uniform變量實際上可以無數次限制地使用,設置一個應用于整個表面的單個顏色值,還可以設置一個時間值。在每次渲染某種類型的頂點動畫時修改它。

注意:這里的uniform 變量每個批次改變一次,而不是每個頂點改變一次。
uniform變量最常見的應用是在頂點渲染中設置變換矩陣
與屬性相同點:可以是浮點值、整數、布爾值
與屬性不同點:頂點著色器和片元著色器都可以使用uniform變量。uniform 變量還可以是標量類型、矢量類型、uniform矩陣。
紋理

傳遞給著色器的第三種數據類型:紋理數據

在頂點著色器、片段著色器中都可以對紋理數據進行采樣和篩選。
典型的應用場景:片段著色器對一個紋理值進行采樣,然后在一個三角形表面應用渲染紋理數據。
紋理數據,不僅僅表現在圖形,很多圖形文件格式都是以無符號字節(每個顏色通道8位)形式對顏色分量進行存儲的。
輸出

在圖表中第四種數據類型是輸出(out);輸出數據是作為一個階段著色器的輸出定義的,二后續階段的著色器則作為輸入定義。
輸出數據可以簡單的從一個階段傳遞到下一個階段,也可以用不同的方式插入。
客戶端的代碼接觸不到這些內部變量我們的OpenGL開發暫時接觸不到。

7種基本的圖元
OpenGL-7中基本圖元.001.jpeg
  • 下面直接上代碼查看圖元相關的內容:
#include <stdio.h>
#include "GLTools.h"
#include "GLMatrixStack.h"
#include "GLFrame.h"
#include "GLFrustum.h"
#include "GLBatch.h"
#include "GLGeometryTransform.h"

#include <math.h>
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif

GLShaderManager          shaderManager;      //存儲著色器管理工具類
GLMatrixStack            projectionMatrix;   //投影矩陣
GLMatrixStack            modelViewMatrix;    //模型視圖矩陣
GLFrame                  cameraFrame;        //設置觀察者視圖坐標
GLFrame                  objectFrame;        //設置圖形環繞時,視圖坐標
//投影矩陣
GLFrustum                viewFrustum;        //設置圖元繪制時的投影方式


//容器類(7種不同的圖元對應7種容器對象)
GLBatch              pointBatch;
GLBatch              lineBatch;
GLBatch              lineStripBatch;
GLBatch              lineLoopBatch;
GLBatch              triangleBatch;
GLBatch              triangleStripBatch;
GLBatch              triangleFanBatch;

//幾何變換管道
GLGeometryTransform  transformPipeline;
GLfloat vGreen[] = {0.0f,1.0,0.0f,1.0f};
GLfloat vBlack[] = {0.0f,0.0f,0.0f,1.0f};

//跟蹤效果步驟
int nStep = 0;


void ChangeSize(int w,int h){
    glViewport(0, 0, w,h);
    //創建投影矩陣,并將它載入投影矩陣堆棧中
    viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0, 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_LIINE_LOOP");
            break;
        case 4:
            glutSetWindowTitle("GL_TRIANGLES");
            break;
        case 5:
            glutSetWindowTitle("GL_TRIANGLE_STRIP");
            break;
        case 6:
            glutSetWindowTitle("GL_TRIANGLE_FAN");
            break;
        default:
            break;
    }
    glutPostRedisplay();//重新展示窗口大小
}
void  SetupRC(){
    //灰色背景
    glClearColor(0.7f, 0.8f,0.9f, 1.0f);//存儲著色器的初始化
    shaderManager.InitializeStockShaders();
    glEnable(GL_DEPTH_TEST);//開啟深度測試
    //設置變換管線 以使用兩個矩陣堆棧
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
    cameraFrame.MoveForward(-15.0f);
    
    GLfloat vCoast[9] = {
      3,3,0,
      0,3,0,
      3,0,0
    };
    //用點的形式
    pointBatch.Begin(GL_POINTS, 3);
    pointBatch.CopyVertexData3f(vCoast);//復制頂點坐標
    pointBatch.End();
    
    //用線的形式
    lineBatch.Begin(GL_LINES, 3);
    lineBatch.CopyVertexData3f(vCoast  );
    lineBatch.End();
    
    //通過線帶的形式
    lineStripBatch.Begin(GL_LINE_STRIP, 3);
    lineStripBatch.CopyVertexData3f(vCoast);
    lineStripBatch.End();
    
    //通過線環的形式
    lineLoopBatch.Begin(GL_LINE_LOOP, 3);
    lineLoopBatch.CopyVertexData3f(vCoast);//復制頂點數據
    lineLoopBatch.End();
    
    //通過三角形創建金字塔
    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.0
    };
    //GL_TRIANGLES 每3個頂點定義一個新的三角形
    triangleBatch.Begin(GL_TRIANGLES, 12);
    triangleBatch.CopyVertexData3f(vPyramid);
    triangleBatch.End();
    
    
    //三角形扇形 --> 六邊形
    GLfloat vPoints[100][3];
    int nVerts = 0;
    //半徑
    GLfloat r = 3.0f;
    //原點(x,y,z) = (0,0,0)
    vPoints[nVerts][0] = 0.0f;
    vPoints[nVerts][1] = 0.0f;
    vPoints[nVerts][2] = 0.0f;
    
    //M3D_2PI 就是2Pi的意思,就一個圓的意思 繪制圓形
    for (GLfloat angle= 0; angle < M3D_2PI; angle+= M3D_2PI/6.0f) {
        //數組下標自增,每自增一次就是表示一個頂點
        nVerts ++;
        /*
         弧長=半徑* 角度,這里的角度是弧度制,不是平時的角度制
         既然知道了cos值,那么角度= arccos,求一個反三角函數就行了
         */
        //x點坐標 cos(angle) * 半徑
        vPoints[nVerts][0] = float(cos(angle)) * r;
        //y點坐標 sin(angle) * 半徑
        vPoints[nVerts][1] = float(sin(angle)) * r;
        //z點坐標
        vPoints[nVerts][2] = - 0.5f;
        
    }
    
    //結束扇形 前面一共繪制7個頂點(包括圓心)
    //添加閉合的終點
    
    nVerts ++;
    vPoints[nVerts][0]  = r;
    vPoints[nVerts][1]  = 0;
    vPoints[nVerts][2]  = 0.0f;
    
    //加載
    triangleFanBatch.Begin(GL_TRIANGLE_FAN, 8);
    triangleFanBatch.CopyVertexData3f(vPoints);
    triangleFanBatch.End();
    
    
    //三角形帶,一個小環或圓柱段
    //頂點下標
    int iCounter = 0;
    //半徑
    GLfloat radius = 3.0f;
    //從0度~360度,以0.3弧度為步長
    for(GLfloat angle = 0.0f; angle <= (2.0f*M3D_PI); angle += 0.3f)
    {
        //獲取圓形的頂點的X,Y
        GLfloat x = radius * sin(angle);
        GLfloat y = radius * cos(angle);
        
        //繪制2個三角形(他們的x,y頂點一樣,只是z點不一樣)
        vPoints[iCounter][0] = x;
        vPoints[iCounter][1] = y;
        vPoints[iCounter][2] = -0.5;
        iCounter++;
        
        vPoints[iCounter][0] = x;
        vPoints[iCounter][1] = y;
        vPoints[iCounter][2] = 0.5;
        iCounter++;
    }
    
    // 關閉循環
    //結束循環,在循環位置生成2個三角形
    vPoints[iCounter][0] = vPoints[0][0];
    vPoints[iCounter][1] = vPoints[0][1];
    vPoints[iCounter][2] = -0.5;
    iCounter++;
    
    vPoints[iCounter][0] = vPoints[1][0];
    vPoints[iCounter][1] = vPoints[1][1];
    vPoints[iCounter][2] = 0.5;
    iCounter++;
    
    // GL_TRIANGLE_STRIP 共用一個條帶(strip)上的頂點的一組三角形
    triangleStripBatch.Begin(GL_TRIANGLE_STRIP, iCounter);
    triangleStripBatch.CopyVertexData3f(vPoints);
    triangleStripBatch.End();
    
}
void DrawWireFramedBatch(GLBatch *pBatch){
   /*
    GLShaderManager 中的Uniform 值---平面著色器
    參數1:平面著色器
    參數2:運行為幾何圖形變換指定 一個 4 * 4 變換矩陣
            ---transformPipeline 變換管線(指定連個矩陣堆棧)
    */ shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vGreen);
    pBatch->Draw();
    
    //畫黑色邊框 偏移深度,在同一位置需要繪制填充和邊線 會產生z沖突,所以需要偏移
    glPolygonOffset(-1.0f, -1.0f);
    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(5.5f);
    
   /*
    GLShaderManager 中的Uniform值--平面著色器
    參數1:平面著色器
    參數2:運行為幾何圖形變換指定一個 4 * 4 變換矩陣
    
    */
 shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.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);
    
    //只要使用GetMatrix函數就可以獲取矩陣堆棧頂部的值,這個函數可以進行2次重載
    //使用GLShaderManager 或者獲取頂部矩陣的頂點副本數據
    M3DMatrix44f mObjectFrame;
    objectFrame.GetMatrix(mObjectFrame);
    
    //矩陣乘以矩陣堆棧的頂部矩陣 想乘的結果隨后簡存在堆棧的頂部
    modelViewMatrix.MultMatrix(mObjectFrame);
    
 shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.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:
            DrawWireFramedBatch(&triangleBatch);
            break;
        case 5:
            DrawWireFramedBatch(&triangleFanBatch);
            break;
        case 6:
            DrawWireFramedBatch(&triangleStripBatch);
            break;
    }
    //還原到以前的模型視圖矩陣(單位矩陣) 繪制完畢 還原矩陣
    modelViewMatrix.PopMatrix();
    //進行緩沖區的交換
    glutSwapBuffers();
}


//特殊鍵位處理
void SpecialKeys(int key, int x ,int y){
    if (key == GLUT_KEY_UP) {
        //圍繞一個指定的X Y Z軸旋轉 弧度->度數的方法
        objectFrame.RotateWorld(m3dDegToRad(-0.5f), 1.0f, 0.0f, 0.0f);
    }
    if (key == GLUT_KEY_DOWN) {
        objectFrame.RotateWorld(m3dDegToRad(5.0f), 1.0, 0.0f, 0.0f);
    }
    if (key == GLUT_KEY_LEFT) {
        objectFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0, 1.0f, 0.0);
    }
    if (key == GLUT_KEY_RIGHT) {
        objectFrame.RotateWorld(m3dDegToRad(5.0f), 0.0f, 1.0f, 0.0f);
    }
    glutPostRedisplay();
}
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);
    
    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW ERROR:%s\n",glewGetString(err));
        return 1;
    }
    //繪制
    SetupRC();
    glutMainLoop();
    return 0;
}

下面是甜甜圈的設置:

  • 剛開始設置的時候,可以看到甜甜圈是凌亂的,有黑色的還有切割狀態的?因為使用點光源著色器看到的3D場景就會有陰影的出現,觀察一個物體那些事可見的?那些是不可見的??
解決方法?
  • 油畫算法:先繪制場景中離觀察者比較遠的物體,在繪制比較近的物體,弊端:如果幾個圖像相互交叉有該怎么辦?
方法二:
  • 正背面剔除:OpenGL可以做到檢查所有正面朝向觀察者的面,并渲染他們,從而丟棄背面朝向他們的面,可以節約片元著色器的性能
深度
  • 深度其實就是該像素點在3D世界中距離攝像機的距離,Z值
深度緩沖區
  • 深度緩沖區就是一塊內存區域,專門存儲每個像素點(繪制在屏幕上的深度值)深度值越大,則離攝像機越遠 在不使用深度測試的時候,如果我們先繪制一個距離比較近的物體,在繪制距離比較遠的物體,則距離遠的位圖因為后繪制,會把距離近的物體覆蓋掉,有了深度緩沖區后,繪制物體的順序就不那么重要了,實際上,只要存在深度緩沖區,OpenGL都會把像素的深度值寫入到緩沖區中,除非調用glDepthMask(GL_FALSE)來禁止寫入
深度測試
  • 深度緩沖區(DeptBuffer)和顏色緩沖區是對應的。顏色緩沖區存儲像素的顏色信號,深度緩沖區存儲像素的深度信息。在決定是否繪制一個物體表面時,首先要將表面對應的像素的深度值與當前緩沖區中的值進行比較。如果大于深度緩沖區中的值,則丟棄這部分,否則利用這個像素值對應的深度值和顏色值。分別更新深度緩沖區和顏色緩存區。這個過程稱為"深度測試"
ZFighting閃爍問題
  • 因為開啟深度測試后,OpenGL就不會再去繪制模式被遮擋的部分,這樣實現的顯示更加真實,但是由于深度緩沖區精度限制對于相差非常小的情況下,OpenGL可能出現判斷不準確的,導致深度測試的結果不可預測,出現交錯閃爍
    怎么辦?
    解決方法:多邊形偏移
    啟用Polygon Offset 讓深度之間產生間隔。如果兩個圖形之間有間隔,是不是意味著就不會產生干涉,可以理解為在執行深度測試前將立方體的深度值做一些細微的增加,于是就能將重疊的兩個圖形深度值之前有所區分

#include <stdio.h>
#include "GLTools.h"        //包含了大部分GLTool中類似C語言的獨立函數
#include "GLMatrixStack.h"  //矩陣工具類,可以利用GLMarixStack加載單元矩陣
#include "GLFrame.h"        //矩陣工具類,表示位置,通過設置
#include "GLFrustum.h"      //矩陣工具類,用來快速設置正、透視投影矩陣,完成坐標從3D->2D映射過程
#include "GLGeometryTransform.h"http://變換管道,用來快速在代碼中傳輸視圖矩陣、投影矩陣、視圖投影變換矩陣等
#include "GLBatch.h"        //三角形批次類,利用它可以傳輸頂點、光照、紋理、顏色數據到存儲著色器中

#include <math.h>
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif

//設置角色幀 作為相機
GLFrame         viewFrame;
//使用GLFrustum類來設置投影視圖
GLFrustum       viewFrustum;//設置圖元繪制時的投影方式
GLTriangleBatch torusBatch;//容器類
GLMatrixStack   modelViewMatrix;//模型視圖矩陣
GLMatrixStack   projectionMatrix;//投影矩陣
GLGeometryTransform  transformPipeLine;//變換管道 存儲模型視圖 投影 模型視圖投影矩陣
GLShaderManager  shaderManager;//存儲著色器管理工具類

//標記:背面剔除、深度測試
int iCull = 0;
int iDepth = 0;
//窗口改變
void ChangeSize(int w,int h){
    if (h == 0) {
        h = 1;
    }
    glViewport(0, 0, w, h);
    //設置透視模式,初始化其透視矩陣
    viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0, 100.f);
    //把透視矩陣加載到透視矩陣堆棧中
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    //初始化渲染管道
    transformPipeLine.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}
void SpecialKeys(int key ,int x,int y){
    if (key == GLUT_KEY_UP) {
        //m3dDegToRad 度數 -> 弧度  以x軸渲染,負值向上
        viewFrame.RotateWorld(m3dDegToRad(-5.f), 1.0, 0.0f, 0.0f);
    }
    if (key == GLUT_KEY_DOWN) {
        //m3dDegToRad 度數 -> 弧度
        viewFrame.RotateWorld(m3dDegToRad(5.f), 1.0, 0.0f, 0.0f);
    }
    if (key == GLUT_KEY_LEFT) {
        //m3dDegToRad 度數 -> 弧度
        viewFrame.RotateWorld(m3dDegToRad(-5.f), 0.0, 1.0f, 0.0f);
    }
    if (key == GLUT_KEY_RIGHT) {
        //m3dDegToRad 度數 -> 弧度
        viewFrame.RotateWorld(m3dDegToRad(5.f), 0.0, 1.0f, 0.0f);
    }
    //重新刷新
    glutPostRedisplay();
}
void ProcessMenu(int value){
    switch (value) {
        case 1:
            iDepth = !iDepth;
            break;
        case 2:
            iCull = !iCull;
            break;
        case 3:
            glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
            break;
        case 4:
            glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
            break;
        case 5:
            glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
            break;
    }
    glutPostRedisplay();
}
//渲染場景
void RenderScene(){
    //清楚窗口和深度緩沖區
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    //開啟、關閉正背面剔除功能
    if (iCull) {
        glEnable(GL_CULL_FACE);
        glFrontFace(GL_CCW);
        glCullFace(GL_BACK);
    }else{
        glDisable(GL_CULL_FACE);
    }
    
    
    //根據設置的iDepth標記判斷是否開啟深度測試
    if (iDepth) {
        glEnable(GL_DEPTH_TEST);
        
    }else{
        glDisable(GL_DEPTH_TEST);
    }
    //把攝像機矩陣壓入模型矩陣中
    modelViewMatrix.PushMatrix(viewFrame);
    //設置顏色
    GLfloat vRed[] = {1.0f,0.0f,0.0f,1.0f};
    //使用默認光源著色器
    shaderManager.UseStockShader(GLT_SHADER_DEFAULT_LIGHT,transformPipeLine.GetModelViewMatrix(),transformPipeLine.GetProjectionMatrix(),vRed);
    torusBatch.Draw();
    modelViewMatrix.PopMatrix();
    glutSwapBuffers();
}
void SetupRC(){
    glClearColor(0.3, 0.3f, 0.3f, 1.0f);
    shaderManager.InitializeStockShaders();
    viewFrame.MoveForward(7.0);//將相機向后移動7個單元:肉眼到物體的距離
    
    
    gltMakeTorus(torusBatch, 1.0, 0.3, 52, 26);
    glPointSize(4.0f);
}
int main(int argc,char * argv[]){
    gltSetWorkingDirectory(argv[0]);
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
    glutInitWindowSize(800, 600);
    glutCreateWindow("Geometry Test Program");
    glutReshapeFunc(ChangeSize);
    
    glutSpecialFunc(SpecialKeys);
    glutDisplayFunc(RenderScene);
    
    //添加右擊菜單欄
    glutCreateMenu(ProcessMenu);
    glutAddMenuEntry("Toggle dept test", 1);
    glutAddMenuEntry("Toggle cull backface", 2);
    glutAddMenuEntry("set Fill Mode", 3);
    glutAddMenuEntry("set Line Mode", 4);
    glutAddMenuEntry("set Point Mode", 5);
    glutAttachMenu(GLUT_RIGHT_BUTTON);
    
    GLenum err= glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error:%s \n",glewGetErrorString(err));
    }
    SetupRC();
    glutMainLoop();
    return 0;
}

裁剪

//
//  main.cpp
//  OpenGL03-裁剪
//
//  Created by apple on 2019/11/7.
//  Copyright ? 2019年 apple. All rights reserved.
//
#include <stdio.h>
#include "GLTools.h"
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include<GL/glut.h>
#endif
void ChangeSize(int w,int h){
    if (h == 0) {
        h = 0;
    }
    glViewport(0, 0, w, h);
}
void RenderScene(){
    glClearColor(0.0, 0.0, 1.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    
    //設置彩鉛區域為紅色
    glClearColor(1.0, 0.0f, 0.0f, 0.0f);
    //設置裁剪尺寸
    glScissor(100, 100, 600, 400);
    //開啟裁剪測試
    glEnable(GL_SCISSOR_TEST);
    //開啟清屏,執行裁剪
    glClear(GL_COLOR_BUFFER_BIT);
    
    
    //裁剪一個綠色小矩形
    glClearColor(0.0f, 1.0f, 0.0f, 0.0f);
    //設置裁剪尺寸
    glScissor(200, 200, 400, 200);
    //開始清屏執行裁剪
    glClear(GL_COLOR_BUFFER_BIT);
    
    //關閉裁剪測試
    glDisable(GL_SCISSOR_TEST);
    
    //強制執行緩沖區
    glutSwapBuffers();
}
int main(int argc,char *argv[]){
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize(800, 600);
    glutCreateWindow("OpenGL Scissor");
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);
    glutMainLoop();
    
    return 0;
}
混合
  • 混合:OpenGL渲染時會把顏色值存在顏色緩沖區,每個片段的深度值也是放在深度緩沖區。當深度緩沖區關閉時,新的顏色將簡單的覆蓋原來顏色緩沖區的顏色值,當深度緩沖區再次打開時,新的顏色片段只是當他們比原來的值更接近臨近的裁剪平面才會替換原來的顏色片段
  • 目標顏色:已經存儲在顏色緩存區的顏色值
  • 源顏色:作為當前渲染命令結果進入顏色緩存區的顏色值

當混合功能被開啟時,源顏色和目標顏色的組合方式是混合方程式控制的。在默認情況下,混合方程式如下所示:
Cf = (Cs * S) + (Cd * D)

Cf: 最終計算參數的顏色
Cs: 源顏色
Cd: 目標顏色
S: 源混合因子
D: 目標混合因子


//
//  main.cpp
//  OpenGL03-混合
//
//  Created by apple on 2019/11/7.
//  Copyright ? 2019年 apple. All rights reserved.
//

#include <stdio.h>

#include "GLTools.h"
#include "GLShaderManager.h"

#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif

GLShaderManager shaderManager;

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

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();
    
    //繪制4個固定矩形
    GLfloat vBlock[] = {
        0.25,0.25,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 ChangeSize(int w,int h){
    glViewport(0, 0, w, h);
}
//上下左右鍵位控制移動
void SpecialKeys(int key, int x, int y)
{
    GLfloat stepSize = 0.025f;
    
    GLfloat blockX = vVerts[0];
    GLfloat blockY = vVerts[7]; //以左上角的為頂點計算 其偏移量到底多少
    
    
    if (key == GLUT_KEY_UP) {
        blockY += stepSize;
    }
    if(key == GLUT_KEY_DOWN)
        blockY -= stepSize;
    
    if(key == GLUT_KEY_LEFT)
        blockX -= stepSize;
    
    if(key == GLUT_KEY_RIGHT)
        blockX += stepSize;
    
    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, 0.5f };
    GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f };
    GLfloat vBlue[] = { 0.0f, 0.0f, 1.0f, 1.0f };
    GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
    
    //召喚場景的時候,將4個固定矩形繪制好
    /*
     使用單位著色器
     參數1:簡單的使用默認笛卡爾坐標系(-1,1),所有的片段都應用一種顏色
     參數2:著色器顏色
     */
    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();
    
    //組件核心代碼
    //1.開啟混合
    glEnable(GL_BLEND);
    //開啟組合函數 計算混合顏色因子
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    //使用著色器管理器
    /*
     使用單位著色器
     參數1:簡單的使用默認笛卡爾坐標系(-1,1) 所有片段都應用一種顏色,GLT_SHADER_IDENTITY
     參數2:著色器顏色
     */
    shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vRed);
    //容器類開始繪制
    squareBatch.Draw();
    
    //關閉混合功能
    glDisable(GL_BLEND);
    //同步繪制命令
    glutSwapBuffers();
}


int main(int argc, char * argv[]){
    
    gltSetWorkingDirectory(argv[0]);
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
    glutInitWindowSize(800, 600);
    glutCreateWindow("移動矩形,觀察顏色");
    
    GLenum err = glewInit();
    if (GLEW_OK != err)
    {
        fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
        return 1;
    }
    
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);
    glutSpecialFunc(SpecialKeys);
    
    SetupRC();
    
    glutMainLoop();
    return 0;
    
    
    return 0;
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,156評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,401評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,069評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,873評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,635評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,128評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,203評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,365評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,881評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,733評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,935評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,475評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,172評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,582評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,821評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,595評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,908評論 2 372