0

EDIT: I have answered the question and the code has been changed so it is usable, feel free to use the code in your own projects. Kind regards, Liam

I'm currentlyworking on 3D model rendering in LWJGL and I have run into a problem, when I run the program the display comes up and everything work apart from the model. I tested the 3D space code with some random dots being drawn and I could see them and walk around so my 3D space code is working but not the model code.

My question is as folows, is there something wrong with my display code or is it my model loading code, the following is my source code (I'm sorry for the long amounts of code but I couldn't shorten it).

Main Game Thread:

public class GameThread implements Runnable {

private boolean running;
private Camera cam = new Camera(0, 0, 0, 0, 0.25f, 25, new int[] {Keyboard.KEY_W, Keyboard.KEY_S, Keyboard.KEY_A, Keyboard.KEY_D});
private Model testModel;

@Override
public void run() 
{
    initialize();

    while(running)
    {
        if(Display.isCloseRequested())
            tryClose();

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        tick();
        Display.update();
    }

    close();
}

private void initialize()
{
    try
    {
        Display.setTitle("Test Game");
        Display.setDisplayMode(new DisplayMode(1280, 768));
        Display.setVSyncEnabled(true);
        Display.create();

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective((float) 30, 1024f / 768f, 0.001f, 100);
        glMatrixMode(GL_MODELVIEW);

        glEnable(GL_DEPTH_TEST);
        glEnable(GL_TEXTURE_2D);
        glEnable(GL_BLEND);
        glEnable(GL_ALPHA_TEST);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

        testModel = new Model(this.getClass().getClassLoader().getResource("res\\untitled.obj"), new Vector3f(0, 0, 0), new Vector3f(0, 0, 0));
        cam.setPosition(new Vector3f(0, 0, -10));

        running = true;
    }
    catch(Exception e)
    {
        Display.destroy();
        e.printStackTrace();
        System.exit(1);
    }
}

private void tick()
{   
    cam.update();

    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    testModel.draw();
}

private void tryClose()
{
    running = false;
}

private void close()
{
    Display.destroy();
}

Model Loading/Render Code:

public class Model {

private HashMap<String, ModelGroup> groups = new HashMap<String, ModelGroup>();
private Vector3f position, rotation;

public Model(URL modelLocation, Vector3f position, Vector3f rotation)
{
    this.setPosition(position);
    this.setRotation(rotation);

    try
    {
        BufferedReader in = new BufferedReader(new InputStreamReader(modelLocation.openStream()));

        String line;
        ModelGroup group = new ModelGroup("default");

        while((line = in.readLine()) != null)
        {
            if(line.startsWith("g "))
            {
                String newGroupName = (new StringTokenizer(line)).nextToken();

                if(newGroupName.equals(group.getGroupName()))
                    continue;

                groups.put(group.getGroupName(), group);
                group = new ModelGroup(newGroupName);
            }
            else if(line.startsWith("v "))
            {
                StringTokenizer vertices = new StringTokenizer(line);

                vertices.nextToken(); // Skips 'v'

                float x, y, z, w = 1;

                x = Float.valueOf(vertices.nextToken());
                y = Float.valueOf(vertices.nextToken());
                z = Float.valueOf(vertices.nextToken());

                if(vertices.hasMoreTokens())
                    w = Float.valueOf(vertices.nextToken());
                else
                    w = 1;

                group.addVertice(new Vector4f(x, y, z, w));                 
            }
            else if(line.startsWith("vn "))
            {
                StringTokenizer normalVertices = new StringTokenizer(line);

                normalVertices.nextToken(); // Skips 'vn'

                float x, y, z;

                x = Float.valueOf(normalVertices.nextToken());
                y = Float.valueOf(normalVertices.nextToken());
                z = Float.valueOf(normalVertices.nextToken());

                group.addNormal(new Vector3f(x, y, z));
            }
            else if(line.startsWith("vt "))
            {
                StringTokenizer textureVertices = new StringTokenizer(line);

                textureVertices.nextToken(); // Skips 'vt'

                float u, v, w;

                u = Float.valueOf(textureVertices.nextToken());

                if(textureVertices.hasMoreTokens())
                    v = Float.valueOf(textureVertices.nextToken());
                else
                    v = 0;

                if(textureVertices.hasMoreTokens())
                    w = Float.valueOf(textureVertices.nextToken());
                else
                    w = 0;

                group.addTextureCoordinate(new Vector3f(u, v, w));
            }
            else if(line.startsWith("f "))
            {
                StringTokenizer token = new StringTokenizer(line.replace('f', ' '));
                String[] indices = new String[token.countTokens()];

                int polygon_type = (indices.length == 3 ? GL_TRIANGLES : GL_QUADS);

                for(int i = 0; i < indices.length; i++)
                    indices[i] = token.nextToken();

                int mode = 0;

                if(line.contains("//"))
                    mode = 3;

                if(mode != 3)
                    if(indices[0].split("/").length == 2)
                        mode = 1;
                    else if(indices[0].split("/").length == 3)
                        mode = 2;

                if(mode == 0)
                {
                    Vector4f vertices = new Vector4f();
                    vertices.set(Float.valueOf(indices[0]), Float.valueOf(indices[1]), Float.valueOf(indices[2]), (indices.length == 4 ? Float.valueOf(indices[3]) : -1));

                    group.addFace(new ModelFace(vertices).setPolygonType(polygon_type));
                }
                else if(mode == 1)
                {
                    float x, y, z, vw;
                    float u, v, tw;

                    x = Float.valueOf(indices[0].split("/")[0]);
                    y = Float.valueOf(indices[1].split("/")[0]);
                    z = Float.valueOf(indices[2].split("/")[0]);

                    if(indices.length == 4)
                        vw = Float.valueOf(indices[3].split("/")[0]);
                    else
                        vw = -1;

                    u = Float.valueOf(indices[0].split("/")[1]);
                    v = Float.valueOf(indices[1].split("/")[1]);
                    tw = Float.valueOf(indices[2].split("/")[1]);

                    group.addFace(new ModelFace(new Vector4f(x, y, z, vw), new Vector3f(u, v, tw), new Vector3f(-1, 0, 0)).setPolygonType(polygon_type));
                }
                else if(mode == 2)
                {
                    float vx, vy, vz, vw;
                    float u, v, tw;
                    float nx, ny, nz;

                    vx = Float.valueOf(indices[0].split("/")[0]);
                    vy = Float.valueOf(indices[1].split("/")[0]);
                    vz = Float.valueOf(indices[2].split("/")[0]);

                    if(indices.length == 4)
                        vw = Float.valueOf(indices[3].split("/")[0]);
                    else
                        vw = -1;

                    u = Float.valueOf(indices[0].split("/")[1]);
                    v = Float.valueOf(indices[1].split("/")[1]);
                    tw = Float.valueOf(indices[2].split("/")[1]);

                    nx = Float.valueOf(indices[0].split("/")[2]);
                    ny = Float.valueOf(indices[1].split("/")[2]);
                    nz = Float.valueOf(indices[2].split("/")[2]);

                    group.addFace(new ModelFace(new Vector4f(vx, vy, vz, vw), new Vector3f(u, v, tw), new Vector3f(nx, ny, nz)).setPolygonType(polygon_type));
                }
                else if(mode == 3)
                {
                    float vx, vy, vz, vw;
                    float nx, ny, nz;

                    System.out.println(indices[0]);

                    vx = Float.valueOf(indices[0].split("//")[0]);
                    vy = Float.valueOf(indices[1].split("//")[0]);
                    vz = Float.valueOf(indices[2].split("//")[0]);

                    if(indices.length == 4)
                        vw = Float.valueOf(indices[3].split("//")[0]);
                    else
                        vw = -1;

                    nx = Float.valueOf(indices[0].split("//")[1]);
                    ny = Float.valueOf(indices[1].split("//")[1]);
                    nz = Float.valueOf(indices[2].split("//")[1]);

                    group.addFace(new ModelFace(new Vector4f(vx, vy, vz, vw), new Vector3f(-1, 0, 0), new Vector3f(nx, ny, nz)).setPolygonType(polygon_type));
                }
            }
        }

        groups.put(group.getGroupName(), group);
        in.close();
    }
    catch(Exception e)
    {
        e.printStackTrace();
    }
}   

public Vector3f getPosition() {
    return position;
}

public void setPosition(Vector3f position) {
    this.position = position;
}

public Vector3f getRotation() {
    return rotation;
}

public void setRotation(Vector3f rotation) {
    this.rotation = rotation;
}

public void draw()
{
    ArrayList<ModelGroup> groups = new ArrayList<ModelGroup>(this.groups.values());

    for(int i = 0; i < groups.size(); i++)
        drawGroup(groups.get(i).getGroupName());
}

public void drawGroup(String name)
{
    ModelGroup group = groups.get(name);

    if(group == null)
        return;

    glPushMatrix();
    {
        glRotatef(rotation.x, 1, 0, 0);
        glRotatef(rotation.y, 0, 1, 0);
        glRotatef(rotation.z, 0, 0, 1);
        glTranslatef(position.x, position.y, position.z);

        for(ModelFace face : group.getFaces())
        {
            glBegin(face.getPolygonType());
            {
                for(int id = 0; id < 3; id++)
                {
                    Vector4f vertex = group.getVertices().get(face.getVerticeIndex(id));
                    glVertex4f(vertex.x, vertex.y, vertex.z, vertex.w);

                    if(face.hasTextureCoordinates())
                    {
                        Vector3f textureCoordinate = group.getTextureCoordinates().get(face.getTextureCoordinateIndex(id));
                        glTexCoord3f(textureCoordinate.x, textureCoordinate.y, textureCoordinate.z);
                    }

                    if(face.hasNormals())
                    {
                        Vector3f normal = group.getNormals().get(face.getNormalIndex(id));
                        glNormal3f(normal.x, normal.y, normal.z);
                    }
                }

                if(face.getPolygonType() == GL_QUADS)
                {
                    Vector4f vertex = group.getVertices().get(face.getVerticeIndex(3));
                    glVertex4f(vertex.x, vertex.y, vertex.z, vertex.w);
                }
            }
            glEnd();
        }
    }
    glPopMatrix();
}

//====================================================================================================//

private class ModelGroup
{
    private final String groupName;

