4.OpenGL正背面剔除與深度測(cè)試

一、繪制甜甜圈

整體繪制流程在之前的案例已經(jīng)描述

#include "GLTools.h"
#include "GLMatrixStack.h"
#include "GLFrame.h"
#include "GLFrustum.h"
#include "GLGeometryTransform.h"
#include <glut/glut.h>
//著色管理器
GLShaderManager shaderManager;
//設(shè)置角色幀, 作為相機(jī)木张, 也就是觀察者
GLFrame viewFrame;
GLFrustum viewFrustum;
GLTriangleBatch torusBatch;
GLMatrixStack modelViewMatix;
GLMatrixStack projectionMatrix;
GLGeometryTransform transformPipeline;
//在窗口大小改變時(shí), 接收新的寬度 & 高度
void changeSize(int w, int h)
{
    glViewport(0, 0, w, h);
    //設(shè)置透視模式众辨,初始化其透視矩陣 參數(shù):表示一個(gè)從頂點(diǎn)方向看去的視場(chǎng)角度
    viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0, 100.0);
    //把透視矩陣加載到透視矩陣對(duì)陣中
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    //初始化渲染管線
    transformPipeline.SetMatrixStacks(modelViewMatix, projectionMatrix);
}
//為程序做一次性設(shè)置
void setupRC()
{
    glClearColor(0.7, 0.7, 0.7, 1.0);
    shaderManager.InitializeStockShaders();
    viewFrame.MoveForward(10.0);
    //創(chuàng)建一個(gè)甜甜圈
    gltMakeTorus(torusBatch, 1.0, 0.3, 50, 50);
    //點(diǎn)的大小 方便點(diǎn)填充時(shí),肉眼觀察舷礼。
    glPointSize(4.0);
}
//鍵位控制
void SpecialKeys(int key, int x, int y)
{    //1.判斷方向
    if(key == GLUT_KEY_UP)
        //2.根據(jù)方向調(diào)整觀察者位置
        viewFrame.RotateWorld(m3dDegToRad(-5.0), 1.0f, 0.0f, 0.0f);
    if(key == GLUT_KEY_DOWN)
        viewFrame.RotateWorld(m3dDegToRad(5.0), 1.0f, 0.0f, 0.0f);
    if(key == GLUT_KEY_LEFT)
        viewFrame.RotateWorld(m3dDegToRad(-5.0), 0.0f, 1.0f, 0.0f);
    if(key == GLUT_KEY_RIGHT)
        viewFrame.RotateWorld(m3dDegToRad(5.0), 0.0f, 1.0f, 0.0f);
    //3.重新刷新
    glutPostRedisplay();
}
//開(kāi)始渲染
void RenderScene(void)
{
    //清楚緩存
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    //將攝像機(jī)矩陣壓入模型矩陣中
    modelViewMatix.PushMatrix(viewFrame);
    //設(shè)置繪圖顏色
    GLfloat vYellow[] = {0.0, 1.0, 0.0, 1.0};
    //默認(rèn)光源著色器
    shaderManager.UseStockShader(GLT_SHADER_DEFAULT_LIGHT, transformPipeline.GetModelViewMatrix(), transformPipeline.GetProjectionMatrix(), vYellow);
    //繪制
    torusBatch.Draw();
    //出棧
    modelViewMatix.PopMatrix();
    glutSwapBuffers();
}

int main(int argc,char* argv[])
{
    gltSetWorkingDirectory(argv[0]);
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
    glutInitWindowSize(600, 600);
    glutCreateWindow("Geometry");
    glutReshapeFunc(changeSize);
    glutSpecialFunc(SpecialKeys);
    glutDisplayFunc(RenderScene);

    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
        return 1;
    }
    setupRC();
    glutMainLoop();
    return 0;
}
效果圖:
甜甜圈.png
甜甜圈.gif

二鹃彻、出現(xiàn)問(wèn)題

我們發(fā)現(xiàn) 當(dāng)轉(zhuǎn)動(dòng)甜甜圈的時(shí)候 出現(xiàn)了 黑色,出現(xiàn)這個(gè)的原因是因?yàn)樵谶@個(gè)OpenGL中也存在“陽(yáng)面”妻献,“陰面”蛛株,陽(yáng)面就是我們能夠看到的面,陰面是看不到的育拨,在我們轉(zhuǎn)動(dòng)甜甜圈的時(shí)候谨履,OpenGL此時(shí)是不知道哪個(gè)是陽(yáng)面 哪個(gè)是陰面,所以導(dǎo)致一些陰面的部分展示了出現(xiàn)熬丧,所以出現(xiàn)了這樣不該被觀察者看到的黑色部分笋粟。

三、解決方法

油畫法.png

1. 油畫法 : 由遠(yuǎn)到近繪圖析蝴,先繪制遠(yuǎn)的圖層害捕,再繪制近的,一層一層疊加闷畸,觀察者看不到的地方也繪制上去了尝盼,所以這個(gè)方法是效率比較低的。

2. 正背面剔除(Face Culling)
此方法在圖元裝配的過(guò)程中就拋棄了一些觀察者看不到的部分佑菩,只繪制觀察者能看到的盾沫,因此這個(gè)方法時(shí)很高效的。

  • 開(kāi)啟背面剔除
glEnable(GL_CULL_FACE);
  • 關(guān)閉背面剔除
glDisable(GL_CULL_FACE);
  • 上面的方法時(shí)沒(méi)有聲明需要剔除的面倘待,設(shè)置要剔除的面
void glCullFace(GLenum mode);
  • 代碼
