Texture loaded from .png is not correctly drawn

Started by
4 comments, last by redru 9 years, 2 months ago

This is my first post, so Hello Everyone.

I've got a strange problem drawing a texture in a Android Project, using OpenGL ES 3.0. This is the resulting draw:

[attachment=25716:Screenshot_2015-01-29-23-41-08.png]

This is when I set 'GLES30.GL_TEXTURE_WRAP_S':

[attachment=25715:Screenshot_2015-01-29-23-34-52.png]

And this is the image:

[attachment=25717:tex_b2spirit.png]

This is my method setup(), where I create VBOs and VAOs:


public void setup() {
StringBuilder str = new StringBuilder();
for (int i = 0, x = 0, y = 0; i < evoObj.getUnifiedData().length; i++) {
str.append(evoObj.getUnifiedData() + ", ");
if (x % 7 == 0 && x != 0) {
Log.i(TAG, "UNIFIED DATA " + y + ": " + str);
str.delete(0, str.length());
x = 0;
y++;
} else {
x++;
}
}
Log.i(TAG, "UNIFIED DATA: LOGGED");
Log.i(TAG, "Buffers setup: start.");
// initialize vertex byte buffer for shape coordinates------------------------------------
vertexBuffer = ByteBuffer.allocateDirect(evoObj.getUnifiedData().length * OpenGLConstants.BYTES_PER_FLOAT)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
vertexBuffer.put(evoObj.getUnifiedData()).position(0);
textureBuffer = ByteBuffer.allocateDirect(evoObj.getTexture().getBitmap().getByteCount())
.order(ByteOrder.nativeOrder());
textureBuffer.put(evoObj.getTexture().getTextureData()).position(0);
//VERTEX DATA CONFIGURATION------------------------------------------------------------------
GLES30.glGenBuffers(1, VBOIds, 0);
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, VBOIds[0]);
GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER, evoObj.getUnifiedData().length * OpenGLConstants.BYTES_PER_FLOAT,
vertexBuffer, GLES30.GL_STATIC_DRAW);
//TEXTURE CONFIGURATION----------------------------------------------------------------------
GLES30.glGenTextures(1, textureId, 0);
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureId[0]);
GLES30.glTexImage2D(GLES30.GL_TEXTURE_2D, 0, GLES30.GL_RGB, 1024, 256, 0, GLES30.GL_RGB, GLES30.GL_UNSIGNED_BYTE, textureBuffer);
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR);
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
// GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE);
// GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE);
//----------------------------------------------------------------------------------------------
// Vertex Array Object (VAO) configuration
GLES30.glGenVertexArrays(1, VAOIds, 0);
GLES30.glBindVertexArray(VAOIds[0]);
// TEXTURES
GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureId[0]);
GLES30.glUniform1i(ShaderFactory.getInstance().SAMPLER_S_TEXTURE, 0);
// TEXTURES END
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, VBOIds[0]);
GLES30.glEnableVertexAttribArray(ShaderFactory.getInstance().LAYOUT_VERTEX);
GLES30.glEnableVertexAttribArray(ShaderFactory.getInstance().LAYOUT_TEXTURE);
GLES30.glVertexAttribPointer(ShaderFactory.getInstance().LAYOUT_VERTEX, 3,
GLES30.GL_FLOAT, false, 8 * OpenGLConstants.BYTES_PER_FLOAT, 0);
GLES30.glVertexAttribPointer(ShaderFactory.getInstance().LAYOUT_TEXTURE, 2,
GLES30.GL_FLOAT, false, 8 * OpenGLConstants.BYTES_PER_FLOAT, 3 * OpenGLConstants.BYTES_PER_FLOAT);
GLES30.glBindVertexArray(0);
//----------------------------------------------------------------------------------------
Log.i(TAG, "Buffers setup: complete.");
}

This is my draw() method:


public void draw() {
        GLES30.glUseProgram(ShaderFactory.getInstance().complexObjectProgram);

        // Load the MVP matrix
        GLES30.glUniformMatrix4fv(ShaderFactory.getInstance().MVP_LOC, 1, false,
                Camera.getInstance().getMvpMatrixAsFloatBuffer());

        // Bind this object Vertex Array Object (VAO) state and then draw the object
        GLES30.glBindVertexArray(VAOIds[0]);
        
        GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, evoObj.getUnifiedData().length);

        GLES30.glBindVertexArray(0);
    }

The vertexAttribPointer uses a buffer with this structure: [V1][V2][V3][T1][T2][VN1][VN2][VN3]. I am pretty sure that the data passed to the buffer is correct, because I have already debugged it. I have the problem with the texture loaded from image, cause drawing colors instead of texture, does his job correctly.

