Starling 2D框架簡介(一)


本系列是對Introducing Starling pdf的翻譯,下文是對adobe開發人員中心的一片日志的轉載,地址為http://www.adobe.com/cn/devnet/flashplayer/articles/introducing_Starling.html

Starling 是在 Stage3D APIs 基礎上開發的一種 ActionScript 3 2D 框架(可用於 Flash Player 11 和 Adobe AIR 3的桌面)。 Starling 是為游戲開發設計的,但是你可以將它應用於很多其它的應用程序。 在不必涉及低級 Stage3D APIs 情況下,Starling 使得編寫具有快速 GPU 加速功能的應用程序成為可能。

大多數 Flash 開發人員希望利用這種能力提高 GPU 的加速功能(通過使用 Stage3D 技術),而不必編寫如此高級的框架和深入研究低級的 Stage3D APIs。 Starling 是完全基於 Flash Player APIs 而設計,並將 Stage3D(Molehill)復雜性抽象化。 因此每個人都能看到直觀的程序。

Starling 是為 ActionScript 3開發人員而設計,尤其是這些涉及2D游戲開發的人員。 在使用 ActionScript 3 之前,你必須基本了解它。由於 Starling 輕便、靈活並易於使用,你也可以將它應用於其它項目需求,例如 UI 編程。 這種框架要求設計得越直觀越好,因此任何 Java™ 或者.Net™ 開發人員都可以馬上開始使用它。

Starling使用概述

Starling 直觀並易於使用。Flash 和 Flex 開發人員能夠快速地了解它,因為它遵循大多數 ActionScript 規則並將低級 Stage3D APIs 的復雜性抽象化。Starling 使用熟知的概念,例如DOM顯示列表、事件模型以及熟知的如 MovieClip、Sprite、TextField 等APIs,而不是依靠諸如頂點緩沖(vertices buffer)、透視矩陣(perspective matrices)、着色程序(shader programs)和組合字節碼(assembly bytecode)進行編碼。

Starling在很多領域都很輕便。 類的數量是有限的(大概有80k的代碼)。 除了Flash Player 11 或者 AIR 3(以及在未來的版本中使用的移動支持)之外,它沒有外部依賴。 這些因素使得你的應用程序很小並使你的工作流程簡單。

Starling能夠免費使用並富有朝氣。 它根據 Simplified BSD 許可獲得授權,因此你可以免費地使用它,即便是在商業應用程序中也是如此。 我們每天都在使用它並且我們依靠一個活躍的團隊不斷地完善它。

在后台操作中,Starling 使用 Stage3D APIs —它們是在桌面上基於 OpenGL 和 DirectX ,在移動設備上基於 OpenGL ES2而運行的低級的 GPU APIs。 需要重點注意的是,Starling 是 Sparrow 的 ActionScript 3 端口,它等同於基於 OpenGL ES2 APIs 的ISO庫(參見圖1):

圖1. Stage3D (Molehill) 分層位於 Starling 之上
圖1. Stage3D (Molehill) 分層位於 Starling 之上

Starling 重新創建了很多 Flash 開發人員熟知的 APIs 。 下圖列舉了通過 Starling 暴露的圖形元素 APIs(參見圖2)。

圖2. Starling支持DisplayObject繼承
圖2. Starling支持DisplayObject繼承

在 3D GPU APIs 基礎上可以創建 2D 內容,這看起來有點奇怪。 當涉及 Stage3D APIs 時,很多人認為這些 APIs 是嚴格地限制在 3D 內容中的。 實際上這是名稱造成的誤解:如果它叫做 Stage3D ,那么你怎么可以使用它創建 2D 元素呢?下圖說明了關於使用 drawTriangles API 繪制 MovieClip 能力的問題(參見圖3)。

圖3. 可以使用drawTriangles API創建2D影片剪輯嗎?
圖3. 可以使用 drawTriangles API 創建2D影片剪輯嗎?

GPU 具有較高的效率並能快速地繪制三角形。 通過使用 drawTriangles API ,你可以繪制兩個三角形,然后選取一種紋理並且使用UV映射將它應用到三角形中。 這樣可以創建了一個帶有紋理的四邊形,它代表一個 sprite 。 通過更新每一個幀上的三角形的紋理,最后的結果就是一個 MovieClip 。

幸好我們沒有必要通過這些細節使用 Starling 。 你只需要提供幀數,將它們提供給一個 Starling MovieClip ,這就是所有需要做的(參見圖4)。

