OpenGL渲染技巧

首先,我們來繪制一個(gè)3D圖形“甜甜圈”鹅搪,示例程序運(yùn)行效果如下:
1.png

咋看站绪,似乎沒什么問題。但當(dāng)我們?cè)囍蛴倚D(zhuǎn)它的時(shí)候丽柿,會(huì)出現(xiàn)以下問題:
2.png

其實(shí)恢准, 這個(gè)“甜甜圈”是由很多個(gè)三角形組成的實(shí)體對(duì)象,其中一些三角形在“甜甜圈”的背面甫题,而另一些則在“甜甜圈”的正面馁筐。但我們看不到背面——至少我們應(yīng)該是看不到的(不考慮透明幾何體的特殊情況)。在默認(rèn)情況下坠非,第一個(gè)繪制的三角形可能會(huì)被后面繪制的三角形覆蓋,三角形繪制的順序就會(huì)一團(tuán)糟,所以會(huì)導(dǎo)致上圖的情況件蚕。對(duì)于這種問題可以有以下的解決辦法:

油畫法

  • 對(duì)這些三角形進(jìn)行排序裆装,并且首先渲染那些較遠(yuǎn)的三角形,再在它們上方渲染那些較近的三角形潦闲,這種方式稱為“油畫法”攒菠。

  • 也就是先繪制場(chǎng)景中離觀察者較遠(yuǎn)的物體,再繪制較近的物體歉闰。

  • 例如下?的圖例:先繪制紅?部分辖众,再繪制??部分,最后再繪制灰?部分和敬,即可解決隱藏?消除的問題
    3.png
  • 使?油畫算法凹炸,只要將場(chǎng)景按照物理距離觀察者的距離遠(yuǎn)近排序,由遠(yuǎn)及近的繪制即可概龄。那么會(huì)出現(xiàn)什么問題? 如果三個(gè)三?形是疊加的情況还惠,油畫算法將?法處理。
    4.png
  • 這種方法在計(jì)算機(jī)圖形處理中是非常低效的私杜,主要原因有兩個(gè)蚕键。其中一個(gè)原因是,我們必須對(duì)任何發(fā)生幾何圖形重疊地方的每個(gè)像素進(jìn)行兩次寫操作衰粹,而在存儲(chǔ)其中進(jìn)行寫操作會(huì)使速度變慢锣光。另外一個(gè)原因是,對(duì)獨(dú)立的三角形進(jìn)行排序的開銷會(huì)過高铝耻。我們有更好的辦法誊爹。

在繪制3D場(chǎng)景的時(shí)候蹬刷,我們需要決定哪些部分是對(duì)觀察者可?的,或者哪些部分是對(duì)觀察者不可?的频丘。對(duì)于不可?的部分办成,應(yīng)該及早丟棄。例如在?個(gè)不透明的墻壁后搂漠,就不應(yīng)該渲染迂卢。這種情況叫做”隱藏?消除”(Hidden surface elimination)。所以延伸出了下面兩種方法桐汤,由OpenGL為我們提供而克,我們只需開啟即可:

