2015年12月20日 星期日

THE BLACKSMITH 開發專案:所有願望一次滿足




作者:SILVIA RASHEVA 原文連結

大家好,我們之前承諾會發佈The Blacksmith影片裡用到的資源和專案定製的工具集與著色器。現在我們全部將他們奉上給你!

首先,你可以下載這個展示用專案的可執行版本

為了方便大家下載,專案的資源包和一些為專案定製的技術被劃分為兩包:角色和環境。

本文會說明每個工具包的內容,也會解釋我們做的一些選擇。

我們想做的不僅僅是發表酷炫的文章而已,而是想給Unity開發者真正有用的東西。希望這些內容可以馬上化作即戰力,被運用到你們自己的專案中。

先讓我來回答一個之前大家問最多也最關心的問題:沒錯!你可以用這些發佈的內容做任何形式的運用,哪怕是將它們用到商業中。

因為我們採用了標準的Asset Store 授權(授權範圍同等於免費資源)。如果你覺得在你成功之路我們所做的工作有帶來幫助的話,那將是我們最大的榮幸。

可執行版本 THE EXECUTABLE


我們增加了一些簡單的介面來控制DEMO的播放:

  • 你可以拖拽滑條來改變播放的進度
  • 點擊 播放/暫停 按鈕或是介面外任意位置,會切換DEMO播放或暫停狀態。
  • 暫停播放然後移動指針可以有小幅度的環視。
  • 一個靜音按鈕。

你可以透過選單選擇四種不同畫質

  • 低畫質—不能執行高階設定的機器建議採用此選項。
  • 中等畫質—在高階筆電或低端PC上推薦採用此選項。它被設定適用於一台擁有 Quad Core i7 2.5GHz的處理器 + GeForce GT 750M顯卡的筆電上以720P的解析度跑30FPS
  • 高畫質—在多數的PC上推薦採用此選項。它被設定適用於一台 Core i7 4770處理器 + GeForce GTX 760顯卡的PC上以1080P的解析度跑30FPS。
  • 超高畫質—如果你有一塊比GTX 760更加強勁的顯卡。它被設定能跑出超過30FPS。


THE BLACKSMITH – 角色包



這個專案包含:

  • 鐵匠角色
  • 維京挑戰者角色
  • 毛髮著色器
  • 皺紋貼圖
  • 獨特的角色陰影技術
  • 平面反射
你可以從這裡下載 THE BLACKSMITH 角色專案

鐵匠和維京挑戰者

我們將每個角色都放在一個單獨的場景中。並重調了維京挑戰者的皮膚,使他更適合用在各種遊戲場景中。所以非常歡迎大家在自己的環境使用維京挑戰者。當然,若你想讓他的動畫更加美觀的話,那你可能還有一些工作要做。

我們提供了兩組動畫「待命」和「行走」。


在這個專案你還會找到另一位主角 - 鐵匠。我們並沒有修改他的皮膚,因為他要比維京挑戰者複雜很多,修改會花費我們太多的時間。這個原始的3D角色模型,你可以透過任何方式自由使用。


專案裡也包含了兩個角色原始的全尺寸4K貼圖。雖然在我們的專案中實際上用的是比較小的版本 - 2K或者更低一些。

角色的模型和貼圖分別由Jonas Thornqvist和Sergey Samuilov創作的。



毛髮渲染 Hair rendering

為了實現角色頭髮上各種高光反差,我們決定做一個獨立的毛髮著色器。

作為補充,我們還增加了一個用於計算頭髮環境光遮蔽的組件,並設計了一種多通道渲染的方法來避免半透明毛髮面之間在層疊次序上的錯誤。

你可以從這裡下載到毛髮專案和一個對應的範例場景。如果你想用在自己的專案中,記得詳讀說明文件。



皺紋貼圖Wrinkle maps

為了在The Blacksmith 專案中賦予角色更多的生命力,我們專門設計一個能夠依照維京挑戰者臉部形狀融合動畫來渲染「皺紋貼圖」的組件。

這個組件會在一個畫面之外的預渲染通道中融合標準貼圖和遮罩貼圖,然後將所得的結果送給標準著色器,最後取代在材質中的標準貼圖和遮罩貼圖。

你可以從這裡下載一個獨立專案,也可以參考之前發表過的皺紋貼圖說明文章(中文)。



特殊的角色陰影 Unique character shadows

我們希望我們的角色在近距離拍攝過程中能夠擁有柔和、高解析的陰影。同時也希望他們的影子在覆蓋場景其他物體時也擁有足夠的解析度。為了做到這一點,我們設計了一種給物件增加獨特陰影的方法。

獨特陰影專案可以從這裡下載,同時也有一篇專門介紹的文章(中文)。


平面反射 Plane reflections

在The Blacksmith中的平面反射,通常呈現為一個能夠反射光線的平靜水面。液態表面的扭曲效果一經渲染,我們便會將反射圖像映射到物件每一層mip等級的反射貼圖。

在這個運算的過程中,我們根據反射的深度資訊來迫使那些接近反射面的像素之間擁有更為清晰的接觸表面,這是為了模擬非鏡面反射情況下的光線效果。

運算的結果是一張反射貼圖,我們可以用它來替換預設反射探測器的方體貼圖。它能夠根據材質的粗糙程度來支配不同mip層級中的採樣。

我們修改了一個標準著色器,使它透過著色器關鍵字觸發後從上述貼圖動態取樣反射,而不是透過反射探測器的方體貼圖來完成反射的取樣。



THE BLACKSMITH – 環境專案


這個專案包含:

  • 鐵匠鋪
  • 野外場景
  • 大氣散射
  • PaintJob 工具集(在任意表面上繪制植被)
  • 植被系統
  • 遮罩混合著色器
  • 經過定製的標準著色器
  • 色調映射

你可以在按V在第一人稱視角和相機視角之間切換,按C可以切換不同的光照。

這裡下載THE BLACKSMITH – 環境專案,請注意:這個專案超大der。



鐵匠鋪 The Smithy

它看起來是這樣的:

The Blacksmith – 專案中鐵匠鋪的遊戲場景預覽



野外場景 The Exterior

我們決定重新組織場景的外觀,讓它更適合遊戲開發,方便大家能盡可能地用上它們。雖說我們還來不及對這些場景做更進行進一步的優化。但如果情況允許你投入更多的精力到這些場景的話,它將在遊戲開發的某些環節幫上大忙。

這就是我們為大家提供最終的場景外觀。



差別在於短片中我們是根據相機來組成環境排列的。如果你對這一點感到好奇的話,這裡有一張原始專案中野外場景總覽抓圖可參考。

The Blacksmith 原始專案場景總覽


另外還有一些資源在短片中並沒有用到,不過我們依然希望能和大家分享。你們可以在專案中找到它們。

幾乎所有素材包是由Plamen ‘Paco’ Tamnev一人創作的,野外場景也是他負責搭建的。



大氣散射Atmospheric Scattering

這個專案包含了我們所定製的大氣散射解決方案。這篇文章中能瞭解更多細節。為方便大家研究,我們也把大氣散射專案獨立出來放在在Asset Store上。那樣你就不用在專案裡大海撈針找了,來這兒下載吧。


PaintJob 工具集

這個小工具允許美術在任意的幾何形體上繪制植物,不限於Unity地形哦。這是我們思考如何最大限度利用Unity預設地形工具的一個方法,同時,這麼做也是為了實現我們在專案中的一項實際需求。

