淺談新一代可程式化行動3D繪圖技術

本文作者:admin       點擊: 2008-12-10 00:00
前言:
自2003年Khoronos Group推出OpenGL ES 1.0標準,行動3D繪圖技術的發展至今已近5年,但行動3D繪圖技術真正開始受到一般消費者大眾所注目,則是來自於去年發表之iPhone的操作介面。iPhone讓消費者發現到,原來他/她每天帶在身上的那個小小裝置,可以有那麼酷炫且好用的操作介面。我國的智慧型手機大廠HTC今年推出的HTC Touch Diamond,更是搭載了全3D的操作介面,試圖給消費者一種全新且超越iPhone的使用經驗。

     
圖1 Mobile phone 3D UI (來源:TAT、Apple與HTC)
  
本文將介紹新一代可程式化行動3D繪圖技術,包括OpenGL ES 2.0、ES Shading Language、以及JSR297 (Mobile Graphics API 2.0) 。透過這些技術的支援,未來的行動電話上將會逐漸出現視覺效果超越PS2的行動遊戲,或是媲美Apple Mac的操作介面(見圖2)。
 
(1)新一代繪圖介面標準 - OpenGL ES 2.0
目前大多數的中高階手機都已支援OpenGL ES 1.x的繪圖介面,應用程式:如遊戲、或是使用者介面(User Interface),可以透過此OpenGL ES繪圖介面對圖形加速硬體進行設定繪圖狀態(Render state)與下達繪圖指令(Draw primitive),進而在螢幕上呈現出以多邊形及貼圖等效果所合成的3D內容。OpenGL ES規格係由Khronos Group所制定,新一代的繪圖介面標準為OpenGL ES 2.0,在2006年的SIGGRAPH會議中正式推出。目前OpenGL ES 2.0的硬體尚未在市場上出現,但包括NVIDIA Tegra與TI OMAP3等高階應用程式處理器(Application Processor)都已經標榜支援OpenGL ES 2.0標準。根據ARM的預估,在2010年始將會有少量的高階智慧手機開始內建OpenGL ES 2.0圖形加速器。

OpenGL ES 1.x到OpenGL ES 2.0的改版在架構上有非常大的改變。不同於OpenGL ES 1.x是固定功能的架構(fixed-function pipeline),OpenGL ES 2.0改為可程式化硬體架構(Programmable),來提供使用者(如:遊戲開發者)大幅擴充硬體繪製功能的空間。我們從Khronos Group所制定的未來藍圖可以知道,未來OpenGL ES將會持續有Fixed-function與programmable兩種不同架構的版本,且OpenGL ES 1.x與OpenGL ES 2.0各自會有自己的演進路程。

全新架構的OpenGL ES 2.0
為了支援更精緻與擬真的3D繪圖品質,針對OpenGL ES 2.0標準Khronos Group一改過去OpenGL ES 1.X版本的固定功能(Fixed-Function Hardware)架構,而是引進桌上型OpenGL 3D應用程序介面所使用的可程式化硬體架構(Programmable Hardware)。但OpenGL ES 2.0與桌上型OpenGL 2最大的不同是,不像OpenGL 2仍有固定管線(Fixed-Function Hardware)架構,OpenGL ES 2.0則是完全移除了固定管線之功能,使得OpenGL ES 2.0在Vertex處理階段與Pixel處理階段是一個完全可程式化硬體的架構。

圖4為OpenGL ES 1.1版本的繪圖管線圖,其中橘色部分所表示的處理階段如:3D空間坐標轉換、光照計算(Lighting)、材質環境、顏色、霧化及透明測試等,在OpenGL ES 2.0皆被著色器(Shader)所取代;其中3D空間坐標轉換與光照計算將會被頂點著色器(Vertex Shader)取代,而其餘部分將由片段著色器(Fragment Shader,又稱Pixel Shader)所取代。OpenGL ES 2.0的繪圖管線圖,如圖5所示。

在OpenGL ES 2.0的架構內,可程式化繪圖硬體全面支援浮點數運算,在使用浮點數的運算與上個版本相比有很大的進步。受惠於可程式化繪圖硬體上有浮點數向量與矩陣計算的硬體,讓OpenGL ES 2.0的Vertex Shader與Pixel Shader可以執行複雜且精確的數學運算,讓OpenGL ES 2.0可支援的功能或效果有非常高的彈性。
  