正背?剔除(Face Culling)

  • 背景

    • 嘗試相信?個(gè)3D圖形,你從任何?個(gè)?向去觀察,最多可以看到?個(gè)?怔毛?
    • 答案是员萍,最多3?。 從?個(gè)??體的任意位置和?向上看拣度,你不可能看到多于3個(gè)?碎绎。
    • 那么思考? 我們?yōu)楹我嘤嗟娜ダL制那根本看不到的3個(gè)??
    • 如果我們能以某種?式去丟棄這部分?jǐn)?shù)據(jù),OpenGL 在渲染的性能即可提?超過50%蜡娶。
  • 解決問題

    • 如何知道某個(gè)?在觀察者的視野中不會(huì)出現(xiàn)?
    • 任何平?都有2個(gè)?混卵,正?/背?。意味著你?個(gè)時(shí)刻只能看到??窖张。
    • OpenGL 可以做到檢查所有正?朝向觀察者的?幕随,并渲染它們。從?丟棄背?朝向的?宿接。這樣可以節(jié)約?元著?器的性能赘淮。
    • 如何告訴OpenGL 你繪制的圖形,哪個(gè)?是正?睦霎,哪個(gè)?是背??
    • 答案: 通過分析頂點(diǎn)數(shù)據(jù)的順序

    分析頂點(diǎn)順序

    分析頂點(diǎn)順序.png
  • 正?/背?區(qū)分

    • 正?: 按照逆時(shí)針頂點(diǎn)連接順序的三?形?
    • 背?: 按照順時(shí)針頂點(diǎn)連接順序的三?形?

    分析??體中的正背?
    5.png

  • 分析

    • 左側(cè)三?形頂點(diǎn)順序?yàn)? 1—> 2—> 3梢卸;右側(cè)三?形的頂點(diǎn)順序?yàn)? 1—> 2—> 3。
    • 當(dāng)觀察者在右側(cè)時(shí)副女,則右邊的三?形?向?yàn)槟鏁r(shí)針?向則為正?蛤高,?左側(cè)的三?形為順時(shí)針則為背?。
    • 當(dāng)觀察者在左側(cè)時(shí)碑幅,則左邊的三?形為逆時(shí)針?向判定為正?戴陡,?右側(cè)的三?形為順時(shí)針判定為背?。
  • 總結(jié)

    • 正?和背?是由三?形的頂點(diǎn)定義順序和觀察者?向共同決定的沟涨。隨著觀察者的?度?向的改變恤批,正?背?也會(huì)跟著改變。

總之裹赴,對(duì)正面和背面三角形進(jìn)行區(qū)分的原因之一就是為了剔除喜庞。背面剔除能夠極大地提高性能诀浪,這種方式是非常高效的,在渲染的圖元裝配階段就整體拋棄了一些三角形延都,并且沒有執(zhí)行任何不恰當(dāng)?shù)墓鈻呕僮骼字怼R话阏趁嫣蕹慈缦路绞介_啟:

開啟表?剔除(默認(rèn)背?剔除)
void glEnable(GL_CULL_FACE);

關(guān)閉表?剔除(默認(rèn)背?剔除)
void glDisable(GL_CULL_FACE);

?戶選擇剔除那個(gè)?(正?/背?)
void glCullFace(GLenum mode);
mode參數(shù)為: GL_FRONT,GL_BACK,GL_FRONT_AND_BACK ,默認(rèn)GL_BACK

?戶指定繞序那個(gè)為正?
void glFrontFace(GLenum mode);
mode參數(shù)為: GL_CW,GL_CCW,默認(rèn)值:GL_CCW

例如,剔除正?實(shí)現(xiàn)(1)
glCullFace(GL_BACK);
glFrontFace(GL_CW);

例如,剔除正?實(shí)現(xiàn)(2)
glCullFace(GL_FRONT);

然后右鍵單擊示例程序,并選擇“開啟背面剔除”菜單選項(xiàng)晰房。
屏幕錄制2020-08-16-下午7.56.29.gif

但當(dāng)我們?cè)倮^續(xù)向右旋轉(zhuǎn)春宣,旋轉(zhuǎn)到一定角度是又出現(xiàn)了新的問題
6.png

所以接下來我們講到另一種高效消除隱藏表面的技術(shù),深度測(cè)試嫉你。