非常歡迎大家從The Blacksmith專案將它抽出來用到自己的專案。



植物植被系統 Vegetation System

我們希望The Blacksmith專案中的植物能夠做到兩件事情:

我們希望它是柔和的、可以自訂著色的、支持動態全域光照並能夠和一切被認定為是地面的東西融合協調併同時且能夠兼容Unity地表系統。

PaintJob 工具已經做到了後面兩項,不過為了達成上述目標,我們仍然需要進行一些額外的改變。

最終我們決定設計一個組件來捕捉PaintJob所產生的手繪資料,並產生一些植被的烘焙網格。這樣一來,渲染的支配權就依然掌握在我們自己的手中。

別的不說,這樣可以做任何自訂排序、重組動態貼圖中的光探測數據都沒有問題。



遮罩混合 MaskyMix Shader

遮罩混合著色器是一個標準著色器的變形,顧名思義,它可以根據特定的遮罩標準混合一組額外的細節貼圖。

遮罩主要基於材質-指定的世界-空間方向,每個像素的法線都從基礎法線貼圖取樣。

它同時會受到來自磁磚遮罩貼圖和網格頂點顏色的alpha通道(如果存在的話)修正。

最終,根據在材質中的遮蔽值,會被一起混合。

如果網格為遮罩提供了頂點alpha通道,那麼也可以採用頂點著色來處理細節層的基礎圖案。



自訂標準著色器Modified Standard Shader

The Blacksmith運用了為數不多的自訂標準著色器。它們會因為需求用來調整事物,或是用來增強著色器的小特性。

並不是所有著色器都可以獨立出這個專案運作,不過裡面一些基於表面著色的標準著色器已被抽出包含在這個包中。

這些修改通常是這樣的:

除貼圖外還可以透過貼圖的alpha通道取樣平滑每個像素,或允許對任何材質做遮擋剔除控制,或是對全域光照的顏色、密度做額外的控制。



色調映射 Tonemapping

我們已在一篇文章(中文)中說明過我們是如何在Unity中實現色調映射和顏色分級的。現在影片也完成了,色調映射也被Unity團隊接手,準備整合到Unity中。包裡面的HDR天空貼圖來自NoEmotionHDRs (Peter Sanitra) / CC BY-ND 4.0.(影片中的天空,沒經過任何修改)


以上就是我們為大家帶來的分享。
我們帶來了這些我們曾答應要分享的一切,接下來,前方新的冒險正在等著我們整裝待發。不論你用任何形式使用了這些資源包,我們都希望你可以在論壇留言或者寫郵件到demos@unity3d.com告訴我們,我們非常樂意知道有用戶使用了我們所分享的資源。

或是你有什麼值得分享的好東西,也別忘了來我們的社區和大家分享。

祝好運!

2015年12月18日 星期五

再見Unity 4,迎向Unity 5之最後Unity 4.7版本發佈

作者:PALANIYANDI JAWAHAR 原文連結


今天,我們發佈了Unity 4.7,這將是Unity 4的最終版本。Unity 4.7的版本並沒有新增加的功能,而是包含了Unity 4.6.9 p1-4.6.9 p4所有更新包的功能。為什麼叫做Unity 4.7而沒有叫做Unity 4.6.10呢?

原因有2點:1、Unity webplayer外掛程式是根據版號來判斷需要下載哪個webplayer來播放內容,舊版本的外掛程式無法識別新版本的版本號(x.x.10)。因為不可能同時更新瀏覽器外掛程式以及Unity執行元件,我們不得遵循現有版本編號規則以使webplayer外掛程式能夠識別。

2、4.6.10還存在另一個問題:版本號可透過腳本API獲取(Application.unityVersion)。我們無法保證現有及協力廠商代碼都能正確處理這個“x.x.10”的版本格式。所以為了避免這樣的風險,我們將本次版本號定義為4.7.0。
非常感謝大家一直以來對Unity 4的支持。接下來我們將集中精力研發Unity 5
最新版本的Unity 5.3擁有更多功能,並且支持更多平臺,如果你的專案打算移植到Unity 5.3,請務必參考這份更新指南,也可以參考Facepunch Studio把他們的遊戲Rust從4移植到5的一些經驗分享,參考這裡(英文)。


2015年12月9日 星期三

Unity 5.3: 全新功能,更多平台


作者:ALEX LIAN 原文連結

現在Unity 5.3已發佈。可以到這裡下載

最新的版本中,我們為您帶來許多新功能與支持更多新平台:


● 新工具:MonoDevelop升級、多場景編輯、2D工具與自動化單元測試
● 圖形優化:包括新OpenGL核心支援、對OS X中Metal的支援、粒子系統升級
● 更好的WebGL與iOS 9平台支持
● 整合IAP內購支援
● VR優化及新的VR DEMO
● tvOS平台測試版已經上線,但本版還沒上線

下面讓我們看下Unity 5.3中的新內容。

新增與升級的工具


Unity 5.3中包含許多讓你開發更簡單的新工具:

更佳的腳本編輯器體驗


在Unity 5.3中,MonoDevelop版本升級成為5.9版本,這是現有Unity腳本編輯器的一個重要升級版本。除了煥然一新的簡約UI之外,除錯也比以前更快速輕鬆。Unity 5.3還修正了許多bug,使你能更好地使用MonoDevelop。

更多詳情訪問:

http://blogs.unity3d.com/2015/10/22/monodevelop-roadmap/

以上是用傳統的方法附加MonoDebugger除錯器到Unity,使用附加的對話框處理(通常需要至少2-3個步驟)


這是新的方法附加MonoDebugger除錯器到Unity,只需一個步驟。


更輕鬆的場景管理


多場景編輯功能對於場景編輯是一個重要提升。Unity現在允許你將一個場景分割成許多小場景,這在某些情況下很有用。例如你的遊戲中有個十分巨大的關卡,為了製作無縫動態載入的場景,你可以對場景進行分割。這在製作較大的關卡時會帶來效能改善,並大大提高你在遊戲內環境構建時的自由度。




全新的2D工具


Unity繼續完善2D功能並帶來了全新的2D物理工具:

●Buoyancy Effector,一個新的2D物理效果器,提供了物體與流體間以及流體互動



●新的相對、固定、目標、以及摩擦關節,為你 2D遊戲創造更多效果

TargetJoint2D使用不同力度追蹤目標


RelativeJoint2D以及可斷連接


FrictionJoint2D摩擦


FixedJoint2D剛性連接

●新的2D基本幾何形狀資源創建工具,可以方便你更快地生成2D的基本形狀以及遊戲玩法原型



Editor Tests:更容易發現問題


Unity 5.3引入了一種在Unity中進行自動化測試管理與運行全新方式:Editor Tests Runner。它是著名.Net單元測試庫NUnit的一個方法。你可以用它對程式中的單個函數進行測試的編寫與執行,進而在開發過程初期定位問題解決方案。


開始使用Editor Tests Runner只要簡單的打開Editor Tests Runner窗口,定義幾個符合你項目測試項目即可。此外你可以配置我們的自動化構建服務—Cloud Build,針對你的遊戲專案自動進行這些測試,以便更早發現問題,更快進行迭代。

更高效的渲染


Unity 5.3帶來了許多可以提高渲染質量與渲染效率的新功能。