//開(kāi)始渲染
void RenderScene(void)
{
    //清楚緩存
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glEnable(GL_CULL_FACE);
    glFrontFace(GL_CCW);
    glCullFace(GL_BACK);

    //將攝像機(jī)矩陣壓入模型矩陣中
    modelViewMatix.PushMatrix(viewFrame);
    //設(shè)置繪圖顏色
    GLfloat vYellow[] = {0.0, 1.0, 0.0, 1.0};
    //默認(rèn)光源著色器
    shaderManager.UseStockShader(GLT_SHADER_DEFAULT_LIGHT, transformPipeline.GetModelViewMatrix(), transformPipeline.GetProjectionMatrix(), vYellow);
    //繪制
    torusBatch.Draw();
    //出棧
    modelViewMatix.PopMatrix();
    glutSwapBuffers();
}

這是運(yùn)行后 轉(zhuǎn)動(dòng)后的效果
會(huì)發(fā)現(xiàn) 黑色的部分已經(jīng)沒(méi)有了疮跑,但是卻出現(xiàn)了一個(gè)新的問(wèn)題,就是當(dāng)這個(gè)甜甜圈旋轉(zhuǎn)到有重疊的部門時(shí)凸舵,出現(xiàn)了一個(gè)缺口祖娘,因?yàn)镺penGL不能區(qū)別哪個(gè)圖層是在前面,哪個(gè)圖層在后面啊奄,導(dǎo)致的問(wèn)題渐苏。

甜甜圈沒(méi)有開(kāi)啟深度測(cè)試.png

3.深度測(cè)試(可解決深度問(wèn)題,也可解決正背面剔除問(wèn)題)
深度
其實(shí)深度就是OpenGL中坐標(biāo)的Z值菇夸,距離觀察者的距離琼富。
而這個(gè)距離的大小是和觀察者所在位置有關(guān)

  • 如果觀察者在Z軸的正方向,Z值越大則靠近觀察者
  • 如果觀察者在Z軸的負(fù)方向庄新,Z值越小則越靠近觀察者

深度緩存區(qū)(DepthBuffer):

  • 存儲(chǔ)在顯存中鞠眉,就是把距離觀察者平面的深度值與窗口中每個(gè)像素點(diǎn)1對(duì)1進(jìn)行關(guān)聯(lián)以及存儲(chǔ)(即像素為 100x100薯鼠,那么也要存儲(chǔ)120x120個(gè)深度值)。
  • 深度緩存區(qū)和顏色緩存區(qū)是對(duì)應(yīng)的械蹋,顏色緩存區(qū)存儲(chǔ)像素的顏色信息出皇,深度緩存區(qū)則存儲(chǔ)像素的深度信息,在決定是否繪制一個(gè)物體表面時(shí)哗戈,首先要將表面對(duì)應(yīng)的像素的深度值與當(dāng)前深度緩存區(qū)中的值進(jìn)行比較郊艘,如果大于深度緩存區(qū)中的值(就是比較當(dāng)前兩個(gè)重疊的圖層哪個(gè)離觀察者更遠(yuǎn)),則丟棄這部分唯咬,不進(jìn)行繪制纱注。
  • 利用這個(gè)像素對(duì)應(yīng)的深度值和顏色值分別更新深度緩存區(qū)和顏色緩存區(qū),這個(gè)過(guò)程稱為 深度測(cè)試

開(kāi)啟深度測(cè)試

glEnable(GL_DEPTH_TEST);

關(guān)閉深度測(cè)試

glDisable(GL_DEPTH_TEST);

深度測(cè)試規(guī)則的枚舉值胆胰,可通過(guò)函數(shù)glDepthFunc(GLenum func)修改狞贱。

測(cè)試規(guī)則的枚舉值.png

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市煮剧,隨后出現(xiàn)的幾起案子斥滤,更是在濱河造成了極大的恐慌,老刑警劉巖勉盅,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件佑颇,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡草娜,警方通過(guò)查閱死者的電腦和手機(jī)挑胸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)宰闰,“玉大人茬贵,你說(shuō)我怎么就攤上這事∫婆郏” “怎么了解藻?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)葡盗。 經(jīng)常有香客問(wèn)我螟左,道長(zhǎng),這世上最難降的妖魔是什么觅够? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任胶背,我火速辦了婚禮,結(jié)果婚禮上喘先,老公的妹妹穿的比我還像新娘钳吟。我一直安慰自己,他們只是感情好窘拯,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布红且。 她就那樣靜靜地躺著坝茎,像睡著了一般。 火紅的嫁衣襯著肌膚如雪直焙。 梳的紋絲不亂的頭發(fā)上景东,一...
    開(kāi)封第一講書(shū)人閱讀 51,573評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音奔誓,去河邊找鬼。 笑死搔涝,一個(gè)胖子當(dāng)著我的面吹牛厨喂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播庄呈,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼蜕煌,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了诬留?” 一聲冷哼從身側(cè)響起斜纪,我...
    開(kāi)封第一講書(shū)人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎文兑,沒(méi)想到半個(gè)月后盒刚,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡绿贞,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年因块,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片籍铁。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡涡上,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出拒名,到底是詐尸還是另有隱情吩愧,我是刑警寧澤,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布增显,位于F島的核電站雁佳,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏甸怕。R本人自食惡果不足惜甘穿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望梢杭。 院中可真熱鬧温兼,春花似錦、人聲如沸武契。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至届垫,卻和暖如春释液,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背装处。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工误债, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人妄迁。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓寝蹈,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親登淘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子箫老,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355