深度測(cè)試

  • 什么是深度?

  • 深度其實(shí)就是該像素點(diǎn)在3D世界中距離攝像機(jī)的距離,z值

  • 什么是深度緩沖區(qū)?

  • 深度緩存區(qū)躏惋,就是?塊內(nèi)存區(qū)域幽污,專?存儲(chǔ)著每個(gè)像素點(diǎn)(繪制在屏幕上的)深度值。深度值(z值)越?簿姨,則離攝像機(jī)就越遠(yuǎn)距误。

  • 為什么需要深度緩沖區(qū)?

  • 在不使?深度測(cè)試的時(shí)候,如果我們先繪制?個(gè)距離?較近的物理扁位,再繪制距離較遠(yuǎn)的物理准潭,則距離遠(yuǎn)的位圖因?yàn)楹罄L制,會(huì)把距離近的物體覆蓋掉。 有了深度緩沖區(qū)后域仇,繪制物體的順序就不那么重要的刑然。 實(shí)際上,只要存在深度緩沖區(qū)暇务,OpenGL 都會(huì)把像素的深度值寫?到緩沖區(qū)中泼掠。除?調(diào)用glDepthMask(GL_FALSE)來禁?寫?。

  • 在繪制一個(gè)像素時(shí)垦细,將一個(gè)值(稱為z值)分配給它择镇,這個(gè)值表示它到觀察者的距離。然后括改,當(dāng)另外一個(gè)像素需要在屏幕上的同樣位置進(jìn)行繪制時(shí)腻豌,新像素的z值將已經(jīng)存儲(chǔ)的像素的z值進(jìn)行比較。如果新像素的z值比較大嘱能,那么它距離觀察者就比較近吝梅,這樣就在原來的像素上面,所以原來的像素就會(huì)被新的像素覆蓋焰檩。如果新像素的z值更低憔涉,那么它就必須位于原來像素的后面,不能遮住原來的像素析苫。在內(nèi)部兜叨,這個(gè)任務(wù)是通過深度緩沖區(qū)實(shí)現(xiàn)的穿扳,它存儲(chǔ)了屏幕上每個(gè)像素的深度值。這就是深度測(cè)試国旷。

  • 深度緩沖區(qū)(DepthBuffer)和顏?緩存區(qū)(ColorBuffer)是對(duì)應(yīng)的矛物。顏?緩存區(qū)存儲(chǔ)像素的顏?信息,?深度緩沖區(qū)存儲(chǔ)像素的深度信息跪但。在決定是否繪制?個(gè)物體表?時(shí)履羞, ?先要將表?對(duì)應(yīng)的像素的深度值與當(dāng)前深度緩沖區(qū)中的值進(jìn)??較。如果?于深度緩沖區(qū)中的值屡久,則丟棄這部分忆首。否則利?這個(gè)像素對(duì)應(yīng)的深度值和顏?值。分別更新深度緩沖區(qū)和顏?緩存區(qū)被环。這個(gè)過程稱為”深度測(cè)試”糙及。

深度測(cè)試在繪制多個(gè)對(duì)象時(shí)能夠進(jìn)一步解決性能問題。就算背面剔除能夠消除位于對(duì)象背面的三角形筛欢,那么如果是重疊的獨(dú)立對(duì)象又該怎么辦呢浸锨?這就會(huì)出現(xiàn)圖6所示的問題,開啟深度測(cè)試將消除那些應(yīng)該被已存在像素覆蓋的像素版姑,這將節(jié)省可觀的存儲(chǔ)器帶寬柱搜。一般深度測(cè)試按如下方式開啟:

申請(qǐng)一個(gè)顏色緩沖區(qū)和一個(gè)深度緩沖區(qū)
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);

開啟深度測(cè)試
glEnable(GL_DEPTH_TEST);

在繪制場(chǎng)景前,清除顏?緩存區(qū),深度緩沖區(qū)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

然后右鍵單擊示例程序,并選擇“開啟深度測(cè)試”菜單選項(xiàng)剥险。
屏幕錄制2020-08-16-下午9.32.08.gif

多邊形模式

多邊形(含三角形)不一定是實(shí)心的聪蘸。在默認(rèn)情況下,多邊形是作為實(shí)心圖形繪制的表制,但我們可以通過將多邊形指定為顯示輪廓或只有點(diǎn)(只顯示頂點(diǎn))來改變這種行為宇姚。可以在多邊形的兩面都應(yīng)用這個(gè)渲染模式夫凸,也可以只在正面或背面應(yīng)用浑劳。

void glPolygonMode(GLenum face,GLenum mode);
和表面剔除一樣,face參數(shù)的可用值為GL_FRONT夭拌、GL_BACK或GL_FRONT_AND_BACK魔熏。
mode參數(shù)的可用值為GL_FILL(默認(rèn)值)、GL_LINE或GL_POINT鸽扁。

