目标, 在.NET 2.0 的托管窗口中框出一块区域进行D3D 绘画. 所谓绘画, 为了减少代码, 暂时定义为纯色屏…

DirectX SDK: 2007 June

Documents:

  • DirectX Documentation for C++
  • DirectX Documentation for Managed Languages (.NET 1.1)
  • Introduction to 3D Game Programming with DirectX 9.0

Samples:

  • DirectX Sample Browser — Tutorial 1: Create a Device

问题的关键就在于, 如何在.Net 的托管环境下使用DirectX, 在托管窗口(Windows::Form) 中进行3D 绘画. 我们有两个选择, 一是使用托管的DirectX (Managed DirectX), 另一种方法是使用Native DirectX (有时候是必须的无奈啊…).

无论是使用托管的, 还是原生的DX, 最核心的, 也是最初的步骤, 都是需要初始化一个D3D 的Device, 使得我们能够通过该Device 来进行3D 绘画.

I. 托管DX 的Device 初始化

以一个基于C++/CLI 的Windows Form Application 为例, 为了获得DX支持, 我们必须添加如下三个.Net References

  • Microsoft.DirectX
  • Microsoft.DirectX.Direct3D
  • Microsoft.DirectX.Direct3DX (Version: 1.0.2911.0)

这三个Reference, 在安装了DirectX 的SDK 后, 会出现在Project->Add Reference->.Net 下. 需要主意的是, 托管的DX 是基于.Net 1.1 的Runtime 的, 在.Net 2.0 和VS 2005 的环境下使用时会抛出一个LoderLock 的Exception. LoadLocker 是VS 2005 引入的MDA (Managed Debugging Assistant) 中的一个, 被设计用来寻找Debug 时一些较难发现的Runtime 问题. 所有的.Net 1.1 的DX 程序集在VS 2005 下都会触发这个Exception (仅在Debugger 下). 暂时的解决方法有三个:

  1. 使用VS 2003 和.Net 1.1 (不是办法的办法 =.=)
  2. 使用MDX 2.0 (要注意的是, MDX 2.0 计划已经被终止, 实际上MDX 2.0已经被Transform 到XNA Framwork)
  3. 禁止VS 2005 Debugger 的LoadLocker Exception (Debug->Exceptions, 去掉LoadLocker 前的钩)

在完成了上面3个步骤中的任何一个以后, 我们就可以专心于我们的托管DX 代码了. 在托管环境下, 我们初始化一个Device 的步骤如下:

  1. 创建一个PresentParameters^ 的对象并填充它.
  2. 创建一个Device^ 对象.

最简单的代码片断如下:

try {
PresentParameters^ paras = gcnew PresentParameters();
paras->Windowed = true;
paras->SwapEffect = SwapEffect::Discard;
Device^ device = gcnew Device(0, DeviceType::Hardware, AControl, CreateFlags::HardwareVertexProcessing, paras);
} catch(DirectXException^ e) {
//Do Something
}

事实上, PresentParameters 定义了很多字段, 完整列表可以参考DX SDK 的帮助文件(Mananged Language 版本).

Device 的构造函数有四个, 例子中使用的原型为:

Device (
int adapter,
DeviceType deviceType,
Control^ renderWindow,
CreateFlags behaviorFlags,
array<PresentParameters^>^ presentationParameters
);

其中adapter 为显卡的编号, 0 代表默认的主显卡( 就是目前在用的那块); deviceType 是DeviceType 的一个枚举类型; renderWindow 可以替换为需要绘图的区域/窗体, 比如一个Form, 一个Panel 等, 类型为Control^; behaviorFlags 是CreateFlags 的一个枚举类型, presentationParameters 就是我们之前创建的用来描述Device 的PresentParameters 的一个实例. 在创建Device 之前, 必须确定显卡支持这些特性, 完整的支持列表和参数可以参考DX 帮助和显卡制造商的说明.

在Device 创建完成后, 就可以使用该Device 进行图形绘制. 最简单的, 绘制一个纯色屏幕, 或者说清屏, 代码如下:

device->Clear(ClearFlags::Target, Color::SkyBlue, 1.0f, 0);
device->BeginScene();
//You can do something here to draw 3D stuff
device->EndScene();
device->Present();

Clear 方法将Device 所指定的区域填充为纯色, 例子中为天蓝色. Clear 的原型有四个, 例子中的为:

void Clear ( ClearFlags flags, Color color, float zdepth, int stencil );

其中flags 是一个ClearFlag 枚举, 用来指定要清除的表面; color 是一个Color 枚举.

我们可以将该清屏代码放入Control 的Paint 事件函数中, 这样每次Control 被Repaint, 就会被Clear 为指定的纯色, 或者某个3D 图形( 如果有的话).

