OpenGL之 公轉(zhuǎn)自轉(zhuǎn)

本篇將會(huì)介紹一個(gè)大球的自轉(zhuǎn)以及一個(gè)小球圍繞大球公轉(zhuǎn)的demo骆姐,效果如下圖:

公轉(zhuǎn)自轉(zhuǎn).gif

實(shí)現(xiàn)過程

image.png

如上圖所示,整個(gè)項(xiàng)目的基本流程較之前幾個(gè)例子沒有太多的變化捏题。都是:

  • 初始化窗口诲锹;
  • 注冊(cè)各函數(shù)的監(jiān)聽,如 重塑函數(shù)涉馅、重繪函數(shù)等归园;
  • 調(diào)用setupRC,初始化窗口背景稚矿、著色器管理器庸诱、頂點(diǎn)數(shù)據(jù)等;
  • 開啟glut的mainloop晤揣,類似iOS的runloop桥爽。

1、SetupRC方法

#pragma mark - 頂點(diǎn)數(shù)據(jù)私有方法
void vertextDataFloor() {
    floorBatch.Begin(GL_LINES, 324);
    
    /*
     GL_LINES  每兩個(gè)點(diǎn)畫一條線
     畫法是
     第一次循環(huán)
     (-20,-0.5,20) 到(-20昧识,-0.5钠四,-20) 畫一條直線
     (20,-0.5跪楞,-20)到(-20缀去,-0.5,-20)畫一條直線
     第二次循環(huán)
     (-19.5,-0.5,20) 到(-19.5甸祭,-0.5缕碎,-20) 畫一條直線
     (20,-0.5池户,-19.5)到(-20咏雌,-0.5凡怎,-19.5)畫一條直線
     
     直到最后一次循環(huán),閉合整個(gè)網(wǎng)格
     */
    for (GLfloat x = -20.f; x <= 20.f; x+=0.5f) {
        floorBatch.Vertex3f(-x, commonY, 20.f);
        floorBatch.Vertex3f(-x, commonY, -20.f);
        
        floorBatch.Vertex3f(20.f, commonY, x);
        floorBatch.Vertex3f(-20.f, commonY, x);
    }
    
    floorBatch.End();
}

void vertextDataBigBall() {
    gltMakeSphere(torusBatch, 0.5f, 40, 80);
}

void vertextDataSmallBallRotate() {
    gltMakeSphere(sphereBatch, 0.2, 20, 40);
}

void vertextDataRandomSmallBall(){
    for (int i = 0; i < SMALL_BALL_NUMBER; i ++) {
        GLfloat randowX = ((random()%400) - 200) * 0.1;
        GLfloat randowZ = ((random()%400) - 200) * 0.1;
        sphereFrames[i].SetOrigin(randowX,0,randowZ);
    }
}

void SetupRC() {
    glClearColor(1, 1, 1, 1);
    
    glEnable(GL_LINE_SMOOTH);
    shaderManager.InitializeStockShaders();
    
    vertextDataFloor();
    
    vertextDataBigBall();
    
    vertextDataSmallBallRotate();
    
    vertextDataRandomSmallBall();
}

在這個(gè)方法中赊抖,主要做一些初始化的工作统倒,如初始化窗口背景色、著色器管理器氛雪、頂點(diǎn)數(shù)據(jù)等檐薯。

2、ChangeSize方法

void ChangeSize(int nWidth, int nHeight) {
    glViewport(0, 0, nWidth, nHeight);
    viewFrustum.SetPerspective(35.f, float(nWidth)/float(nHeight), 1.f, 500.f);
    
    //將投影矩陣載入投影矩陣堆棧
    projectionMatrixStack.LoadMatrix(viewFrustum.GetProjectionMatrix());
    
    //可以不調(diào)用注暗,默認(rèn)會(huì)有一個(gè)單元矩陣
    modelViewMatrixStack.LoadIdentity();
    transformPipeline.SetMatrixStacks(modelViewMatrixStack, projectionMatrixStack);
    
}

如代碼所示,在這個(gè)方法中依然是常規(guī)的設(shè)置視口的位置和大小墓猎、設(shè)置投影方式捆昏、載入投影矩陣到投影矩陣堆棧、載入單元矩陣進(jìn)模型視圖矩陣堆棧毙沾,然后將這兩個(gè)堆棧設(shè)置到變化管道對(duì)象里骗卜,方便使用和管理。

3左胞、RenderScence方法