    private ArrayList<Vector4f> vertices = new ArrayList<Vector4f>();
    private ArrayList<Vector3f> normals = new ArrayList<Vector3f>();
    private ArrayList<Vector3f> textureCoordinates = new ArrayList<Vector3f>();
    private ArrayList<ModelFace> faces = new ArrayList<ModelFace>();

    public ModelGroup(String name) {
        this.groupName = name;
    }

    public String getGroupName() {
        return this.groupName;
    }

    public void addVertice(Vector4f vertice) {
        this.vertices.add(vertice);
    }

    public ArrayList<Vector4f> getVertices() {
        return this.vertices;
    }

    public void addNormal(Vector3f normal) {
        this.normals.add(normal);
    }

    public ArrayList<Vector3f> getNormals() {
        return this.normals;
    }

    public void addTextureCoordinate(Vector3f coordinate) {
        this.textureCoordinates.add(coordinate);
    }

    public ArrayList<Vector3f> getTextureCoordinates() {
        return this.textureCoordinates;
    }

    public void addFace(ModelFace face) {
        this.faces.add(face);
    }

    public ArrayList<ModelFace> getFaces() {
        return this.faces;
    }
}

private class ModelFace {

    private Vector4f vertices;
    private Vector3f textureCoordinates, normals;
    private int POLYGON_TYPE = 0;