OpenGL ES 2.0 內的Shader Model 
在OpenGL ES 2.0的可程式化Shader模組內主要可以分為兩大塊,分別為頂點著色器(Vertex Shader Stage)與片段著色器(Fragment Shader Stage)。對於頂點著色器來說,它處理的對象就是頂點(vertex)。頂點內部的資訊我們稱為該頂點的屬性(Attributes),它通常是被用來描述那些變動相當頻繁的資訊,像是頂點位置等。在OpenGL ES 2.0標準中一個頂點最多可以包含8個屬性欄位,每一個屬性欄位可以最多擁有4 component-vector的大小。在頂點著色器內,各頂點間其屬性資訊是無法共享的,且頂點彼此之間並無法得到互相的頂點屬性。而在屬性的輸入方面要注意的是,每一次的繪製呼叫(也就是說,繪製一個三角片串列(Triangle list)或是一個三角片帶(Triangle strip)),所有的頂點都必須擁有相同數量與型態的頂點屬性。

要正確地啟動頂點著色器,必須透過API把頂點資訊(Attributes)與頂點Uniforms參數這兩類輸入資訊傳遞給頂點著色器。其中,頂點資訊是一定要輸入進去。而頂點的Uniforms參數則是一個從外部傳進來給頂點著色器內部運算用的全域變數,通常是用來描述一些對於頂點來說變動較少的資訊,如:轉換矩陣、光源位置及顏色等相關資訊,相對於頂點屬性參數來說,這些Uniforms資訊不會因為頂點的不同而有所不同,每一個Uniforms參數對於全部要被處理的Primitives都是不變的,且所有Uniforms參數都是唯讀。

處理頂點後(以一個Primitive為單位,如一個三角片),頂點著色器會將已處理好的各種資料輸出至Rasterizer,而Rasterizer將會對Primitive作描繪(rasterization)的處理。這時一個三角形將根據其在螢幕座標的位置與範圍,被細切成多個的像素。相對於頂點著色器處理完的各種資料(Varying),會傳遞到Rasterizer產生之像素,且其內容將會根據三角形的頂點與像素之位置來作內插,計算出經過描繪後來頂點著色器傳給每一個像素的Varying參數資料。Varying參數將跟隨像素資訊傳遞給片段著色器去做下一階段的處理。這裡需要特別說明的是,即便頂點著色器可以針對各頂點去作控制運算來達到我們想要的效果,但僅僅限於控制當下這一個頂點,在著色器內無法允許去存取在處理中頂點鄰近的其他頂點資訊。

片段著色器的運作與頂點著色器非常相像,每一次著色器是處理一個像素(Pixel)。相同地,片段著色器的輸入端是像素Uniform參數與頂點著色器所傳遞過來的Varying參數。如同頂點著色器一般,Uniforms是外部傳進來的參數,在片段著色器這邊,可以使用Uniform參數將材質(Textures)由外部傳遞進來作貼圖與顏色合成等的動作。Varying參數如同頂點著色器的頂點屬性,它所代表的是由頂點傳遞過來細切後的資訊。經由片段著色器計算完的pixel顏色值,會再進行Raster Operation,包括Depth test、Alpha Blending、與Multi-sampling Anti-aliasing等處理,最後之pixel結果將會被使用來更新Frame buffer或是材質(Textures)的記憶體。要控制更新Frame buffer還是材質是取決於給予的OpenGL ES指令與狀態來決定的。
 
OpenGL ES著色語言 - ESSL
在編寫控制頂點著色器(Vertex Shader)與片段著色器(Fragment Shader)之程式碼(即shader code)所使用的程式語言方面,Khronos Group定義了OpenGL ES著色語言(OpenGL ES Shading Language, ESSL)。ESSL是根據OpenGL 2.0的OpenGL著色語言(GLSL, OpenGL Shading Language)當作參考依據,針對嵌入式裝置的需求,以簡易使用與實作目標而設計出來的。在使用的語法及流程上皆與桌上型OpenGL著色語言相同。ESSL語法類似C語言的著色語言,對於C/C++/Java的程式開發者而言,它很容易學習且使用。不同的是在著色語言內並沒有指標的存在,這意味著shader程式開發人員無法直接地控制記憶體。由於著色器內的暫存器數量有限(參考前述之shader model),shader程式的複雜度與暫存器的使用必須非常謹慎。過度複雜的著色器程式將會有非常差的執行效率,甚至是無法正確的執行。另一個ESSL與GLSL之不同點是,它新追加了三個精度修飾詞:highp、mediump、lowp,目的是為了增加嵌入式系統硬體使用彈性與效率,讓不同的使用狀況可以應用不同的精確度來作運算。以浮點數為例,highp的使用範圍是(-262, 262),大小範圍則是(2-62, 262),mediump的使用範圍是(-214, 214),大小範圍則是(2-14, 214),lowp的使用範圍是(-2, 2),大小範圍則是(2-8, 2)。

