混合语言编程—C#使用原生的Directx和OpenGL绘图的方法
发布时间:2022-06-18 14:36:41
由于项目需要做一些图形展示,所以就想到了使用Directx和OpenGL来绘图,但项目准备使用C#来开发(大家比较熟悉C#),在网上看了相关的资料,有一些第三方的控件可用,试用了下,一运行就占了几百M的内存,而且也不知道是否稳定,教程也少,还不如直接使用原生的。在网上看的Directx和OpenGL的教程基本上都是C/C++的,找了很久也就找到相关介绍,只能自己研究下。
我以前做过C#和C++混合语言编程相关的东西,在C++实现一些C#不好实现的功能,C#动态调用DLL文件,所以也想到了用C++的代码来控制Winform控件的绘画,这样就可实现用Direct和OpenGL在Winform的控件上绘画了。
由于我对Direct和OpenGL都不熟悉,没有这方面的编程经验,只能去瞎折腾,下面分别说说最近在Directx和OpenGL怎么试验的。
Directx:
之前没学过Directx,拿了同学的代码来看,也是雾里看花啊,不过有一点启示了我,在初始化的时候,要传入一个句柄去创建设备(CreateDevice),通常都是传入窗口的设备,我想如果传入一个控件的句柄,那所有的绘画都将在这个控件上实现,因为控件也是继承自Window的。而Winform的控件在底层的实现应该和WIN32是一样的。这样的话只要把Winform的控件的句柄传入C++代码进行初始化,那么绘画的结果将显示在这个控件上。结果一试,还真行。关键代码如下:
extern "C" _declspec(dllexport) HRESULT InitD3D( HWND hWnd );
extern "C" _declspec(dllexport) VOID Render();
在InitD3D传入控件的句柄进行初始化,C#再调用Render进行绘画,以下是C#代码:
HWND handle = this.button1.Handle;
InitD3D(handle);
private void Draw()
{
for (; ; )
{
Render();
}
}
效果图:
OpenGL:
查看了OpenGL的相关教程(推荐http://www.yakergong.net/nehe/),OpenGL是通过RC来执行的,创建RC时就必须指定一个DC,还要设置DC的像素格式。每个线程有且只能拥有一个RC。
如果在初始化OpenGL的绘画环境时传入一个Winform的控件句柄,再通过这个句柄取到HDC,就可使用这个HDC来创建RC,这样OpenGL的绘画环境就准备好了,并且这个RC关联到Winform的控件上。
在给制前,先为当前线程选择RC(之前通过HDC创建的),再进行绘制,这样绘制的结果将显示在这个Winform控件上。
关键代码如下:
C++:
extern "C" _declspec(dllexport) void Init( HWND hWnd);
extern "C" _declspec(dllexport) void Render();
void Init(HWND hWnd)
{
int PixelFormat;
int bits = 16;
hDC = GetDC(hWnd);
static PIXELFORMATDESCRIPTOR pfd= // pfd Tells Windows How We Want Things To Be
{
sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
1, // Version Number
PFD_DRAW_TO_WINDOW | // Format Must Support Window
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
PFD_DOUBLEBUFFER, // Must Support Double Buffering
PFD_TYPE_RGBA, // Request An RGBA Format
bits, // Select Our Color Depth
0, 0, 0, 0, 0, 0, // Color Bits Ignored
0, // No Alpha Buffer
0, // Shift Bit Ignored
0, // No Accumulation Buffer
0, 0, 0, 0, // Accumulation Bits Ignored
16, // 16Bit Z-Buffer (Depth Buffer)
0, // No Stencil Buffer
0, // No Auxiliary Buffer
PFD_MAIN_PLANE, // Main Drawing Layer
0, // Reserved
0, 0, 0 // Layer Masks Ignored
};
PixelFormat=ChoosePixelFormat(hDC,&pfd);
SetPixelFormat(hDC,PixelFormat,&pfd);
hRC=wglCreateContext(hDC);
}
void Render()
{
wglMakeCurrent(hDC, hRC);
draw();
SwapBuffers(hDC);
wglMakeCurrent(NULL, NULL);
}
C#:
Init(this.pictureBox1.Handle);
//开始绘制
var timer = new System.Timers.Timer();
timer.Interval = 100;
timer.Elapsed += (tsender, te) =>
{
Render();
};
timer.AutoReset = true;
timer.Enabled = true;
效果图:
WPF:WPF的控件没有句柄,但是可以换个思路,把绘画代码封装在Winform控件上,在WPF使用自定义的Winform控件。


猜你喜欢
- Eclipse 最佳字体 推荐:步骤:Eclipse->Windows[窗口]->Preferences[首选项]->Ge
- 一、滑动验证码生成思路1、随机选择一张图片2、生成滑块起点位置(x, y)3、生成滑块轮廓4、抠出滑块5、将滑块部位去除颜色二、主要方法这里
- 最近在使用springboot过程中用到了mybatis-plus ,springboot版本是2.3.1.RELEASE,mybatis-
- 访问权限符:(1)public:对于成员来说:任何其他类都可以访问它们,不管在同一个包中还是在另外的包中。对于类来说:  
- 平时用到的库仓库名地址备注mavenCentralhttps://repo1.maven.org/maven2/
- 一、简介Mybatis-Plus(简称MP)是一个 Mybatis 的一个增强工具,在 Mybatis 的基础上只做增强不做改变,为简化开发
- 问题最近 Cordova 项目里有一个需求,这里需要从 assets 目录中读取文件,加载配置信息,并且代码中要用到。因为看到 gradle
- 今天导入了一个模型,但是模型贴图丢失了,而且Inspector面板中处于不能编辑的状态虽然可以通过重新创建材质来替换,但是这样会生成一个新的
- 一、环形队列是什么 队列是一种常用的数据结构,这种结构保证了数据是按照“先进先出”的原则进行操作的,即最先进去的元素也是最先出来的元素.环形
- 我们经常看到使用了ViewPager的App,在每页上面都会有一个滑块来标志当前处于哪一页。在PagerView包里有android.sup
- 使用enum进行定义/*枚举类型演示*/#include <stdio.h>int main() { enum /*
- 本文实例为大家分享了Android来电拦截的方法,供大家参考,具体内容如下权限 <uses-permission andr
- 本文实例讲述了C#通过创建Windows服务启动程序的方法。分享给大家供大家参考,具体如下:1. 新建一个Windows服务应用程序创建项目
- Android launcher中模拟按home键的实现Intent mHomeIntent = new Intent(Intent.ACT
- Transactional事务的使用及注意Transactional的事务使用,主要引用两个包中的Bean,一个是jpa的javax.tra
- 本文实例讲述了Java类加载器和类加载机制。分享给大家供大家参考,具体如下:一 点睛1 类加载器负责将.class文件(可能在磁盘上,也可能
- 前 言最近和我们老大一起做技术面试(我是旁听的),发现前来面试的没几个掌握甚至是丁点了解LINQ。这让我很纳闷,LINQ伴随2008一起发布
- docx4j变量替换的问题最近工作上需要自己完成word文档变量替换的问题把里面的变量给替换成数据库里的值,但是由于在word文档渲染成xm
- 使用GridView实现表格分割线效果,网格布局表格布局也是可以实现的。效果如下:1.主函数代码:package com.example.q
- 简单工厂模式的概念就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创