    private boolean hasTextureCoords = true, hasNormals = true;

    public ModelFace(Vector4f vertices) {
        this(vertices, new Vector3f(-1, 0, 0), new Vector3f(-1, 0, 0));
    }

    public ModelFace(Vector4f vertices, Vector3f textureCoordinates, Vector3f normals)
    {
        this.vertices = vertices;
        this.textureCoordinates = textureCoordinates;
        this.normals = normals;

        if(this.textureCoordinates.x == -1)
            this.hasTextureCoords = false;

        if(this.normals.x == -1)
            this.hasNormals = false;
    }

    public boolean hasTextureCoordinates() {
        return this.hasTextureCoords;
    }

    public boolean hasNormals() {
        return this.hasNormals;
    }

    public int getVerticeIndex(int id)
    {
        if(id == 0)
            return (int)vertices.x - 1;
        else if(id == 1)
            return (int)vertices.y - 1;
        else if(id == 2)
            return (int)vertices.z - 1;
        else if(id == 3)
            return (int)vertices.w - 1;
        else
            return -1;
    }

    public int getTextureCoordinateIndex(int id)
    {
        if(id == 0)
            return (int)textureCoordinates.x - 1;
        else if(id == 1)
            return (int)textureCoordinates.y - 1;
        else if(id == 2)
            return (int)textureCoordinates.z - 1;
        else
            return -1;
    }

    public int getNormalIndex(int id)
    {
        if(id == 0)
            return (int)textureCoordinates.x - 1;
        else if(id == 1)
            return (int)textureCoordinates.y - 1;
        else if(id == 2)
            return (int)textureCoordinates.z - 1;
        else
            return -1;
    }

    public ModelFace setPolygonType(int type) {
        this.POLYGON_TYPE = type;
        return this;
    }

    public int getPolygonType() {
        return this.POLYGON_TYPE;
    }
}
}

Thanks, Liam.

Liam Haworth
  • 848
  • 1
  • 9
  • 27

1 Answers1

0

Ok, I fixed the problem.

It was in the model constructor code, when the while loop finished it didn't add the last group to the list. That meant that if there was only one group(or none) it wouldn't get added to the list and wouldn't be rendered.

I have changed the model code in the question so it is usable, feel free to use it in your projects

Kind regards, Liam

Liam Haworth
  • 848
  • 1
  • 9
  • 27