• C#使用DirectX SDK 加载.x三维模型


    最近因为项目要做显示一个三维模型,所以研究了下如何在Winform中加载并显示三维模型。在Windows平台巨硬公司提供了DirectX SDK用于渲染图形,参考了几篇文章做了个demo记录下,以便日后温习只用。这个SDK涉及到了计算机图形学的一些基础知识,需要掌握一点基础,推荐可以看看OpenGL初学手册。

    创建项目

    我们开始返回正题,首先使用Visual Studio 2019创建一个Winform项目,然后添加DirectX 三个dll库的引用,路径是:C:\Windows\Microsoft.NET\DirectX for Managed Code\1.0.2902.0, 主要是前3个dll,后面的可用可不用。

    添加控件

    通过工具箱添加timer和panel控件,panel用于显示三位模型(也可不添加这个,直接用form显示),timer用于实时渲染。

     代码实现
    1. /*--------成员变量声明-----------*/
    2. //设备
    3. private Device device;
    4. //显示参数
    5. private PresentParameters pres;
    6. //保存3D文件
    7. private Mesh mesh;
    8. //渲染材质
    9. private Material[] materials;
    10. private Texture[] textures;
    11. /*--------方法实现-----------*/
    12. public bool InitializeGraphics()
    13. {
    14. pres = new PresentParameters();
    15. pres.Windowed = true;
    16. pres.SwapEffect = SwapEffect.Discard;
    17. pres.EnableAutoDepthStencil = true;
    18. pres.AutoDepthStencilFormat = DepthFormat.D16;
    19. device = new Device(0, DeviceType.Hardware, panel1, CreateFlags.SoftwareVertexProcessing,
    20. pres);
    21. device.RenderState.CullMode = Cull.None;
    22. CreateMesh(@"airplane 2.x");
    23. //CreateMesh(@"lobby_skybox.x");
    24. return true;
    25. }
    26. public void CreateMesh(string path)
    27. {
    28. ExtendedMaterial[] exMaterials;
    29. mesh = Mesh.FromFile(path, MeshFlags.SystemMemory, device, out exMaterials);
    30. if (textures != null)
    31. {
    32. DisposeTextures();
    33. }
    34. textures = new Texture[exMaterials.Length];
    35. materials = new Material[exMaterials.Length];
    36. for (int i = 0; i< exMaterials.Length; ++i)
    37. {
    38. if (exMaterials[i].TextureFilename != null)
    39. {
    40. string texturePath = Path.Combine(Path.GetDirectoryName(path), exMaterials[i].TextureFilename);
    41. textures[i] = TextureLoader.FromFile(device, texturePath);
    42. }
    43. materials[i] = exMaterials[i].Material3D;
    44. materials[i].Ambient = materials[i].Diffuse;
    45. }
    46. }
    47. public void DisposeTextures()
    48. {
    49. if (textures == null)
    50. {
    51. return;
    52. }
    53. foreach (Texture t in textures)
    54. {
    55. if (t != null)
    56. {
    57. t.Dispose();
    58. }
    59. }
    60. }
    61. public void SetupMatrices()
    62. {
    63. float yaw = Environment.TickCount / 500.0F;
    64. float pitch = Environment.TickCount / 500.0F;
    65. device.Transform.World = Matrix.RotationYawPitchRoll(yaw, pitch, 0);
    66. device.Transform.View = Matrix.LookAtLH(new Vector3(0, 0, -6), new Vector3(0, 0, 0), new Vector3(0, 1, 0));
    67. device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 2.0F, 1.0F, 1.0F, 10.0F);
    68. }
    69. public void SetupLights()
    70. {
    71. device.RenderState.Lighting = true;
    72. device.Lights[0].Diffuse = Color.White;
    73. device.Lights[0].Specular = Color.White;
    74. device.Lights[0].Type = LightType.Directional;
    75. device.Lights[0].Direction = new Vector3(-1, -1, 3);
    76. device.Lights[0].Enabled = true;
    77. device.RenderState.Ambient = Color.FromArgb(0x00, 0x00, 0x00);
    78. }
    79. public void RenderMesh()
    80. {
    81. for (int i = 0; i< materials.Length; ++i)
    82. {
    83. if (textures[i] != null)
    84. {
    85. device.SetTexture(0, textures[i]);
    86. }
    87. device.Material = materials[i];
    88. mesh.DrawSubset(i);
    89. }
    90. }
    91. public void Render()
    92. {
    93. device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.SkyBlue, 1.0F, 0);
    94. device.BeginScene();
    95. SetupMatrices();
    96. SetupLights();
    97. RenderMesh();
    98. device.EndScene();
    99. device.Present();
    100. }
    101. public void DisposeGraphics()
    102. {
    103. DisposeTextures();
    104. device.Dispose();
    105. }
    渲染实现

    在Form1_Load事件中调用初始化函数,然后在timer的timer1_Tick事件中调用Render函数实时渲染

    1. private void Form1_Load(object sender, EventArgs e)
    2. {
    3. InitializeGraphics();
    4. }
    5. private void timer1_Tick(object sender, EventArgs e)
    6. {
    7. Render();
    8. }

     编译程序,编译之前设置32位模式,需要自己新建一个32位的编译模式

    准备素材

    需要安装为微软的DirectX SDK,链接: https://www.microsoft.com/zh-cn/download/details.aspx?id=6812

    到这个路径下C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Samples\Media\Airplane复制三个资源文件到本地的的exe文件目录 RobotSimulator\DirectX3D\bin\x86\Debug

    运行程序

    PS:

     如遇“托管调试助手 “LoaderLock”报错“Message=托管调试助手 “LoaderLock”:“正尝试在 OS 加载程序锁内执行托管代码。不要尝试在 DllMain 或映像初始化函数内运行托管代码,这样做会导致应用程序挂起。””,可以快捷键Ctrl+Alt+E,改动Managed Debuggin Assistants->LoaderLock 的选中状态去掉。

  • 相关阅读:
    Vxlan协议原理及基本配置——网络测试仪实操手册
    React Native常用的Text和Image组件
    GIS 数据结构整理:网格索引
    spring cache (默认方式)
    基于SpringBoot的网上超市系统
    无胁科技-TVD每日漏洞情报-2022-11-2
    h5中左边有侧边栏,如何将右边bootstrap的div的布局设置为两列
    【位带操作对寄存器赋值】基于ADuCM4050的GPIO复用模式初始化
    代码随想录二刷day36
    无限上下文,多级内存管理!突破ChatGPT等大语言模型上下文限制
  • 原文地址:https://blog.csdn.net/wujizhishang/article/details/132926208