2011-08-30 50 views
1

我想在OpenGL中繪製文本。我用一個小的C#程序將所有字符從0x21到0x7E繪製到位圖中。我將它作爲紋理加載並嘗試使用它來繪製文本。它似乎工作,但我似乎有一些奇怪的問題。 http://i54.tinypic.com/mmd7k8.png注意'a'旁邊的額外像素以及'c'被略微切斷的事實。看起來整個事情略有轉移。有人知道我爲什麼會遇到這個問題嗎?我不想使用像gltext這樣的庫,因爲我不想依賴libfreetype,因爲我只繪製了幾個字符串。下面是我使用的代碼:試圖在OpenGL中繪製文本,但紋理略微偏移

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); 
} 

編輯我加4到紋理座標(0,2,4,6),這似乎已經解決了這一問題。但是,現在我需要知道這是否會繼續工作或可能因不明原因而中斷。這裏是位圖創建代碼,以防出現問題。

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"); 
    } 
} 
} 

回答

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)

或更一般地用於像素i的正寬紋理正確的紋理座標是

(2i-1)/(2N)

但是,如果您想將您的紋理與屏幕像素完美對齊,請記住,您指定的座標不是四邊形的像素,而是邊緣,根據投影可能與屏幕像素邊緣對齊而不是中心,因此可能會需要其他紋理座標。