公開課“3D勳章”實現方案
------ opengl es 2.0中加載.obj 與 .mtl
先上一個效果圖
看到這個需求,直接反應是用OpenGLES加載一個.obj(頂點數據)與.mtl(顏色材質信息)文件
就搞定了( .obj與.mtl文件由設計師用3dmax、Maya等工具導出)。
本以爲是一個簡單需求,但做起來發現困難點並不少:
- OpenGLES如何加載.obj與.mtl文件?
- 勳章的進入和退出動畫效果?
- 勳章進入和退出過程中的實時光照效果該怎麼做?
解決這三個問題,是需求實現的關鍵。
爲此,我設計了以下架構實現方式,先看架構圖:
架構實現:
我們從下向上說:
- 最下邊運行在Android系統上,這個不用細說
- .obj 3D文件解析引擎:
自己手動解析的,並不是網上開源框架(大都泛泛而談,只能做demo) 。如果開源,那我的這個工程應該就是第一個開源的比較完善的.obj3D文件.mtl材質文件的Java解析庫
; - 光照系統:
shader 主要用於模擬 環境光、散射光、鏡面光(高光)。上線產品,爲了效果,必須有光照; - 動畫引擎:
雖然看起來簡單,但設計確是按照一個動畫引擎標準設計的;
整個動畫引擎可以劃分爲:場景、層、動畫精靈。引擎的架構借鑑了遊戲引擎Cocos2d;
這樣設計的優點是:
a、若底層不依賴Opengl ES 底層依賴的是View 或者SurfaceView 可直接移植爲一個2D動畫引擎;
b、繼續擴展還可以發展做成骨骼動畫;
下面我們對這個架構實現進行詳細說明。
一、OpenGLES如何加載.obj與.mtl文件?
本來以爲網上應該有兼容性較好的obj與mtl的java解析庫,但在網上找了好多代碼,發現其在加載obj與mtl中,基本都存在較大問題。
網上代碼主要分爲了以下幾個部分:
- mind3d 2011年就已停止維護(爲opengl es1.0),並且在加載多圖形上存在很大的不兼容(主要解析了obj,mtl沒有解析)。
- 其他一些obj解析代碼,基本都是解析了obj,不管mtl文件;
或者簡單解析了mtl,卻沒有把對應的材質信息應用到opengl 繪製的圖形上。 - 《Android 3D遊戲開發技術寶典——OpenGL ES 2.0》(2012年我和幾個同學寫的書) 第九章 3D模型加載。 當時寫這本書時,也只是簡單解析了obj文件,而且對mtl文件並未做解析(網上很多的例子是把這一章的案例直接照搬了)
mind3d官方地址與源碼:
https://code.google.com/archive/p/min3d/
https://github.com/deadmoose/min3d
1.1 Obj 與mtl文件簡單舉例
obj文件是3D模型文件格式。由Alias|Wavefront公司爲3D建模和動畫軟件”Advanced Visualizer”開發的一種標準,適合用於3D軟件模型之間的互導,也可以通過Maya讀寫。
- 只支持模型三角面數據和材質信息,無動畫功能支持;
- 其中幾何信息由.obj文件提供,材質信息由.mtl文件定義;
- 文件以行爲單位表示一條數據,可以根據行開頭的字符判斷後續的內容;
- 其中 # 字符表示註釋行
1.1.1 obj文件中主要存放的以下幾何信息
- 三維空間中頂點座標信息
- 頂點的紋理座標(貼圖座標)信息
- 頂點的法向量信息(計算光照用)
這裏我手寫了一份triangle.obj文件:
triangle.obj
# mtl材質文件
# mtllib testvt.mtl
# o 對象名稱(Object name)
o adfaf
# 組名稱
g default
# 頂點
v 0 0.5 0
v -0.5 -0.5 0
v 0.5 -0.5 0
# 紋理座標
vt 0.0 1.0
vt 0.0 0.0
vt 1.0 1.0
# 頂點法線
vn 0 0 1
# 當前圖元所用材質
usemtl Default
# s Smooth shading across polygons is enabled by smoothing groups.
# Smooth shading can be disabled as well.
s off
# v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3(索引起始於1)
f 1/1/1 2/2/1 3/3/1
triangle.obj 增加了詳細的註釋;
- triangle.obj 中規定了模型頂點、紋理、法向量等信息,確定了模型的頂點數據;
1.1.2 mtl文件
這裏我手寫了一份triangle.mtl文件:
mtl中主要規定了幾何圖形的貼圖信息,對環境光、散射光、鏡面光的反射情況、透明度等
triangle.mtl
# 定義一個名爲 'Default'的材質
newmtl Default
# 材質的環境光
Ka 0 0 0
# 散射光
Kd 0.784314 0.784314 0.784314
# 鏡面光
Ks 0 0 0
# 透明度
d 1
# 爲漫反射指定顏色紋理文件
map_Kd test_vt.png
triangle.mtl 增加了詳細的註釋;
- triangle.mtl 中規定了模型材質相關的信息,包括紋理貼圖、環境光、鏡面光、散射光等相關配置都來自這個文件;
1.1.3 triangle.obj與triangle.mtl加載到OpenGL後的運行效果
- 加載triangle.obj與triangle.mtl 模型後的運行效果圖如上圖所示;
- 這裏爲了方便理解,所以僅僅加載的是一個最簡單的普通三角形;
- 加載的triangle.obj與triangle.mtl 三角形,在三維空間中的位置如上圖所示。
- 三維空間中頂點的位置信息來源於triangle.obj文件中。
關於關照與材質相關,詳細信息,可參考我的另一篇文章:
http://blog.csdn.net/xiaxl/article/details/76826812
二、動畫引擎實現
說動畫實現之前,先要說一下動畫引擎架構的設計。
動畫引擎實現,參考了Cocos2d遊戲引擎的設計思想,整個動畫引擎分爲了三層:
2.1、動畫引擎架構實現
前邊說了,這個設計實際參考了Cocos2d遊戲引擎的設計思想,所以實現上與Cocos2d有很多的相似之處:
- 場景:場景負責繪製其所包含的全部層;
- 層:層負責管理、繪製其中的精靈;
層亦可以攜帶精靈做出一些旋轉、平移、縮放 等簡單的動畫效果; - 精靈:精靈是遊戲實體,精靈是活潑的,可以做很多的動畫效果;
精靈應該是活潑的、好動的
!!!
而動畫引擎中的SpriteAnima
,則是我賦予精靈的動畫實現,也是精靈活潑起來
的根本。
2.2、具體的代碼實現
在具體分層代碼實現上:
- 場景:場景繼承自
GLSurfaceView
管理者衆多的層,負責頁面繪製; - 層: 層管理者衆多的精靈,並且繼承自
SpriteAnima
;
層亦被賦予了動畫屬性,可以攜帶衆多的精靈完成動畫,而不影像精靈的動畫;
同時也賦予了層活潑好動的天性
; - 精靈:當然亦繼承自
SpriteAnima
,天然活潑好動。
2.3、SpriteAnima 動畫實現
具體動畫類的實現,則參考了Android屬性動畫
的實現方案:
Opengl ES中的屬性動畫
以上代碼截圖,就是我自定義實現的Opengl ES中的屬性動畫
。
參考Android屬性動畫:
- 通過反射調用,不斷更改精靈的AngleY屬性值來完成精靈屬性的變更。
- 這裏我還加入了Android的
動畫差值器 OvershootInterpolator
,使得勳章動畫在運行時,具備動畫越過便邊界後,回彈的效果
。我們的勳章精靈變得更加活潑。
讓精靈活潑起來
如以上代碼截圖所示:只要動畫尚未結束,則不斷請求GLThread的場景重繪
,來完成精靈的活潑運動效果
三、3D空間對光的模擬
當光照射到一個物體表面上時,會出現三種情形。
- 首先,光可以通過物體表面向空間反射, 產生反射光。
- 其次,對於透明體,光可以穿透該物體並從另一端射出,產生透射光。
- 最後,部分光將被物體表面吸收而轉換成熱。
在上述三部分光中,僅僅是透射光和反射光能夠進入人眼產生視覺效果。這裏只考慮被照明物體表面的反射光影響,假定物體表面光滑不透明且由理想材料構成,環境假設爲由白光照明。
一般來說,反射光可以分成三個分量,即環境反射、漫反射和鏡面反射。
- 鏡面光:上圖中,最亮部分爲鏡面光
- 散射光(漫反射光):上圖中,比鏡面光稍暗部分爲散射光
- 環境光:上圖中,最暗部分爲環境光
三維場景中,只要能模擬出以上三種光照效果,則成功模擬了虛擬世界中的光照。完成產品經理、設計是要求,成功上線則不成問題。
3.1、環境光 模擬
從四面八方照射向物體的光,這種光是非發光物體反射的其他光;
因此,環境光可以選擇一個較暗的顏色值進行模擬
。
shader代碼實現
shader 代碼實現如下:選擇一個較暗的顏色值模擬環境光。
3.2、散射光(漫反射光) 模擬
光源照射到物體的表面,經過物體表面的漫反射,四面八方反射出去的光。
如上圖所示,一個光源照直射到一個球面,半個球面會有相應的反射光,這裏要模擬的就是這樣的光:
半球面中心點最亮,一直到球面邊緣逐漸變暗
。
公式來計算
我們可以用如下公式來計算散射光:
- 光照的
中心點最亮
; - 入射角越大,最終的散射光強度就越小;
從中心到邊緣慢慢變暗
。
shader代碼實現
newNormal 點的法向量、vp 點到光源的向量 均爲單位向量,因此,向量點乘即爲入射角的cos值;
3.3、鏡面光 模擬
相比散射光,高光的亮度區域進一步縮小,是光照射到物體中最亮的一塊
- V點到攝像機的向量
- L點到光源的向量
- H V與L的半向量
模擬公式
我們可以用以下公式來模擬:
shader代碼實現
四、最終效果
- OpenGLES如何加載.obj與.mtl文件?
- 勳章的進入和退出動畫效果?
- 勳章進入和退出過程中的實時光照效果該怎麼做?
以上三個問題解決完成,我們來瞅瞅最終效果(炫耀一下):
五、開源
最後,兩個字:代碼開源...
文檔地址:
http://blog.csdn.net/xiaxl/article/details/77048507
案例實現代碼:
https://github.com/xiaxveliang/GLES2_Anima_LoadFrom_Obj