Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VBO with textures, without deprecated functions

I am trying to write a basic Quad-renderer, using VBO, VAO, IBO and shaders. I am trying to use mainly only one VBO, VAO, IBO and rebuffer the data when an element is added/removed. Mostly everything worked fine, until I decided to implement textures, instead of color gradings.

It just doesn't draw anyhting, no matter what I try, because I want to avoid using deprecated functions like ClientStates and maybe use the textures inside the shaders.

Next to the problem, that nothing is being drawn, I have the problem that the Textures are saved inside the BRectangle class, and now I don't know, how to access them while using DrawElements.

And can I reuse my IBO, so I don't have to add the additional indices?

My current approach:

The Renderer, you can add a Rectangle atm and it will buffer the needed data.

    public class ShaderRenderer {

    public static final int POSITION_INDEX = 0; // index of vertex attribute "in_Position"
    public static final int TEXTURE_INDEX = 1; // index of vertex attribute "in_Texture"

    public static final int FLOAT_NUM_BYTES; // sizeof(float) in bytes
    public static final int INT_NUM_BYTES; // sizeof(int) in bytes
    public static final int VEC4_BYTES; // sizeof(vec4) in bytes

    static {
        FLOAT_NUM_BYTES = Float.SIZE / Byte.SIZE;
        INT_NUM_BYTES = Integer.SIZE / Byte.SIZE;
        VEC4_BYTES = 4 * FLOAT_NUM_BYTES;
    }

    private VAO vao = new VAO();
    private VBO vbo = new VBO();
    private IBO ibo = new IBO();

    private int elements = 0;

    public ShaderRenderer() {
        try {
            ShaderUtilities.compileShader("shaders/screen.vert", "shaders/screen.frag", POSITION_INDEX, TEXTURE_INDEX);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void add( BRectangle rect ) {

        // Bind the VAO
        // This OpenGL-object groups the "in_Position" and "in_Color"
        // vertex attributes.
        vao.bind();

        // Bind the VBO and add the FloatBuffer from the Rect
        vbo.bind();
        vbo.addBuffer(rect.vertexData);

        ibo.bind();
        ibo.addIndices(generateIndices());
        ibo.buffer();

        //==============================================================       
        // Now we tell OpenGL that we will use POSITION_INDEX and COLOR_INDEX
        // to communicate respectively the vertex positions and vertex colors
        // to our shaders.
        {
            // First we enable the indices. This will affect the vertex
            // array object from above.
            glEnableVertexAttribArray(POSITION_INDEX);
            Util.checkGLError();


            // Then we tell OpenGL how it should read the GL_ARRAY_BUFFER
            // (to which we have bound our vertex data, see above).

            // The position data starts at the beginning of the vertex data
            glVertexAttribPointer(POSITION_INDEX, 4, GL_FLOAT, false,
                    2 * VEC4_BYTES, 0);
            Util.checkGLError();

            // The color data starts after the first 4 floats of position data
            glVertexAttribPointer(TEXTURE_INDEX, 2, GL_FLOAT, false,
                    0, VEC4_BYTES);
            Util.checkGLError();
        }

        vbo.bufferData();

        // Just to be VERY clean, we will unbind the vertex attribute object
        // and only bind it when we render. This way we cannot accidentally modify
        // it anymore.
        vao.unbind();

        // Only after the vertex array is disabled, we unbind the buffers
        // to the GL_ARRAY_BUFFER and GL_ELEMENT_ARRAY_BUFFER targets, because
        // otherwise the vertex array object would become invalid again.
        vbo.unbind();

        ibo.unbind();
    }

    void DestroyVBO() {

        glDisableVertexAttribArray(POSITION_INDEX);
        Util.checkGLError();

        glDisableVertexAttribArray(TEXTURE_INDEX);
        Util.checkGLError();

        glBindBuffer(GL_ARRAY_BUFFER, 0);
        Util.checkGLError();

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        Util.checkGLError();

        glDeleteBuffers(ibo.id);
        Util.checkGLError();

        glDeleteBuffers(vbo.id);
        Util.checkGLError();

        glBindVertexArray(0);
        Util.checkGLError();

        glDeleteVertexArrays(vao.id);
        Util.checkGLError();
    }


    private int[] generateIndices() {
        int c = elements * 3;
        int v[] = { c, c+1, c+2,
                    c, c+3, c+2};
        elements++;
        return v;
    }

    public void render () {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        Util.checkGLError();


        vao.bind();
        glDrawElements(
                GL_TRIANGLES,
                ibo.size,
                GL_UNSIGNED_INT,
                0);
        Util.checkGLError();

        vao.unbind();
    }

}

My basic Rectangle class

public class BRectangle  {
    final int amountOfVertices = 8;
    final int vertexSize = 3;
    final int textureSize = 2;

    public FloatBuffer vertexData;

    Texture texture;

    public BRectangle(float x, float y ) {
        float[] VerticesArray = new float[]{
                -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
                -0.1f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
                -0.1f, 0.4f, 0.0f, 1.0f, 1.0f, 1.0f,
                -0.5f, 0.4f, 0.0f, 1.0f, 0.0f, 1.0f
            };
        vertexData = BufferUtils.createFloatBuffer(24);
        vertexData.put(VerticesArray);



        try {
            texture = Textures.loadTexture("data/floor.jpg");
        } catch (IOException e) {
            e.printStackTrace();
        }
        glBindTexture(GL_TEXTURE_2D, texture.getTextureID());

    }

}

The test with main[]

public class ShaderTest {

    ShaderRenderer sr;

    FpsCounter c;

    public ShaderTest() {
    }

    public void create() throws LWJGLException, Exception {

        new SimpleDisplay(800, 600, "test", false, false);
        glOrtho(0, 800, 0, 600, 1, -1);
        //Keyboard
        Keyboard.create();

        c = new FpsCounter();

        Textures.setUpTextureLoader();

        //Mouse
        Mouse.setGrabbed(false);
        Mouse.create();

        sr = new ShaderRenderer();
        //OpenGL
        initGL();


    }


    public void destroy() {
        Mouse.destroy();
        Keyboard.destroy();
        Display.destroy();
    }

    public void initGL() throws IOException {



        ShaderUtilities.compileShader("shaders/screen.vert", "shaders/screen.frag", ShaderRenderer.POSITION_INDEX, ShaderRenderer.TEXTURE_INDEX);
        sr.add(new BRectangle(0f, 0f));
    }

    public void processKeyboard() {
    }

    public void processMouse() {
    }

    public void render() throws LWJGLException {
        sr.render();
    }


    public void run() throws LWJGLException {
        while (!Display.isCloseRequested() && !Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) {
            if (Display.isVisible()) {
                processKeyboard();
                processMouse();
                update();
                render();
            } else {
                if (Display.isDirty()) {
                    render();
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException ex) {
                }
            }

            Display.update();
            //Display.sync(60);
        }
    }

    public void update() {
        c.updateFPS();
    }

    public static void main(String[] args) {
        ShaderTest main = null;
        try {
            main = new ShaderTest();
            main.create();
            main.run();
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            if (main != null) {
                main.destroy();
            }
        }
    }
}

and the openglinit

public static void initGLSlim() {
    glClearColor(0, 0, 0, 0);
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_LIGHTING);

    glEnable(GL11.GL_TEXTURE_2D);  

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, 800, 600, 0, 1, -1);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

}

vertex shader

#version 140

in vec4 in_Position;
in vec2 in_Texture;
out vec2 out_Texture;

void main(void)
{
   gl_Position = vec4(in_Position.x *0.75 ,in_Position.y, in_Position.z, in_Position.w);
   out_Texture = in_Texture;
}

fragment shader

#version 140

in vec2 out_Texture;
uniform sampler2D mytexture;
out vec4 fragColor;

void main(void)
{
   fragColor = texture2D(mytexture, out_Texture);
}
like image 647
Frotty Avatar asked Dec 31 '25 21:12

Frotty


1 Answers

Your stride parameters are not correct.

Here's what you have:

glVertexAttribPointer(POSITION_INDEX, 4, GL_FLOAT, false, 2 * VEC4_BYTES, 0); 
glVertexAttribPointer(TEXTURE_INDEX, 2, GL_FLOAT, false, 0, VEC4_BYTES);

You're telling the position index that it has 8 float stride, which is not correct. As far as I can tell you're uploading 4 vertices, with 6 floats per vertex (4x position + 2x texture). That means your POSITION stride should be 6 * FLOAT_NUM_BYTES.

Your texture stride should be the same, as it's packed into the same array. Here you're telling it that the texcoords are tightly packed, but in reality theres only one pair of texcoords per 6 floats. So again you need 6 * FLOAT_NUM_BYTES here.


And can I reuse my IBO, so I don't have to add the additional indices?

Yes, you can use an IBO to draw as many objects as you want, provided that they all want the same indices.


Other less serious comments:

  • You don't need to clearColor to zero in initialization, it's zero by default.
  • You don't need to disable depth_test/lighting in initialization, they are off by default.
  • Don't call glEnable(GL_TEXTURE_2D) when you're using shaders. This switch only enables texturing for the fixed pipeline, and it has no effect on shader programs. This will generate an error if you ever move to a core profile, so just get rid of it.
like image 53
Tim Avatar answered Jan 03 '26 10:01

Tim



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!