至此, Managed DX 和C++/CLI 工作地很好.

II. Native Device 的初始化

Native 的DX 要在托管环境下使用就稍微有点麻烦了. 不过由于是Native 的, 所以在性能上会比托管DX 有所优势( 设计良好的前提下), 而且有时候由于一些第三方库的原因, 不得不使用Native 的DX. 下面简要说明以下在托管环境中使用Native DX 时容易遇到的问题.

首先, 我们要设定头文件的include 路径(%DX SDK%\include), 然后, 添加Library 的路径(%DX SDK%\lib), 接着, 将d3d9.lib, d3dx9.lib, winmm.lib 添加到Input Library 中.

然后在需要的地方包含头文件<d3dx9.h>

初始化一个Native 的DX Device 比托管代码要多一些步骤, 也要格外小心一些, 典型代码如下:

IDirect3D9 *_d3d9 = Direct3DCreate9(D3D_SDK_VERSION); //为了包含正确的头文件, 必须使用D3D_SDK_VERSION

D3DCAPS9 caps; //检查显卡的Capability

HRESULT hr = _d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);

int vp = 0;

if( SUCCEEDED( hr ) ) {
if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) {
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
} else {
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}
} else {
//FAIL;
}

D3DPRESENT_PARAMETERS paras;

//填充完整的Present Parameters 信息, 完整的字段含义参考DX 帮助
paras.BackBufferWidth = 200;
paras.BackBufferHeight = 192;
paras.BackBufferFormat = D3DFMT_A8R8G8B8;
paras.BackBufferCount = 1;
paras.MultiSampleType = D3DMULTISAMPLE_NONE;
paras.MultiSampleQuality = 0;
paras.Windowed = true;
paras.SwapEffect = D3DSWAPEFFECT_DISCARD;
paras.hDeviceWindow = (HWND)(pnlOther->Handle.ToPointer());
paras.EnableAutoDepthStencil = true;
paras.AutoDepthStencilFormat = D3DFMT_D24S8;
paras.Flags = 0;
paras.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
paras.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;

IDirect3DDevice9* device = 0; //D3D9 Device

hr = _d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, (HWND)(panel->Handle.ToPointer()),
vp, ¶s, &device);

if( SUCCEEDED( hr ) ) {
//创建Device 成功
} else {
//FAIL
}

大致的步骤和托管DX 是一样的, 事实上, 在任何时候初始化一个Device 最好都要检查显卡的支持, 在上面的托管代码中, 这部分被省略了, 估计.Net 帮我们完成了很多事情, 默认值工作的很好. 但在Native 代码中, 省略初始化任何一个Paras 的字段都有可能导致Device 的创建失败(Investiagting 中).

另外, CreateDevice 方法的第三个参数接受的是一个HWND 类型的窗口句柄, 但是我们是使用的是一个托管窗口的托管Panel, 因此, 我们要获取这个Panel 的句柄, 方法是调用Panel::Handle 属性, 它返回一个IntPtr, 实际上包含了该控件的句柄, 所以, 我们通过ToPointer() 获得void*, 再强制转换为HWND 传给CreateDevice.

获得了Device , 我们同样可以在Paint 时间中重绘屏幕, 如下:

m_device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0×00000000, 1.0f, 0);
m_device->Present(0, 0, 0, 0);

0×00000000 是颜色的16 进制代码, 代表黑色.

这里还有一个问题, 由于IDirect3DDevice9* 是Native 类型, 因此在ref class 定义中, 如果定义IDirect3DDevice9* 为member, 那我们无法直接通过&device 将成员地址传给CreateDevice() 来创建设备, 因为这时候的IDirect3DDevice9* 被wrap 成CLR 的ptr 类型, 因此, 我们必须先创建一个临时变量IDirect3DDevice9* device ,然后再将创建成功的device 赋值给IDirect3DDevice9* 类型的member, 比如m_device. ( if( SUCCEEDED( hr ) ) m_device = device;)

至此, 我们就完成了Native D3D Device 在托管代码中的初始化, 接下来可以用该Device 可以来进行3D 图形的绘制…

//End of Step First D3D

在编译前需要安装DirectX SDK, 并且重新定义Native Code 部分的头文件路径, LIB 路径地址. 需要禁止LoadLocker (见上文).

转载于:https://www.cnblogs.com/ronli/archive/2010/05/15/1735966.html

