Help with geometry shader text drawing

Started by Andrew_3ds, August 10, 2015, 19:54:42

Previous topic - Next topic

Andrew_3ds

I found a cool geometry shader from a website that lets you draw text in a single call by using a monospaced font map. It really only explained the geometry shader, and I don't know what to do to actually get the uniforms and other stuff working correctly. Nothing is being drawn when I try to use the shader, I'm not sure if it's the shader itself or I'm not setting it up correctly or something. This is my text class, I'm thinking the problem is with the cellsize vector, I'm not quit sure how it works in the shader.
public class TextHandler {
    static Texture bmpFontSheet;
    static Shader shader;

    private static Vector2f glyphSize;
    private static int CellSize_loc;
    private static int RenderOrigin_loc;
    private static int RenderSize_loc;

    public static void init(int glyphWidth, int glyphHeight) {
        bmpFontSheet = TextureLoader.loadTexture(GameStructure.mainModule.texture, "BMP_font");

        shader = new Shader(new File(GameStructure.mainModule.shader+"/Text")) {
            @Override
            public void getUniformLocations() {
                CellSize_loc = this.getUniformLocation("CellSize");
                RenderOrigin_loc = this.getUniformLocation("RenderOrigin");
                RenderSize_loc = this.getUniformLocation("RenderSize");
            }
        };

        glyphSize = new Vector2f(1/glyphWidth, 1/glyphHeight);
    }

    public static void drawText(String s, float x, float y, float scale) {
        ByteBuffer string = BufferUtils.createByteBuffer(s.length());
        string.put(s.getBytes());
        glVertexAttribIPointer(0, 1, GL_UNSIGNED_BYTE, 1, string);
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, bmpFontSheet.getTexId());
        shader.start();
        shader.loadVec2(CellSize_loc, glyphSize.x, glyphSize.y);
        shader.loadVec2(RenderOrigin_loc, x, y);
        shader.loadVec2(RenderSize_loc, scale, scale);
        glDrawArrays(GL_POINTS, 0, s.length());
        shader.stop();
        glActiveTexture(0);
        glBindTexture(GL_TEXTURE_2D, 0);
        string.clear();
    }

    public static void cleanUp() {
        shader.delete();
    }
}


Vertex shader: http://pastebin.com/9WfHLfW8
Geometry shader: http://pastebin.com/sY5TPfVK
Fragment shader: http://pastebin.com/SDYgQwv8

spasi

It's hard to provide any feedback on the code you posted. Try to debug each piece on its own; is the texture loaded correctly? are you getting the correct uniform locations? does the fragment shader get any data? Also make sure to use a debug context, setup the debug message callback, print the shader compilation and program linking logs.

Btw, if you're on LWJGL 3, it has fantastic support for font rendering. See these samples for details. The EasyFont is a geometry-based monospaced font that you can use very easily. The Truetype demos read .ttf files and pack characters into textures.

Andrew_3ds

The texture and uniform locations seem to be working. Do I need to create a vertex array object (This is OpenGL 3)? If I use STB, I will get glyph textures but I would still need an efficient way of drawing text without using a draw call for each character. This geometry shader only needs one call and it draws based on the BMP font map given by using ASCII code of the chars passed through the glVertexAttribIPointer call. The shaders compiled correctly because I already have shader compile reports set up and I am not getting any errors. How do I check if the fragment shader is getting any data? Should I try multiplying the vertices in the shader by an ortho matrix?

spasi

Quote from: Andrew_3ds on August 12, 2015, 02:57:46Do I need to create a vertex array object (This is OpenGL 3)?

Yes, if you're running on a core profile context.

Quote from: Andrew_3ds on August 12, 2015, 02:57:46If I use STB, I will get glyph textures but I would still need an efficient way of drawing text without using a draw call for each character. This geometry shader only needs one call and it draws based on the BMP font map given by using ASCII code of the chars passed through the glVertexAttribIPointer call.

You can (and should) do that with STB. Note that the sample code is just that; sample. All demos uses compatibility/deprecated functionality because otherwise the rendering code would be too big and the actual functionality being demoed would be hard to distinguish.

Quote from: Andrew_3ds on August 12, 2015, 02:57:46How do I check if the fragment shader is getting any data? Should I try multiplying the vertices in the shader by an ortho matrix?

The problem with debugging shaders usually is that the compiler will optimize away unused declarations. Do something like:

color = texture(sampler, gTexCoord * 0.00001 + gl_FragCoord.xy); // to see the texture contents
color = texture(sampler, gTexCoord) * 0.00001 + vec4(gTexCoord, 0.0, 1.0); // to see if you're getting the correct texcoords from the geometry shader

abcdef

Andrew_3ds

I use a VAO / VBO to draw text, it sounds a lot easier than using a geometry shader to generate the quads rather than generating the quads on the CPU. The basic premise is that you create a quad per character and you position that quad on the screen, each quad has texture coordinates which map from the the single texture which has all the characters. A group of quads make a String of characters and you can add these to a single vertex buffer and draw in a single call