然后右鍵單擊示例程序蒜绽,并選擇“設(shè)置線模式”菜單選項(xiàng)。
7.png

然后右鍵單擊示例程序桶现,并選擇“設(shè)置點(diǎn)模式”菜單選項(xiàng)躲雅。
8.png

z沖突(z-fighting)

  • 為什么會(huì)出現(xiàn)z沖突問題
  • 因?yàn)殚_啟深度測(cè)試后,OpenGL 就不會(huì)再去繪制模型被遮擋的部分骡和。這樣實(shí)現(xiàn)的顯示更加真實(shí)相赁。但是由于深度緩沖區(qū)精度的限制對(duì)于深度相差?常?的情況下相寇。(例如在同?平?上進(jìn)?2次繪制),OpenGL 就可能出現(xiàn)不能正確判斷兩者的深度值钮科,會(huì)導(dǎo)致深度測(cè)試的結(jié)果不可預(yù)測(cè)唤衫。顯示出來的現(xiàn)象時(shí)交錯(cuò)閃爍,前?2個(gè)畫?交錯(cuò)出現(xiàn)绵脯。
9.png
10.png
  • 第?步: 啟? Polygon Offset ?式解決
  • 解決?法:讓深度值之間產(chǎn)?間隔佳励。如果2個(gè)圖形之間有間隔,是不是意味著就不會(huì)產(chǎn)??涉蛆挫≡叱校可以理解為在執(zhí)?深度測(cè)試前將??體的深度值做?些細(xì)微的增加。于是就能將重疊的2個(gè)圖形深度值與之前有所區(qū)分悴侵。
//啟?Polygon Offset ?式
glEnable(GL_POLYGON_OFFSET_FILL)

參數(shù)列表: 
GL_POLYGON_OFFSET_POINT 對(duì)應(yīng)光柵化模式: GL_POINT 
GL_POLYGON_OFFSET_LINE 對(duì)應(yīng)光柵化模式: GL_LINE 
GL_POLYGON_OFFSET_FILL 對(duì)應(yīng)光柵化模式: GL_FILL
  • 第?步: 指定偏移量
  • 通過glPolygonOffset 來指定楣导。glPolygonOffset 需要2個(gè)參數(shù): factor ,units
  • 每個(gè)Fragment 的深度值都會(huì)增加如下所示的偏移量: 
    Offset = ( m * factor ) + ( r * units); 

    m : 多邊形的深度的斜率的最?值,理解?個(gè)多邊形越是與近裁剪?平?畜挨,m就越接近于0。
    r : 能產(chǎn)?于窗?坐標(biāo)系的深度值中可分辨的差異最?值噩凹。r 是由具體是由具體OpenGL 平臺(tái)指定的?個(gè)常量巴元。
  • ?個(gè)?于0的Offset 會(huì)把模型推到離你(攝像機(jī))更遠(yuǎn)的位置,相應(yīng)的?個(gè)?于0的Offset 會(huì)把模型拉近
  • ?般??驮宴,只需要將-1.0 和 -1 這樣簡(jiǎn)單賦值給glPolygonOffset 基本可以滿?需求逮刨。
void glPolygonOffset(Glfloat factor,Glfloat units);

應(yīng)?到?段上總偏移計(jì)算?程式
Depth Offset = (DZ * factor) + (r * units);

DZ:深度值(Z值)
r:使得深度緩沖區(qū)產(chǎn)?變化的最?值

負(fù)值,將使得z值距離我們更近堵泽,?正值修己,將使得z值距離我們更遠(yuǎn),一般把factor和units設(shè)置為-1迎罗,-1即可
  • 第三步: 關(guān)閉Polygon Offset
glDisable(GL_POLYGON_OFFSET_FILL)

示例程序的代碼如下:

