我正在尝试在OpenGL中绘制文本。我用一个小的C#程序将0x21到0x7E中的所有字符绘制成一个位图。我将其作为纹理加载并尝试使用它来绘制我的文本。它似乎有效,但我似乎遇到了一些奇怪的问题。 http://i54.tinypic.com/mmd7k8.png注意'a'旁边的额外像素以及'c'稍微被切断的事实。似乎整个事情都略有转变。有谁知道我为什么会遇到这个问题?我不想使用像gltext这样的库,因为我不想依赖libfreetype,因为我只绘制了几个字符串。这是我正在使用的代码:
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");
}
}
}
答案 0 :(得分:3)
精确地在纹理中寻址像素有点棘手。请参阅OpenGL Texture Coordinates in Pixel Space
中给出的答案这已被问过几次,但我手边没有链接,所以快速而粗略的解释。假设纹理宽度为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)
但是,如果您想要将纹理与屏幕像素完美对齐,请记住您指定为坐标的不是四边形的像素,而是边缘,这取决于投影可能与屏幕像素边缘对齐,而不是中心,因此可能需要其他纹理坐标。