2014-02-27 8 views
5

Ich möchte Text in LWJGL mit modernen OpenGL Rendering (Rendering mit VBO und Shader) aber ich habe keine Ahnung, wie es geht. HierRendern von Text in modernen OpenGL mit GLSL

+0

Mögliches Duplikat [Wie Text mit nur OpenGL Methoden ziehen?] (Http://stackoverflow.com/questions/8847899/how-to-draw-text-using-only-opengl-methods) –

Antwort

9

ist ein Ansatz:

  • Erstellen Sie eine Textur enthält alle Zeichen, bei einer bestimmten Größe gerastert.
  • Für jedes Zeichen, speichern Sie die Lage des Pflasters der Textur den Charakter

class CharCoords { 
    public int x, y, width, height; 
} 
  • Hochladen auf die GPU eine 2D quadratische Geometrie mit den Eckpunkten (0,0), (0,1), (1,0), (1,1)
  • enthält Der Vertex-Shader könnte folgendermaßen aussehen:

#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.); 
} 
  • Das Fragment-Shader ist trivial:

#version 120 

uniform vec4 color; 
uniform sampler2D tex; 

varying vec2 tc; 

void main() { 
    gl_FragColor = color * texture2D(tex, tc); 
} 
  • Ihre Zeichnung Funktion könnte dann wie folgt aussehen (Anmerkung: die c ode wird unter Verwendung einer Shader-Klasse mit einigen Komfortmethoden, aber die Idee sollte klar sein):

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

wo die Funktionen getHeigth und getWidth sind:

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(); 
} 
  • Hinweis: Um den Maßstab und die Position Ihres Textes festzulegen, ändern Sie die Modellmatrix entsprechend.
+0

Aber Ich denke, das wäre sehr langsam, weil ich die Uniformen für jeden Char zweimal wechseln muss. –

+0

Denken Sie daran, dass die Fließtext-Methode für feste Funktionen die Eckpunkt- und Texturkoordinaten für jedes Zeichen, das Sie zeichnen, an die GPU sendet. Es ist also schon definitiv schneller als diese Methode. Aber ich schlage vor, es zu versuchen und zu sehen, ob die Leistung angemessen ist, ansonsten optimieren wie nötig. Hier ist es gut genug. – smani