没有 GL.Begin() 的 OpenTK 文本渲染

OpenTK Text rendering without GL.Begin()

我正在使用 OpenTK 编写一个应用程序,并且到了我想要呈现文本的地步。从示例中,我使用 Graphics.DrawString() 拼凑了一个版本,该版本使用我需要的字符创建位图。那个版本工作得很好,但我很生气它依赖于 GL.Begin(BeginMode.Quads) 和 GL.End() 来渲染文本,这就是为什么我想从现在开始使用 VAO 和 VBO。

我的程序某处有问题,因为我总是得到单一颜色的方块,文本应该出现的地方。

到目前为止,我为更新我的功能所做的工作如下: 我创建的位图和以前一样,我不明白为什么问题出在那里。 之后,我创建了一个“Char”对象列表,每个对象创建一个 VBO,存储位置和纹理坐标,如下所示:

float u_step = (float)GlyphWidth / (float)TextureWidth;
float v_step = (float)GlyphHeight / (float)TextureHeight;
float u = (float)(character % GlyphsPerLine) * u_step;
float v = (float)(character / GlyphsPerLine) * v_step;
float x = -GlyphWidth / 2, y = 0;


_vertices = new float[]{
    x/rect.Width, -GlyphHeight/rect.Height,    u,          v,
   -x/rect.Width, -GlyphHeight/rect.Height,    u + u_step, v,
   -x/rect.Width, y/rect.Height,               u + u_step, v + v_step,

    x/rect.Width, -GlyphHeight/rect.Height,    u,          v,
   -x/rect.Width, y/rect.Height,               u + u_step, v + v_step,
    x/rect.Width, y/rect.Height,               u,          v + v_step
};

_VBO = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, _VBO);
GL.BufferData<float>(BufferTarget.ArrayBuffer, (IntPtr)(sizeof(float) * _vertices.Length),
 _vertices, BufferUsageHint.DynamicDraw);

接下来我生成一个纹理,将 texture0 设置为活动并将该纹理绑定为 TextureTarget.Texture2D。然后我将位图加载到纹理,执行以下操作:

_shader.Use();
_vertexLocation = _shader.GetAttribLocation("aPosition");
_texCoordLocation = _shader.GetAttribLocation("aTexCoord");

_fontTextureID = GL.GenTexture();

GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, _fontTextureID);

using (var image = new Bitmap("container.png")) //_fontBitmapFilename))// 
{
    var data = image.LockBits(
        new Rectangle(0, 0, image.Width, image.Height),
        ImageLockMode.ReadOnly,
        System.Drawing.Imaging.PixelFormat.Format32bppArgb);

    GL.TexImage2D(TextureTarget.Texture2D,
        0,
        PixelInternalFormat.Rgba,
        image.Width,
        image.Height,
        0,
        OpenTK.Graphics.OpenGL.PixelFormat.Bgra,
        PixelType.UnsignedByte,
        data.Scan0);
}

GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);

我现在创建一个VAO,绑定它,再绑定一个VBO。然后我设置 VertexAttribPointers 来解释 VBO 数据:

_VAO = GL.GenVertexArray();
GL.BindVertexArray(_VAO);

GL.BindBuffer(BufferTarget.ArrayBuffer, _charSheet[87].VBO);

GL.EnableVertexAttribArray(_vertexLocation);
GL.VertexAttribPointer(_vertexLocation, 2, VertexAttribPointerType.Float, false, 4 * sizeof(float), 0);

GL.EnableVertexAttribArray(_texCoordLocation);

GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, _fontTextureID);
GL.VertexAttribPointer(_texCoordLocation, 2, VertexAttribPointerType.Float, false, 4 * sizeof(float), 2);

GL.BindVertexArray(0);
_shader.StopUse();

我的渲染函数首先使用着色器、绑定 VAO 并启用 VertexAttribArrays。然后我绑定 VBO,在这个函数中一个固定的用于测试,并重用 VertexAttribPointer 函数,以便 VAO 更新它的数据(我也可能是错误的想法......)。最后我画了两个三角形,形成一个正方形,字母应该出现的地方。

_shader.Use();
GL.BindVertexArray(_VAO);
GL.EnableVertexAttribArray(_texCoordLocation);
GL.EnableVertexAttribArray(_vertexLocation);
GL.BindBuffer(BufferTarget.ArrayBuffer, _charSheet[87].VBO);
GL.VertexAttribPointer(_vertexLocation, 2, VertexAttribPointerType.Float, false, 4 * sizeof(float), 0);

GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, _fontTextureID);
GL.VertexAttribPointer(_texCoordLocation, 2, VertexAttribPointerType.Float, false, 4 * sizeof(float), 2);

GL.DrawArrays(PrimitiveType.Triangles, 0, 6);
GL.BindVertexArray(0);
_shader.StopUse();

我不知道,我的程序哪里做错了,也许有人能给我提示。

顶点着色器

#version 330 core

layout(location = 0) in vec2 aPosition;

layout(location = 1) in vec2 aTexCoord;

out vec2 texCoord;

void main(void)
{
    texCoord = aTexCoord;

    gl_Position = vec4(aPosition, 0.0, 1.0);
}

片段着色器:

#version 330

out vec4 outputColor;

in vec2 texCoord;

uniform sampler2D texture0;

void main()
{
    outputColor = texture(texture0, texCoord);
}

如果绑定了命名缓冲区对象,则 GL.VertexAttribPointer 的最后一个参数将被视为缓冲区对象数据存储的字节偏移量。
偏移量必须是 2*sizeof(float) 而不是 2:

GL.VertexAttribPointer(_texCoordLocation, 2, VertexAttribPointerType.Float, false, 4 * sizeof(float), 2);

GL.VertexAttribPointer(_texCoordLocation, 2, 
    VertexAttribPointerType.Float, false, 4 * sizeof(float), 2*sizeof(float));

参见 glVertexAttribPointer and Vertex Specification