//GLTool.h頭?件包含了?部分GLTool中類似C語?的獨(dú)?函數(shù)
#include "GLTools.h"
//矩陣的?具類.可以利于GLMatrixStack 加載單元矩陣/矩陣相乘/壓棧/出棧/縮放/平移/旋轉(zhuǎn)
#include "GLMatrixStack.h"
//矩陣?具類,表示位置.通過設(shè)置vOrigin, vForward ,vUp
#include "GLFrame.h"
//矩陣?具類,?來快速設(shè)置正/透視投影矩陣.完成坐標(biāo)從3D->2D映射過程.
#include "GLFrustum.h"
//三?形批次類,幫助類,利?它可以傳輸頂點(diǎn)/光照/紋理/顏?數(shù)據(jù)到存儲(chǔ)著?器中.
#include "GLBatch.h"
//變換管道類,?來快速在代碼中傳輸視圖矩陣/投影矩陣/視圖投影變換矩陣等.
#include "GLGeometryTransform.h"
//數(shù)學(xué)庫
#include <math.h>

//在Mac 系統(tǒng)下睬愤,`#include<glut/glut.h>` 在Windows 和 Linux上,我們使?freeglut的靜態(tài)庫版本并且需要添加?個(gè)宏
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif


//設(shè)置觀察者視圖坐標(biāo)
GLFrame viewFrame;
//設(shè)置圖元繪制時(shí)的投影?式.
GLFrustum viewFrustum;
//幫助類/容器類
GLTriangleBatch torusBatch;
//模型視圖矩陣
GLMatrixStack modelViewMatrix;
//投影矩陣
GLMatrixStack projectionMatrix;
//變換管道,存儲(chǔ)投影/視圖/投影視圖變換矩陣
GLGeometryTransform transformPipeline;
//存儲(chǔ)著?器管理?具類.
GLShaderManager shaderManager;

//標(biāo)記:背?剔除纹安、深度測(cè)試
int iCull = 0;
int iDepth = 0;





//ChangeSize 函數(shù):?定義函數(shù).通過glutReshaperFunc(函數(shù)名)注冊(cè)為重塑函數(shù).當(dāng)屏幕??發(fā)?變化/或者第?次創(chuàng)建窗?時(shí),會(huì)調(diào)?該函數(shù)調(diào)整窗???/視???.
void ChangeSize(int w ,int h)
{
    //設(shè)置視口窗口尺寸
    glViewport(0, 0, w, h);
    //創(chuàng)建投影矩陣尤辱,并將它載?投影矩陣堆棧中
    viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0f, 500.0f);
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    
    // 初始化渲染管線
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}

//RenderScene 函數(shù):?定義函數(shù).通過glutDisplayFunc(函數(shù)名)注冊(cè)為顯示渲染函數(shù).當(dāng)屏幕發(fā)?變化/或者開發(fā)者主動(dòng)渲染會(huì)調(diào)?此函數(shù),?來實(shí)現(xiàn)數(shù)據(jù)->渲染過程
void RenderScene(void)
{
    //清理緩存區(qū)(顏?,深度,模板緩存區(qū)等)
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
    
    //根據(jù)設(shè)置iCull標(biāo)記來判斷是否開啟背?剔除
    if (iCull)
    {
        glEnable(GL_CULL_FACE);
        glFrontFace(GL_CCW);
        glCullFace(GL_BACK);
    }
    else
    {
        glDisable(GL_CULL_FACE);
    }
    
    //根據(jù)設(shè)置iDepth標(biāo)記來判斷是否開啟深度測(cè)試
    if (iDepth)
    {
        glEnable(GL_DEPTH_TEST);
    }
    else
    {
        glDisable(GL_DEPTH_TEST);
    }
    
    //把攝像機(jī)矩陣壓?模型矩陣中
    modelViewMatrix.PushMatrix(viewFrame);
   
    GLfloat vRed[] = {1.0f,0.0f,0.0f,1.0f};


     //使用默認(rèn)光源著色器
      //通過光源、陰影效果跟提現(xiàn)立體效果
      //參數(shù)1:GLT_SHADER_DEFAULT_LIGHT 默認(rèn)光源著色器
      //參數(shù)2:模型視圖矩陣
      //參數(shù)3:投影矩陣
      //參數(shù)4:基本顏色值
    shaderManager.UseStockShader(GLT_SHADER_DEFAULT_LIGHT,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),vRed);
    
    //繪制
    torusBatch.Draw();
    
    //繪制完畢則還原矩陣
    modelViewMatrix.PopMatrix();
    
    //交換緩存區(qū)
    glutSwapBuffers();
}