首先,全新的OpenGL 4.x支援將替換過去的OpenGL 2.1。這將使你在Windows,OS X以及Linux上都能受益於最新的OpenGL特性,同時也能根據用戶OpenGL驅動的支持能力切換至舊版本的OpenGL。需要注意的是在Unity 5.3中,Unity會預設使用新OpenGL核心,但你可以手動切換至傳統的OpenGL 2.1以相容以前的版本。我們打算在Unity 5.4中移除舊的OpenGL核心支援。

我們還對Unity編輯器中的發佈到OS X的應用提供了Apple Metal技術的試驗性支持,以便在OS X遊戲中獲得更快地圖形處理速度。可以在Unity編輯器的Player Settings窗口,Graphics API選擇下拉框中啓用Metal。

Screen Space Raytraced Reflections (SSRR)增強了Unity的圖形渲染的真實度。SSRR允許物體比反射探頭更精確的對周遭環境進行動態反射,因此,場景中的移動物體在表面上會得到精確反射。我們最近發佈的Bedroom demo,展現了使用SSRR可以達到何等程度的視覺真實度。


目前SSRR的實現處於測試狀態,所以請到Asset Store下載它,並在論壇提供反饋,幫助我們改進它。

Unity的粒子系統進行了大量的改動。所有的粒子系統屬性現在可以通過腳本進行配置,賦予你前所未有的掌控權以及全新的創造性可能。另外,我們還增加了:

-3D Rotation控制(全方位控制粒子在3個坐標軸上的方向與旋轉)

-System Scaling

-Mesh Shape Source(你現在可以使用蒙皮網格作為粒子發生器的源了)

-新3D、2D物體粒子碰撞控制選項



閃亮新功能是一回事,那校能方面又如何呢?在Unity 5.3中,粒子、精靈、光暈、光環、線、拖尾效果均得到了性能提升,這要感謝對引擎內線程管理方面的改進。另外,我們還更新了幀調試器,以便在遠程設備(比如一個安卓手機)上執行它。例如,這意味著你可以查看一個Draw Call中使用了哪個著色器屬性,從而在在運行時更加可視化地定位渲染方面的問題。

此外,我們採取措施對著色器的載入時間與內存使用都進行了削減,提高了「昂貴」的著色器們的運行效率。最後,我們在渲染線程上啓用了磁盤紋理數據的異步加載以及時間分片上載紋理到GPU,大大提升了渲染性能。耶~!

用tvOS征服客廳

tvOS很快將成為一個可選擇的目標平台,目前它正處於人人可以參與的beta階段(到論壇參與),並在接下來的幾周內隨Unity 5.3.x正式發佈。

http://forum.unity3d.com/threads/official-unity-for-apple-tv-open-beta.371324/

tvOS目標平台支持通過Unity Input API 使用Apple TV Siri Remote輸入,支持通過Asset Bundles使用按需加載資源。

現在Apple TV上已有大量的優秀Unity遊戲 —— 歡迎查看Apple TV遊戲清單,或者閱讀我們的博文,聽取已成功發佈Apple TV遊戲的開發者們所提供的中肯建議。




另外,Unity 5.3還帶來了大量針對iOS 9以及tvOS新特性的更新,包括iPhone 6S與6S Plus上的3D Touch、iPad Pro與Apple Pencil,以及Bitcode支持。如果想要瞭解如何在Unity開發tvOS與iOS 9時使用按需載入資源,可前往查看我們的文章

WebGL平台支持更新


2015年3月,Unity 5.0發佈時,我們在Unity編輯器中加入了帶「preview」標籤的發佈至WebGL功能。在隨後的5.1與5.2版本中,我們都對此功能進行著一系列持續的改進。如今,隨著 Unity 5.3的發佈,我們決定移除「preview」標籤,使WebGL成為正式的構建目標。值得注意的是,WebGL的平台化是個正在演進的工作—但總的來說,我們對於自己的WebGL實現十分自信,它在目前的WebGL生態框架中工作地很好。

除了修正大量的bug與提供更多的文檔外,5.3版本還對WebGL著色器、陰影以及文件壓縮處理做了許多改進,提供更佳的性能表現與圖形保真度。

在過去的一年中,針對WebGL的瀏覽器支持工作也取得了重大進展,這意味著你遊戲的潛在目標客戶數量也在不斷增加。雖然目前WebGL還不支持所有的Unity特性,但我們會繼續致力於該平台的研發,並在未來的Unity編輯器發佈時提供新特性的常態化更新。要瞭解目前Unity中WebGL的進展狀況,以及引擎中已有的功能,請訪問我們的深度專題

還有,現在我們的Cloud Build服務也支持將WebGL作為目標平台。只需配置項目一次,就可以自動從Cloud Build網站構建與分享你的WebGL遊戲。有關如何為遊戲使用Cloud Build的更多信息,請到這裡

更輕鬆的應用IAP


如果當前你的遊戲正在使用遊戲內購功能,你應該很清楚配置和集成不同的應用商店需要很多繁瑣的工作。

Unity 5.3為解決這個過程中的痛點,提供了一個新服務:Unity In-App Purchase。Unity IAP可以幫你在應用中輕鬆加入支持各大熱門應用商店的應用內購功能,你只需在Unity編輯器的Services窗口中打開它即可。


此外,Unity IAP與Unity Analytics平台深度集成,你可以對應用內行為進行持續跟蹤並根據實際收入與購買數據對遊戲進行調整。目前Unity IAP支持iOS App Store, Mac App Store, Google Play 以及Windows Store,未來將支持更多平台。你可以訪問此處瞭解有關該新服務的更多內容,或者馬上研讀我們的手把手教學,瞭解在遊戲中集成Unity IAP的具體步驟。

VR示例


我們致力於使Unity編輯器成為創作沈浸式VR內容的可靠全功能解決方案。在最近幾次的編輯器常規更新中,我們持續為包括Oculus Rift以及三星Gear VR在內的各種VR頭戴式設備提供支持。

今天我們高興的宣佈,與Unity 5.3同時發佈的還有一個新的VR示例項目。該項目可為那些希望瞭解如何用Unity進行VR內容開發的人提供幫助。

該項目通過一些低眩暈風險的VR遊戲示例幫助你開始VR之旅。示例項目中包含了一個VR影院曲面顯示風格的菜單,以及四個不同的小遊戲,支持三種不同的遊戲玩法與遊戲輸入方式:

-Flyer 可使用頭部跟蹤來控制一架飛行器穿越隕石地帶


-Maze 是一個頂視圖桌面遊戲,使用頭部跟蹤與按鍵輸入控制角色


-Target Gallery 是一個畫廊風格射擊遊戲,使用頭部跟蹤瞄准目標


-Target Arena 是一個360度競技射擊遊戲,需要站立消滅穹頂中出現的所有目標


這個示例項目背後附帶有一系列高價值文章,不僅介紹了該項目的製作過程,還提供了Oculus VR平台的新手入門建議。我們希望它們能助你盡快開始VR開發,並殷切期待你的大作問世。

還有.......

我們在Unity 5.3中還加了很多好東西:

●大量的bug修正
●一個支援在物件與JSON格式間互相轉化的新JSON API — 可用於客戶端與服務器端間通訊及遊戲狀態的保存與恢復
●多顯示支持 — 單一應用可最多支持渲染8個顯示器

