久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

WeAthFolD的Modding渲染教程 第一章

 gljin_cn 2015-02-08

讓我們來(lái)一只新鮮的miku鎮(zhèn)樓吧~

WeAthFolD的Modding教程:OpenGL,、特效和渲染
第一章 MC渲染基礎(chǔ):OpenGL,、坐標(biāo)變換、貼圖

在這一章,,我們并不會(huì)接觸任何實(shí)際的Modding代碼。然而,,這一章所描述的基本概念卻至關(guān)重要,,在從粒子特效到物品、方塊渲染的范疇內(nèi),,這些在MC中關(guān)于渲染的基本方法都在無(wú)時(shí)無(wú)刻的被應(yīng)用著,。總而言之,,打好基礎(chǔ)是十分重要的,,所以請(qǐng)打起精神來(lái)哦~
由于個(gè)人才疏學(xué)淺,教程的說(shuō)明難免有錯(cuò)漏之處,還請(qǐng)各位及時(shí)指出咯~> <
注意:OpenGL的部分略有難度,,如果覺得理解困難可以多讀幾次或者選擇性略過(guò),。


OpenGL,lwjgl和鑲嵌器

MC的整個(gè)渲染引擎,,基于開源游戲API:lwjglOpenGL部分而搭建,。這也就意味著MC的渲染過(guò)程中,會(huì)大量的用到OpenGL的方法(所以,,在之前就寫過(guò)GL程序的同學(xué)有福了~~),。
不過(guò),MC并不趨向于讓使用者全部直接調(diào)用OpenGL的方法,。為了處理光照,、法線貼圖等等屬性的繪制,MC將OpenGL的繪制函數(shù)進(jìn)行了一個(gè)包裝,,也就是Tessellator(鑲嵌器)類,。所有添加頂點(diǎn)、繪制多邊形的操作,,都需要通過(guò)這個(gè)類來(lái)進(jìn)行,。

在一個(gè)繪制過(guò)程中,我們可以這樣獲取Tessellator的實(shí)例:
  1. Tessellator t = Tessellator.instance;
復(fù)制代碼

然后,,通過(guò)
  1. t.startDrawingQuads();
復(fù)制代碼
或者
  1. t.startDrawing(int MODE);
復(fù)制代碼
來(lái)開始一次繪制動(dòng)作,。
在繪制動(dòng)作中,你可以設(shè)定當(dāng)前繪制動(dòng)作的顏色,、設(shè)置面的法向量,,以及添加一個(gè)頂點(diǎn)等等:
  1. t.setColorRGBA_F(r, g, b, a);
  2. t.setNormal(u, v, w);
  3. t.addVertexWithUV(x, y, z, u0, v0);……
復(fù)制代碼
在狀態(tài)設(shè)置結(jié)束,添加了頂點(diǎn)之后,,結(jié)束整個(gè)繪制過(guò)程:
  1. t.draw();
復(fù)制代碼
此時(shí),,Tessellator會(huì)將計(jì)算好的渲染數(shù)據(jù)傳遞給OpenGL,進(jìn)行實(shí)際的繪制,。


說(shuō)明:Tessellator的方法
t.startDrawing(MODE):使用指定的繪制模式開始繪制,。繪制模式和OpenGL的glBegin(MODE)中所使用的常量一模一樣,有GL_QUADS, GL_LINES, GL_TRIANGLE_FAN等等,,詳見
t.setColorOpaque(), setNormal(), ...:設(shè)置當(dāng)前繪制過(guò)程的狀態(tài)量,。這也就意味著如果使用Tessellator進(jìn)行這些狀態(tài)的設(shè)定的話,同一個(gè)繪制call中,,不同的頂點(diǎn)是無(wú)法使用不同的顏色和法向量值的,。如果需要多種狀態(tài)值,則推薦不同狀態(tài)值分成不同的繪制call,。

以下是一個(gè)使用Tessellator繪制一個(gè)紅色,,透明度50%,,法向量為(0, 0, 1)的矩形的例子:
  1. Tessellator t = Tessellator.instance;
  2. t.startDrawing(GL11.GL_QUADS); //或t.startDrawingQuads()
  3. t.setColorRGBA_F(1.0F, 0.0F, 0.0F, 0.5F);
  4. t.setNormal(0, 0, 1);
  5. t.addVertex(0.0, 0.0, 0.0);
  6. t.addVertex(1.0, 0.0, 0.0);
  7. t.addVertex(1.0, 1.0, 0.0);
  8. t.addVertex(0.0, 1.0, 0.0);
  9. t.draw(); //結(jié)束繪制call
復(fù)制代碼