//SetupRC 函數(shù): ?定義函數(shù),設(shè)置你需要渲染的圖形的相關(guān)頂點(diǎn)數(shù)據(jù)/顏?數(shù)據(jù)等數(shù)據(jù)裝備?作
void SetupRC()
{
    //背景顏?
    glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
    //存儲(chǔ)著?器管理器初始化
    shaderManager.InitializeStockShaders();
    //將相機(jī)向后移動(dòng)7個(gè)單元:?眼到物體之間的距離
    viewFrame.MoveForward(7.0f);
    
    //創(chuàng)建?個(gè)甜甜圈
    //void gltMakeTorus(GLTriangleBatch& torusBatch, GLfloat majorRadius, GLfloat minorRadius, GLint numMajor, GLint numMinor);
    //參數(shù)1:GLTriangleBatch 容器幫助類
    //參數(shù)2:外邊緣半徑
    //參數(shù)3:內(nèi)邊緣半徑
    //參數(shù)4厢岂、5:主半徑和從半徑的細(xì)分單元數(shù)量
    gltMakeTorus(torusBatch, 1.0f, 0.3f, 52, 26);
    //點(diǎn)的??
    glPointSize(4.0f);
    
}


//鍵位設(shè)置光督,通過不同的鍵位對(duì)其進(jìn)?設(shè)置
//控制Camera的移動(dòng),從?改變視?
void SpecialKeys(int key, int x, int y)
{
    if (key == GLUT_KEY_UP)
    {
        viewFrame.RotateWorld(m3dDegToRad(-5.0f), 1.0f, 0.0f, 0.0f);
    }
    
    if (key == GLUT_KEY_DOWN)
    {
        viewFrame.RotateWorld(m3dDegToRad(5.0f), 1.0f, 0.0f, 0.0f);
    }
    
    if (key == GLUT_KEY_LEFT)
    {
        viewFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f);
    }
    
    if (key == GLUT_KEY_RIGHT)
    {
        viewFrame.RotateWorld(m3dDegToRad(5.0f), 0.0f, 1.0f, 0.0f);
    }
    
    glutPostRedisplay();
}


//右鍵菜單欄選項(xiàng)
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();
}

