Wrong image after multitexturing and GLSL

[edited]
As dletozeun said, my code maybe is too complicated (anyway I let it), so let’s change the question… Is there no problem on using VBO and glsl? Do you know any page with an example? What I’d like to do transform with vertex shaders 3 textures which should be mapped over a mesh.
Thanks!!

[edited]

Hi again!

I’m working with 3 textures, and glsl to create a RBG image from a YUV image. As the the image should be transformed by an extern function, the 3 textures must be mapped over a mesh (this mesh is created using the http://www.java-tips.org/other-api-tips/jogl/vertex-buffer-objects-nehe-tutorial-jogl-port-2.html example, also with vbo). While with just one texture and no GLSL it works, I get the problems trying the new config; the result image is shown all over the frame and If I try to use glTranslatef in order to move more than 10 units it breaks. Am I sending the wrong pixels? Is is a problem between vbo and the textures or from glsl?

Mesh:



public class MeshYUV {
	  // Mesh Data
    private int vertexCount;								// Vertex Count
    private FloatBuffer vertices;								// Vertex Data
    private FloatBuffer texCoordsY, texCoordsU;								// Texture Coordinates


    // Vertex Buffer Object Names
    private int[] VBOVertices = new int[1];								// Vertex VBO Name
    private int[] VBOTexCoords = new int[2];							// Texture Coordinate VBO Name
    private boolean fUseVBO;

    public int getVertexCount() {
        return vertexCount;
    }
    public boolean isVBOSupported(GL gl){
    	 // Check For VBO support
        return gl.isFunctionAvailable("glGenBuffersARB") &&
                gl.isFunctionAvailable("glBindBufferARB") &&
                gl.isFunctionAvailable("glBufferDataARB") &&
                gl.isFunctionAvailable("glDeleteBuffersARB");
    }

    public boolean init(GL gl, int texWidth, int texHeight, float flHeightScale, float flResolution) {

    	fUseVBO = isVBOSupported(gl);
        // Generate Vertex Field
        vertexCount = (int) (texWidth * texHeight * 6 / (flResolution * flResolution));
        vertices = BufferUtil.newFloatBuffer(vertexCount * 3);						// Allocate Vertex Data
        texCoordsY = BufferUtil.newFloatBuffer(vertexCount * 2);				// Allocate Tex Coord Data
        texCoordsU = BufferUtil.newFloatBuffer(vertexCount * 2);
     
        for (int nY = 0; nY < texHeight; nY += (int) flResolution) {
            for (int nX = 0; nX < texWidth; nX += (int) flResolution) {
                for (int nTri = 0; nTri < 6; nTri++) {
                    // Using This Quick Hack, Figure The X,Y Position Of The Point
                    float flY = (float) nY + ((nTri == 1 || nTri == 2 || nTri == 5) ? flResolution : 0.0f);
                    float flX = (float) nX + ((nTri == 2 || nTri == 4 || nTri == 5) ? flResolution : 0.0f);

                    // Set The Data
                    vertices.put(flX - (texWidth / 2.0f));
                    vertices.put(flY - (texHeight / 2.0f));
                    vertices.put(0.0f); //
                    // Stretch The Texture Across The Entire Mesh
                    texCoordsY.put(flX);
                    texCoordsY.put(flY);

                    texCoordsU.put(flX / 2.0f);
                    texCoordsU.put(flY / 2.0f);
                    
                                   }
            }
        }
        vertices.flip();
        texCoordsY.flip();
        texCoordsU.flip();
      

        if (fUseVBO) {
            // Load Vertex Data Into The Graphics Card Memory
            buildVBOs(gl);			//Build The VBOs
        }
        return true;
    }

    public void render(GL gl) {

    	  // Enable Pointers
        gl.glEnableClientState(GL.GL_VERTEX_ARRAY);						// Enable Vertex Arrays
        gl.glEnableClientState(GL.GL_TEXTURE_COORD_ARRAY);

        // Set Pointers To Our Data
        if (fUseVBO) {
        	      
            gl.glActiveTexture(GL.GL_TEXTURE0);
            gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, VBOTexCoords[0]);
            gl.glTexCoordPointer(2, GL.GL_FLOAT, 0, 0);		// Set The TexCoord Pointer To The TexCoord Buffer

            gl.glActiveTexture(GL.GL_TEXTURE1);
            gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, VBOTexCoords[1]);
            gl.glTexCoordPointer(2, GL.GL_FLOAT, 0, 0);		// Set The Vertex Pointer To The Vertex Buffer

            gl.glActiveTexture(GL.GL_TEXTURE2);
            gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, VBOTexCoords[1]);
            gl.glTexCoordPointer(2, GL.GL_FLOAT, 0, 0);		// Set The Vertex Pointer To The Vertex Buffer
            
            
            gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, VBOVertices[0]);
            gl.glVertexPointer(3, GL.GL_FLOAT, 0, 0);		// Set The TexCoord Pointer To The TexCoord Buffer
        } else {
        
            gl.glVertexPointer(3, GL.GL_FLOAT, 0, vertices); // Set The Vertex Pointer To Our Vertex Data
            gl.glTexCoordPointer(2, GL.GL_FLOAT, 0, texCoordsY); // Set The Vertex Pointer To Our TexCoord Data
            gl.glTexCoordPointer(2, GL.GL_FLOAT, 0, texCoordsU); // Set The Vertex Pointer To Our TexCoord Data
        }

        // Render
        gl.glDrawArrays(GL.GL_TRIANGLES, 0, vertexCount);	// Draw All Of The Triangles At Once

        // Disable Pointers
        gl.glDisableClientState(GL.GL_VERTEX_ARRAY);					// Disable Vertex Arrays
        gl.glDisableClientState(GL.GL_TEXTURE_COORD_ARRAY);				// Disable Texture Coord Arrays
    }


    private void buildVBOs(GL gl) {
        // Generate And Bind The Vertex Buffer
        gl.glGenBuffersARB(1, VBOVertices, 0);							// Get A Valid Name
        gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, VBOVertices[0]);			// Bind The Buffer
        // Load The Data
        gl.glBufferDataARB(GL.GL_ARRAY_BUFFER_ARB, vertexCount * 3 * BufferUtil.SIZEOF_FLOAT, vertices, GL.GL_STATIC_DRAW_ARB);

        // Generate And Bind The TextureY Coordinate Buffer
        gl.glGenBuffersARB(2, VBOTexCoords, 0);							// Get A Valid Name

        gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, VBOTexCoords[0]);		// Bind The Buffer
        // Load The Data
        gl.glBufferDataARB(GL.GL_ARRAY_BUFFER_ARB, vertexCount * 2 * BufferUtil.SIZEOF_FLOAT, texCoordsY, GL.GL_STATIC_DRAW_ARB);

        // Generate And Bind The TextureUV Coordinate Buffer
        gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, VBOTexCoords[1]);		// Bind The Buffer
        // Load The Data
        gl.glBufferDataARB(GL.GL_ARRAY_BUFFER_ARB, vertexCount * 2 * BufferUtil.SIZEOF_FLOAT, texCoordsU, GL.GL_STATIC_DRAW_ARB);
        // Generate And Bind The TextureUV Coordinate Buffer
      

        // Our Copy Of The Data Is No Longer Necessary, It Is Safe In The Graphics Card
        vertices = null;
        texCoordsY = null;
        texCoordsU = null;
        
        fUseVBO = true;
    }
}

Renderer:


	// Mesh Generation Paramaters
	private static final float MESH_RESOLUTION = 4.0f;									// Pixels Per Vertex
	private static final float MESH_HEIGHTSCALE = 1.0f;									// Mesh Height Scale

	private int programObject = 0;
	private boolean textureChanged = false;
	private GlShaders glFragment = null;
	private GlShaders glVertex = null;
	private int[] textures = new int[3];
	private UnicapFrame text = null;
	private int yTexture,uTexture,vTexture;
	private MeshYUV mesh = null;
	private GLErrorChecker glErrorCheker = new GLErrorChecker();

	public TestYUVMeshRenderer(int width, int height) {
		super(width, height);
	}

	@Override
	public void init(GLAutoDrawable gLDrawable) {

		final GL gl = gLDrawable.getGL();

		mesh = new MeshYUV();										// Instantiate Our Mesh

		mesh.init(gl,this.texWidth,this.texHeight ,
				MESH_HEIGHTSCALE,
				MESH_RESOLUTION
		);

		glVertex = new GlShaders(gl,"yuvToRgb.vert",true);
		glFragment = new GlShaders(gl, "yuvToRgb.frag", false);

		GlShaders.checkShaderExtensions(gl);

		programObject = gl.glCreateProgramObjectARB();
		programObject = glFragment.load(programObject);
		programObject = glVertex.load(programObject);
		gl.glLinkProgramARB(programObject);
		gl.glValidateProgramARB(programObject);

		// Setup GL States
		gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
		gl.glClearDepth(1.0f);
		gl.glDepthFunc(GL.GL_LEQUAL);
		gl.glEnable(GL.GL_DEPTH_TEST);
		gl.glShadeModel(GL.GL_SMOOTH);
		gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);

		gl.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);

		gl.glGenTextures(3, textures, 0);

		yTexture = textures[0];
		uTexture = textures[1];
		vTexture = textures[2];

	}

	@Override
	public void display(GLAutoDrawable drawable) {
		GL gl = drawable.getGL();

		gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
		gl.glLoadIdentity();
		gl.glUseProgramObjectARB(programObject);

		if (textureChanged) {
			int offset = 0;
			offset += updateTexture(gl, yTexture, GL.GL_TEXTURE0, "yTex", offset, text.getWidth(), text.getHeight());
			offset += updateTexture(gl, uTexture, GL.GL_TEXTURE1, "uTex", offset, text.getWidth() / 2, text.getHeight() / 2);
			offset += updateTexture(gl, vTexture, GL.GL_TEXTURE2, "vTex", offset, text.getWidth() / 2, text.getHeight() / 2);

			textureChanged = false;
		}

		glErrorCheker.checkErrors(gl, "After creating textures");
		gl.glTranslatef(0.0f, 0.0f, -1000.0f);
		mesh.render(gl);

		gl.glUseProgramObjectARB(0);
		glErrorCheker.checkErrors(gl, "after all ");
	}

	private int updateTexture(GL gl, int texture, int glTextureUnit, String variableName, int byteOffset, int width, int height) {

		int i;
		gl.glActiveTexture(glTextureUnit);

		i = gl.glGetUniformLocationARB(programObject, variableName);
		gl.glBindTexture (GL.GL_TEXTURE_RECTANGLE_ARB, texture);
		gl.glUniform1iARB(i, texture);
		

		text.getPixels().position(byteOffset);
		updateTextureData (gl, BufferUtil.copyByteBuffer(text.getPixels()), width, height);

		return width * height;
	}

	private void updateTextureData(GL gl, ByteBuffer pixels, int width, int height) {
		glErrorCheker.checkErrors(gl, "displayGlElement");

		gl.glTexImage2D (GL.GL_TEXTURE_RECTANGLE_ARB,
				0,
				1,
				width , height,
				0,
				GL.GL_LUMINANCE, GL.GL_UNSIGNED_BYTE,
				pixels
		);

		gl.glTexParameteri (GL.GL_TEXTURE_RECTANGLE_ARB, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
		gl.glTexParameteri (GL.GL_TEXTURE_RECTANGLE_ARB, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
		glErrorCheker.checkErrors(gl, "gl.glTexParameteri");
	}

As you see, the textures are re-bind each display-time, because the images came from a video camera.

All advice are welcome and thanks to everyone.

Hi,

Your code is too complicated, don’t hope that someone will read this entirely to figure it out.

All I can do is advice you to deactivate texture units where it is not necessary with for example:

glActiveTexture(GL_TEXTURE[0 1 2 …]);
glDisable(GL_TEXTURE_2D);

Maybe it would help you to solve your problem.

There should be no problem using VBO and shaders.

A couple of points, setting a pointer to NULL does not free the data (except with garbage collectin added to your language). VBO allocations need to be created the right way to avoid copies and indicate they are non volatile to the application. If they are volatile you need to tell the driver they are but that undermines the main benefit.

I’ve only skimmed your code and it’s not all there but you probably need to clear up the understanding of exactly how memory is being used, allocated, copied, freed, dereferenced etc. Something with garbage collection which could be bad for VBOs if you dereference the pointer since the driver won’t be GC aware, but usually to do this you’d have to pin the memory to stop GC anyway, so it’s probably moot unless you have a horribly dangerous homegrown allocator & all sorts of overloaded operators, which doesn’t seem realistic.

Anyhoo, I’m rambling, the main point of VBOs is there’s a hint at usage not inferable via the basic API and this can lead to copies being made to fast video memory or an assumption that the memory is non-volatile so copies don’t get made etc. This can cause problems if you don’t honor the usage you promised. Things that might cause problems are freeing the memory after passing the pointer to the API or attempting to change the data (both depend heavily on usage and implementation).

Ok, I’ m going to try ask it better, because i think my explanations were really bad.

A first test send the 3 textures to the shaders with combine them each time I call a display (It comes from a videocamera). The way I do it is as follows:


    gl.glBindTexture(GL.GL_TEXTURE_RECTANGLE_ARB, texture); 
    gl.glTexImage2D(
	GL.GL_TEXTURE_RECTANGLE_ARB,
	0,
	GL.GL_LUMINANCE8,
	width , height,
	0,
	GL.GL_LUMINANCE, GL.GL_UNSIGNED_BYTE,
	text.getPixels()
	);

gl.glTexParameteri (GL.GL_TEXTURE_RECTANGLE_ARB,         GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
gl.glTexParameteri (GL.GL_TEXTURE_RECTANGLE_ARB, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
gl.glTexParameteri (GL.GL_TEXTURE_RECTANGLE_ARB, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP);
gl.glTexParameteri (GL.GL_TEXTURE_RECTANGLE_ARB, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP);

gl.glActiveTexture(glTextureUnit);
gl.glEnable(GL.GL_TEXTURE_RECTANGLE_ARB);
gl.glBindTexture(GL.GL_TEXTURE_RECTANGLE_ARB, texture);
gl.glUniform1iARB(gl.glGetUniformLocationARB(programObject, variableName), texture);
 

This is a loop to declare the 3 textures, and then:


gl.glBegin(GL.GL_QUADS);
	// Screen draw
	gl.glTexCoord2f(0, height);
	gl.glVertex2f(-2, -3/2);

	gl.glTexCoord2f(width, height);
	gl.glVertex2f(2, -3/2);

	gl.glTexCoord2f(width, 0);
	gl.glVertex2f(2, 3/2);

	gl.glTexCoord2f(0, 0 );
	gl.glVertex2f(-2, 3/2);
gl.glEnd();

The result is that I just get 2 textures to the shaders, and also If I don’t use shaders (disabling glUseProgramObjectARB and giving the coordinates with a loop made of:
gl.glMultiTexCoord2f(GL.GL_TEXTURE0, textureX, textureY);
gl.glMultiTexCoord2f(GL.GL_TEXTURE2, textureX/2, textureY/2 );
gl.glMultiTexCoord2f(GL.GL_TEXTURE1, textureX/2, textureY/2 );
gl.glVertex2f(vertexX, vertexY);
)

After this first test I must use VBO, but seeing the bad results mapping over just one square I don’t even wanna think in use 30000 triangles…)

One quick note :

shouldn’t

gl.glUniform1iARB(gl.glGetUniformLocationARB(programObject, variableName), texture);

be

gl.glUniform1iARB(gl.glGetUniformLocationARB(programObject, variableName), textureUnit);

where texture unit is 0 for GL_TEXTURE0,1 for GL_TEXTURE1, etc.

??

Yes it should.

I already found the problem… It was that i try to refactor too much and i made loops with create image, bind the image, sending the data to the uniform, instead of first create the 3 textures, then send the uniform, etc. So the pipeline get the data wrong and just sent one texture to the shaders.

Anyway, thanks to all the people and i will send the final code to nehe tutorials. Maybe it can help someone.