在Unity中使用Direct2D

在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着色器很不錯,簡直贊



發佈了35 篇原創文章 · 獲贊 18 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章