OpenTK: 3D图形、音频和计算功能的C#库

OpenTK是一个开源的C#工具包,它封装了OpenGL、OpenCL和OpenAL。它适用于游戏、科学应用以及任何需要3D图形音频计算功能的项目。简而言之,它被称为OpenTK。

OpenTK不仅仅是一个快速的C#实现OpenGL,它是最好的。尽管之前有一些如CSGL、TAO框架等实现,但它们是不完整的,并且受到一些限制。现在,它们完全无法跟上.NET Framework的发展。

在OpenTK中,每个OpenGL函数都可以通过GL类调用,例如OpenGL中的glVertex2f(-2.0,-2.0)OpenTK中作为GL.Vertex2(-2.0,-2.0)使用。它提供了一个非常好且灵活的GUI选项,包括跨平台的GLControl(Windows.Forms),它可以轻松地添加到Visual Studio工具箱中,GLWidget是另一个丰富且有用的组件,用于GTK#和WPFControl类。还有一个专为游戏设计的高性能原生GameWindow。可以比想象的更快地开发游戏。

它还有一个非常有用的API集合,如3D数学工具包,提供Vector、Matrix、Quaternion和Bezier结构。输入API提供键盘、鼠标和游戏杆接口。显示API有助于多显示器支持。OpenTK.Compatibility支持TAO框架应用程序。

如果想要思考平台独立性,它支持Windows、Linux和Mac OS X的32位和64位版本。不需要误管理库——一次编译,到处运行。而且,可以自由使用、修改和重新分发源代码。它适合开源和闭源项目。

使用代码,不需要有任何OpenGLC#图形的先验知识来学习OpenTK。只需要一些Windows表单设计的基础知识就足够了。

要使用OpenTK,需要在Visual Studio引用中添加两个DLL:OpenTK.dll和OpenTK.Graphics.OpenGL.dll。两者都可以在这里轻松找到。

不会使用OpenTK的众所周知的游戏窗口,假设熟悉Windows表单设计。只是使用一个普通的Windows表单。OpenTK提供了一个非常好的控件/工具。为此,需要将其添加到Visual Studio工具箱中,它被称为GLControl,可以在这里找到它。首先点击工具箱并选择项目,然后浏览并添加这个控件的DLL。现在可以使用它了。

首先,创建一个表单,将在其中放置GLControl。右键单击工具箱中的一些空白区域,选择“选择项目…”,然后浏览OpenTK.GLControl.dll。确保可以在.NET Framework组件中找到GLControl,如下所示。然后可以像任何.NET控件一样将GLControl添加到表单中。一个名为glControl1的GLControl将被添加到表单中。

首先添加这个控件并在端口中命名为glControl1,并编写以下代码。同时在该控件的加载事件中添加这个方法。有关更多详细信息,可以在这里查看。

private void glControl1_Resize(object sender, EventArgs e) { int w = glControl1.Width; int h = glControl1.Height; glControl1.MakeCurrent(); GL.MatrixMode(MatrixMode.Projection); GL.LoadIdentity(); GL.ClearColor(Color.SkyBlue); GL.Ortho(-w / 2, w / 2, -h / 2, h / 2, -1, 1); GL.Viewport(0, 0, w, h); GL.End(); glControl1.SwapBuffers(); }

如果运行它,会找到一个如下所示的表单:

那么它是如何完成的呢?这很简单。首先,看到:

glControl1.MakeCurrent();

它使所有接下来的GL命令对这个控件启用。

GL.MatrixMode(MatrixMode.Projection); GL.LoadIdentity();

将投影矩阵模式设置为投影,并加载身份。如果想了解更多关于这些模式的信息,可以在这里查看。

下一个命令非常重要,理解它之前,首先需要成为一个好的OpenGL公民,并设置一个正交投影矩阵使用GL.Ortho()。还需要调用GL.Viewport()

GL.Ortho(-w / 2, w / 2, -h / 2, h / 2, -1, 1);

这使得GL框的中心为x、y轴的0,0。因为w是GL框的宽度,h是高度。如果想将左下角像素设置为0,0,可以这样写:

GL.Ortho(0, w, 0, h, -1, 1) GL.Viewport(0, 0, w, h);

Viewport用于选择控件中的绘画区域。

GL.ClearColor(Color.SkyBlue);

它将其设置为蓝色。对于命令处理和窗口缓冲区,必须写:

GL.End(); glControl1.SwapBuffers();

现在,首先必须在glcontrol中绘制一个圆。对于draw方法,必须在glcontrol的paint事件中使用paint方法,如下所示:

private void glControl1_Paint(object sender, PaintEventArgs e) { GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); drawclock(); glControl1.SwapBuffers(); } void Draw_clock() { drawCircle(80); Draw_digit(); }

对于drawcircle,使用以下代码:

void drawCircle(float radius) { GL.Color3(Color.White); GL.Begin(BeginMode.TriangleFan); for (int i = 0; i < 360; i++) { double degInRad = i * 3.1416 / 180; GL.Vertex2(Math.Cos(degInRad) * radius, Math.Sin(degInRad) * radius); } GL.End(); }

现在,看起来它发生得如此容易。

GL.Begin(BeginMode.TriangleFan);

这种模式绘制一个三角形,并使用提供的顶点点填充白色。所有这些三角形使圆,就像三角形披萨片使圆形披萨一样。

如果想了解GL.Begin,可以在这里查看。必须记得在GL.Begin();之后写GL.End();,否则什么也不会发生,编译器也不会因为这个而给错误。现在必须绘制一个数字和两条线,用于分钟和小时。

编写一个简单的顶点操作代码,就像那样。记住,圆的半径是80。

void Draw_digit() { GL.MatrixMode(MatrixMode.Projection); GL.LoadIdentity(); GL.Color3(Color.Red); GL.Begin(BeginMode.TriangleFan); GL.Vertex2(0, +5); GL.Vertex2(0, -5); GL.Vertex2(70, 0); GL.Vertex2(70, 0); GL.Color3(Color.Red); GL.End(); GL.Begin(BeginMode.TriangleFan); GL.Vertex2(+5, 0); GL.Vertex2(-5, 0); GL.Vertex2(-65, 40); GL.Vertex2(-65, 40); GL.End(); GL.Color3(Color.Black); GL.Begin(BeginMode.Lines); GL.Vertex2(5, 60); GL.Vertex2(5, 70); GL.Vertex2(0, 60); GL.Vertex2(0, 70); GL.Vertex2(-5, 70); GL.Vertex2(-15, 60); GL.Vertex2(-15, 70); GL.Vertex2(-5, 60); GL.End(); GL.Color3(Color.Black); GL.Begin(BeginMode.Lines); GL.Vertex2(60, 0); GL.Vertex2(60, 8); GL.Vertex2(70, 0); GL.Vertex2(70, 8); GL.Vertex2(65, 0); GL.Vertex2(65, 8); GL.End(); GL.Color3(Color.Black); GL.Begin(BeginMode.Lines); GL.Vertex2(10, -60); GL.Vertex2(10, -70); GL.Vertex2(0, -60); GL.Vertex2(0, -70); GL.Vertex2(5, -60); GL.Vertex2(0, -70); GL.Vertex2(5, -60); GL.Vertex2(0, -70); GL.End(); GL.Color3(Color.Black); GL.Begin(BeginMode.Lines); GL.Vertex2(-75, -5); GL.Vertex2(-75, -15); GL.Vertex2(-70, -5); GL.Vertex2(-60, -15); GL.Vertex2(-70, -15); GL.Vertex2(-60, -5); }

这里是连接一个顶点到另一个顶点的代码。有关详细信息,可以在这里查看类似的OpenGL函数。

绘制完成后,可以看到输出表单如下所示:

现在必须为它创建一个计时器事件,所以首先添加一个计时器选择间隔为1000的1秒,启用它,并在计时器滴答时添加这个事件:

private void timer1_Tick(object sender, EventArgs e) { glControl2.MakeCurrent(); PaintEventArgs p = null; glControl2_Paint(sender, p); GL.End(); }

现在paint方法将在一秒钟后被调用。必须在那里绘制一条线,用于秒,所以paint事件将如下所示:

private void glControl2_Paint(object sender, PaintEventArgs e) { glControl2.MakeCurrent(); GL.End(); glControl2.SwapBuffers(); GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); Draw_clock(); GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); GL.End(); glControl2.SwapBuffers(); drawsecond(); glControl2.SwapBuffers(); }

这里为了绘制秒数,需要一个静态变量。为了改变秒数线顶点位置的坐标,采用:

static int i = 0;

现在drawsecond()函数:

void drawsecond() { GL.Color3(Color.Red); GL.Begin(BeginMode.Quads); GL.Vertex2(5, 0); GL.Vertex2(-5, 5); double degInRad = i * 3.1416 / 180; GL.Vertex2(Math.Cos(degInRad) * 80, Math.Sin(degInRad) * 80); GL.Vertex2(Math.Cos(degInRad) * 85, Math.Sin(degInRad) * 85); i = i - 6; GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); GL.End(); }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485