關注Unity,您可以找到更全面的Unity 5.3指導文章

2015年11月24日 星期二

Unity開放高階的多人連線網路層原始碼

作者:LÁRUS ÓLAFSSON 原文連結

開源的意義是甚麼?


Unity的多人連線功能可以分為高階和低階兩個階層,低階是用來傳輸層,大多時候是
過NetworkTransport 類別進行溝通。這一層功能在Unity引擎中是用C++寫的,主要目的是優化Socket接口的通訊傳輸。在這上面我們提供了用C#編寫以DLL形式存在的高階API。這些文件我們已經開放原始碼,開發者只需遵守MIT/X11協議,便可以根據自身需要修改成自己的。

兩個抽像層的使用介紹


DLL文件我們可以分為兩個部分:高階和低階。當使用NetworkClient 和 NetworkServer類別時,你可以在低階層手動建立連接,而使用NetworkManager和NetworkLobbyManager則可以對高階進行存取。將上述NetworkClient等組件加到游戲物件後,即可在游戲物件的inspector窗口獲得相應的鏈結選項以及預設的HUD組件。當然你也可以修改、延伸這些類別,自訂行為和功能。上述內容都是基於C/S架構以及伺服器授權模式實現。當你想了解和使用通訊層,或者去實現你自訂的高階API時,這些類別會是絕佳的參考資料。

注意事項


我們所提供的資源包含三個Visual Studio專案:分別針對Runtime、Editor以及Editor-Runtime。最後一個是在編輯器裡的Runtime模式,當在編輯器進入Playmode時,由於Unity引擎內部的Update方法是由Unity引擎內部觸發,所以必須讓它能呼叫到NetworkIdentity.UNetUpdate(),否則會無法正常執行。在編輯器中,我們還會即時進行一些程式編譯,這個工具叫做UNetWeaver,我們也正在討論是否將這部分內容開放源碼。這個工具負責分析NetworkBehavior並產生序列化程式碼,像是Command/ClientRPC程序或各種查詢表格。有些東西在擴展時必須注意保持名稱一致(如SyncVar、Command等..),以確保對應的功能正常。


現在,你可以從 這裡 下載這些原始碼

2015年11月16日 星期一

Web Player離線安裝包提供下載

由於各大瀏覽器廠商陸續宣佈將不再支持瀏覽器外掛程式(NPAPI),所以我們在10月宣佈了:從Unity5.4版本開始將不再支持WebPlayer(本文截稿時間時最新版是Unity 5.2)。
現在我們開始提供這些對應版本的離線Unity player,讓開發者可以放在玩家能夠下載到的地方,以利管理。

現在,我們將提供給開發者,對應版本的Web Player離線安裝包。

· Unity5.3 版本:將與5.3正式版一起發佈。

· Unity5.2版本

· Unity5.0-5.1.4 版本

· Unity3-Unity4.6.9版本


壓縮包中包含:

· UnityWebPlayerFull.exe:正常的player,可在Windows平臺下32位的Firefox和IE中運行。

· UnityWebPlayerDevelopment.exe:開發版player,可在Windows平臺下32位的Firefox和IE中運行。

· webplayer-x86_64.dmg: 正常的player,可在OS X平臺下的Firefox和Safari中運行。

以上player已經包含了庫,不需連網即可執行,需要注意不同版本難免出現相容性相關的問題,請測試完畢再更新。

如:已經安裝4.6.9版本的player只能使用Unity3.x-4.6.9製作的內容。無法執行Unity5.0以上版本的內容,需要重新下載對應的安裝包。


2015年11月12日 星期四

淺談THE BLACKSMITH製作流程:場景搭建、著色和光照


作者:SILVIA RASHEVA 原文連結

在本系列之前的文章中,我們介紹了The Blacksmith的創作團隊,與短片美感的製作流程。

由於打算用Unity5來開發這個專案,所以我們必須把更多的注意力轉移到技術問題上,在這篇文章中,我們將著重場景建設、著色和照明。

引擎版本和內部測試


The Blacksmith在很早版本的Unity alpha和 beta版本中進行開發,並在Unity 5.0.b22中最終穩定下來,並發佈。整個專案也跟著升級到了發佈時的Unity版本。

要知道使用一個研發中的引擎代表著會有許多不穩定因素,導致產品製作效率低下。所以我們每周都要面對兩難題,到底是要升級新版本更新?還是跳過一個版本避免打斷團隊現有的工作步調

此外,The Blacksmith中的動畫和鏡頭序列是基於Director系統的。它是Unity故事工具的一部分,而Unity故事工具在當時仍處在發展的早期階段(它的發佈日期迄今也沒有公佈)。

我們在專案進行到差不多一半時,為了添加故事工具功能,每次的Unity更新我們都得重新把系統集成到新版本。一直持續到我們最終發佈為止。