//main 函數(shù): 程序??.OpenGL 是?向過程編程.所以你會(huì)發(fā)現(xiàn)利?OpenGL處理圖形/圖像都是鏈?zhǔn)叫问?以及基于OpenGL封裝的圖像處理框架也是鏈?zhǔn)骄幊?int main(int argc, char* argv[])
{
    glutInit(&argc, argv);
    //申請(qǐng)一個(gè)顏色緩存區(qū)塔粒、深度緩存區(qū)结借、雙緩存區(qū)、模板緩存區(qū)
    glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
    //設(shè)置窗口的尺寸
    glutInitWindowSize(800, 800);
    //設(shè)置窗口的名稱
    glutCreateWindow("OpenGL 渲染技巧");
    //注冊(cè)回調(diào)函數(shù)(改變尺寸)
    glutReshapeFunc(ChangeSize);
    //注冊(cè)顯示函數(shù)
    glutDisplayFunc(RenderScene);
    //特殊鍵位函數(shù)(上下左右)
    glutSpecialFunc(SpecialKeys);
    //右擊菜單
    glutCreateMenu(ProcessMenu);
    glutAddMenuEntry("開啟深度測(cè)試",1);
    glutAddMenuEntry("開啟背面剔除",2);
    glutAddMenuEntry("設(shè)置面模式", 3);
    glutAddMenuEntry("設(shè)置線模式", 4);
    glutAddMenuEntry("設(shè)置點(diǎn)模式", 5);
    glutAttachMenu(GLUT_RIGHT_BUTTON);
    
    
    
    //判斷一下是否能初始化glew庫卒茬,確保項(xiàng)目能正常使用OpenGL 框架
    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
        return 1;
    }
    
    //設(shè)置繪制數(shù)據(jù)
    SetupRC();
    
    //runloop運(yùn)行循環(huán)
    glutMainLoop();
    
    return 0;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末船老,一起剝皮案震驚了整個(gè)濱河市咖熟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌努隙,老刑警劉巖球恤,帶你破解...
    沈念sama閱讀 211,639評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異荸镊,居然都是意外死亡咽斧,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門躬存,熙熙樓的掌柜王于貴愁眉苦臉地迎上來张惹,“玉大人,你說我怎么就攤上這事岭洲⊥鸲海” “怎么了?”我有些...
    開封第一講書人閱讀 157,221評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵盾剩,是天一觀的道長(zhǎng)雷激。 經(jīng)常有香客問我,道長(zhǎng)告私,這世上最難降的妖魔是什么屎暇? 我笑而不...
    開封第一講書人閱讀 56,474評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮驻粟,結(jié)果婚禮上根悼,老公的妹妹穿的比我還像新娘。我一直安慰自己蜀撑,他們只是感情好挤巡,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著酷麦,像睡著了一般矿卑。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上沃饶,一...
    開封第一講書人閱讀 49,816評(píng)論 1 290
  • 那天粪摘,我揣著相機(jī)與錄音,去河邊找鬼绍坝。 笑死徘意,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的轩褐。 我是一名探鬼主播椎咧,決...
    沈念sama閱讀 38,957評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了勤讽?” 一聲冷哼從身側(cè)響起蟋座,我...
    開封第一講書人閱讀 37,718評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎脚牍,沒想到半個(gè)月后向臀,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,176評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡诸狭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評(píng)論 2 327
  • 正文 我和宋清朗相戀三年券膀,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片驯遇。...
    茶點(diǎn)故事閱讀 38,646評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡芹彬,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出叉庐,到底是詐尸還是另有隱情舒帮,我是刑警寧澤,帶...
    沈念sama閱讀 34,322評(píng)論 4 330
  • 正文 年R本政府宣布陡叠,位于F島的核電站玩郊,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏枉阵。R本人自食惡果不足惜译红,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望岭妖。 院中可真熱鬧,春花似錦反璃、人聲如沸昵慌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽斋攀。三九已至,卻和暖如春梧田,著一層夾襖步出監(jiān)牢的瞬間淳蔼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工裁眯, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留鹉梨,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,358評(píng)論 2 360
  • 正文 我出身青樓穿稳,卻偏偏與公主長(zhǎng)得像存皂,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 上一篇我們繪制的一些基礎(chǔ)圖元樣式,效果還是很粗糙的旦袋。代碼也比較簡(jiǎn)單,今天我們來看看OpenGL的渲染技巧,通過繪制...
    紅發(fā)_KVO閱讀 808評(píng)論 0 0
  • 在本篇文章開始之前呢骤菠。我們需要先了解一個(gè)非常重要的概念:環(huán)繞。環(huán)繞是OpenGL中任何三角形都需要遵循的重要特性疤孕。...
    Mr_Lxh閱讀 659評(píng)論 0 0
  • 1商乎、渲染過程產(chǎn)?的問題 在繪制3D場(chǎng)景的時(shí)候,我們需要決定哪些部分是對(duì)觀察者 可見的祭阀,或者哪些部分是對(duì)觀察者不可?...
    希爾羅斯沃德_董閱讀 478評(píng)論 0 0
  • 1鹉戚、隱藏面消除 在渲染3D場(chǎng)景過程中可能會(huì)產(chǎn)生以下問題 我們需要決定哪些部分是對(duì)觀察者可?的,或者哪些部分是對(duì)觀察...
    小溜子閱讀 291評(píng)論 0 1
  • OpenGL渲染技巧 了解了OpenGL的渲染流程和常用API后,就可以簡(jiǎn)單的繪制出圖形了柬讨。但是在繪制中可能會(huì)碰到...
    silasjs閱讀 315評(píng)論 0 4