Mr Pablo
Mr Pablo

Reputation: 4188

OpenGL texture not mapping correctly

I am working on fixing the following project: objLoader

It works well, loading in an OBJ I found.

However, the project was missing code to deal with mapping a texture onto the object, so I have been adding it in.

I can now load my OBJ (a banana) and I can in fact see a texture on it!

BUT, the texture is not mapped properly. It appears to be tiled and distorted (see below)

image

Below is my code:

TDModel.java

public void draw(GL10 gl) {
    gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]); // bind texture

    gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
    gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

    for(int i=0; i<parts.size(); i++){
        TDModelPart t=parts.get(i);
        Material m=t.getMaterial();
        if(m!=null){
            FloatBuffer a=m.getAmbientColorBuffer();
            FloatBuffer d=m.getDiffuseColorBuffer();
            FloatBuffer s=m.getSpecularColorBuffer();
            gl.glMaterialfv(GL10.GL_FRONT_AND_BACK,GL10.GL_AMBIENT,a);
            gl.glMaterialfv(GL10.GL_FRONT_AND_BACK,GL10.GL_SPECULAR,s);
            gl.glMaterialfv(GL10.GL_FRONT_AND_BACK,GL10.GL_DIFFUSE,d);
        }
        gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
        gl.glNormalPointer(GL10.GL_FLOAT, 0, t.getNormalBuffer());
        gl.glDrawElements(GL10.GL_TRIANGLES,t.getFacesCount(),GL10.GL_UNSIGNED_SHORT,t.getFaceBuffer());
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
    }

}

public void loadGLTexture(GL10 gl, Context context) {
    // loading texture
    InputStream is = null;
    Bitmap bitmap = null;
    try {
        is = context.getAssets().open("banana.jpg");

        bitmap = BitmapFactory.decodeStream(is);
    } catch (IOException e) {
        e.printStackTrace();
    }

    gl.glGenTextures(1, textures, 0);
    // ...and bind it to our array
    gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);

    // create nearest filtered texture
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);

    // Use Android GLUtils to specify a two-dimensional texture image from our bitmap
    GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);

    // Clean up
    bitmap.recycle();
}

MyRenderer.java

public void onSurfaceCreated(GL10 gl, EGLConfig config) {

    model.loadGLTexture(gl, getContext()); // load texture

    gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, lightAmbientBuffer);
    gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, lightDiffuseBuffer);      
    gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, lightPositionBuffer);    
    gl.glEnable(GL10.GL_LIGHT0);

    gl.glEnable(GL10.GL_TEXTURE_2D); // Enable texture
    gl.glShadeModel(GL10.GL_SMOOTH);            
    gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
    gl.glClearDepthf(1.0f);                     
    gl.glEnable(GL10.GL_DEPTH_TEST);            
    gl.glDepthFunc(GL10.GL_LEQUAL);         

    gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST); 
}

Any ideas why its not wrapping correctly?

Here is the texture

enter image description here

Upvotes: 2

Views: 1286

Answers (1)

Anonymous
Anonymous

Reputation: 2172

The real problem is with indices in your OBJ file.

Every attribute: pos, normal, texcoord use separate indexing.

So your faces specify which index should be used for every attribute separately on each of its 3 vertices.

You need to rearrange normals and texcoords so their indices will match vertex position indices.

Simplest solution is to allocate new array (not indexed with vertices count = 3 * face count) and fill it manually looking up attributes from indexed data.

Then you can draw it using DrawArrays (instead of DrawElements)

int faces, vertices, normals, texcoords;
int indexes[faces][3][3]; // currently your indices [face][vertex][attrib_index]
float vertex[vertices][3]; // your vertex positions
float normal[normals][3]; // your normals
float texcoord[texcoords][3]; // your texcoords

you need to convert to:

int vertices = 3*faces;
float vertex2[vertices][3]; // your vertex positions
float normal2[vertices][3]; // your normals
float texcoord2[vertices][2]; // your texcoords

in following way:

int v=0;
for (int f=0; f<faces; f++)
{

    for (int fv=0; fv<3; fv++,v++)
    {
        vertex2[v][0] = vertex[ indexes[f][fv][0] ][0];
        vertex2[v][1] = vertex[ indexes[f][fv][0] ][1];
        vertex2[v][2] = vertex[ indexes[f][fv][0] ][2];

        normal2[v][0] = normal[ indexes[f][fv][1] ][0];
        normal2[v][1] = normal[ indexes[f][fv][1] ][1];
        normal2[v][2] = normal[ indexes[f][fv][1] ][2];

        texcoord2[v][0] = texcoord[ indexes[f][fv][2] ][0];
        texcoord2[v][1] = texcoord[ indexes[f][fv][2] ][1];
    }
}

Upvotes: 1

Related Questions