因為我們是Unity的內容製作團隊,我們會提出bug或功能需求給核心團隊,然後祈禱他們能快點搞定XD。假如他們搞不定,那我們就只好自己想辦法了:-(

事實上,我們提出的反饋會和廣大Unity用戶的需求放在一起被權衡,通常不會得到任何優先待遇。

場景搭建

在The Blacksmith的製片初期,我們便在Unity中利用白模搭建了一個場景。


我們從Asset Store找來了一些素材,比如Quantum Theory的Better Rocks and Cliffs,非常有助於原型的設計,同時這也能夠盡早開始視覺相關的開發工作。我們
很快做出了細節豐富的場景:


根據我們的故事情節,我們在前期製作過程中需要做的是,利用一組相機進行迭代,緩緩地接近所要拍攝的景象。在此基礎上,我們需要劃分好每一個鏡頭都需要的哪些資源。同時,角色的3D美術設計也正式開工。

對我們來說,盡可能地保留對每一個鏡頭中的藝術把控能力對我們而言非常重要。因此,我們基於Unity編輯器專門擴展了一個場景管理器,然後用它為每個鏡頭中的對象分組。

我們用它來啓用或禁用某些物件,或更改它們的屬性-地點,規模,材料等等-來求得一個特定的鏡頭,以獲得更好的構圖。同樣地,每一個鏡頭都可以擁有自己特定的光照設置,也多虧了實時全局光照系統,我們可以對鏡頭切換之間的光照做出即時改變。


著色


Unity基於物理的著色器使用和配置起來都相當容易上手。

我們對它的運用可謂貫穿了整個專案。這個專案中,我們並不打算開發一個專門的皮膚著色器,於是我們就直接採用了Standard Shader標準著色器:
挑戰者 - 從編輯器抓下來的圖

Unity 5中標準著色器最大的優勢之一就是:我們可以根據專案需求隨心所欲地擴展和修改它,因為它就是為此而生的。

標準著色器的源碼可以從這兒下載:http://unity3d.com/get-unity/download/archive(在對應平台的「下載」下拉選單中選擇「Built in Shaders」)。

有了源碼後,在此基礎上開發具有專案針對性的著色器是非常容易的,我們在The Blacksmith中做了很多這樣的工作。我們下面就來分享一些例子。

我們修改了標準著色器,使之能夠感知到我們已經在專案中添加的自定義著色器。我們對這種修改進行了兩個不同版本的運用:一個用在環境上(例如:讓它感知到我們的大氣散射)另一個更複雜一些的用在角色上(用來感知我們獨特的角色陰影和皺紋貼圖)。後者的界面用滑塊對鏡面貼圖選項做了小小的增強。




為了讓維京挑戰者的面部更加生動、擁有更多的細節,我們決定開發一個感知形狀融合的皺紋貼圖解決方案。基於判斷最為突出的形狀融合,我們在一個屏幕空間的預渲染通道內混合運算了法線和遮蔽紋理。

然後直接從這個屏幕空間將經過採樣和解包的法線和遮蔽數據輸入到一個標準的著色器變量中,從而取代了常規的材質。




標準著色器非常適用於絕大多數現實世界中存在的材質,可惜的是不包含頭髮。雖然頭髮的渲染從來都不是The Blacksmith的著重點,我們依然希望能做出各向異性的頭髮高亮,並使它們能正確地整合其他材質所用的物理的環境。
為了實現這一點,我們修改了一個標準著色器,使其在採用了一個不同的反射率分布模型的同時,保留了反射和光照探測的採樣。

頭髮著色器 - 一樣是從編輯器直接抓圖


我們希望鏡頭中有一些柔軟的植物,同時探索出在場景中繪制不同植物的簡單方法。這裡的解決方案是對Unity內置的植被功能分兩個階段進行擴展。

一個叫做PaintJob的小工具能生成一個臨時地形自動打包場景中的靜態幾何物件。加上一個簡單的打包規則控制,這使我們能夠圍繞地形和建築在地面網格上繪制植物地形。


渲染時,我們再將繪制好的數據放到一個自定義組件當中,這個組件專門用來處理視野依賴的排序、動態全局光照的採樣,管理遮擋關係和LOD層次。



光照

我們採用分層的方式來分離照明人物和環境,並為每個光源分別配置了各自的剔除遮罩。這樣一來,我們對人物和環境都有了更好的控制。這種方法常被運用在電影拍攝,會根據角色呈現的位置而設置特定的光照條件。

為了改進角色的外觀,我們使用了額外的局部光照來柔化他們面部的陰影部分(暗部)。




因為角色形象的呈現可謂是全片的重中之重,在DEMO中,我們有大量的特寫鏡頭,必須確保這些角色能夠以很高的分辨率接受陰影。為此,我們增加了一個獨立的陰影紋理,專門用來處理角色的陰影。




在鐵匠鋪中的光照被設定為是從牆壁和屋頂的鏤洞中透射進來的。這種效果是通過把一張恰當的圖案當成光打在場景來實現的。



對於海洋和海灘的淺窪,我們想要表現物體穿入水面的尖銳感表現,當其距離越深時所具有的散射效果就越強。

我們最終打造出了類似於水面反射的功能,採用了一個的深度感知的計算方式,來計算出一個變數給surface smoothness。最後輸出結果放入到一個標準的著色器,然後再用我們定制的反射紋理來替換反射的Cubemap(方塊貼圖)。




在The Blacksmith創作系列的下一篇文章中,我們將繼續探討DEMO團隊所做的一些接後期處理,包括動畫和音頻和視頻的製作方式。
所以欲知後事如何,請持續關心我們的The Blacksmith專案文章分享!

2015年11月10日 星期二

Unity引擎打造遊戲登陸APPLE TV

我們很高興在此分享一些在Apple TV上發佈採用Unity開發的遊戲!Unity正在與開發者緊密結合並全力支援tvOS的所有特性,包括On-Demand resources和全新的Siri Remote。非常感謝開發者給予了我們大量優質的回饋。以下是一些由Unity開發者所創造出的出色遊戲:

1.Breakneck
2.Crossy Road
3.Bruce Lee: Enter the Game – Unchained Edition
4.TanooJump
5.Beneath the Lighthouse
6.Spin Sports
7.Alto’s Adventure
8.Couch Heroes Vs The Dungeon
9.Evel Knievel
10.Tiny TrackZ
11. 想瞭解更多,請關注Madewith.Unity.com上的列表。


開發者們對於將Apple TV發展成為下一個大型的遊戲平臺抱有極大興趣。圖像的高保真度和A8晶片出色性能為大屏遊戲提供了優越的環境,使遊戲在實現優越畫質的同時,能保持類似Apple的App store那樣廣闊的分發模式。

一些開發者告訴我們,Apple TV上的Siri Remote,加上大面積的Touch Surface,讓他們的遊戲體驗比在任何主機式TV螢幕上的體驗更具代入感。當你添加MFI遊戲控制器或是將你的遊戲連接到已有的iOS設備上時(如同Crossy Road的開發者在早先Apple的秋季發佈會上演示的那樣),它會帶來在以往任何Apple設備上都無法實現的豐富的多人遊戲體驗。

當然,對於許多已經在iOS平臺上擁有遊戲,曾考慮進軍tvOS平臺的開發者來說,一旦Apple開放這一領域,他們就會準備全面投入其中。而Unity不僅正在努力使這些(擁有iOS遊戲的)開發者的願望成為可能,也將幫助其他白手起家的開發者創造出(適用於這一新平臺的)遊戲。

Beneath the Lighthouse


以下是開發者使用Unity開發Apple TV遊戲的建議:

  • 去真正地習慣並瞭解Siri Remote, 並好好地利用它設計你的遊戲。記住你能在觸控板上完成輕敲和點擊;)-Strange Flavour Ltd. – Tiny TrackZ
  • 不要認為觸控板能完全取代觸控式螢幕。Touch Surface要小很多,而當你看不到要觸摸的物件時,感覺會有不同。-Nitrome – Beneath the Lighthouse
  • 當前Apple TV上還不能植入廣告,所以仔細考慮你的貨幣化策略。-Nitrome – Beneath the Lighthouse
  • 我們建議儘早處理檔的大小(資源,音效,打包),即使在“小型專案”中,Apple規定的200Mb上限很快就會使大文件變成問題。On-Demand-Resources系統很棒,但需要經過實踐,花費一些時間來習慣它。-Polar Beard – TanooJump
  • 測試你的操控,一定要測試,還要跟其他人/朋友一起測試。儘早地測試遊戲的操控方式,因為使用Siri Remote來進行遊戲操作是一種全新的方式,它會為玩家帶來新穎有趣的操作能力,但也會產生新的問題與回饋。-Polar Beard – TanooJump
  • 放手去做!如果你覺得你的遊戲在Apple TV上會很好玩,就不要再猶豫了。Unity對這個平臺的支持非常棒,你可以非常順暢地進入這個新平臺。千萬別忘了Unity社區!他們會給你無盡的幫助,資源和啟發。你會瞬間克服所有障礙。-Mass Creation – Corridor Z
  • 為你自己節約一些寶貴的開發時間,去訪問Unity Asset Store吧。無論是使用者介面的工具,玩家操控繪製的程式或是人工智慧系統,你都能從Asset Store中眾多實用而且功能強大的資料庫中找到,然後應用到你的專案中,使你能專注于遊戲開發。-Hibernum Creations – Bruce Lee: Enter the Game – Unchained Edition
  • 確保在你的專案中使用Unity的Asset Bundles功能。這不僅是一個很好的實踐,而且它會促進Apple On-Demand Resources的實施,進而極大地幫助你在Apple TV上的發佈。-Hibernum Creations – Bruce Lee: Enter the Game – Unchained Edition
  • 注意iOS和tvOS之間的差異。不要認為你在iOS上使用每一款外掛程式和功能在tvOS上都同樣適用,在觸控式螢幕上適用的輸入範式也不能完全照搬到Touch Surface上。利用Unity節省的開發時間,為新的Apple TV平臺改進用戶交互,並且改善UI的功能表設計,可以分析並借鑒Apple自身的UI作為改進的範本。-Touchfactor – TouchFish
  • 當你把iOS的遊戲移植到tvOS時,仔細考慮你的UI結構,保證可靠的UI交互。確保它符合“Apple的人性化介面指導”。如果你認為需要使用On Demand Resources,儘早地著手實施,並將它併入你的工作流程中。-PikPok – Breakneck

