OpenGL4与OpenTK在C#中的使用:绘制第一个三角形

这是关于使用C#中的OpenTK库实现OpenGL4的系列教程的第五部分。在之前的教程中,介绍了如何初始化游戏窗口、编译着色器、链接着色器、传递数据给着色器以及重构代码和添加错误处理。本部分将基于之前的游戏窗口和着色器进行扩展。

初始化缓冲区

首先,需要定义一个结构体来存储顶点的位置和颜色。

public struct Vertex { public const int Size = (4 + 4) * 4; private readonly Vector4 _position; private readonly Color4 _color; public Vertex(Vector4 position, Color4 color) { _position = position; _color = color; } }

上述结构体与顶点着色器相匹配,即它包含一个Vec4用于位置和一个Vec4用于颜色。Vector4和Color4由OpenTK提供。

创建顶点数组和缓冲区

_vertexArray = GL.GenVertexArray(); _buffer = GL.GenBuffer(); GL.BindVertexArray(_vertexArray); GL.BindBuffer(BufferTarget.ArrayBuffer, _buffer);

接下来,需要告诉OpenGL如何使用这个新的缓冲区:

GL.NamedBufferStorage( _buffer, Vertex.Size * vertices.Length, vertices, BufferStorageFlags.MapWriteBit);

现在,需要提供关于着色器中属性数据位置的信息,即位置和颜色。首先是位置:

GL.VertexArrayAttribBinding(_vertexArray, 0, 0); GL.EnableVertexArrayAttrib(_vertexArray, 0); GL.VertexArrayAttribFormat( _vertexArray, 0, 4, VertexAttribType.Float, false, 0);

然后是颜色:

GL.VertexArrayAttribBinding(_vertexArray, 1, 0); GL.EnableVertexArrayAttrib(_vertexArray, 1); GL.VertexArrayAttribFormat( _vertexArray, 1, 4, VertexAttribType.Float, false, 16);

最后,使用以下命令将它们链接在一起:

GL.VertexArrayVertexBuffer(_vertexArray, 0, _buffer, IntPtr.Zero, Vertex.Size);

渲染所有内容:

GL.BindVertexArray(_vertexArray); GL.DrawArrays(PrimitiveType.Triangles, 0, 3);

重构到RenderObject类

由于代码较多,决定创建一个名为RenderObject的类。上述初始化代码放入构造函数,渲染代码放入Render方法。

public class RenderObject : IDisposable { private bool _initialized; private readonly int _vertexArray; private readonly int _buffer; private readonly int _verticeCount; public RenderObject(Vertex[] vertices) { _verticeCount = vertices.Length; _initialized = true; } public void Render() { GL.BindVertexArray(_vertexArray); GL.DrawArrays(PrimitiveType.Triangles, 0, _verticeCount); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (disposing) { if (_initialized) { GL.DeleteVertexArray(_vertexArray); GL.DeleteBuffer(_buffer); _initialized = false; } } } }

这将有助于在将来向场景中添加更多对象时的工作。

GameWindow中的更改

将VertexBuffer的初始化替换为初始化渲染对象列表。示例顶点数组应该在屏幕上显示一个粉红色的三角形,类似于本文标题图片。

private List<RenderObject> _renderObjects = new List<RenderObject>(); protected override void OnLoad(EventArgs e) { Vertex[] vertices = { new Vertex(new Vector4(-0.25f, 0.25f, 0.5f, 1f), Color4.HotPink), new Vertex(new Vector4(0.0f, -0.25f, 0.5f, 1f), Color4.HotPink), new Vertex(new Vector4(0.25f, 0.25f, 0.5f, 1f), Color4.HotPink), }; _renderObjects.Add(new RenderObject(vertices)); CursorVisible = true; _program = CreateProgram(); GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill); GL.PatchParameter(PatchParameterInt.PatchVertices, 3); Closed += OnClosed; }

OnExit方法更改为释放已初始化的渲染对象。

public override void Exit() { Debug.WriteLine("Exit called"); foreach (var obj in _renderObjects) obj.Dispose(); GL.DeleteProgram(_program); base.Exit(); }

最后,OnRenderFrame代码循环遍历渲染对象,并调用它们独立的Render方法将它们显示在屏幕上。

protected override void OnRenderFrame(FrameEventArgs e) { _time += e.Time; Title = $"{_title}: (Vsync: {VSync}) FPS: {1f / e.Time:0}"; Color4 backColor; backColor.A = 1.0f; backColor.R = 0.1f; backColor.G = 0.1f; backColor.B = 0.3f; GL.ClearColor(backColor); GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); GL.UseProgram(_program); foreach (var renderObject in _renderObjects) renderObject.Render(); SwapBuffers(); } #version 450 core layout (location = 0) in vec4 position; layout(location = 1) in vec4 color; out vec4 vs_color; void main(void) { gl_Position = position; vs_color = color; } #version 450 core in vec4 vs_color; out vec4 color; void main(void) { color = vs_color; }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485