void RenderScence() {
    //GL_STENCIL_BUFFER_BIT 在這個(gè)demo中寇仓,可以不清
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    
    //開啟深度測(cè)試
    glEnable(GL_DEPTH_TEST);
    
    modelViewMatrixStack.PushMatrix();
    
    //畫地面
    static GLfloat vBlue[] = {0.f,0.5f,1.f,1.f};
    static GLfloat vBigBall[] = {0,0,1,1};
    static GLfloat vSmallBall[] = {1,0.5,0,1};
    static GLfloat vSmallBallRandom[] = {0,0.5,1,1};
    
    static CStopWatch watchObj;
    GLfloat angle = watchObj.GetElapsedSeconds() * 60.f;
    
    M3DMatrix44f viewMatrix;
    viewFrame.GetCameraMatrix(viewMatrix);
    modelViewMatrixStack.MultMatrix(viewMatrix); 
shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vBlue);
    floorBatch.Draw();
    
    //棧頂矩陣z軸負(fù)方向方向平移
    modelViewMatrixStack.Translate(0, 0, -3);
    
    //復(fù)制一份,畫完大球之后烤宙,pops棧頂數(shù)據(jù)遍烦,然后棧頂數(shù)據(jù)是設(shè)置過平移的矩陣
    modelViewMatrixStack.PushMatrix();
    modelViewMatrixStack.Rotate(angle, 0, 1, 0);
    
    M3DVector4f pointPosition = {0,10,5,1};
    shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),
                                 transformPipeline.GetProjectionMatrix(),pointPosition,vBigBall);
    
    torusBatch.Draw();
    
    modelViewMatrixStack.PopMatrix();
    
    
    for (int i = 0; i < SMALL_BALL_NUMBER; i ++) {
        GLFrame frame = sphereFrames[i];
        modelViewMatrixStack.PushMatrix();
        
        modelViewMatrixStack.MultMatrix(frame);
        
        shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),
                                     transformPipeline.GetProjectionMatrix(),pointPosition,vSmallBallRandom);
        sphereBatch.Draw();
        
        modelViewMatrixStack.PopMatrix();
    }
    
    
    //無需壓棧,因?yàn)檫@是當(dāng)前繪制的最后一個(gè)圖形
    modelViewMatrixStack.Rotate(angle * -2.f, 0, 1, 0);
    //z值的絕對(duì)值越大躺枕,離大球越遠(yuǎn)服猪。
    modelViewMatrixStack.Translate(0, 0, 1.1);
    
    shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),
                                 transformPipeline.GetProjectionMatrix(),pointPosition,vSmallBall);
    
    sphereBatch.Draw();
    
    modelViewMatrixStack.PopMatrix();
    
    glutSwapBuffers();
    glutPostRedisplay();
    //關(guān)閉深度測(cè)試
    glDisable(GL_DEPTH_TEST);
}

這個(gè)方法是本次案例中,與之前的案例相比最大的方法拐云。

3.1 畫地板
  • 清理顏色緩存區(qū)和深度緩存區(qū)罢猪,這里的模板緩存區(qū)在本demo中可以不清。
  • 開啟深度測(cè)試
  • 棧頂矩陣copy一份壓棧
  • 初始化各顏色值以及一個(gè)定時(shí)器叉瘩,定時(shí)器用于計(jì)算當(dāng)前旋轉(zhuǎn)角度
  • 從觀察者角色幀獲取觀察者矩陣膳帕,并用當(dāng)前模型視圖矩陣堆棧棧頂矩陣乘以觀察者矩陣,得到結(jié)果覆蓋棧頂矩陣
  • 使用平面著色器處理數(shù)據(jù)
  • 通過批次類畫出地板
  • 在全部圖形繪制完之后薇缅,會(huì)交換緩存區(qū)
3.2 畫大球
  • 棧頂矩陣沿z軸負(fù)方向移動(dòng)3危彩;
  • 棧頂矩陣copy一份壓棧(后續(xù)計(jì)算完成出棧之后,棧頂矩陣依然是之前沿著z軸負(fù)方向移動(dòng)3之后的矩陣)
  • 沿著y軸旋轉(zhuǎn)
  • 設(shè)置光源位置
  • 使用點(diǎn)光源著色器處理數(shù)據(jù)
  • 通過三角形批次類畫出大球
  • 針對(duì)最近一次的入棧操作進(jìn)行出棧泳桦,保證棧頂矩陣為之前沿著z軸負(fù)方向移動(dòng)3之后的矩陣恬砂。
  • 在全部圖形繪制完之后,會(huì)交換緩存區(qū)
3.3 畫多個(gè)分散的小球

在上述的SetupRC方法中調(diào)用的vertextDataRandomSmallBall方法里蓬痒,做了很多頂點(diǎn)數(shù)據(jù)的初始化泻骤,這些就是隨機(jī)小球的位置數(shù)據(jù)漆羔。
在RenderScence方法中也需要將他們繪制出來。

  • 開啟for循環(huán)
  • 每次循環(huán)都復(fù)制一份棧頂矩陣壓棧
  • 將棧頂矩陣乘以當(dāng)前小球的角色幀數(shù)據(jù)狱掂,賦值給棧頂數(shù)據(jù)
  • 使用點(diǎn)光源著色器處理數(shù)據(jù)
  • 使用三角形批次類進(jìn)行繪制
  • 將每次循環(huán)的棧頂矩陣出棧
  • 在全部圖形繪制完之后演痒,會(huì)交換緩存區(qū)