以下是已擁有&即將發佈的支援Apple TV的功能列表:

1. Unity’s joystick API對Apple TV Siri Remote的支持
2. Unity 5.2.1版本中可通過Asset bundles實現的ODR
3. 將tvOS平臺作為一個單獨的構建目標進行部署
4. 分層圖像和tvOS Top Shelf支援
5. 改良版的Unity UI功能,支援TV控制器的導航交互
6. Bitcode支持


針對Apple TV的Unity功能將在11月底進行公測。如果你擁有Unity Pro,想更早地加入測試,請聯繫我們加入內測
Breakneck

2015年10月28日 星期三

MONODEVELOP-Unity未來計畫

作者:LUKASZ PACZKOWSKI
原文:http://blogs.unity3d.com/2015/10/22/monodevelop-roadmap/

正如我們之前所發佈過的Unity Roadmap中所述,我們將在12月,隨著Unity5.3版本推出MonoDevelop-Unity 5.9。MonoDevelop-Unity是為Unity量身訂做的MonoDevelop版本,MonoDevelop-Unity 5.9收錄了很多MonoDevelop 4.0.1的中改進和修正,目前是最新的穩定版本。


我們在開發MonoDevelop-Unity 5.9的時候為它增加了全新的工作流程。在target選項列表中,現在顯示有Unity targets,參見上圖頂部用橙色線框標出的部位。在點擊「Run」按鈕的時候,MonoDevelop-Unity 將自動連接到所選的target,媽媽再也不用擔心我要對著「Attach to Process」對話框點點點了!


現已可以從論壇中下載MonoDevelop-Unity 5.9 預覽版進行試用,歡迎大家在論壇中對我們的工作給出意見反饋!MonoDevelop-Unity 5.9可以直接替換掉Unity 4.6和Unity 5中附帶的MonoDevelop 4.0.1,最低的版本需求為:



. Windows系統:必須安裝有.NET 4.5。

詳見: http://go.microsoft.com/fwlink/p/?LinkId=397703

. Unity 4.6+:4.6.5p2 或更高版本
. Unity 5.0:5.0.2p2 或更高版本
. Unity 5.1+:5.1.0p1 或更高版本



修正腳本除錯功能

除了升級新版的MonoDevelop-Unity,我們也同時致力於修正和改進MonoDevelop-Unity與 Visual Studio Tools for Unity 中在腳本除錯方面的缺陷。


Unity5.3和Unity5.2.2中值得注意的腳本除錯功能的修正:


. 修復了在switch語句中步進會遇到的一些問題。
. 解決了在連續前進多次中斷點Unity會偶爾崩潰的問題。
. 修復了試圖在暫停後繼續步進時,會導致Unity崩潰的問題。
. 修正了單步跳過Resources.Load和其他用到序列化的Unity API函數時可能遇到的問題。
. 修復了試圖鑒別返回泛型數組的泛型方法時會遇到的問題。例如

GameObject.GetComponents<Component>()方法。


我們同時修復了一些MonoDevelop-Unity 5.9中特有的除錯缺陷。

MonoDevelop-Unity 5.9中值得注意的腳本除錯功能的修正:


. 修復了在開關斷點時會遇到的「The requested item has been unloaded」的問題。
. 修復了在鑒定枚舉時會遇到的「The requested item has been unloaded」的問題。
. 請從論壇中下載MonoDevelop-Unity 5.9 預覽版:



MonoDevelop和Unity的REST整合

目前,MonoDevelop-Unity和Unity是通過解決方案(.sln)和專案文件(.csproj)來進行整合的。


Unity在你每次增加、刪除、移動或重命名腳本文件的操作後,都需要修改專案的解決方案。所以,這一設定顯得並不理想。每當解決方案和專案文件被寫入到硬碟中時,MonoDevelop都需要重新載入它們。而更好的辦法是,每次更改Assets目錄中的文件或子目錄時,讓Unity與MonoDevelop直接通信,並使MonoDevelop進行相應的更新。


使用解決方案文件帶來的另一個問題是,我們並沒有在Unity和MonoDevelop中使用同一個C#編譯器來編譯您的腳本。這可能在MonoDevelop中導致與Unity不同的編譯錯誤和警告,在某些情況下,腳本可以在Unity中通過編譯卻在MonoDevelop中報錯,反之亦然。


為瞭解決這些問題,從而將Unity和MonoDevelop整合得更加緊密,我們正在研發一項新的功能,它將使得MonoDevelop和Unity能夠通過REST進行交流。這代表在實際操作中,MonoDevelop和Unity將通過一個network socket進行直接通訊,從而避免了不斷地生成解決方案和專案文件。


取而代之的是,MonoDevelop將根據Unity傳來的REST信息,在一個層級視圖中顯示您的Assets目錄。MonoDevelop中的Assets視圖將隨著Unity專案中Assets目錄的變化而變化。同時,我們甚至可以直接在MonoDevelop的Assets 視圖中增加、刪除、移動或重命名文件,這些操作會發送給Unity進行處理。一旦完成了這些文件操作,Unity將通知MonoDevelop Assets目錄的結構變化,使得MonoDevelop能夠據此更新其中的Assets 視圖。


下面的截圖展示了目前MonoDevelop中的Assets 視圖,我們可能會在最終發佈前進一步改進它。

MonoDevelop將通過REST服務在Unity中編譯您的腳本,然後在將編譯的結果反饋給MonoDevelop。上面截圖中的編譯結果就是由Unity傳達給MonoDevelop的。

REST服務並不局限於文件操作和腳本編譯。它也可以運用於任意暴露為REST endpoint的Unity功能。


在此,我們列舉出我們計劃在MonoDevelop和Unity整合中的功能:

. MonoDevelop和Unity之間免文件的專案同步方案。
. Assets 目錄中,文件增加、刪除、移動或重命名操作的雙向即時同步。
. 一致的編譯行為。總是在Unity中編譯您的腳本,然後在MonoDevelop中顯示Unity的編譯結果。
. 通過點擊MonoDevelop中的運行按鈕來進入play mode,或者綁定除錯器。


我們目前正緊鑼密鼓地進行著Unity和MonoDevelop的開發,兩者的REST整合將在Unity5.5中發佈。請持續關注Unity官方平台,我們將在接下來的幾個月中繼續分享更多的細節。

2015年10月8日 星期四

深度技術文章-IL2CPP 深入講解系列介紹之5:泛型共享

作者:JOSH PETERSON
原文:http://blogs.unity3d.com/2015/06/16/il2cpp-internals-generic-sharing-implementation/
翻譯:IndieAce論壇-Bowie


這是 IL2CPP深入講解的第五篇。在上一篇中,我們有說到由IL2CPP產生的C++程式碼是如何進行各種不同的方法呼叫的。而在本篇中,我們則會講解這些C++方法是如何被實現的。特別的,我們會對一個非常重要的特性 -- 泛型共享 加以詮釋。泛型共享使得泛型函數可以共享一段通用的程式碼。這對於減少由IL2CPP產生的可執行文件的大小有非常大的幫助。

需要指出的是泛型共享不是一個新鮮事物,Mono和.Net的執行庫(譯注:這裡說的.Net執行庫指的是微軟官方的)也同樣採用泛型共享技術。IL2CPP起初並不支持泛型共享,我們到最近的改進版中才使得泛型共享機制夠穩定。既然il2cpp.exe產生C++程式碼,我們可以分析這些程式碼來瞭解泛型共享機制是如何實現的。

我們將探索對於引用類型或者值類型而言,泛型函數在何種情況下會進行泛型共享,而在何種情況下不會。我們也會討論泛型參數是如何影響到泛型共享機制。

請記住,所有以下的討論都是細節上的實現。這裡的討論和所涉及的程式碼很有可能在未來發生改變。只要有可能,我們都會對這些細節進行探討。

什麼是泛型共享


思考一下如果你在C#中寫一個List<T>的實現。這個List的實現會根據T的類型不同而不同麼?對於List的Add函數而言,List<string>和List<object>會是一樣的程式碼麼?那如果是List<DateTime>呢?

實際上,泛型的強大之處在於這些C#的實現都是共享的,List<T>泛型類可以適用於任何的T類型。但是當C#程式碼轉換成可執行程式碼,比如Mono的匯編程式碼或者由IL2CPP產生的C++程式碼的時候會發生什麼呢?我們能在這兩個層面上也實現Add函數的程式碼共享麼?

答案是肯定的,我們能在大多數的情況下做到共享。正如本文後面將要討論的:泛型函數的泛型共享與否主要取決於這個T的大小如何。如果T是任何的引用類型(像string或者是object),那T的尺寸永遠是一個指針的大小。如果T是一個值類型(比如int或者DateTime),大小會不一樣,情況也會相對複雜。程式碼能共享的越多,那麼最終可執行文件的尺寸就越小。

在Mono中實現了泛型共享的大師:Mark Probst,有一個關於Mono如何進行泛型共享的很棒的系列文章(英文),我們在這裡不會對Mono深入到那麼的底層去。相反的,我們討論IL2CPP是怎麼做的。希望這些訊息可以幫助你去理解和分析你們專案最終的大小。

IL2CPP的共享是啥樣子的?


就目前而言, 當SomeGenericType<T>中的T是下面的情況時,IL2CPP會對泛型函數進行泛型共享:

  • 任何引用類型(例如:string,object,或者用戶自定義的類)
  • 任何整數或者是枚舉類型

當T是其他值類型的時候,IL2PP是不會進行泛型共享的。因為這個時候類型的大小會很不一樣。

實際的情況是,對於新加入使用的SomeGenericType<T>,如果T是引用類型,那麼它對於最終的可執行程式碼的尺寸幾乎是沒有影響的。然而,如果新加入的T是直類型,那就會影響到尺寸。這個邏輯對於Mono和IL2CPP都適用。如果你想知道的更多,請繼續往下讀,到了說實現細節的時候了!

專案搭建


這裡我會在Windows上使用Unity 5.0.2p1版本,並且將平台設置到WebGL上。在構建設置中將「Development Player」選項打開,並且將「Enable Exceptions」選項設置成「None」。在這篇文章的例子程式碼中,有一個驅動函數在一開始就把我們要分析的泛型類型的實例創建好。
1
2
3
4
5
6
public void DemonstrateGenericSharing() {
  var usesAString = new GenericType<string>();
  var usesAClass = new GenericType<AnyClass>();
  var usesAValueType = new GenericType<DateTime>();
  var interfaceConstrainedType = new InterfaceConstrainedGenericType<ExperimentWithInterface>();
}
接下來我們定義在這個函數中用到的泛型類:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class GenericType<T> {
  public T UsesGenericParameter(T value) {
    return value;
  }
 
  public void DoesNotUseGenericParameter() {}
 
  public U UsesDifferentGenericParameter<U>(U value) {
    return value;
  }
}
 
class AnyClass {}
 
interface AnswerFinderInterface {
  int ComputeAnswer();
}
 
class ExperimentWithInterface : AnswerFinderInterface {
  public int ComputeAnswer() {
    return 42;
  }
}
 
class InterfaceConstrainedGenericType<T> where T : AnswerFinderInterface {
  public int FindTheAnswer(T experiment) {
    return experiment.ComputeAnswer();
  }
}

以上這些程式碼都放在一個叫做HelloWorld的類中,此類繼承於MonoBehaviour。

如果你查看il2cpp.exe的命令行,你會發現命令行中是不帶本系列第一篇文所說的--enable-generic-sharing參數的。雖然沒有這個參數,但是泛型共享還是會發生,那是因為我們將它變成預設打開的選項。

引用類型的泛型共享


讓我們從最常發生的泛型共享情況開始吧:對於引用類型的泛型共享。由於所有的引用類型都是從System.Object繼承過來的。因此對於C++程式碼而言,這些類型都是從Object_t類型繼承而來。所有的引用類型在C++中都能以Object_t*作為替代。一會兒我們會講到什麼這點非常重要。

讓我們搜索一下DemonstrateGenericSharing函數的泛型版本。在我的專案中,它被命名為HelloWorld_DemonstrateGenericSharing_m4。通過CTags工具,我們可以跳到GenericType<string>的構造函數:GenericType_1__ctor_m8。請注意,這個函數實際上是一個#define定義,這個#define又把我們引向另一個函數:GenericType_1__ctor_m10447_gshared。

讓我們跳回(譯注:使用CTags工具,程式碼關係往回回溯兩次)。可以找到GenericType<AnyClass> 類型的申明。如果我們對其構造函數GenericType_1__ctor_m9進行追溯,我們同樣能夠看到一個#define定義,而這個定義最終引向了同一個函數:GenericType_1__ctor_m10447_gshared。

如果我們跳到GenericType_1__ctor_m10447_gshared的定義,我們能從程式碼上面的注釋得出一個訊息:這個C++函數對應的是C#中的HelloWorld::GenericType`1<System.Object>::.ctor()。這是GenericType<object>類型的標準構造函數。這種類型稱之為全共享類型,意味著對於GenericType<T>而言,只要T是引用類型,所有的函數都使用同一份程式碼。

在這個構造函數往下一點,你應該能夠看到UsesGenericParameter函數的C++實現:
1
2
3
4
5
6
7
extern "C" Object_t * GenericType_1_UsesGenericParameter_m10449_gshared (GenericType_1_t2159 * __this, Object_t * ___value, MethodInfo* method)
{
  {
    Object_t * L_0 = ___value;
    return L_0;
  }
}

在兩處使用泛型參數T的地方(分別在返回值和函數參數中),C++程式碼都使用了Object_t*。因為任何引用類型都能在C++程式碼中被Object_t*所表示,所以我們也就能夠對於任何引用T,呼叫相同的UsesGenericParameter函數。

在系列的第二篇中,我們有提到過在C++程式碼中,所有的函數都是非成員函數。il2cpp.exe不會因為在C#有重載函數而在C++中使用繼承。在是在類型的處理上卻有所不同:il2cpp.exe確實會在類型的處理上使用繼承。如果我們查找代表C#中AnyClass類的C++類型AnyClass_t,會發現如下程式碼:
1
2
3
struct  AnyClass_t1  : public Object_t
{
};