表1是個簡單的Vertex Shader範例,內容是對頂點進行矩陣運算,其中頂點值是透過attribute變數由主程式透過OpenGL ES API取得,而uniform變數也是來自主程式的給定。計算後的結果則設定至gl_position此內建變數。gl_Position為OpenGL ES內部Built-in variables,要讓片段著色器正確的知道繪製的螢幕坐標,gl_Position是正確執行著色器所必須要給定的參數,如此經過轉換後的位置將會透過Rasterizer將每個頂點的螢幕座標細切成為每個像素的螢幕座標。

(2) JSR297 – 支援可程式化3D之Java 3D Engine
現在的手機不論是Feature phone或是高階智慧型手機,絕大多數都有提供下載與執行Java應用程式(Midlet)的功能。至於手機能執行那些功能的Midlet,則取決於該手機有搭載哪些Profile及Package。在2003年的11月,負責制訂Java Profile規格的JCP組織公布了一個可於行動平台上執行3D功能的Package – Mobile 3D Graphics API。Mobile 3D Graphics API簡稱M3G,其JSR(Java Specification Request)代號為184,是由Nokia所主導制訂的,其餘參與制定的專家群(Expert Group)成員包括:SonyEricsson、Motorola、Siemens、Sun、ARM、Intel、Texas Instruments等等。在2005年的6月JCP組織公佈了M3G的更新版本- M3G 1.1,此次更新主要包括:擴增Loader支援所有PNG的格式、多了一些查詢的API以及移除一些不必要的exceptions。考量到硬體技術的不斷更新與演進,行動繪圖技術也隨著PC產業的腳步邁進可程式化的時代,JCP委員會近期發布了支援OpenGL ES 2.0的新一代M3G規格草案 - JSR 297。JSR 297同樣是由Nokia公司起草,於2006年5月提交到JCP委員會。JSR 297是基於原JSR 184架構的進一步擴充,它被設計為可以直接實作在OpenGL ES 2.0和1.1的圖形加速硬體上,充分利用手持裝置的3D加速硬體。

JSR184概述
JSR 184(M3G 1.0、1.1)共有30個Class,依功能性可以分為:繪圖模組( Rendering Module)、材質與光源模組(Material and Lighting Module)、動畫模組(Animation Module)、場景模組(Scene Module)、2D影像模組(2D Image Module)、載入模組(Loader Module)等六大模組。各模組簡述如下:

「繪圖模組」:以Graphics3D此Java Class為主,共有Retain Mode與Immediate Mode兩種不同模式。Retain Mode是把整個虛擬場景(World)一次繪製;而Immediate Mode則是針對虛擬場景中的某個單位(Node)或是更低階的Vertex Buffer資料來進行繪製的動作。此繪圖模組為M3G的核心引擎,由它來驅動呈現整個輸出結果。

「場景模組」:包括 World、Group、Camera、Light、Mesh、MorphingMesh、SkinnedMesh、Sprite3D等8個Java Class。M3G利用這些物件來構成整個虛擬場景之樹狀階層結構中的各式節點。其中,World,用來建構場景的根節點(Root Node),群體(Group)用來建構 Scene Graph 中具有子節點(Children) 的節點,而Camera、Group、Light、Mesh、MorphingMesh、SkinnedMesh、Sprite3D則為葉節點(Leaf Node),此種節點下不能再有任何的子節點。

「材質與光源模組」:包括Apearance、CompositingMode、Fog、Material、PolygonMode和Texture2D等6個Java Class。每個Mesh和Sprite3D物件,都有一份記錄它對應的繪圖屬性(rendering attributes),稱之為Appearance。如果任一個Mesh或Sprite3D物件沒有這份資料,則我們將無法在畫面上看到它,也無法對它做選取(picking)的動作。一個Appearance物件包含了至多一個「CompositingMode」物件、至多一個「Fog」物件、至多一個「Material」物件、至多一個「PolygonMode」物件以及0個到數個「Texture2D」物件,其關係如下圖所示。

「2D影像模組」:包括 Image2D、Background以及Sprite3D等3個Java Class。雖然是M3G是以3D為主的函示庫,不過M3G仍提供許多對2D處理的函示。一般2D影像的縮放、對影像內容即時修改等動作,Image2D 物件都有相對應的API可以使用。再配合上Appearance class的相關函示,M3G在 2D 影像的變化上可產生多種不同的效果。