I do not expect a response like 'your fault is this line'. I am asking if you know how to handle this kind of errors, because I cannot understand where I have to look (maybe is the buffer loaded partially? or maybe the image is not loaded correctly? can the shader be wrong? ).

**********EDIT 1***********

Hello, sorry about not posting all needed code, it was only for not show you useless things. Here it goes:

Here I am getting all the information from the file, passed as a String[]:


private EvoObj wrap(String[] lines, String name) {
        String[] lineParts;
        String[] indicesParts;

        ArrayList<Float> positions = new ArrayList<Float>();
        ArrayList<Float> textures = new ArrayList<Float>();
        ArrayList<Float> normals = new ArrayList<Float>();
        ArrayList<short[]> indices = new ArrayList<short[]>();
        
        for (int index = 0; index < lines.length; index++) {

            if (lines[index].startsWith("v ")) {
            	lines[index] = lines[index].substring(2);
                lineParts = lines[index].split(" ");

                for (int i = 0; i < OpenGLConstants.SINGLE_V_SIZE; i++) {
                    positions.add(Float.parseFloat(lineParts[i]));
                }

            } else if (lines[index].startsWith("vt ")) {
            	lines[index] = lines[index].substring(3);
                lineParts = lines[index].split(" ");

                for (int i = 0; i < OpenGLConstants.SINGLE_VT_SIZE; i++) {
                	textures.add(Float.parseFloat(lineParts[i]));
                }

            } else if (lines[index].startsWith("vn ")) {
            	lines[index] = lines[index].substring(3);
                lineParts = lines[index].split(" ");

                for (int i = 0; i < OpenGLConstants.SINGLE_VN_SIZE; i++) {
                	normals.add(Float.parseFloat(lineParts[i]));
                }
                
            } else if (lines[index].startsWith("f ")) {
                lines[index] = lines[index].substring(2);
                lineParts = lines[index].split(" ");

                for (int i = 0; i < OpenGLConstants.SINGLE_F_SIZE; i++) {
                    indicesParts = lineParts[i].split("/");

                    if (indicesParts.length > 0) {
                    	short[] tmp = new short[3];
                    	
                        for (int e = 0; e < OpenGLConstants.SINGLE_F_INDICES_SIZE; e++) {
                            tmp[e] = Short.parseShort(indicesParts[e]);
                        }
                        
                        indices.add(tmp);
                    }

                }

            }

        }
        
        float[] positionsTmp = new float[positions.size()];
        for (int i = 0; i < positions.size(); i++) {
        	positionsTmp[i] = positions.get(i);
//        	Log.i(TAG, "Position " + i + ": " + positionsTmp[i]);
        }
        
        float[] texturesTmp = new float[textures.size()];
        for (int i = 0; i < textures.size(); i++) {
        	texturesTmp[i] = textures.get(i);
//        	Log.i(TAG, "Texture " + i + ": " + texturesTmp[i]);
        }
        
        float[] normalsTmp = new float[normals.size()];
        for (int i = 0; i < normals.size(); i++) {
        	normalsTmp[i] = normals.get(i);
//        	Log.i(TAG, "Normal " + i + ": " + normalsTmp[i]);
        }
        
        short[][] indicesTmp = new short[indices.size()][indices.get(0).length];
        for (int i = 0; i < indices.size(); i++) {
        	for (int e = 0; e < indices.get(0).length; e++) {
        		indicesTmp[i][e] = (short) (indices.get(i)[e] - 1);
//        		Log.i(TAG, "Indices " + i + ": " + indicesTmp[i][e]);
        	}
        }
        
        float[] unifiedData = OpenGLUtils.generateUnifiedData(positionsTmp, texturesTmp, normalsTmp, indicesTmp);
        EvoObj obj  = new EvoObj(positionsTmp, texturesTmp, normalsTmp, unifiedData, name);

        return obj;
    }

Here I unify all data into a single array, parsing the index data:


public static float[] generateUnifiedData(float[] positions, float[] textures, float[] normals, short[][] indices) {
		float[] tmp = new float[(OpenGLConstants.SINGLE_V_SIZE + OpenGLConstants.SINGLE_VT_SIZE + OpenGLConstants.SINGLE_VN_SIZE) * indices.length];
		
		for (int i = 0, x = 0; i < indices.length; i++) {
			for (int e = 0; e < indices[i].length; e++) {
				if (e == 0) {
					for (int w = 0; w < OpenGLConstants.SINGLE_V_SIZE; w++) {
						tmp[x] = positions[indices[i][e] * OpenGLConstants.SINGLE_V_SIZE + w];
						x++;
					}
				} else if (e == 1) {
					for (int w = 0; w < OpenGLConstants.SINGLE_VT_SIZE; w++) {
						tmp[x] = textures[indices[i][e] * OpenGLConstants.SINGLE_VT_SIZE + w];
						x++;
					}
				} else if (e == 2) {
					for (int w = 0; w < OpenGLConstants.SINGLE_VN_SIZE; w++) {
						tmp[x] = normals[indices[i][e] * OpenGLConstants.SINGLE_VN_SIZE + w];
						x++;
					}
				}
			}
			
			Log.i(TAG, "i: " + i + " / x: " + x);
		}
		
		return tmp;
	}