因為AnyClass_t1是從Object_t繼承而來,我們就能合法的傳遞一個 AnyClass_t1的指針給GenericType_1_UsesGenericParameter_m10449_gshared函數。

那函數的返回值又是個什麼情況呢?如果函數需要返回一個繼承類的指針,那我們就不能返回它的基類對吧。那就讓我們看看GenericType<AnyClass>::UsesGenericParameter的方法:
1
#define GenericType_1_UsesGenericParameter_m10452(__this, ___value, method) (( AnyClass_t1 * (*) (GenericType_1_t6 *, AnyClass_t1 *, MethodInfo*))GenericType_1_UsesGenericParameter_m10449_gshared)(__this, ___value, method)

C++程式碼其實是把返回值(Object_t*類型)強制轉換成了AnyClass_t1*類型。因此在這裡IL2CPP對C++編譯器使了個障眼法。因為C#的編譯器會保證UsesGenericParameter中的T是可兼容的類型,因此IL2CPP這裡的強轉是安全的。

帶泛型約束的共享


假設如果我們想要讓T能夠呼叫一些特定的函數。因為System.Object只有最基本的一些函數而不存在你想要使用的任何其他函數,那麼在C++中使用Object_t*就會造成障礙了,不是嘛?是的,你說的沒錯!但是我們有必要在此解釋一下C#編譯器中的泛型約束的概念。

讓我們再仔細看看InterfaceConstrainedGenericType的C#程式碼。這個泛型類型使用了一個‘where’關鍵字以確保T都是從一個特定的接口(Interface):AnswerFinderInterface繼承過來的。這就使得呼叫ComputeAnswer 函數成為可能。大家還記得上一篇博文中我們討論的:當呼叫一個接口函數的時候,我們需要在虛表(vtable structure)中進行查找。因為FindTheAnswer可以從約束類型T中被直接呼叫,所以C++程式碼依然能夠使用全共享的實現機制,也就是說T由Object_t*所代表。

如果我們由HelloWorld_DemonstrateGenericSharing_m4function的實現開始,跳到InterfaceConstrainedGenericType_1__ctor_m11函數的定義,會發現這個函數任然是一個#define定義,映射到了InterfaceConstrainedGenericType_1__ctor_m10456_gshared函數。在這個函數下面,是InterfaceConstrainedGenericType_1_FindTheAnswer_m10458_gshared函數的實現,發現它也是一個全共享函數,接受一個Object_t*參數,然後呼叫InterfaceFuncInvoker0::Invoke函數轉而呼叫實際的ComputeAnswer程式碼。

1
2
3
4
5
6
7
8
9
10
11
12
13
extern "C" int32_t InterfaceConstrainedGenericType_1_FindTheAnswer_m10458_gshared (InterfaceConstrainedGenericType_1_t2160 * __this, Object_t * ___experiment, MethodInfo* method)
{
  static bool s_Il2CppMethodIntialized;
  if (!s_Il2CppMethodIntialized)
  {
    AnswerFinderInterface_t11_il2cpp_TypeInfo_var = il2cpp_codegen_class_from_type(&AnswerFinderInterface_t11_0_0_0);
    s_Il2CppMethodIntialized = true;
  }
  {
  int32_t L_0 = (int32_t)InterfaceFuncInvoker0<int32_t>::Invoke(0 /* System.Int32 HelloWorld/AnswerFinderInterface::ComputeAnswer() */, AnswerFinderInterface_t11_il2cpp_TypeInfo_var, (Object_t *)(*(&amp;amp;___experiment)));
  return L_0;
  }
}

因為IL2CPP把所有的C#中的接口(Interface)都當作System.Object一樣處理,其所產生的C++程式碼也就能說得通了。這個規則在C++程式碼的其他情況中也同樣適用。

基類的約束


除了對接口(Interface)進行約束,C#還允許對基類進行約束。IL2CPP並不是把所有的基類都當成System.Object處理。那麼對於有基類約束的泛型共享又是怎樣的呢?

因為基類肯定都是引用類型,所以IL2CPP還是使用全共享版本的泛型函數來處理這些受約束的類型。任何有用到約束類型中特定成員變量或者成員函數的地方都會被C++程式碼進行強制類型轉換。再次強調,在這裡我們仰仗C#編譯器強制檢查這些約束類型都符合轉換要求,我們就可以放心的蒙蔽C++編譯器了。

值類型的泛型共享


讓我們回到HelloWorld_DemonstrateGenericSharing_m4函數看下 GenericType<DateTime>的實現。DateTime是個值類型,因此GenericType<DateTime>不會被共享。我們可以看看這個類型的構造函數GenericType_1__ctor_m10。這個函數是GenericType<DateTime>所特有的,不會被其他類使用。

系統的思考泛型共享


泛型共享的實現是比較難以理解的,問題的本身在於它自己充滿著各種不同的特殊情況(比如:奇特的遞歸模板模式)(譯注:這是C++中的一個概念,簡單的說就是諸如:class derived:public base<derived>這樣的形式,使用派生類本身來作為模板參數的特化基類。目的是在編譯期通過基類模板參數來得到派生類的行為,由於是編譯期綁定而不是運行期綁定,可以增加執行效率)。

從以下幾點著手可以幫助我們很好的思考泛型共享:

  • 泛型類中的函數都是共享的
  • 有些泛型類只和他們自己共享程式碼(比如泛型參數是值的泛型類)
  • 泛型參數是引用的泛型類總是全共享-他們總是使用System.Object來適用於各種參數類型
  • 有兩個或者更多泛型參數的泛型類能夠被部分共享。前提是在泛型參數中至少有一個參數是引用類型
il2cpp.exe總是先產生全共享程式碼。其他特別的程式碼在有用到時才會特別單獨產生。

泛型函數的共享


泛型類可以被共享,泛型函數同樣也可以。在我們原始的C#示例程式碼中,有一個UsesDifferentGenericParameter函數,這個函數用了另外一個泛型參數而不是GenericType。我們在GenericType類的C++程式碼中查找不到UsesDifferentGenericParameter的實現。事實上,它在GenericMethods0.cpp中:
1
2
3
4
5
6
7
extern "C" Object_t * GenericType_1_UsesDifferentGenericParameter_TisObject_t_m15243_gshared (GenericType_1_t2159 * __this, Object_t * ___value, MethodInfo* method)
{
  {
   Object_t * L_0 = ___value;
   return L_0;
  }
}

請注意這個是一個泛型函數的全共享版本,因為它接受Object_t*作為參數。雖然這是一個泛型函數,但是它的行為在非泛型的情況下是一樣的。il2cpp.exe總是試圖先產生一個使用泛型參數的實現。

結論


泛型共享是自IL2CPP發佈以來一個最重要的改進。通過共享相同的程式碼實現,它使得C++程式碼盡可能的小。我們也會繼續利用共享程式碼機制來進步一減少最終二進制文件的尺寸。

在下一篇文章中,我們將探討 p/invoke 封裝程式碼是如何產生的。以及托管程式碼中的類型數據是如何轉換到原生程式碼(C++程式碼)中的。我們將檢視各種類型轉換所需要的開銷,並且嘗試除錯有問題的數據轉換程式碼。

著作人

網誌存檔