没有 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));
我正在使用 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));