3.4 畫公轉(zhuǎn)的小球
  • 棧頂矩陣?yán)@y軸旋轉(zhuǎn)一定的角度,角度根據(jù)當(dāng)前的計(jì)時(shí)器的時(shí)間來計(jì)算
  • 棧頂矩陣沿z軸平移操作趋惨,無論正負(fù)鸟顺,絕對(duì)值越大,離大球越遠(yuǎn)
  • 使用點(diǎn)光源著色器處理數(shù)據(jù)
  • 使用三角形批次類進(jìn)行繪制
  • 將當(dāng)前棧頂矩陣出
3.5 收尾
  • 交換緩存區(qū)
  • 提交重新渲染器虾,保證重復(fù)調(diào)用RenderScence方法盾计,形成旋轉(zhuǎn)動(dòng)畫
  • 關(guān)閉深度測(cè)試

總結(jié):
RenderScence方法中变勇,會(huì)有各種矩陣變換的計(jì)算操作,將原始的頂點(diǎn)數(shù)據(jù),經(jīng)過各種變換逝淹,全部到達(dá)一個(gè)新的位置谚赎,最終實(shí)現(xiàn)我們要的效果诬烹。在計(jì)算的過程中此虑,需要注意的幾個(gè)點(diǎn):

  • 整體的入棧和出棧要成對(duì)出現(xiàn),有入棧就必須有出棧库正,否則下次繪制的時(shí)候數(shù)據(jù)會(huì)錯(cuò)亂
  • 對(duì)于整個(gè)變換過程曲楚,拿公轉(zhuǎn)小球舉例,雖然它是經(jīng)過了
modelViewMatrixStack.Translate(0, 0, -3);
modelViewMatrixStack.Rotate(angle * -2.f, 0, 1, 0);
modelViewMatrixStack.Translate(0, 0, 1.1);

這三部褥符,但是在OpenGL實(shí)現(xiàn)的時(shí)候龙誊,由于OpenGL采用的是右乘的方式,所以喷楣,其實(shí)小球是經(jīng)過了先z軸平移载迄,再旋轉(zhuǎn),再z軸平移的操作抡蛙。
而對(duì)于大球來說护昧,它經(jīng)過了

modelViewMatrixStack.Translate(0, 0, -3);
modelViewMatrixStack.PushMatrix();
modelViewMatrixStack.Rotate(angle, 0, 1, 0);

這三部操作,而OpenGL實(shí)現(xiàn)的時(shí)候粗截,其實(shí)大球是先旋轉(zhuǎn)惋耙,再z軸平移。
因此熊昌,對(duì)于大球來說绽榛,它是自轉(zhuǎn),而對(duì)于小球來說婿屹,它是公轉(zhuǎn)灭美。

最終總結(jié)

上述為個(gè)人實(shí)現(xiàn)與總結(jié),如有錯(cuò)漏之處昂利,歡迎并感謝批評(píng)指正届腐。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末铁坎,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子犁苏,更是在濱河造成了極大的恐慌硬萍,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件围详,死亡現(xiàn)場(chǎng)離奇詭異朴乖,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)助赞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門买羞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人雹食,你說我怎么就攤上這事畜普。” “怎么了婉徘?”我有些...
    開封第一講書人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長咐汞。 經(jīng)常有香客問我盖呼,道長,這世上最難降的妖魔是什么化撕? 我笑而不...
    開封第一講書人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任几晤,我火速辦了婚禮,結(jié)果婚禮上植阴,老公的妹妹穿的比我還像新娘蟹瘾。我一直安慰自己,他們只是感情好掠手,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開白布憾朴。 她就那樣靜靜地躺著,像睡著了一般喷鸽。 火紅的嫁衣襯著肌膚如雪众雷。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,727評(píng)論 1 305
  • 那天做祝,我揣著相機(jī)與錄音砾省,去河邊找鬼。 笑死混槐,一個(gè)胖子當(dāng)著我的面吹牛编兄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播声登,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼狠鸳,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼揣苏!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起碰煌,我...
    開封第一講書人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤舒岸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后芦圾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蛾派,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年个少,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了洪乍。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡夜焦,死狀恐怖壳澳,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情茫经,我是刑警寧澤巷波,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站卸伞,受9級(jí)特大地震影響抹镊,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜荤傲,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一垮耳、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧遂黍,春花似錦终佛、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至芯咧,卻和暖如春豌研,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背唬党。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來泰國打工鹃共, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人驶拱。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓霜浴,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蓝纲。 傳聞我的和親對(duì)象是個(gè)殘疾皇子阴孟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355