釋放潛力:使用OpenGL進(jìn)行其他的圖形操作
在介紹了Tessellator之后,我們已經(jīng)了解了MC中基本的圖形繪制是如何進(jìn)行的,。然而只憑借Tessellator,,我們能做到的事是相當(dāng)受限的。要對(duì)我們所繪制的東西進(jìn)行變換,、混合,、遮罩操作……我們都需要用到OpenGL的原生函數(shù)。
在lwjgl中,,OpenGL的庫(kù)函數(shù)被包裝在GL[XX](XX是GL版本號(hào))類中,。你只需要訪問(wèn)這些類的公有函數(shù)就可以調(diào)用GLAPI了。
實(shí)際上,,大部分的GL函數(shù)在GL11類當(dāng)中,。


基本的變換操作
在MCMod中(以及其他所有的游戲渲染過(guò)程中),我們最常遇到的問(wèn)題就是對(duì)繪制的圖形進(jìn)行移動(dòng)和變換的問(wèn)題,。例如:將在原點(diǎn)繪制好的子彈實(shí)體平移到當(dāng)前實(shí)體的位置,;根據(jù)時(shí)間流逝的長(zhǎng)度讓光束旋轉(zhuǎn)一個(gè)角度,等等,。在OpenGL中,,我們可以進(jìn)行如下的幾種變換:
·平移 將所有頂點(diǎn)坐標(biāo)平移(Δx, Δy, Δz)個(gè)單位
-對(duì)應(yīng)函數(shù):glTranslate*(dx, dy, dz);
·旋轉(zhuǎn) 將所有頂點(diǎn)繞某個(gè)軸,旋轉(zhuǎn)α度,。
-對(duì)應(yīng)函數(shù):glRotate*(α, u, v, w);
·縮放 將所有頂點(diǎn)關(guān)于原點(diǎn),,縮放scale倍。
-對(duì)應(yīng)函數(shù):glScale*(scaleX, scaleY, scaleZ);
關(guān)于這些OpenGL變換函數(shù)的具體效果和操作方法,,請(qǐng)參見網(wǎng)上各種各樣的OpenGL參考和教程,。我相信隨便一個(gè)教程都說(shuō)的比我好>. <


變換操作和變換的復(fù)合(啥?代碼要倒著讀,??。?/strong>
通過(guò)以上的三個(gè)變換函數(shù),我們已經(jīng)可以對(duì)繪制出來(lái)的東西干很多有趣的事了,。比如說(shuō),,下面的代碼讓我們繪制的東西繞(0, 0, 0),關(guān)于Y軸周期性旋轉(zhuǎn):
  1. GL11.glRotated(Minecraft.getSystemTime() / 100, 0, 1, 0);
  2. t.startDrawingQuads();
  3. //...
  4. t.draw();
復(fù)制代碼
注意,,我們的變換方法是在開始繪制之前調(diào)用的,。這是因?yàn)槊總€(gè)變換方法實(shí)際上都在GL內(nèi)部存儲(chǔ)了一個(gè)狀態(tài)。而在繪制的那一刻,,GL就會(huì)把之前指定的變換狀態(tài)進(jìn)行綜合,再把這個(gè)綜合的變換結(jié)果應(yīng)用在所有頂點(diǎn)上,。所以如果你在繪制之后再調(diào)用變換函數(shù)的話,,就太遲了?。ㄈ绻銓W(xué)過(guò)線性代數(shù)的話,實(shí)際上我們?cè)趯?duì)一個(gè)變換矩陣不停的做矩陣乘法),。

一個(gè)變換通常是遠(yuǎn)遠(yuǎn)不夠用的,,我們經(jīng)常想要對(duì)一個(gè)物體進(jìn)行很多的復(fù)合變換。而在進(jìn)行復(fù)合變換的時(shí)候,,有些神奇的代碼規(guī)則是你不得不注意的,。
例如,下面的代碼讓繪制的物體繞中心周期旋轉(zhuǎn),,然后再將它往Y軸正方向移動(dòng)一個(gè)單位
  1. GL11.glTranslated(0, 1, 0);
  2. GL11.glRotated(Minecraft.getSystemTime() / 100, 0, 1, 0);
  3. //你的繪制代碼
復(fù)制代碼
是的,,變換的順序和代碼的順序是反過(guò)來(lái)的!如果你知道一點(diǎn)關(guān)于矩陣的東西,,并且想要探究到底是為什么的話,,可以讀讀下面的擴(kuò)展閱讀;否則,,請(qǐng)你牢牢的記住這個(gè)結(jié)論:在渲染過(guò)程中,,任何和GL坐標(biāo)變換的代碼應(yīng)該放在繪制過(guò)程上方,而且實(shí)際變換順序和方法的調(diào)用順序恰好相反,。