「載入模組」:以Loader此Java Class為主,其目的是將已製作好的M3G檔案載入進來。有了這個模組,M3G之midlet開發者可以直接將別人製作好的3D場景載入進來。目前主要的3D製作軟體如:3DS Max或Maya,都可以透過內建的Exporter將檔案輸出成JSR184之”.m3g”檔。

「動畫模組」:包括AnimationController、AnimationTrack、KeyframeSequence等Java Class。每個具動畫效果的物件(Animatable Object)將連結有1到數個的「AnimationTrack」來負責動畫物件中某個被改變的項特性(Property)如:位置、顏色等等。而每個「AnimationTrack」都有其相對的「KeyframeSequence」和「AnimationController」,其中,KeyframeSequence負責儲存物件特性的「動畫資料」,而由AnimationController負責控制動畫如何變化。

下面為兩個JSR184的範例遊戲圖示。目前的中高階款手機大部分都有支援JSR184,而JSR184更被納入JSR248/249(Mobile Service Architecture)中,成為電信業者日後採購手機之必要規格之一。
 
JSR297與JSR184之差異
JSR 297設計的目標主要是希望支援現階段所有的裝置,甚至是未來的產品,而設計的一個重要的準則為可以向下相容於現行的JSR 184。為了要能確保在日後JSR 184可漸漸地被JSR 297取代,且使用JSR184開發遊戲的廠商能夠快速的移植原有的程式碼以及遊戲資源到JSR 297,因此JSR 297被設計為可讓之前存在的JSR 184應用程式的程式碼可以正確編譯無誤,而原來的.m3g檔案也可正確的載入。

基於製造成本、產品定位等因素,行動電話的硬體能力差異非常的大,從單獨的ARM 7/9等級的CPU,到ARM 11等級CPU搭配3D加速器等。為滿足行動裝置產業特殊的硬體規格差異性,JSR297的設計分為兩個部分:一個是必須實作的『Core Block』、另一個是選擇性實作的『Advanced Block』。『Advanced Block』包含了可程式化的Shader以及一些必須要有繪圖硬體才能實現的功能。若一個JSR297的實作只有支援『Core Block』被稱為『Core Implementation』,而能支援所有功能的實作被稱為『 Advanced Implementation』,這兩個block與M3G 1.1的關係如下圖所示:

『Core Block』相對於JSR 184能提供較佳的繪圖品質、效能以及較少的記憶體使用量;而『Advanced Block』主要是針對有可程式化的繪圖硬體所設計,能夠提供更好且不受限於過往OpenGL ES 1.x固定功能(Fixed-Function)的繪圖品質。簡單的說,未來我們可以預期高階手機會支援『Advanced Block』以及『Core Block』的部分,而低階手機將僅僅能支援『Core Block』。

『Core Block』新增了一些特徵讓它相對於JSR 184能提供較優的繪圖品質、效能以及較少的記憶體使用量,分述如下:

DynamicImage2D:一個二維的圖像,其內容會自動的從它關聯的資料源做更新的動作,可用來做”Video Texture Mapping”。”Video Texture Mapping”是目前最好的材質貼圖效果,其可將一段連續的圖像(可能是即時運算所得或是來自一個video檔案)以材質的方式做處理然後貼到3D物體的表面上。

Multi-channel keyframe tracks:對於一些動畫的角色而言通常會有一些AnimationTrack來驅動角色的動畫。為了有效表示這樣的動畫,M3G 2.0支援單一的資料序列可以有多組的keyframe資料(multiple channels),此多組keyframe資料可以共享相同的時間值,當這些多組的keyframe資料要驅動相同的動畫屬性時僅僅需要一個AnimationTrack物件即可,如此可降低記憶體使用量。
     
Point Sprite:Point Sprite可以藉由繪製一個3D的點將一張2D貼圖繪製在螢幕的任何一個地方,利用Point Sprite可以實作粒子效果,大量的粒子在螢幕上移動可以產生許多視覺的粒子效果,諸如:煙、火以及水花。

在還沒有Point Sprite之前要製作粒子效果通常是利用繪製大量有貼圖的四邊形(quads),但必須要對每個粒子做旋轉以確保每個粒子都有面對視點(view-point),此項操作十分耗費效能。透過Point Sprite可以允許利用單一個3D的點來繪製貼圖的四邊形,如此本來每個粒子需要傳送4個點到硬體,現在使用Point Sprite只需要一個點。這樣降低記憶體使用量,也可不需要對每個粒子做旋轉以確保每個粒子都有面對視點(view-point)。

TextureCombiner:『Core Block』中新增的TextureCombiner功能對Texture Blending有更多的彈性。例如:新的”DOT3”Combiner Function可用來實作Bump Mapping。