.NET2.0+ D3D绘画 : Microsoft.DirectX.Direct3D程序集問題相关推荐

  1. ASP.NET Ajax 1.0 RC 'Sys' 未被定義 問題

    ASP.NET Ajax 1.0 RC 'Sys' 未被定義 問題 您在依照筆者的影片安裝ASP.NET Ajax 1.0 RC 之後,可能會在測試時發現有底下的錯誤訊息: 請在 Web.Config ...

  2. DirectX 9.0笔记]第一章 初始化 Direct3D

    1.Direct3D概述 Direct3D的工作框架图如下图所示. 应用程序通过调用Direct3D的API来绘图,Direct3D不直接作用于图形设备,而是通过硬件抽象层(HAL,Hardware ...

  3. ASP.NET2.0国际化/本地化应用程序的实现总结(多语言,多文化页面的实现)

    相关文章导航 Sql Server2005 Transact-SQL 新兵器学习总结之-总结 Flex,Fms3相关文章索引 FlexAir开源版-全球免费多人视频聊天室,免费网络远程多人视频会议系统 ...

  4. 混合模式程序集是针对“v2.0.50727”版的运行时生成的,在没有配置其他信息的情况下,无法在 4.0 运行时中加载该程序集...

    其调用的方法是从sqlite数据库中获取原来已经使用过的数据库连接,当时也没注意,就是准备设断点然后单步调试,结果竟然是断点无法进入方法体内,后来仔细看了一下方法体的时候发现了一个问题,就是现有的Sy ...

  5. VS2005 ASP.NET2.0安装项目的制作(包括数据库创建、站点创建、IIS属性修改、Web.Config文件修改)

    站点: 如果新建默认的Web安装项目,那它将创建的默认网站下的一个虚拟应用程序目录而不是一个新的站点.故我们只有创建新的安装项目,而不是Web安装项目.然后通过安装类进行自定义操作,创建新站如下图: ...

  6. 用Microsoft DirectX光线跟踪改善渲染质量

    用Microsoft DirectX光线跟踪改善渲染质量 Implementing Stochastic Levels of Detail with Microsoft DirectX Raytrac ...

  7. 从.NET1.1升级到.NET2.0时出现的PInvokeStackImbalance错误

    从.NET1.1升级到.NET2.0时出现的PInvokeStackImbalance错误 微软官方的解释(http://msdn2.microsoft.com/zh-cn/library/0htdy ...

  8. [转]ASP.NET1.0升级ASP.NET2.0问题总结

    来自:http://www.enet.com.cn/article/2006/0310/A20060310510518.shtml 1.Global.asax文件的处理形式不一样,转化后将出现错误 在 ...

  9. ASP.NET2.0 文本编辑器FCKeditor的冰冷之心 【月儿原创】

    ASP.NET2.0 文本编辑器FCKeditor的冰冷之心 作者:清清月儿 主页:http://blog.csdn.net/21aspnet/           时间:2007.4.9 FCKed ...

最新文章

  1. nsqjs客户端的部署
  2. 工业大数据系统与应用北京市重点实验室给大家拜年啦!
  3. DELL服务器重做RAID
  4. python扩展文件_1. 使用 C 或 C++ 扩展 Python
  5. AndroidStudio 开发基础知识【翻译完成】
  6. 鸿蒙的应用列表,图解鸿蒙列表组件ListContainer
  7. android真实项目教程(四)——MY APP MY STYLE_by_CJJ
  8. 区块链开发公司:区块链技术如何改变个人数据安全
  9. Python爬虫——Python基础笔记
  10. Kali linux 学习笔记(十三)主动信息收集——端口扫描(UDP扫描、TCP扫描) 2020.2.22
  11. 将BC26连接至OneNET平台
  12. php导出excel列宽,PHP导出Excel 之 Spreadsheet_Excel_Writer
  13. 微信小程序-扫码点餐系统设计
  14. Centos 异步 IO framework io_uring,基本原理,程序示例与性能压测
  15. 手机上app测试总结
  16. Linux中文件搜索,查找,读取
  17. react的超详细讲解
  18. JavaScript 测试题 (2021-6-21)
  19. 《我们的梦》——我公司形象歌曲
  20. vscode同时编辑多行,插入递增数字,递减数字,递增字母,递减字母。

热门文章

  1. 干货|常用3D建模软件有哪些?
  2. 一文彻底理解机器学习高斯核函数和基函数
  3. OAuth 2.0 概念及授权流程梳理
  4. Android之录音功能
  5. uniapp 开发微信小程序踩坑:TypeError: Cannot read property ‘FormData‘ of undefined
  6. Angular JS中的then()
  7. android+布局倾斜,Android实现倾斜角标样式
  8. Python模块学习 之zipfile zip文件操作
  9. 探索嗖拉拉防弹咖啡的秘密
  10. 金蝶云星空对接打通积加ERP物料查询接口与录入产品信息接口