Here I am loading the bitmap from the file .png:


public static Texture importTexture(Context context, int resourceId) {
    	Texture tex = null;
    	
    	InputStream is = Redru.getContext().getResources().openRawResource(R.raw.tex_b2spirit);
    	Bitmap bitmap = BitmapFactory.decodeStream(is);
    	
    	tex = new Texture("Spirit texture");
    	tex.setBitmap(bitmap);
    	
    	/* UNUSED
    	ByteArrayOutputStream stream = new ByteArrayOutputStream();
    	bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
    	
    	tex.setTextureData(stream.toByteArray());*/
    	
    	try {
			is.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
    	
    	return tex;
    }

At this links you can find the log, obj and shaders files:

http://www.ibizing.es/images/log.txt

http://www.ibizing.es/images/obj_b2spirit.txt

http://www.ibizing.es/images/shader_fragment_complex_object.txt

http://www.ibizing.es/images/shader_vertex_complex_object.txt

PS: the .obj is not mine, I downloaded from internet to learn OpenGL.

Thank you everyone,

Luca

Advertisement
What happens if you flat shade the model instead of texturing it, do you still get the same odd colour pattern?

This might eliminate the possibility of some shader errors..

have you tried with a different image?

What things have you tried already?

maybe the image is not loaded correctly?

That’s pretty hard to tell since you didn’t post anything related to the loading of the texture. Yes, it can be wrong.

can the shader be wrong?

That’s pretty hard to tell since you didn’t post anything related to shaders. Yes, it can be wrong.

I am asking if you know how to handle this kind of errors, because I cannot understand where I have to look

Look at the results on your screen.

#1: The colors you see on the object are not present in the original image. This means it is either loaded incorrectly or for any other reason you have uploaded junk to the texture slot for the shader to read. If the shader samples from a texture slot that is not bound by a texture, it will return black, so we can assume you have set the sampler state correctly and bound a texture (although why you would leave it bound while creating the VBO instead of binding it when drawing is beyond me).
The pattern of the image is not the same in both images, which further suggests the texture is nothing but random junk taken from CPU-side RAM.

You didn’t explain what modes you were using in the first shot, so I can only guess it was the default GL_REPEAT.
There is a maximum number of repeats the hardware can do, which might explain why it becomes black after a while.
You didn’t post any shaders so I can’t tell if you are passing UV’s through correctly.

If your texturing looks weird, one of the first things you do is print the UV coordinates so you can verify them.

The vertexAttribPointer uses a buffer with this structure: [V1][V2][V3][T1][T2][VN1][VN2][VN3].

No it’s not.
It’s [V1][V2][V3][T1][T2][X][X][X] according to your code.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

From looking at your post, the issue is most likely related to how the image is being loaded, but like mentioned before you did not post anything to that end, since the assumption is the texcoords are incorrect. Incorrect texture coordinate would at least give you colors that are actually in the 'correct' image, but your post seem to show what appears to be 'noise'.
How is the texture being loaded ?

I made an edit. Thank you.

Finally I solved this problem, after several days of looking and following your suggestions:

I have replaced my method for loading the texture with this:


     final BitmapFactory.Options options = new BitmapFactory.Options();
     options.inScaled = false;
     final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);
After, I have changed the method to generate texture. I have replaced this:

//        textureBuffer = ByteBuffer.allocateDirect(evoObj.getTexture().getBitmap().getByteCount())
//        		.order(ByteOrder.nativeOrder());
//        textureBuffer.put(evoObj.getTexture().getTextureData()).position(0);


// ..................................

//        GLES30.glTexImage2D(GLES30.GL_TEXTURE_2D, 0, GLES30.GL_RGB, 1024, 256, 0, GLES30.GL_RGB, GLES30.GL_UNSIGNED_BYTE, textureBuffer);

with this:


GLUtils.texImage2D(GLES30.GL_TEXTURE_2D, 0, evoObj.getTexture().getBitmap(), 0);

This is doing his work. After that I will try to buffer the data and generate it, like I was doing before. But is clear that my first code was wrong at loading, buffering or generating the texture.

Thank you all.

This topic is closed to new replies.

Advertisement