擴(kuò)展閱讀:矩陣乘法,,左乘和右乘
↓點(diǎn)我
根據(jù)線性代數(shù)和計(jì)算機(jī)圖形學(xué)知識(shí),我們知道:一切基本坐標(biāo)變換都可以以矩陣變換的形式表示,。
在OpenGL計(jì)算中中,,任意點(diǎn)的坐標(biāo)都是用列向量表示的:

在進(jìn)行變換的時(shí)候,我們只需要把變換矩陣乘以列向量矩陣就可以得到結(jié)果的坐標(biāo),。例如,,偏移量為Δx,Δy,,Δz的變換矩陣是:

兩者相乘,,得到結(jié)果:

根據(jù)矩陣運(yùn)算的結(jié)合律,所有的變換矩陣可以在乘以列向量之前進(jìn)行乘法的復(fù)合之后,,再乘以列向量,,得到的是和這些矩陣分別乘以列向量相同的結(jié)果。也就是:
T1·T2·T3·...·Tn·V = (T1·T2·T3·...·Tn)·V
而后一種方法的運(yùn)算量明顯會(huì)小很多,,因此OpenGL在內(nèi)部會(huì)預(yù)先把我們指定的變換矩陣全部相乘,,只保存一個(gè)總的變換矩陣。
在添加新的變換矩陣的時(shí)候,,OpenGL進(jìn)行的是右乘(也就是把新的矩陣放到當(dāng)前變換矩陣的最右邊,,兩者相乘)。如果我們依次添加T1,,T2,,T3,,……,我們得到的最終的變換結(jié)果是這樣的:
(T1·T2·T3·...·Tn)·V
讓我們從另一個(gè)角度看待這個(gè)運(yùn)算:(T1·(T2·(...·(Tn·V))))
用語(yǔ)言解釋這個(gè)運(yùn)算過(guò)程就是:用Tn乘以V得到坐標(biāo)V1,,用Tn-1乘以V1得到坐標(biāo)V2,,……最后得到V’。由于矩陣乘法的運(yùn)算性質(zhì),,驚人的事發(fā)生了:實(shí)際變換的順序和我們指定變換矩陣的順序是完全相反的,!
參考:
http:///questions/2258910/opengl-scale-then-translate-and-how/2259263#2259263
http://en./wiki/Transformation_matrix




變換的復(fù)合(記得推棧和彈棧!)
假設(shè)在渲染過(guò)程中,,我們想要進(jìn)行一定的復(fù)合變換,。比如說(shuō):讓風(fēng)車的扇葉部分周期旋轉(zhuǎn),而支架部分固定不動(dòng),,該怎么辦呢,?最簡(jiǎn)單方法是這樣的:
(這里假設(shè)mainPart和fan都是一個(gè)類似模型的類的實(shí)例,調(diào)用其draw函數(shù)會(huì)把面繪制出來(lái))
  1. mainPart.draw();
  2. GL11.glTranslated(0, offsetY, 0); //將扇葉移動(dòng)到正確的位置上
  3. GL11.glRotated(Math.cos(Minecraft.getSystemTime() / 100D), 1, 0, 0); //讓扇葉關(guān)于中心旋轉(zhuǎn)
  4. fan.draw();
復(fù)制代碼
這是基于一個(gè)重要的姿勢(shì):坐標(biāo)變換函數(shù)僅對(duì)調(diào)用之后發(fā)生的繪制call有影響,。

然而,,假設(shè)你為了更好的渲染效果,給這個(gè)風(fēng)車加了兩層不同的轉(zhuǎn)動(dòng),,那么又該怎么繪制呢,?
  1. mainPart.draw();
  2. GL11.glTranslated(0, offsetY, 0); //將扇葉移動(dòng)到正確的位置上
  3. GL11.glRotated(Minecraft.getSystemTime() / 100D, 1, 0, 0); //讓扇葉關(guān)于中心旋轉(zhuǎn)
  4. fan.draw();
  5. GL11.glRotated(Minecraft.getSystemTime() / 80D, 1, 0, 0); //讓扇葉2關(guān)于中心旋轉(zhuǎn)(速度不同)
  6. fan2.draw();
復(fù)制代碼
很容易可以意識(shí)到,這個(gè)方法得到的并不是你想要的效果,。fan2的旋轉(zhuǎn)同時(shí)受到了兩次旋轉(zhuǎn)變換的影響,,導(dǎo)致了復(fù)合變換。
如果我們想要讓每個(gè)部分進(jìn)行分別的變換動(dòng)作,,而不讓它們影響到彼此,,該怎么辦呢?