一般來說Bump Mapping是需要在每個像數點來計算光的顏色,而一般OpenGL ES內部的固定繪製排線光的顏色是在頂點做處理,如此必須自行撰寫Fragment Shader來達到Bump Mapping的效果,而TextureCombiner可以讓程式設計師不需要撰寫Shader。意即使用固定繪製排線,即可有Bump Mapping的效果。”DOT3”Combiner Function亦可用來實作Toon Shading 。
                         
Toon Shading可利用一張Normal Map Texture來實作。首先透光源位置和眼睛位置分別計算出光的方向以及視線的方向,再利用Normal Map和光的方向經過DOT3計算出Lighting Diffuse的顏色,並利用Normal Map和視線的方向經過DOT3計算出的Scale值來決定輪廓的走向及寬度,如此可實現將一個3D物件利用近似手繪的卡通圖案來呈現。

而『Advanced Block』主要是針對有可程式化的繪圖硬體所設計,可讓程式員自行撰寫ESSL shader程式,其主要功能介紹如下:

AppearanceBase:一個抽象的基礎類別,底下直接繼承的類別為固定式繪圖排線的”Appearance”類別以及新的”ShaderAppearance”類別,若一個物件的Appearance為固定式繪圖排線“Appearance”的話那就會使用固定式繪圖排線來繪製此物件,如果是新的”ShaderAppearance”的話就會使用程式員自行撰寫的shader來繪製此物件,如此可增加彈性。

ImageCube與TextureCube:一個Cube Map Image會有6張影像,它能夠附加在一個TextureCube上來構成Cube Map的6個面。Cube Map在即時shader的應用十分廣泛,透過視線和法線計算出的反射光線來查詢Cube Map可以創造一個真實的反射鏡面體,利用視線和法線計算出的折射光線來查詢Cube Map可以創造一個透明體。

RenderPass:RenderPass可加在場景中任何一個節點上,使得系統在繪製整個場景之前,可以先對節點執行一些附加的繪製。此新增的功能可以用在程序性的貼圖產生、以及整個場景的後處理等等,當要繪製一個炫麗的物件時,除了本身的貼圖以外,如果還必須呈現光的反射以及該物體反射周遭環境的情況時,就必須對此物件作多重的繪製。

在此範例中會對該物件作三次的繪製:首先是本身的貼圖部分(Beauty Pass),再來是該物件要呈現對周遭光反射的部分(Highlight Pass),最後是該物件要呈現對周遭環境反射的部分(Reflection Pass)。

VertexShader:此類別用來管理利用ESSL所撰寫的”Vertex Shader”程式。Vertex Shader可讓程式設計師控制每個頂點的資料,諸如頂點位置、頂點顏色以及頂點法向量等等。程式設計師想實作Vertex Lighting以及將頂點在不同的空間中做轉換等運算都可以在Vertex Shader中進行。

FragmentShader:此類別用來管理利用ESSL撰寫的”Fragment Shader”程式。Fragment Shader可讓程式員控制每個fragment如何繪製在螢幕上,諸如Texture Blending、Alpha Testing、Fog、pixel discard以及Bump Mapping和Cube Mapping等等。

ShaderProgram:此類別用來管理一個OpenGL ES 2.0的Shader Program,包含已經編譯過並完成連結(Link)的Vertex Shader以及Fragment Shader。

ShaderAppearance:用來定義一個Mesh的外觀,其內含一個ShaderProgram以及一組ShaderUniforms。ShaderProgram內部存有編譯和連結好的Vertex Shader以及Fragment Shader,而ShaderUniforms主要是存放shader會使用到的一些參數,其意義與前面所討論的ESSL之uniform一樣。當Mesh的外觀設定為ShaderAppearance即表示在繪製此Mesh時是利用內部使用者所撰寫的Vertex Shader以及Fragment Shader。此外在ShaderAppearance中Texture算是一種特殊型態的Uniforms,shader內部會根據設定的Texture sampler的值取得相對應的Texture Unit來做存取,其他還包括Polygon Mode、LineMode以及CompositingMode用來描述Mesh的幾何屬性以及記錄每個點(pixel)的屬性。

結語
OpenGL ES 2.0標準規格的制定,正式宣告了行動裝置將走上遊戲機所能支援之視覺品質的時代,日後手機上將會出現視覺效果媲美XBox的遊戲。而JSR297的制定則進一步表示,在Java這一個共同執行平臺的加持下,遊戲廠商發展行動遊戲的門檻與風險將會降低,而消費者在行動裝置上享受高品質之行動遊戲的日子將指日可待。

電子郵件:look@compotechasia.com

聯繫電話:886-2-27201789       分機請撥:11