Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I have a problem with loading an .obj file in LWJGL and its textures. The object is a tree(it's a paid model from TurboSquid, so I can't post it here,but here's the link if you want to see how it should look like): http://www.turbosquid.com/FullPreview/Index.cfm/ID/701294

I wrote a custom OBJ loader using the LWJGL tutorial from their wiki. It looks like this:

public class OBJLoader {
public static Model loadModel(File f) throws FileNotFoundException, IOException
{
    BufferedReader reader = new BufferedReader(new FileReader(f));

    Model m = new Model();
    String line;
    Texture currentTexture = null;
    while((line=reader.readLine()) != null)
    {
        if(line.startsWith("v "))
        {
            float x = Float.valueOf(line.split(" ")[1]);
            float y = Float.valueOf(line.split(" ")[2]);
            float z = Float.valueOf(line.split(" ")[3]);
            m.verticies.add(new Vector3f(x,y,z));
        }else if(line.startsWith("vn "))
        {
            float x = Float.valueOf(line.split(" ")[1]);
            float y = Float.valueOf(line.split(" ")[2]);
            float z = Float.valueOf(line.split(" ")[3]);
            m.normals.add(new Vector3f(x,y,z));
        }else if(line.startsWith("vt "))
        {
            float x = Float.valueOf(line.split(" ")[1]);
            float y = Float.valueOf(line.split(" ")[2]);
            m.texVerticies.add(new Vector2f(x,y));
        }else if(line.startsWith("f "))
        {
            Vector3f vertexIndicies = new Vector3f(Float.valueOf(line.split(" ")[1].split("/")[0]), 
                    Float.valueOf(line.split(" ")[2].split("/")[0]), 
                    Float.valueOf(line.split(" ")[3].split("/")[0]));
            Vector3f textureIndicies = new Vector3f(Float.valueOf(line.split(" ")[1].split("/")[1]), 
                    Float.valueOf(line.split(" ")[2].split("/")[1]), 
                    Float.valueOf(line.split(" ")[3].split("/")[1]));
            Vector3f normalIndicies = new Vector3f(Float.valueOf(line.split(" ")[1].split("/")[2]), 
                    Float.valueOf(line.split(" ")[2].split("/")[2]), 
                    Float.valueOf(line.split(" ")[3].split("/")[2]));

            m.faces.add(new Face(vertexIndicies,textureIndicies,normalIndicies,currentTexture.getTextureID()));
        }else if(line.startsWith("g "))
        {
            if(line.length()>2)
            {
                String name = line.split(" ")[1];
                currentTexture = TextureLoader.getTexture("PNG", ResourceLoader.getResourceAsStream("res/" + name + ".png"));
                System.out.println(currentTexture.getTextureID());
            }
        }
    }


    reader.close();

    System.out.println(m.verticies.size() + " verticies");
    System.out.println(m.normals.size() + " normals");
    System.out.println(m.texVerticies.size() + " texture coordinates");
    System.out.println(m.faces.size() + " faces");
    return m;
}
}

Then I create a display list for my model using this code:

objectDisplayList = GL11.glGenLists(1);
    GL11.glNewList(objectDisplayList, GL11.GL_COMPILE);
    Model m = null;
    try {
        m = OBJLoader.loadModel(new File("res/untitled4.obj"));
    } catch (Exception e1) {
        e1.printStackTrace();
    } 

    int currentTexture=0;
    for(Face face: m.faces)
    {
        if(face.texture!=currentTexture)
        {
            currentTexture = face.texture;
            GL11.glBindTexture(GL11.GL_TEXTURE_2D, currentTexture);
        }


        GL11.glColor3f(1f, 1f, 1f);
        GL11.glBegin(GL11.GL_TRIANGLES);

        Vector3f n1 = m.normals.get((int) face.normal.x - 1);
        GL11.glNormal3f(n1.x, n1.y, n1.z);
        Vector2f t1 = m.texVerticies.get((int) face.textures.x -1);
        GL11.glTexCoord2f(t1.x, t1.y);
        Vector3f v1 = m.verticies.get((int) face.vertex.x - 1);
        GL11.glVertex3f(v1.x, v1.y, v1.z);



        Vector3f n2 = m.normals.get((int) face.normal.y - 1);
        GL11.glNormal3f(n2.x, n2.y, n2.z);
        Vector2f t2 = m.texVerticies.get((int) face.textures.y -1);
        GL11.glTexCoord2f(t2.x, t2.y);
        Vector3f v2 = m.verticies.get((int) face.vertex.y - 1);
        GL11.glVertex3f(v2.x, v2.y, v2.z);


        Vector3f n3 = m.normals.get((int) face.normal.z - 1);
        GL11.glNormal3f(n3.x, n3.y, n3.z);
        Vector2f t3 = m.texVerticies.get((int) face.textures.z -1);
        GL11.glTexCoord2f(t3.x, t3.y);
        Vector3f v3 = m.verticies.get((int) face.vertex.z - 1);
        GL11.glVertex3f(v3.x, v3.y, v3.z);

        GL11.glEnd();
    }
    GL11.glEndList();

The currentTexture is an int - it contains the ID of the currently used texture.

So my model looks absolutely fine without textures:

1

But look what happens if I enable GL_TEXTURE_2D:
2
3
4

As you can see an entire side of the tree appears to be missing - and it's not transparent, since it's not in the colour of the background - it's rendered black.

It's not a problem with the model - if I load it using Kanji's OBJ loader it works fine(but the thing is,that I need to write my own OBJ loader) 5

this is my OpenGL init section:

//init display
    try {
        Display.setDisplayMode(new DisplayMode(Support.SCREEN_WIDTH, Support.SCREEN_HEIGHT));
        Display.create();
        Display.setVSyncEnabled(true);
    } catch (LWJGLException e) {
        e.printStackTrace();
        System.exit(0);
    }
    GL11.glLoadIdentity();
    GL11.glEnable(GL11.GL_TEXTURE_2D);               
    GL11.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);          

    GL11.glShadeModel(GL11.GL_SMOOTH);
    GL11.glEnable(GL11.GL_DEPTH_TEST);
    GL11.glDepthFunc(GL11.GL_LESS);
    GL11.glDepthMask(true);
    GL11.glEnable(GL11.GL_NORMALIZE); 



    GL11.glMatrixMode(GL11.GL_PROJECTION);

    GLU.gluPerspective (90.0f,800f/600f, 1f, 500.0f);
    GL11.glMatrixMode(GL11.GL_MODELVIEW);

    GL11.glEnable(GL11.GL_CULL_FACE);
    GL11.glCullFace(GL11.GL_BACK);

    //enable lighting
    GL11.glEnable(GL11.GL_LIGHTING);

    ByteBuffer temp = ByteBuffer.allocateDirect(16);
    temp.order(ByteOrder.nativeOrder());

    GL11.glMaterial(GL11.GL_FRONT, GL11.GL_DIFFUSE, (FloatBuffer)temp.asFloatBuffer().put(lightDiffuse).flip());
    GL11.glMaterialf(GL11.GL_FRONT, GL11.GL_SHININESS,(int)material_shinyness);

    GL11.glLight(GL11.GL_LIGHT2, GL11.GL_DIFFUSE, (FloatBuffer)temp.asFloatBuffer().put(lightDiffuse2).flip());              // Setup The Diffuse Light
    GL11.glLight(GL11.GL_LIGHT2, GL11.GL_POSITION,(FloatBuffer)temp.asFloatBuffer().put(lightPosition2).flip()); 
    GL11.glLight(GL11.GL_LIGHT2, GL11.GL_AMBIENT,(FloatBuffer)temp.asFloatBuffer().put(lightAmbient).flip()); 
    GL11.glLight(GL11.GL_LIGHT2, GL11.GL_SPECULAR,(FloatBuffer)temp.asFloatBuffer().put(lightDiffuse2).flip()); 

    GL11.glLightf(GL11.GL_LIGHT2, GL11.GL_CONSTANT_ATTENUATION, 0.1f);
    GL11.glLightf(GL11.GL_LIGHT2, GL11.GL_LINEAR_ATTENUATION, 0.0f);
    GL11.glLightf(GL11.GL_LIGHT2, GL11.GL_QUADRATIC_ATTENUATION, 0.0f);
    GL11.glEnable(GL11.GL_LIGHT2);