圖4. 使用 drawTriangles API 和一個帶有紋理的四邊形,你可以創建一個2D圖形
圖4. 使用 drawTriangles API 和一個帶有紋理的四邊形,你可以創建一個2D圖形

為了更好地了解 Starling 如何降低復雜性,檢查你必須寫入的代碼以便於用低級的 Stage3D APIs 顯示簡單的帶有紋理的四邊形。

 1 // create the vertices
2 var vertices:Vector.<Number> = Vector.<Number>([
3 -0.5,-0.5,0, 0, 0, // x, y, z, u, v
4 -0.5, 0.5, 0, 0, 1,
5 0.5, 0.5, 0, 1, 1,
6 0.5, -0.5, 0, 1, 0]);
7
8 // create the buffer to upload the vertices
9 var vertexbuffer:VertexBuffer3D = context3D.createVertexBuffer(4, 5);
10
11 // upload the vertices
12 vertexbuffer.uploadFromVector(vertices, 0, 4);
13
14 // create the buffer to upload the indices
15 var indexbuffer:IndexBuffer3D = context3D.createIndexBuffer(6);
16
17 // upload the indices
18 indexbuffer.uploadFromVector (Vector.<uint>([0, 1, 2, 2, 3, 0]), 0, 6);
19
20 // create the bitmap texture
21 var bitmap:Bitmap = new TextureBitmap();
22
23 // create the texture bitmap to upload the bitmap
24 var texture:Texture = context3D.createTexture(bitmap.bitmapData.width,
25
26 bitmap.bitmapData.height, Context3DTextureFormat.BGRA, false);
27
28 // upload the bitmap
29
30 texture.uploadFromBitmapData(bitmap.bitmapData);
31
32 // create the mini assembler
33 var vertexShaderAssembler : AGALMiniAssembler = new AGALMiniAssembler();
34
35 // assemble the vertex shader
36 vertexShaderAssembler.assemble( Context3DProgramType.VERTEX,
37 "m44 op, va0, vc0\n" + // pos to clipspace
38 "mov v0, va1" // copy uv
39 );
40
41 // assemble the fragment shader
42 fragmentShaderAssembler.assemble( Context3DProgramType.FRAGMENT,
43 "tex ft1, v0, fs0 <2d,linear, nomip>;\n" +
44 "mov oc, ft1"
45 );
46
47 // create the shader program
48 var program:Program3D = context3D.createProgram();
49
50 // upload the vertex and fragment shaders
51 program.upload( vertexShaderAssembler.agalcode, fragmentShaderAssembler.agalcode);
52
53 // clear the buffer
54 context3D.clear ( 1, 1, 1, 1 );
55
56 // set the vertex buffer
57 context3D.setVertexBufferAt(0, vertexbuffer, 0, Context3DVertexBufferFormat.FLOAT_3);
58 context3D.setVertexBufferAt(1, vertexbuffer, 3, Context3DVertexBufferFormat.FLOAT_2);
59
60 // set the texture
61 context3D.setTextureAt( 0, texture );
62
63 // set the shaders program
64 context3D.setProgram( program );
65
66 // create a 3D matrix
67 var m:Matrix3D = new Matrix3D();
68
69 // apply rotation to the matrix to rotate vertices along the Z axis
70 m.appendRotation(getTimer()/50, Vector3D.Z_AXIS);
71
72 // set the program constants (matrix here)
73 context3D.setProgramConstantsFromMatrix(Co
74 ntext3DProgramType.VERTEX, 0, m, true);
75
76 // draw the triangles
77 context3D.drawTriangles( indexBuffer);
78
79 // present the pixels to the screen
80 context3D.present();

上述范例中的代碼創建了一個正方形的2D實例(參見圖5):

圖5. 使用drawTriangles API 和一個帶有紋理的四邊形創建一個2D對象的結果
圖5. 使用drawTriangles API 和一個帶有紋理的四邊形創建一個2D對象的結果

上述范例中所示的代碼無疑是非常復雜的。 那是訪問低級 APIs 需要付出的代價。 從另一方面說,你可以控制很多方面,但是它需要大量的代碼來設置一切。

通過 Starling,你可以編寫如下代碼替換上述代碼:

 1 // create a Texture object out of an embedded bitmap
2 var texture:Texture = Texture.fromBitmap ( new embeddedBitmap() );
3
4 // create an Image object our of the Texture
5 var image:Image = new Image(texture);
6
7 // set the properties
8 quad.pivotX = 50;
9 quad.pivotY = 50;
10 quad.x = 300;
11 quad.y = 150;
12 quad.rotation = Math.PI/4;
13
14 // display it
15 addChild(quad);

