您的位置:首页 > 移动开发 > Unity3D

在Unity中使用Direct2D

2014-08-30 01:27 197 查看
在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?随意啦!

但是,我建议这样做:



[cpp]
view plaincopyprint?

#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);

}

#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#中的托管方法。

比如先定义:

[csharp]
view plaincopyprint?

// 初始化 D2D 管理器
public delegate System.UInt32 D2DManagerInit();

public D2DManagerInit m_D2DManagerInit;

// 初始化 D2D 管理器
    public delegate System.UInt32 D2DManagerInit();
    public D2DManagerInit m_D2DManagerInit;


使用:

[csharp]
view plaincopyprint?

proc = GetProcAddressWrap(m_unityd2ddll, "D2DManagerInit");

m_D2DManagerInit = (D2DManagerInit)Marshal.GetDelegateForFunctionPointer(proc,
typeof(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参考如下:

[cpp]
view plaincopyprint?

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;

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着色器很不错,简直赞

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: