Programming pipeline & shading language
大家好,今天想給大家介紹一下可編程渲染管線和著色器語言的相關基礎知識,使想上手SHADER編程的童鞋們可以快速揭開SHADER語言的神秘面紗
由于時間有限,我決定只講三個主要方面的內容,其過程中肯定會有不詳細之處,還請見諒,就算是拋磚引玉,給大家一個簡單的入門引路。
本章內容總共分為三個部分 一、3D渲染管線工作流程 二、可編程管線 三、著色器語言
3D渲染管線作為整個工作流程的基礎,是不可或缺的基本知識。因此,作一定的講解是有必要的。 但作為一個回顧內容,就不會對具體的內容進行講解,比如如何進行坐標系變換,如何進行光柵化等等。 我們僅關注的是整個工作的過程。
甚至,我們更關心的不是整個工作過程中的細節,而是我們所必須要關注的幾大流程。 如下圖
數據填充
當我們想實現一次渲染效果的時候,數據的提交(填充)是不可缺少的。 因此,工作流程的第一步就是要處理輸入的數據。
而我們最直接的接觸3D渲染流程的時機,也就是數據填充時,更確切的說,就是那一堆set數據的API。
數據填充允許我們提交我們想要的數據,比如頂點數據(如位置,法線,顏色,紋理坐標等)。常量(如世界矩陣,觀察矩陣,投影矩陣,紋理因子等等)。
變換&頂點光照
在這個階段,頂點會經過世界變換,觀察變換,投影變換。 通常情況下,在頂點經過觀察變換后,便開始做一些光照計算。 這一階段也是可編程管線所提供的頂點處理階段。也就是說,我們可以通過著色器程序來控制這一階段的結果。 在著色器程序中,我們可以任意地處理想要的數據,比如進行紋理坐標縮放,旋轉,隨機偏移等等。
裁剪&光柵化
當經過坐標變換和光照后,頂點已經被投影為2D坐標+深度信息。 一些不可見的頂點會被裁剪掉,比如那些處于背面的點。 同時,剩下的頂點會被插值計算,以形成由像素構成的圖元。 所有的信息都會被插值,如紋理坐標,法線,顏色等。
像素處理
像素處理階段是一個最耗時,但是也是最能夠使你的渲染效果品質更高的地方,像素最終的樣子會在此決定,你可以進行紋理映射,紋理混合,模糊,擴散等效果。
這也是可編程管線中可以使用SHADER控制的另一個處理過程,
像素的一些額外處理和輸出
當像素經過像素處理階段后,并不能都有機會輸出到屏幕上,因為它們還要經過深度(也有一些比較優化的渲染管線將深度測試提到了像素處理前)和模板測試,ALPHA測試,經過這些測試后, 還要進行一次ALPHA混合,這次與目標緩沖區的混合,就能夠實現半透明效果。 虛擬世界中的五光十色就是因為這個半透明效果而生動。
-------------------------------------------------------
正如上面所說,在3D渲染流程中,我們能夠用著色器語言控制的就是“頂點變換和光照” 以及 “像素處理”階段。 在我們講如何控制之前我大概介紹一下GPU中用于處理著色器的最基本的幫手 - 寄存器。
GPU中的寄存器與CPU中的普通寄存器有一點不同, GPU中的每一個寄存器都是一個四維向量寄存器,即一個寄存器擁有4個浮點分量。 通常我們用
(x,y,z,w)或者(r,g,b,a)來表示。
輸入寄存器
輸入寄存器是GPU用來接受數據的寄存器,當我們將渲染數據填充到GPU時,其實就是將這些數據填充到這些輸入寄存器上。
比如,當我們將一個頂點的位置和法線提交后,GPU在處理這個頂點時,其對應的寄存器就會擁有這個頂點相應的值。
頂點處理階段和像素處理階段用到的輸入寄存器是不同的。輸入寄存器決定了對應的處理階段能夠做的事情。
比如,我們提交了一個三角形的頂點和紋理坐標信息,并且我們提交了一張紋理,用來對這個三角形做紋理映射。 但是,我們是不能在頂點處理階段就對其紋理做處理的。 因為我們不能在頂點處理時訪問紋理數據(如果真要這樣,那就只能夠使用頂點紋理了,這個內容超出了本次介紹的范圍,固不再多說)。
常量寄存器
常量寄存器用來向著色器傳遞我們所需要控制的常量信息,比如,世界矩陣,觀察矩陣,投影矩陣,紋理矩陣等。 以及我們可以設置一些值,比如當前時間,用來實時偏移一個頂點的紋理坐標,使其紋理呈移動的效果。 又或者通過這個值,動態改變頂點的位置,使其出現波動效果。 這些就是常量寄存器可以干的事。
同樣,常量頂點處理階段和像素處理階段使用的常量寄存器也是不同的。不過,這種情況在SM 4.0以后得到改善,并且有一個趨勢,就是頂點處理和像素處理階段界線不再那么明顯。 他們可以共用寄存器,共用一些緩存。 但在你沒有完全掌握它們的特點以前,還是老老實實記住這個特性吧。
臨時寄存器
臨時寄存器使我們能夠在著色器處理的過程中存放一些臨時的值,若你是用高級著色語言編寫著色程序,那你是感覺不到臨時寄存器存在的,因為你僅僅是聲明了一個臨時變量。 但確實,這就是臨時寄存器的功勞。 它才是真正的幕后黑手。
紋理采樣寄存器
紋理寄存器用于存放你所提交的紋理,并且提供紋理采樣功能。 如臨近點采樣,雙線性采樣,三線性采樣等。 這些都肯定你的指示來做相應的工作。 它主要是輔助你完成紋理映射工作。
輸出寄存器
輸出寄存器就是你著色程序能夠輸出的內容,輸出內容通過輸出寄存器傳遞出來。 頂點處理程序的輸出有兩種, 一種是輸出到幀緩沖,另一種是輸出給像素處理程序,最典型的就是紋理坐標數據, 當頂點處理程序拿到輸入寄存器傳遞過來的紋理坐標值后,經過一些處理,又輸出。 而真正需要使用這個信息的,就是像素處理程序。
常見的有 位置,紋理坐標,顏色等。
-----------------------------------
下面,我們來看一下著色器語言吧。
著色器程序就如上面講的那樣,分為了頂點著色程序和像素著色程序。 你可能會發現,這里多了一個幾何著色程序,這個是后來新加入的兄弟,傳統的著色程序不能增加刪除頂點。 但是,它可以。 有興趣的童鞋中以繼續去了解。
著色器語言有高級語言和低級語言兩種。 低級語言采用的是匯編那種助記符方式。
如 dp4 r0,v0,c0 這樣的,表示將v0,c0點乘,并放入臨時寄存器r0中。
而高級語言則是C風格的,很符合人們的編程習慣。 與傳統的編程語言發展規律是相同的。
如 float temp = dot(dir,normal);
而常見的著色器語言中,低級語言如D3D中的LLSL,以及Adobe新出的Statge3D協同工作的AGAL.
高級語言如 CG,HLSL,GLSL應該很熟了吧。
CG是NVIDIA公司出的語言,它可以在D3D和OPENGL中工作,但需要使用NVIDIA對應的SDK。
HLSL是D3D協同工作的高級著色器語言。
GLSL是OPENGL協同工作的高級著色器語言。
--------------------------------------------------------------------------------------------------------------
說了這么多,我們來看看一個簡單的例子吧。 HLSL版
我打上了注釋,就不再敘述
//VERTEX SHADER
float4x4 matViewProjection; //世界-觀察-投影矩陣
struct VS_INPUT //輸入結構,這個結構中的內容,表示我們SHADER所關心的內容,同時,程序在進行數據填充時,應該保證這些關注的數據被提交
{
float4 Position : POSITION0; //位置
float2 Texcoord : TEXCOORD0; //紋理信息
};
struct VS_OUTPUT //輸出結構,這個結構中的內容,表示此SHADER的輸出
{
float4 Position : POSITION0; //位置信息,已經經過坐標系變換
float2 Texcoord : TEXCOORD0; //紋理信息
};
VS_OUTPUT vs_main( VS_INPUT Input ) //頂點程序的入口函數
{
VS_OUTPUT Output; //聲明一個結構體
Output.Position = mul( Input.Position, matViewProjection ); //做矩陣變換
Output.Texcoord = Input.Texcoord; //直接輸出紋理信息, 如果你想對它做點手腳,是很容易的。 這就是FFP中紋理矩陣所做的事情。
return( Output );
}
//PIXEL SHADER 它就相對簡單多了
sampler2D baseMap; //紋理
struct PS_INPUT //輸入結構,與VS中的輸入結構類似,但此輸入結構均來自于VS的輸出。
{
float2 Texcoord : TEXCOORD0; //表示我們只需要用到紋理坐標信息
};
float4 ps_main( PS_INPUT Input ) : COLOR0 //出口函數。 COLOR0表示我們輸出的float4是用作顏色輸出, 也可以定義類似 PS_OUTPUT的結構
{
return tex2D( baseMap, Input.Texcoord ); //很簡單,就是取得對應紋理坐標處的像素值,輸出, 你可以在此做一些事情,比如調得更亮,或者拿另一張紋理采樣,與它混合。 混合的公式就由你自己定了,你想寫得多復雜都可以。 理論是如此。
}
//========== 感興趣的朋友可以看看上面的SHADER對應的低級版本==========
// VS
// Generated by Microsoft (R) HLSL Shader Compiler 9.22.949.2248
//
// Parameters:
//
// float4x4 matViewProjection;
//
//
// Registers:
//
// Name Reg Size
// ----------------- ----- ----
// matViewProjection c0 4
//
vs_2_0
dcl_position v0
dcl_texcoord v1
dp4 oPos.x, v0, c0
dp4 oPos.y, v0, c1
dp4 oPos.z, v0, c2
dp4 oPos.w, v0, c3
mov oT0.xy, v1
// approximately 5 instruction slots used
//PS
//
// Generated by Microsoft (R) HLSL Shader Compiler 9.22.949.2248
//
// Parameters:
//
// sampler2D baseMap;
//
//
// Registers:
//
// Name Reg Size
// ------------ ----- ----
// baseMap s0 1
//
ps_2_0
dcl t0.xy
dcl_2d s0
texld r0, t0, s0
mov oC0, r0
// approximately 2 instruction slots used (1 texture, 1 arithmetic)
說到這里,差不多要結束了。但還是再多說兩句。
由于硬件條件的限制 VS和PS中對指令條數和可使用的寄存器個數都有限制,雖然隨著硬件的發展,這個限制已經可以被忽略了。比如SM 4.0就已經將這個限制放寬到很大。
但當我們在寫著色程序時,除了追求效果外,還要追求效率。因此,節約使用資源將會提升效率, 一個很好我評判標準就是你的SHADER所使用的指令數
如上面低級語言版本中 VS,PS都有如下內容
// approximately 5 instruction slots used
// approximately 2 instruction slots used (1 texture, 1 arithmetic)
因此,它將能夠很直觀地評估出你SHADER的效率。 但真正的結果,還是要實際測試。 由于硬件的不同,可能還存在兼容性上的問題。
祝各位一路順風。
上面的SHADER代碼取自 RenderDonkey 這個軟件 在ATI官網上可以下載。
或者,直接點這里http://developer.amd.com/archive/gpu/rendermonkey/pages/default.aspx
強勢三國卡版風頁游《五虎上將》----等你來戰
《五虎上將》神跡官網:點擊進入游戲
看著五虎上線了,說實話,心里還是有一絲竊喜,卻又一絲悲傷。
竊喜的是這也算是自己參與過的項目上線了,悲傷的是,這不是自己手把手從頭到尾一路走來的項目。
沒有那種一路風雨走過來的感覺。
話說,雖然自己不是從五虎從頭到尾跟過來的,但我確實從五虎中學到了許多, 特別是學到了 “如果我也這樣做,那結果就是現在這樣”。
它就像是一面鏡子,時刻讓自己反醒。
我并不是說五虎代碼差成什么樣,而是,這就是傳說中的“經驗”。恰巧,這些東西,被我悄悄地偷取了。
由于是后入五虎項目組的,所以我并不能參與五虎的功能部分開發。當然,這也是我所期望的。 我不想讓自己糾結于泥潭中無法抽身,又或者當我抽身后,
把別人陷入了泥潭中。
因此,我只能在資源加載,瀏覽器緩存,代碼規范上給予他們幫助。
在為五虎尋找解決方案的同時,另一個項目也在進行著, 一個教育類養成頁游項目。于是,我將所有的方案先應用于養成頁游中,經測試和優化完畢后,再投入五虎項目組。
下面是我研究和整理出來的一些方案,這些方案并不完美,甚至說僅僅是一些很常見的手法。于是,我大可公布于下,不必擔心任何糾葛。因為這并非是我個人所創的專利,也不是五虎項目所特有的東西,而是我在擁有蕓蕓眾生的網絡中擺渡,谷歌而來。同時,希望有志同道合的朋友能夠給我提出建議,相互交流,共同進步。
資源加載相關事項:
一、首要的任務,就是要將資源請求打包為一個隊列。 這樣外部需要加載多個資源時,就可以把隊列作為一個整體來進行事件監聽等。
二、其次就是資源的分類,資源至少可以分為三類, 一類是Modules.即FLEX中用來模塊化的東西,類似于C++中的DLL,(swc即類似于lib)。其次是ApplicationDomain.這多半是FLASH IDE編輯資源后的導出類。 最后就是純數據了, 如XML或者一些配置文件。 所以,需要將其分類,并能夠以一個很方便訪問的方式來管理。
三、Loading方式。 Loading方式大概也可以分為兩類, 一類是阻塞式,一類是非阻塞式。 阻塞式就是那種需要出現Loading條的方式,使用這種方式時,資源必須要完全加載完成后,才可以使用。如一些配置文件,UI組件的皮膚資源等。 非阻塞式就是不需要等待,而是在資源未加載完成時,統一采用一個顯示資源來替換。 比如一些圖標,或者RPG地圖中一些人物的顯示(許多游戲在人物未加載完成時,顯示一個球形)。
pureMVC使用注意事項:
一、pureMVC的使用應盡量標準,如果MVC使用得不標準,還不如不用。
二、盡量只在UI與業務邏輯通信時才使用pureMVC,邏輯與邏輯通信應當避免使用,否則會導致邏輯BUG的完全不可控。
模塊劃分注意事項:
一、游戲是一個巨大的項目,模塊劃分在所難免。 不論是否拆分為新工程,都必須明確規定各模塊代碼所能操作的權限,若權限過大,會導致無力維護,人走茶涼的現象。
二、若是采用Flex module進行模塊劃分, 若各Modules分開建立項目,則需要注意文件夾的層級,以及Modules編譯時相對主模塊的優化選項要開啟。
三、若將所有的Module依然放到一個項目里,則依然要注意文件夾的層級,規范各模塊代碼的操作權限,通信方式等。
UI方案:
一、Flex Button大小問題 若采用Flex Button并使用CSS Style方案,則要注意 對于 downSkin,若需要改變大小,則要保證其up down over狀態使用的皮膚都具有同樣的大小。(特別是FLASH IDE中導出元件的話,更要注意,僅僅將縮小后的元件錨點偏移,是會失真的,因為FLEX BUTTON只識別一個元件有效像素的包圍框作為元件尺寸。 可以新建一個透明層或者遮罩層來解決這個問題。
二、Button的特殊性 采用CSS使用FlexButton需要將Button各幀拆開。這涉及到美術工作量問題,所以,對于那種以圖片展現(即不需要在BUTTON上添加文本)的BUTTON,可以直接使用FLASH IDE導出SimpleButton并直接使用即可。 而對于那種需要動態修改文本的按鈕,采用CSS即可。
三、CSS文件的使用。 CSS的使用可以說極大地方便了UI的工作,其實就是將FLEX的UI換膚而已。 但是采用CSS文件方式并不適合我們。因為CSS文件的靜態和動態使用方式都會導致文件巨大。
靜態使用方式, 即<mx:Style source=”ooxx.css”/> 方式,這種方式會把 ooxx.css中所嵌入的資源都嵌入到嵌入ooxx.css樣式的SWF中來。
動態使用方式, 即將css編譯為swf 如 ooxx.swf 并用styleManager加載。 這個方案有一個好處,就是可以動態加載和卸載需要的CSS樣式。 看似天衣無縫的方案,卻有極大的弱點。 當你查看ooxx.swf的大小時,你會發現,就算你什么資源也沒嵌入,也會有300KB+的大小。 這是因為css本身是一個module.它會引入一個flex module所要import的符號。可惜,CSS編譯時,并不能指定針對某個主模塊進行優化。 我也曾嘗試將ooxx.css嵌入到一個module A.mxml中。并在編譯時針對主模塊進行優化,文件減小到了60+KB. 60+KB足夠一個公共UI庫的大小了。所以,CSS文件一定要慎用。
四、CSSStyleDeclaration與setStyle. 可以通過動態注冊CSS樣式來達到修改FLEX組件樣式的目的。 具體使用方法可以搜索這兩個關鍵字。 但是,在使用時,請先將所需要的資源載入。
五、TabNavigator 視情況而用。
六、可拖動窗口 并不一定要使用TitleWindow 若要使窗口可拖動,只需要將窗口startDrag()即可。 而對于許多窗口來說,我們想要實現的是點擊某個位置或者僅當點擊標題欄才拖動。 這個時候,我們可以添加一些透明的組件在這個窗口上,監聽這些透明的組件,并startDrag()窗口即可。
功能劃分:
一、不管是哪種游戲類型,都應該把場景和UI劃分清楚,就算是鼠標流的策略游戲,也是如此。 否則在邏輯功能上也會模糊不清。
二、游戲,永遠都有場景和UI,沒有PAGE。。。 這是頁游和網頁的本質區別。希望做網頁轉為做頁游的朋友能夠接受這個現實,轉變一下思路。
----------------------------------分割線-----------------------------------
瀏覽器緩存避免
瀏覽器緩存方案也是世人皆知的,我也僅簡單說一下。 更多內容,可以參考本BLOG中,瀏覽器緩存相關文章。
要想完成瀏覽器緩存避免需要弄清楚兩個事情 一、瀏覽器會緩存以URL全路徑方式緩存HTTP所請求的資源(js,html,swf,txt等等都可以)。 二、FLEX中的資源加載,是 HTTP請求方式。 也就是說, FLEX項目中加載的資源,都會被瀏覽器緩存, 這也是導致許多時候,游戲資源更新失敗的原因。
而要完全解決瀏覽器緩存問題,需要保證兩個東西 第一、主文件 (比如whsj.swf)更新正常。 第二、主文件所使用的資源(如 assets/loading.swf)更新正常 .
這里,我們要用到HTTP請求時的傳參功能 即在請求的資源URL后面加上?號 如 assets/loading.swf?v=1.0 。
在時行資源請求時,HTTP會忽略掉?號,以及以后的字符。 但瀏覽器緩存會緩存整個URL路徑。 并且在進行緩存訪問匹配時,也是采用的全路徑。 所以,我們可以在資源請求時,給每個資源加上一個版本號。
網上的一個兄弟說的采用SVN生成每一個資源的版本號方案確實很給力,但我認為實在很麻煩。于是,我們大可在請求每個資源時,加上游戲的發布版本號。 這樣,瀏覽器在進行資源緩存時,會將版本號信息一起緩存,當版本更新時,匹配則不會成功,從而解決了資源更新時,使用了舊資源的問題。
而最主要的,還是主文件的緩存, 因為就算你資源更新了, 但主文件沒更新, 那么,游戲功能就不會變。 當你采用舊版游戲功能與新版的服務器端通信時,自然會出現各種各樣的DOWN和黑屏。 因此, 主文件也要加版本號 如whsj_1_0.swf 而每次版本發布時,運營官網作相應的更改即可。
此方案也是目前我用在五虎項目上的初步方案。 對于主文件版本號的管理,許多公司的做法是加一個殼, 即做一個專門用于加載主文件的swf 它幾乎不會更改, 永遠都是采用隨機數或者時間戳讀取主文件版本號信息 如 version.xml?v=20111113,并使用 whsj.swf?v=1.0這樣的方式來加載主文件。 這在版本發布時,可以一層不變。僅修改版本號信息文件即可。 而版本號文件采用時間戳等方式讀取,可以保證每次都加載到最新的。
最后,祝賀一下二部項目天地劫即將測試。
天地劫神跡官網:點擊進入
在網上搜瀏覽器緩存問題時,遇上了很多問題。一是不知道應該用何種關鍵字搜索,二是一搜出來,就全是講的是如何禁用瀏覽器緩存的方案。
作為大型點的FLASH WEBGAME來說,不緩存顯然是不行的。總體上來說,我們要想達到的目標就是
一、瀏覽器需要緩存
二、當服務器資源更新時,瀏覽器緩存里相應的老版本資源失效。
下面兩篇文章講到了一個很好的解決方案,并且給出了源碼。。
更新文件避免瀏覽器緩存的解決方案(基于svn)
http://www.itamt.com/2010/06/browser_cache_prevent_base_on_svn/
更新文件避免瀏覽器緩存的解決方法(源碼)
http://www.itamt.com/2010/07/file-revision-prevent-browser-cache-svn/#comment-163
由于作者BLOG上的代碼無法下載,并且作者的實現與第一篇中描述的略有差異,于是我試著留言給作者。熱心的作者當天就給了我回復。
以下是我整理后的回復內容:
你好, 關于你說的:
1 、你最后的方案是不是 僅僅在資源請求時,追加一個版本號? 我發現IE瀏覽器緩存是將整個請求URL緩存下來了的。也就是說,版本號也緩存了。 這樣,當我們使用版本號請求資源時,就可以實現總是得到服務器上的資源了。
2、IE和Firefox的緩存機制差異有多大? 主要是緩存后的URL路徑上。。。
我把我的想法說一下, 盡量表述清楚-_-:
不管IE和Firefox瀏覽器緩存都是將整個請求url緩存下來的. 而我的解決方案本質與你說的是一樣的, 即"僅僅在資源請求時,追加一個版本號".
一般的做法,發布新版本時,比如v1.5,我們大可以在所有資源請求都加上"....?v=1.5", 這樣做沒有錯.肯定是會避免瀏覽器緩存的.
問題是:這種方法會重新請求所有的資源. 而項目發布的通常情況是:只有少部分資源有修改. 所以這種方法是很浪費帶寬的, 也加重了服務器的壓力. 理想的情況就是:只重新請求那些被修改過的資源.
下面表述一下我的解決方案:
假設現在項目是v1.0, 我們要發布v1.5上去. 我們利用SVN產生一份文件, 來記錄v1.5中所有資源的SVN版本號. 當請求一個資源時, 追加這個資源的SVN版本號. 如果一個資源(比如: icon.jpg, SVN版本號是1010)在v1.5中沒有被修改, 那么它的SVN版本號與在v1.0的SVN版本號肯定是一樣的都是1010:
在v1.0中,瀏覽器請求icon.jpg的url是:http://.....icon.jpg?svn=1010
在v1.5中,瀏覽器請求icon.jpg的url是:http://.....icon.jpg?svn=1010, 這時候會直接從瀏覽器緩存中取出. 不會重新請求.
如果v1.5中一個資源(比如: logo.jpg, SVN版本號是1234)是修改過的, 它在v1.0的SVN版本號是1222, 請求資源時:
在v1.0中,瀏覽器請求icon.jpg的url是:http://.....logo.jpg?svn=1222
在v1.5中,瀏覽器請求icon.jpg的url是:http://.....logo.jpg?svn=1234, 這時候與瀏覽器緩存中的請求是不一樣的. 所以會重新向服務端請求.
思路就是這樣的. 所以關鍵是利用SVN來記錄的版本號請求資源.
這個解決方案最終實現出來主要是兩個文件.
1.cur.txt記錄整個項目當前的SVN版本號.
2.revision.txt記錄項目當前版本中所有資源的SVN版本號.
整個項目程序一開始(Preloader.swf), Preloader.swf會先確定整個項目SVN版本號(加載最新cur.txt, 或者在網頁中指定:...Preloader.swf?cur=20), 然后根據整個項目SVN版本號加載revision.txt, 比如現在項目SVN版本是20, 那么Preloader.swf會加載:
http://.....revision.txt?svn=20
加載完成后, 就可以完成mFileRevisionManager的初始化...
注意Preloader.swf不是進度條(load.swf), 它是整個項目最開始的地方, 所以應該盡可能小, 而且一旦完成最不要再去修改它.
附件里,有我做的demo. 我的開發環境是FDT4.5+Flash CS5.5, 文件夾tool里一個ant腳本, 和jsfl腳本. 使用時你需要修改publish.xml開頭的路徑. 然后運行這個ant腳本.
運行ant前, 注意設置下:這樣ant運行期間的輸出信息會顯示在eclipse里.
---------------------------------------------------------------
并且,我問了一下他對Preloader.swf的理解和用法
回復:
結合我參與的項目,說一下Preloader.swf是干么用的:
一般項目肯定會有一個load.swf和main.swf, 其中
1.load.swf用于顯示加載main.swf的進度,說白了load.swf就是個進度條.
2.main.swf就是整個項目的主程序.
而Preloader.swf是在load.swf之前加載的.也就是說加載順序是Preloader.swf->load.swf->main.swf
Preloader.swf主要用來加載"資源版本號文件"(revision.txt, cur.txt). 并且把整個資源版本機制初始化(在我的方案里就是mFileRevisionManager).
當然, 也完全可以把Preloader.swf并入load.swf(進度條)中. 但我的經驗是load.swf(進度條)其實是經常需要修改更新的. 而且為了重用性考慮, 我會把Preloader.swf用于不同的項目中. 所以把Preloader.swf與load.swf分開.
-----------------------------分割線--------------------------------
而考慮到目前項目的原因,我們決定暫時采用一個很簡單的方案。 就是在資源的根目錄下加版本號。
比如 1.0.0版本的資源目錄為
Assets_v1.0.0
我要加載一個ui.swf的URL就是 “Assets_v1.0.0/ui.swf”
而當版本更新時,比如到了1.0.1
我要加載一個ui.swf的URL就是 “Assets_v1.0.1/ui.swf”
這樣就像回復內容中說的,這會使瀏覽器緩存中所緩存的所有資源都失效。 雖然是如此,但總比用戶繼續使用老版本資源好。 并且,對于一個發布版的更新總會有時間間隔的,不會一天到晚都是這樣的情況。
而待項目趨于穩定后,再集中替換成上面那種最小資源更新的解決方案。
希望上面的信息能夠幫助到和我一樣迷惑的人。如果這些信息幫助到了你,請去參拜本文開頭引用的兩篇文章的作者,謝謝!!!!!!