Could somebody please help me?

share|improve this question
1  
Try rendering a textured quad first. If it doesn't work, you have a reduced problem to solve. It it works, try to find what you are doing differently than with the OBJ model. –  msell Dec 11 '12 at 6:31
    
Can you please show me your Model class? I think you have something interesting for me there. Thanks –  user30148 Apr 30 '13 at 8:35
    
Hi. Just posted a new answer with a link to the github repo of the entire project, please take a look at all the classes if you fancy: gamedev.stackexchange.com/a/54770/23776 –  gambiting Apr 30 '13 at 14:10

2 Answers 2

You just need to flip your texture! Your texture width and height must to be like in this order:

(2X2), (8X8), (32X32), (64X64), (128X128), (256X256), (512X512), (1024X1024) and so on! (else your texture will fill with black areas!)

The solution is to use slick library for loading your textures!

(You must download the Slick library and add it to your java program!)

First import this lines to your java program:

import org.newdawn.slick.opengl.Texture;
import org.newdawn.slick.opengl.TextureLoader;

Then use this method to load your texture:

private Texture loadTexture(String key){
    try {
        Texture texture = TextureLoader.getTexture("png", new FileInputStream( new File(key)), true);
        return texture;
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

This method flip your texture coordinates because OBJ origin is at upper left and OpenGL origin is at lower left.

And last thing you need to do before calling glBegin is bind your texture:

texture.bind();

I hope it will help you to solve your problem! ^^

share|improve this answer

This problem has been solved and it works now. This used to be a university project,but now it has been marked and returned I am free to share the entirety of it with you. This is 3D space invaders game, with a custom OBJ loader writing in Java, you can download it from this repo on GitHub:

https://github.com/gambiting/Graphics_Project

git://github.com/gambiting/Graphics_Project.git

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.