2014-02-27 5 views
5

Я хочу сделать текст в LWJGL, используя современный OpenGL (рендеринг с VBO и шейдером), но я не знаю, как это сделать.Как визуализировать текст в современном 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 2D-квадрат геометрия с вершинами (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); 
} 
  • Ваша функция рисования может выглядеть следующим образом (примечание: с ода использует класс шейдера с некоторыми удобными методами, но идея должна быть ясна):

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

где функции getHeigth и getWidth являются:

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

Имейте в виду, что метод конструирования контуров с фиксированной функцией посылает координаты вершины и текстуры в графический процессор для каждого персонажа, который вы рисуете, поэтому он определенно быстрее, чем этот подход. Но я предлагаю попробовать и посмотреть, достаточна ли производительность, иначе оптимизируйте по мере необходимости. Здесь он работает достаточно хорошо. – smani

Смежные вопросы