答案是下面的代碼:
  1. GL11.glMatrixMode(GL11.GL_MODELVIEW); //設(shè)置當(dāng)前活躍的矩陣為ModelView(模型視角)矩陣
  2. mainPart.draw();
  3. GL11.glTranslated(0, offsetY, 0); //將扇葉移動(dòng)到正確的位置上
  4. GL11.glPushMatrix(); //保存
  5. GL11.glRotated(Minecraft.getSystemTime() / 100D, 1, 0, 0); //旋轉(zhuǎn)A
  6. fan.draw();
  7. GL11.glPopMatrix(); //還原
  8. GL11.glPushMatrix(); //保存
  9. GL11.glRotated(Minecraft.getSystemTime() / 80D, 1, 0, 0); //旋轉(zhuǎn)B
  10. fan2.draw();
  11. GL11.glPopMatrix(); //還原
復(fù)制代碼
為什么這樣可以做到保存狀態(tài)呢,?接下來(lái)的篇幅介紹了glPushMatrix和glPopMatrix這對(duì)孿生兄弟,。


知識(shí)點(diǎn):glPushMatrix和glPopMatrix

OpenGL提供了便捷的恢復(fù)其某一時(shí)刻的部分狀態(tài)的方法:推棧和彈棧
在這里,,我們使用glPushMatrixglPopMatrix來(lái)存儲(chǔ)和恢復(fù)當(dāng)前活躍矩陣的狀態(tài),。 活躍的矩陣可以用glMatrixMode(MODE)指定。除了Modelview(模視變換)矩陣,,還有Projection(投影)矩陣,,用來(lái)設(shè)置攝像機(jī)位置/投影方法
你可以把這對(duì)函數(shù)的功能想象成對(duì)一個(gè)棧的操作(實(shí)際上就是……),,就像這樣:

glPushMatrix()glPopMatrix()必須成對(duì)使用,,否則會(huì)造成棧的上溢和下溢

在你的渲染器里面,mc一般會(huì)給你傳遞類似這樣的參數(shù):
  1. public void render(double x, double double z, ......)
復(fù)制代碼
所以對(duì)應(yīng)的,,在你的代碼里,,肯定會(huì)有這么一行:
  1. GL11.glTranslated(x, y, z);
復(fù)制代碼
這個(gè)狀態(tài)設(shè)置既會(huì)作用于你當(dāng)前的繪制語(yǔ)句,也會(huì)作用于你的整個(gè)繪制函數(shù)結(jié)束之后的繪制語(yǔ)句,。MC并沒有在外面幫你儲(chǔ)存變換信息。因此,,如果你在繪制的過(guò)程中忘記pushMatrix和popMatrix,,那么之后的繪制就遭殃了。你可能看到一堆實(shí)體跟隨著你自己創(chuàng)建的實(shí)體謎之移動(dòng)……

因此,,強(qiáng)烈建議把渲染代碼寫成如下形式:

  1. //其他狀態(tài)設(shè)置
  2. GL11.glPushMatrix();
  3. //坐標(biāo)變換
  4. //繪制
  5. GL11.glPopMatrix();
  6. //恢復(fù)設(shè)置的狀態(tài)
復(fù)制代碼
這個(gè)注意點(diǎn)也適用于其他所有的GL狀態(tài)設(shè)置,。因?yàn)闋顟B(tài)設(shè)置是作用于全局的,所以如果你設(shè)置了某些局部的繪制狀態(tài)(e.g.開啟線框渲染,,關(guān)閉貼圖,,關(guān)閉面剔除),那么請(qǐng)務(wù)必在繪制完成后將狀態(tài)復(fù)原,。否則,,等待你的將是一堆謎之玩壞的渲染效果喲^^



總結(jié)
在這一章中,我們簡(jiǎn)要的介紹了MC中繪制的基本方法:OpenGL原生函數(shù)鑲嵌器的配合,。其中,,鑲嵌器處理頂點(diǎn)的基本繪制和一些光照屬性,而OpenGL則處理這以外的所有工作(變換,,貼圖,,alpha混合……)。因此,,OpenGL基礎(chǔ)對(duì)MCMod的渲染是至關(guān)重要的,。我們首先介紹了Tessellator和其基本的繪制多邊形的方法,然后簡(jiǎn)要的介紹了OpenGL中最最常用的幾個(gè)函數(shù):坐標(biāo)變換,、矩陣的存儲(chǔ)與復(fù)原,。在你的渲染代碼的結(jié)尾,一定要記得將設(shè)置過(guò)的狀態(tài)復(fù)原,。
盡管都是枯燥繁瑣的理論,,但是這些東西和實(shí)際的實(shí)現(xiàn)碰撞起來(lái)的時(shí)候,才往往能迸發(fā)出意想不到的火花呢,。那么,,準(zhǔn)備好進(jìn)一步往前探索了么?

下一章:[層主努力填坑中,,敬請(qǐng)期待……]

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多