试图在OpenGL中绘制文本,但纹理略有偏移
我正在尝试在OpenGL中绘制文本。我使用一个小型C#程序将0x21到0x7E之间的所有字符绘制成位图。我将其作为纹理加载,并尝试使用它来绘制文本。这似乎有效,但我似乎遇到了一些奇怪的问题。请注意“a”旁边的额外像素和“c”被略微截断的事实。看起来整个事情都有轻微的变化。有人知道我为什么会遇到这个问题吗?我不想使用gltext这样的库,因为我不想依赖libfreetype,因为我只画了几个字符串。以下是我正在使用的代码:试图在OpenGL中绘制文本,但纹理略有偏移,opengl,text,Opengl,Text,我正在尝试在OpenGL中绘制文本。我使用一个小型C#程序将0x21到0x7E之间的所有字符绘制成位图。我将其作为纹理加载,并尝试使用它来绘制文本。这似乎有效,但我似乎遇到了一些奇怪的问题。请注意“a”旁边的额外像素和“c”被略微截断的事实。看起来整个事情都有轻微的变化。有人知道我为什么会遇到这个问题吗?我不想使用gltext这样的库,因为我不想依赖libfreetype,因为我只画了几个字符串。以下是我正在使用的代码: static void textDrawChar(char c, int
static void textDrawChar(char c, int x, int y)
{
GLfloat vert[8];
GLfloat texcoord[8];
vert[0] = x; vert[1] = y;
vert[2] = x; vert[3] = y + TEXT_HEIGHT;
vert[4] = x + font_char_width[c-0x21]; vert[5] = y + TEXT_HEIGHT;
vert[6] = x + font_char_width[c-0x21]; vert[7] = y;
texcoord[0] = (float)(font_char_pos[c-0x21])/TOTAL_WIDTH;
texcoord[1] = 1.0f;
texcoord[2] = (float)(font_char_pos[c-0x21])/TOTAL_WIDTH;
texcoord[3] = 0.0f;
texcoord[4] = (float)(font_char_pos[c-0x21] + font_char_width[c-0x21])/TOTAL_WIDTH;
texcoord[5] = 0.0f;
texcoord[6] = (float)(font_char_pos[c-0x21] + font_char_width[c-0x21])/TOTAL_WIDTH;
texcoord[7] = 1.0f;
glBindTexture(GL_TEXTURE_2D, texture);
glVertexPointer(2, GL_FLOAT, 0, vert);
glTexCoordPointer(2, GL_FLOAT, 0, texcoord);
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, indices);
}
void textDraw(void)
{
textDrawChar('a', 300, 300);
textDrawChar('b', 300+font_char_width['a'-0x21], 300);
textDrawChar('c', 300+font_char_width['a'-0x21]+font_char_width['b'-0x21], 300);
}
编辑我在纹理坐标(0,2,4,6)中添加了4,这似乎解决了问题。然而,现在我需要知道这是否会继续有效,或者由于未知的原因可能会中断。这是位图创建代码,以防出现问题
using System;
using System.Drawing;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Collections;
namespace font_to_bmp
{
class Program
{
static void Main(string[] args)
{
Bitmap b = new Bitmap(1715, 36);
Graphics g = Graphics.FromImage(b);
g.FillRectangle(new SolidBrush(Color.Transparent), 0, 0, 1715, 36);
Font f = new Font("Liberation Sans", 24, GraphicsUnit.Point);
g.PageUnit = GraphicsUnit.Pixel;
int curx = 0;
StreamWriter w = new StreamWriter(new FileStream("font_width.h", FileMode.Create, FileAccess.Write, FileShare.Read));
w.WriteLine("static const int font_char_width[] = {");
ArrayList hax = new ArrayList();
for (int i = 0x21; i <= 0x7E; i++)
{
char c = (char)i;
string s = c.ToString();
SizeF sz = g.MeasureString(s, f);
StringFormat sf = new StringFormat();
sf.SetMeasurableCharacterRanges(new CharacterRange[] {new CharacterRange(0,1)});
Region r = g.MeasureCharacterRanges(s, f, new RectangleF(0, 0, 1000, 1000), sf)[0];
RectangleF r2 = r.GetBounds(g);
Console.WriteLine("{0} is {1}x{2}", s, r2.Width, r2.Height);
int w_int = (int)(Math.Ceiling(r2.Width));
g.DrawString(s, f, new SolidBrush(Color.Black), curx, 0);
hax.Add(curx);
curx += w_int;
w.WriteLine("\t{0},", w_int);
}
Console.WriteLine("Total width {0}", curx);
w.WriteLine("};");
w.WriteLine();
w.WriteLine("static const int font_char_pos[] = {");
foreach(int z in hax)
{
w.WriteLine("\t{0},", z);
}
w.WriteLine("};");
w.Close();
b.Save("font.png");
}
}
}
使用系统;
使用系统图;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.IO;
使用系统集合;
命名空间字体\u到\u bmp
{
班级计划
{
静态void Main(字符串[]参数)
{
位图b=新位图(1715,36);
图形g=图形。来自图像(b);
g、 FillRectangle(新的SolidBrush(颜色.透明),0,0,1715,36);
Font f=新字体(“解放号”,24,GraphicsUnit.Point);
g、 PageUnit=GraphicsUnit.Pixel;
int-curx=0;
StreamWriter w=新的StreamWriter(新的文件流(“font_width.h”,FileMode.Create,FileAccess.Write,FileShare.Read));
w、 WriteLine(“static const int font_char_width[]={”);
ArrayList hax=新的ArrayList();
对于(int i=0x21;i而言,精确地在纹理中寻址像素有点棘手。请参阅中给出的答案
这已经被问了好几次了,但我手头没有链接,所以我给出了一个快速而粗略的解释。假设纹理是8像素宽:
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
^ ^ ^ ^ ^ ^ ^ ^ ^
0.0 | | | | | | | 1.0
| | | | | | | | |
0/8 1/8 2/8 3/8 4/8 5/8 6/8 7/8 8/8
数字表示纹理的像素,条形表示纹理的边缘,如果是最近的过滤,则表示像素之间的边界。但是,您希望击中像素的中心。因此,您对纹理坐标感兴趣
(0/8+1/8)/2=1/(2*8)
(1/8+2/8)/2=3/(2*8)
(7/8+8/8)/2=15/(2*8)
或者更一般地,对于N宽纹理中的像素i,适当的纹理坐标为
(2i-1)/(2N)
但是,如果要将纹理与屏幕像素完全对齐,请记住,指定为坐标的不是四边形的像素,而是边缘,根据投影情况,边缘可能与屏幕像素边缘对齐,而不是中心对齐,因此可能需要其他纹理坐标