作為一個熟知如何使用 Flash APIs 的 ActionScript 3 開發人員,你可以立即使用這些已暴露的 APIs 開始工作,與此同時 Stage3D APIs 的所有復雜部分都可以在后台進行處理。

如果你使用重繪區域(redraw regions)功能進行試驗,在 Starling 將在 Stage3D 上,而不是在預期的傳統顯示列表上渲染一切。 如下的截圖說明了這種行為。 該四邊形在每一幀上旋轉,重繪區域(redraw regions)只顯示FTP計數器,而不是 Stage3D 的內容(參見圖6):

圖6. 使用Stage3D渲染內容的范例
圖6. 使用Stage3D渲染內容的范例

需要記住在使用 Stage 3D 構架時,通過 GPU 可以完全地渲染並合成相應的內容。 因此,在 GPU 上運行的用於顯示列表的重繪區域(redraw regions)功能不能使用。

分層限制

當你使用 Starling(以及Stage 3D)時,記住開發內容有一個限制。 正如之前所述,Stage3D 完全是嵌入在 Flash Player 中的全新的渲染構架。 GPU 表層放置在顯示列表之下,這意味着任何在顯示列表中運行的內容將放置到 Stage3D 內容之上。 在編寫這篇文章時,運行在顯示列表里的內容仍然不能放置在 Stage3D 分層之下(參見圖7)。

圖7. 使用Stage3D渲染內容的堆疊順序
圖7. 使用Stage3D渲染內容的堆疊順序

此外,還要注意 Stage3D 對象不是透明的。 如果這是可能的,那么你可以使用 Stage Video 技術(Flash Player 10.2引入的功能)播放視頻,同時可以用通過 Stage3D 渲染的內容覆蓋視頻。 希望未來的 Flash Player 版本支持這一功能。

設置項目

你可以訪問官方的 Github頁面下載Starling。 此外,你可能發現訪問 Starling 網站也會受益匪淺。

Starling根據 Simplified BSD許可獲得授權,所以你可以在任何類型的商業或者非商業項目上使用Starling。 如果你需要更多的信息,你可以聯系 Starling 框架團隊

在你下載Starling之后,你可以像引用其它AS3庫一樣引用Starling庫。 為了使用Flash Player 11 beta的新版本,你必須把SWF版本13作為目標,這是通過將額外的編譯器參數即-swf-version=13 傳遞給Flex編譯器實現的。如果你正在使用 Adobe Flex SDK,那么請按照如下步驟操作:

  1. Flash Player 11下載新的playerglobal.swc。
  2. 從Flex 4.5 SDK表中下載 Flex 4.5 SDK (4.5.0.20967)。
  3. 將相應的版本安裝到你的開發環境中。
  4. 在 Flash Builder 中,通過選中File > New > ActionScript project 創建一個新的ActionScript項目。
  5. 打開 Property inspector(右擊並選中Properties選項)。 在左邊的菜單列表中,選中ActionScript Compiler。
  6. 使用右上角的 Configure Flex SDK 選項將項目指向 Flex build 20967。單擊OK。
  7. 設置你的項目目標為SWF版本13。
  8. 打開Property inspector並從左側菜單列表選中 ActionScript Compiler。
  9. -swf-version=13 添加至 'Additional compiler arguments' 輸入。這就保證了輸出的 SWF 把 SWF 版本13當做目標版本。如果你在命令行而不在 Flash Builder 中進行編譯,那么你必須添加相同的編譯器參數。
  10. 核查你已經在你的瀏覽器中安裝了新的Flash Player 11 版本。

設置場景

在你已經准備好了你的開發環境之后,你就可以深入研究相應的代碼,並且看看你如何能夠充分利用這一框架。 使用 Starling 非常簡單,你只需創建一個 Starling 對象並添加到你的主類即可。 在本文中,當涉及到諸如 MovieClip, Sprite 以及其它對象時,我所指的都是 Starling APIs,而不是來源於 Flash Player 的本地對象。

首先,Starling構造器(constructor)需要多重參數。 下面是簽名:

1 public function Starling(rootClass:Class, stage:flash.display.Stage, viewPort:Rectangle=null, stage3D:Stage3D=null, renderMode:String="auto")

 

事實上,只有前面3個經常使用。 相關的 rootClass 參數需要一個至擴展 starling.display.Sprite 的類的引用,而第二個參數是我們的 stage,然后是一個 Stage3D 對象:

 1 package 
2 {
3 import flash.display.Sprite;
4 import flash.display.StageAlign;
5 import flash.display.StageScaleMode;
6 import starling.core.Starling;
7
8 [SWF(width="1280", height="752", frameRate="60", backgroundColor="#002143")]
9 public class Startup extends Sprite
10 {
11 private var mStarling:Starling;
12
13 public function Startup()
14 {
15 // stats class for fps
16 addChild ( new Stats() );
17
18 stage.align = StageAlign.TOP_LEFT;
19 stage.scaleMode = StageScaleMode.NO_SCALE;
20
21 // create our Starling instance
22 mStarling = new Starling(Game, stage);
23
24 // set anti-aliasing (higher is better quality but slower performance)
25 mStarling.antiAliasing = 1;
26
27 // start it!
28 mStarling.start();
29 }
30 }
31 }

 

在下面的代碼中,Game類在被添加到 Stage 時可以創建一個簡單的四邊形:

 1 package 
2 {
3 import starling.display.Quad;
4 import starling.display.Sprite;
5 import starling.events.Event;
6
7 public class Game extends Sprite
8 {
9 private var q:Quad;
10
11 public function Game()
12 {
13 addEventListener(Event.ADDED_TO_STAGE, onAdded);
14 }
15
16 private function onAdded ( e:Event ):void
17 {
18 q = new Quad(200, 200);
19 q.setVertexColor(0, 0x000000);
20 q.setVertexColor(1, 0xAA0000);
21 q.setVertexColor(2, 0x00FF00);
22 q.setVertexColor(3, 0x0000FF);
23 addChild ( q );
24 }
25 }
26 }

上述代碼將一個偵聽器添加到 Event.ADDED_TO_STAGE 事件中,並在事件處理程序中對應用程序進行初始化。 這樣你就可以安全地訪問 Stage。

注意: 關注一下這個微妙的細節:上面描述的 Game 類從 starling.display 程序包中,而不是從 flash.display 程序包中擴展了 Sprite 類。必須檢查你的導入語句並確保你不是使用本地 API 來替代 Starling API。

正如在 Flash 中所預期的,Starling 中的對象有一個默認的位置0,0。因此添加幾行命令使四邊形位於 Stage 的中央:

1 q.x = stage.stageWidth - q.width >> 1;
2 q.y = stage.stageHeight - q.height >> 1;

現在,測試一下項目以便於觀察相應的結果(參見圖8):

圖8. 四邊形位於Stage的中央
圖8. 四邊形位於Stage的中央

注意鋸齒消除功能(anti-aliasing)值允許你設置鋸齒消除功能所需的類型。 一般來說,值為1就基本上可以接受,但是你可以選擇其它值。 該框架支持的鋸齒消除功能(anti-aliasing)值的變化范圍是0到16,但是,下面的列表給出了最常用的值:

  • 0: 無鋸齒消除(anti-aliasing)。
  • 2: 最低程度的鋸齒消除(anti-aliasing)。
  • 4: 高質量的鋸齒消除(anti-aliasing)。
  • 16: 極高質量的鋸齒消除(anti-aliasing)。

你很少需要用到超過2的設置,尤其是對2D內容。 然而,根據你的項目要求,你需要針對具體情況作出相應的決定。 在圖9中,比較一下兩個截圖,觀察兩個鋸齒消除(anti-aliasing)值(1和4)之間的細微差別。

圖9. 比較一下鋸齒消除(anti-aliasing)值為1(左)和4(右)之間的視覺差別
圖9. 比較一下鋸齒消除(anti-aliasing)值為1(左)和4(右)之間的視覺差別

試驗一下使用2以上的值為你的項目設置所需的質量。 當然,選擇較高的值會影響性能。 注意 Stage3D 不會受到 SWF 文件的 Stage 質量影響。

