PDA

View Full Version : Wrong image after multitexturing and GLSL



daxel
04-04-2008, 06:28 AM
[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.

dletozeun
04-04-2008, 09:11 AM
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.

dorbie
04-05-2008, 01:38 PM
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).

daxel
04-11-2008, 01:28 AM
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(progr amObject, 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..)

babis
04-11-2008, 09:46 PM
One quick note :

shouldn't

gl.glUniform1iARB(gl.glGetUniformLocationARB(progr amObject, variableName), texture);

be

gl.glUniform1iARB(gl.glGetUniformLocationARB(progr amObject, variableName), textureUnit);

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

??

-NiCo-
04-12-2008, 04:05 AM
One quick note :

shouldn't

gl.glUniform1iARB(gl.glGetUniformLocationARB(progr amObject, variableName), texture);

be

gl.glUniform1iARB(gl.glGetUniformLocationARB(progr amObject, variableName), textureUnit);

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

??

Yes it should.

daxel
04-14-2008, 02:28 AM
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.