在Unity中可能需要在紋理上面繪製文字、圖像等。比如遊戲中的顯示器,手機等等等等等。太多了。
Unity的Textute2D類提供了設置像素的操作,但是這效率實在不敢恭維。
漢字數量巨大,全部貼在一張圖上既耗空間,不方便改變字體樣式。
使用FreeType2等CPU計算的文字庫一幀又畫不了多少,畢竟還要提交到顯存
於是瞄準了Direct2D,當初學習這圖像接口時就被微軟說的“能與Direct3D進行完美交互”所吸引。
好在Unity支持DX11了,我們能夠在Unity上面使用Direct2D了。所以只能在支持DX11的機器上面運行。
首先得說一下授權許可,畢竟Unity是一款商業軟件。
Unity明確指出:Unity Pro才能使用Plug-in,即插件。Unity Free版本是不可以使用的。
但是,它說的是“插件”,而不是“本地代碼”。
有童鞋肯定就會說我這是咬文嚼字了。非也非也,“插件”是指遵循當前環境並按照其對接口的相關規定寫的代碼。
那麼,Unity插件有什麼規定呢?
需要提供UnitySetGraphicsDevice與UnityRenderEvent
前者獲取圖形設備信息與圖像設備相關事件,後者提供渲染事件。這兩個接口是Unity自動調用的(或者也算半自動),
不能顯式調用——因爲沒意義.....
你的本地代碼提供了這兩個接口就算插件,否則就是普通的本地代碼庫。
作爲本地代碼庫不能放在plugin文件夾內,不能調用,因爲Unity會認爲是個插件,而應該直接放在工廠目錄下。
再者,假設你寫了個插件卻放在這個目錄下,那麼那兩個接口不能自動被調用。
好了,就這樣可以創建Direct2D了,那個版本的?1.0?1.1?甚至1.2?隨意啦!
但是,我建議這樣做:
#include "windows.h"
HMODULE WINAPI LoadLibraryWrapA(char* file_name){
return LoadLibraryA(file_name);
}
HMODULE WINAPI LoadLibraryWrapW(wchar_t* file_name){
return LoadLibraryW(file_name);
}
BOOL WINAPI FreeLibraryWrap(HMODULE hLibModule){
return FreeLibrary(hLibModule);
}
FARPROC WINAPI GetProcAddressWrap(HMODULE hModule, char* lpProcName){
return GetProcAddress(hModule, lpProcName);
}
面的代碼封裝成dll文件,這樣像C++一樣顯式調用dll文件。
好處如下:
1. 方便: 不知道是不是Unity的原因,反正假設你想一般dll一樣使用Unity C#中的DllImport,
使用後除非關閉Unity,否則不能再次修改dll文件。這簡直蛋疼,修改一行代碼就需要:
關閉Unity -> 複製dll -> 打開Unity
2. 方便調試,在VS Express 2013 for Windows Desktop中,選擇
工具——附加到進程,選擇Unity進程
就能直接調試dll文件了,很方便。
使用GetProcAddressWrap獲取函數指針之後使用C#中的
Marshal.GetDelegateForFunctionPointer
就能將函數指針換成C#中的託管方法。
比如先定義:
// 初始化 D2D 管理器
public delegate System.UInt32 D2DManagerInit();
public D2DManagerInit m_D2DManagerInit;
使用:
proc = GetProcAddressWrap(m_unityd2ddll, "D2DManagerInit");
m_D2DManagerInit = (D2DManagerInit)Marshal.GetDelegateForFunctionPointer(proc, typeof(D2DManagerInit));
之後使用m_D2DManagerInit()就能調用dll文件中的D2DManagerInit函數了。
最後在OnApplicationQuit裏面釋放即可。
創建 D2D 1.0 的 流程:
首先創建一個公共的 D2D工廠 ,畢竟可能創建多個
Unity中 Texture2D::GetNativeTextureID在DX11環境下就能獲取一個ID3D11Texture2D的指針
這個指針能獲取 D3D11設備 ,D3D11設備 能獲取當前 D3D11設備上下文。
D3D與D2D交互要D3D設備有D3D11_CREATE_DEVICE_BGRA_SUPPORT(D3D11環境下)
D3D11設備 -------> 創建Texture2D,D3D11_TEXTURE2D_DESC參考如下:
sharedTextureDesc.Width = 512;
sharedTextureDesc.Height = 512;
sharedTextureDesc.MipLevels = 1;
sharedTextureDesc.ArraySize = 1;
sharedTextureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sharedTextureDesc.SampleDesc.Count = 1;
sharedTextureDesc.Usage = D3D11_USAGE_DEFAULT;
sharedTextureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
必須有D3D11_BIND_RENDER_TARGET,否則不能創建渲染目標呈現器。記得保留這個指針。
然後對 D3D11Textue2D 使用QueryInterface獲取 Dxgi表面
使用這個Dxgi表面利用D2D工廠CreateDxgiSurfaceRenderTarget創建RT
就好了,記得釋放這個Dxgi表面:
渲染D2D
如同一般那樣,不過由於變成了dll,可能一些習慣要改成C語言那樣。
呈現D2D
渲染完成後,使用
D3D11設備上下文的CopyResource方法就能拷貝渲染結果到目標紋理了:
DirectWrite簡直不錯:
稍微寫點代碼就能模仿某遊戲那樣的效果:
嗯,看來還不夠完善,再加油吧:
話說自帶的Sprite着色器很不錯,簡直贊