下面給出能夠與 Starling 對象一起使用的其它 API 的描述:

  • enableErrorChecking: 允許你啟用或者禁止啟用錯誤檢查。 指定是否將渲染器遇到的問題報告給應用程序。 當 enableErrorChecking 設置為ture時,Starling 內部調用的 clear() 和 drawTriangles() 方法是同步的並可以拋出錯誤。 當 enableErrorChecking 設置為 false 時,clear() 和 drawTriangles() 方法是異步的且不報告錯誤。 啟用錯誤檢查將會減弱渲染性能。 只有當調試項目時啟用錯誤檢查功能,而在部署最終版本前禁止啟用該功能。
  • isStarted:指示是否調用了 start。
  • juggler: juggler 是一個簡單對象。 它僅保存了一列執行 IAnimatable 的對象,並且在被要求這樣做的情形下提前了它們的時間(通過調用它自己的 advanceTime:方法)。 當一個動畫完成時,它將會將其拋棄。
  • start: 開始渲染和進行事件處理。
  • stop: 停止渲染和進行事件處理。 當游戲進入后台運行狀態以節約資源時,使用這個方法可以停止渲染。
  • dispose: 當你希望處理當前 GPU 內存上已渲染的全部內容時,調用這個方法。 該API能夠在其內部處理了一切事務(例如着色程序(shader programs)、紋理和其它一切事務)。

一旦創建了你的 Starling 對象,調試記錄會自動地輸出,顯示關於渲染的信息。 在默認情形下,當 SWF 文件正確地嵌入到頁面或者當在獨立的 Flash Player 中進行測試時,Starling 會輸出如下代碼:

[Starling] Initialization complete.
[Starling] Display Driver:OpenGL Vendor=NVIDIA Corporation Version=2.1 NVIDIA-7.2.9 Renderer=NVIDIA GeForce GT 330M OpenGL Engine GLSL=1.20 (Direct blitting)

當然,特定的硬件細節將會隨着你的配置而變化。 上述信息表明已經使用了 GPU 加速功能,因為它包括驅動版本的細節。 為了便於調試,你可能希望能夠強迫 Flash Player 內部使用的軟件回退,以便了解當你的內容在軟件上運行時它的表現如何。

添加如下的代碼以便於通知 Starling 你希望使用軟件回退功能(software rasterizer):

1 mStarling = new Starling(Game, stage, null, null, Context3DRenderMode.SOFTWARE);

當你使用軟件時,輸出的信息會確認你正在使用software 模式:

[Starling] Initialization complete.
[Starling] Display Driver:Software (Direct blitting)

確保你也在 software 模式下測試了你的內容,以便於更好地了解它在這種模式下的性能。 如果用戶的配置使用舊版本的驅動(為了保持一致性,所有2009年之前的驅動都包含於黑名單中),那么你的內容可能回退到軟件。

在下一節中,當你將你的 SWF 文件嵌入到頁面時,你需要看一下 Stage3D 的要求。

Wmode 要求

你必須記住為了啟用Stage 3D 和 GPU 加速功能,在頁面中你必須使用 wmode=direct 作為嵌入模式。 如果你沒有指定任何值或者選擇除“direct”之外其它值,例如 “transparent”、“opaque” 或 “window”,則Stage 3D 將均不可用。相反,當 requestContext3D on Stage3D被調用時,你會得到一個運行時異常的提示,告知你Context3D對象的創建失敗。

下圖列舉了一個運行時異常的對話框:

圖10. 在 Context3D不可用的情形下,運行時異常對話框
圖10. 在 Context3D不可用的情形下,運行時異常對話框

如果你的應用程序嵌入時使用了錯誤的wmode,那么必須小心處理這種情形。 你需要通過顯示一條解釋這一問題的信息以便給出合理的響應。 幸運的是,Starling為你自動地處理了這一問題並顯示如下信息:

圖11. 當應用程序沒有正確嵌入時顯示的警告信息
圖11. 當應用程序沒有正確嵌入時顯示的警告信息

Stage質量

作為一個Flash開發人員,stage質量的概念對你來說並不陌生。 記住當使用 Stage3D以及作為結果的Starling時,stage質量不會影響相應的性能。

漸進的增強功能

當GPU加速功能不起作用時,Stage3D將回退到軟件中,並且將在內部使用一個名稱為SwiftShader (Transgaming)的軟件回退引擎。 為了保證你的內容在此種情形下運行正常,你需要檢測什么時候你應該在software模式下運行,並且移除在software模式下可能會減慢運行速度的潛在影響。

在2D內容環境下,軟件回退功能能夠處理很多對象並提供良好的性能,但是,為了檢測這一點,你仍然可以使用靜態的屬性環境從Starling對象中讀取Context3D對象:

// are we running hardware or software?
var isHW:Boolean = Starling.context.driverInfo.toLowerCase().indexOf("software") == -1;

記住使用軟件回退功能設計你的內容是一種很好的做法,它將提供一種漸進式的體驗,從而確保在任何情形下都能獲得最佳體驗效果


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM