2014-02-27 65 views
5

我想通過使用現代OpenGL(使用VBO和着色器渲染)在LWJGL中渲染文本,但我不知道如何去做。如何在現代OpenGL中使用GLSL渲染文本

+0

的可能的複製[如何使用OpenGL的唯一方法繪製文本?](http://stackoverflow.com/questions/8847899/how-to-draw-text-using-only-opengl-methods) –

回答

9

這裏有一個辦法:

  • 創建一個包含所有角色,在一定的尺寸光柵紋理。
  • 對於每個字符,存儲紋理的包含字符

class CharCoords { 
    public int x, y, width, height; 
} 
  • 上傳到GPU的補丁​​的位置的二維正方形幾何形狀,頂點(0,0), (0,1), (1,0), (1,1)
  • 頂點着色器可能如下所示

#version 120 

uniform mat4 PVMmat;  // The projection-view-model matrix 
uniform vec4 charCoords; // The CharCoord struct for the character you are rendering, {x, y, w, h} 
uniform float texSize;  // The size of the texture which contains the rasterized characters (assuming it is square) 
uniform vec2 offset;  // The offset at which to paint, w.r.t the first character 

attribute vec2 vertex; 

varying vec2 tc; 

void main(){ 
    // Transform from absolute texture coordinates to normalized texture coordinates 
    // This works because the rectangle spans [0,1] x [0,1] 
    // Depending on where the origin lies in your texture (i.e. topleft or bottom left corner), you need to replace "1. - vertex.y" with just "vertex.y" 
    tc = (charCoords.xy + charCoords.zw * vec2(vertex.x, 1. - vertex.y))/texSize; 

    // Map the vertices of the unit square to a rectangle with correct aspect ratio and positioned at the correct offset 
    float x = (charCoords[2] * vertex.x + offset.x)/charCoords[3]; 
    float y = vertex.y + offset.y/charCoords[3]; 

    // Apply the model, view and projection transformations 
    gl_Position = PVMmat * vec4(x, y, 0., 1.); 
} 
  • 片段着色器很簡單:

#version 120 

uniform vec4 color; 
uniform sampler2D tex; 

varying vec2 tc; 

void main() { 
    gl_FragColor = color * texture2D(tex, tc); 
} 
  • 您的繪圖功能,那麼可以看看如下(注意:C頌是使用一些方便的方法着色器類,但這個想法應該清楚):

public void drawString(Matrix4f PVMmat, String text, Color color, HAlign halign, VAlign valign) { 
    Vector2f offset = new Vector2f(); 

    // Font alignment 
    if(halign == HAlign.Center){ 
     offset.x = -(int) (0.5f * getWidth(text)); 
    }else if(halign == HAlign.Right){ 
     offset.x = -getWidth(text); 
    } 
    if(valign == VAlign.Middle){ 
     offset.y = -(int) (0.5f * getHeight()); 
    }else if(valign == VAlign.Top){ 
     offset.y = -getHeight(); 
    } 

    m_shader.bind();   
    m_shader.setAttributeBuffer("vertex", m_vertexBuffer, 2); 
    m_shader.setUniformMatrix("PVMmat", PVMmat); 
    m_shader.setUniformVector("color", color); 
    m_shader.setUniformScalar("texSize", (float)m_textureSize); 
    m_shader.setTexture("tex", m_fontTexture, GL11.GL_TEXTURE_2D); 
    GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, m_model.getIndexBuffer()); 
    for(int i = 0; i < text.length(); ++i) { 
     CharCoords coo = m_charMap.get(text.charAt(i)); 
     m_shader.setUniformVector("charCoords", new Vector4f(coo.x, coo.y, coo.width, coo.height)); 
     m_shader.setUniformVector("offset", offset); 
     GL11.glDrawElements(GL11.GL_TRIANGLES, m_indexCount, GL11.GL_UNSIGNED_INT, 0); 
     offset.x += coo.width; 
    } 
    GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0); 
    m_shader.unbind(); 
} 

其中函數getHeigthgetWidth是:

public int getWidth(String text) { 
    int totalwidth = 0; 
    for (int i = 0; i < text.length(); i++) { 
     CharCoords coo = m_charMap.get(text.charAt(i)); 
     totalwidth += coo.width; 
    } 
    return totalwidth; 
} 

public int getHeight() { 
    return m_fontMetrics.getHeight(); 
} 
  • 注意:要設置文字的比例和位置,請相應修改模型矩陣。
+0

但我認爲這會很慢,因爲我必須爲每個字符兩次更換制服。 –

+0

請記住,繪製文本的固定功能流水線方式會將繪製的每個角色的頂點和紋理座標發送給GPU,因此它已經明顯比此方法更快。但我建議嘗試一下,看看性能是否足夠,否則會根據需要進行優化。在這裏它表現的不錯。 – smani