LWJGL .OBJ Средство чтения файлов иногда искажает или не отображает файл - PullRequest
0 голосов
/ 10 декабря 2011

Я работаю над игрой с друзьями, и чтобы облегчить жизнь, я решил, что все 3D-модели будут создаваться с использованием файлов .obj, экспортируемых в такие программы, как 3DSMax, Maya и Blender3D.

Итак, я написал программу для чтения файлов .obj и опробовал ее на простой сцене, некоторые файлы .obj отрисовывались хорошо (например, простой куб), некоторые отображались действительно странно, а затем некоторые вообще не отображались. Я надеялся, что кто-то может указать мне, что я сделал неправильно, следующий код содержит один класс с двумя встроенными классами, один из которых содержит другой встроенный класс. Это может сбить с толку, так что вы можете скопировать и вставить в файл для удобства чтения.

Скрипт читает строку за строкой в ​​файле и, если он начинается с "v" (вершина), он разбивает строку на пробелы и принимает индексы 1, 2 и 3 (xy и z) и сохраняет целочисленные значения в классе. называется Vertex и добавляет его в массив объектов Vertex. объект Vertex действует как вектор, только он содержит два вектора, один для положения и один для нормалей.

Если строка начинается с "vn" (Vertex Normal), она разбивает строку на "" и берет индексы 1 2 и 3 и добавляет затем к объекту Vertex, который до сих пор действует как вектор, а затем Vertex добавляется в другой массив Vertex специально для нормалей.

Теперь вот интересная часть, когда строка начинается с "f" (Face), строка может выглядеть так:

f 1//3 5//3 6//1 2//4

каждый # 1 // # 2, # 1 - это индекс правильной вершины, а # 2 - это индекс для правильной нормали. Таким образом, я беру каждую часть строки, разделенную на «» и разделяющую ее на «//», и извлекаю вершину из массива вершин и вершину из массива нормали, устанавливаю нормали вершин в xy и z нормали, сделал объект Face и добавил его в список граней, в которых только 3 или 4 объекта Vertex.

Надеюсь, это объяснение может сделать файл не таким грязным.

Ну, вот код:

package org.ic3d.utils;

import java.io.*;
import org.ic3d.utils.ObjReader.Face.FaceStateException;
import org.lwjgl.opengl.GL11;

public class ObjReader
{   
    public ObjReader(String file)
    {
        try
        {
            BufferedReader reader = new BufferedReader(new FileReader(new File(file)));
            parse(reader);
        }
        catch(Exception e)
        {
            System.out.println(file+" Failed To Load! Can't continue.");
            System.exit(0);
        }
    }

    /**
     * Parse all lines in the BufferedReader to convert the .obj file
     * 
     * @param br - A BufferedReader object pointing to the desired .obj file
     * @throws IOException If the obj file can not be read for any reason.
     * @throws FaceStateException If the obj file is malformed and vertice are added to a face of different shape (tri - quad)
     */
    public void parse(BufferedReader br) throws IOException, FaceStateException
    {
        String s="";

        Vertex[] v1 = new Vertex[15000];
        Vertex[] n1 = new Vertex[15000];

        while((s = br.readLine())!=null)
        {
            if(s.startsWith("v"))
            {
                String[] pv = s.split(" ");

                Vertex vert_0x = new Vertex(Float.parseFloat(pv[1]), Float.parseFloat(pv[2]), Float.parseFloat(pv[3]));

                v1 = appendVert(v1, vert_0x);
            }
            if(s.startsWith("vn"))
            {
                String[] pv = s.split(" ");

                Vertex vert_0x = new Vertex(Float.parseFloat(pv[1]), Float.parseFloat(pv[2]), Float.parseFloat(pv[3]));

                n1 = appendVert(n1, vert_0x);
            }
            if(s.startsWith("f"))
            {
                String[] pv = s.split(" ");

                Vertex[] temp = new Vertex[pv.length-1];

                for(int i=1;i<pv.length;i++)
                {
                    String[] vn = pv[i].split("//");

                    Vertex v = v1[Integer.parseInt(vn[0])];

                    Vertex n = n1[Integer.parseInt(vn[1])];

                    v.setNormals(n.getX(), n.getY(), n.getZ());

                    temp = appendVert(temp, v);
                }
                try
                {
                    Face f = new Face(temp.length==3?Face.GL_FACE_TRI:Face.GL_FACE_QUAD, temp);
                    faces = appendFace(faces, f);
                }
                catch(FaceStateException e)
                {
                    throw e;
                }
            }
        }
    }
    private Vertex[] appendVert(Vertex[] l, Vertex v)
    {
        for(int i=0;i<l.length;i++)
        {
            if(l[i]==null)
            {
                l[i] = v;
                return l;
            }
        }
        System.out.println("Vertex[] can only hold "+l.length+" Vertices at one time");
        return l;
    }
    private Face[] appendFace(Face[] l, Face f)
    {
        for(int i=0;i<l.length;i++)
        {
            if(l[i]==null)
            {
                l[i] = f;
                return l;
            }
        }
        System.out.println("Face[] can only hold "+faces.length+" Faces at one time");
        return l;
    }
    public void renderTri(Face f, float x, float y, float z)
    {
        Vertex[] v = f.getVerts();

        GL11.glBegin(GL11.GL_TRIANGLES);

        Vertex cv = v[0];
        GL11.glNormal3f(cv.getNormalX(), cv.getNormalY(), cv.getNormalZ());
        GL11.glVertex3f(x+cv.getX(), y+cv.getY(), z+cv.getZ());

        cv = v[1];
        GL11.glNormal3f(cv.getNormalX(), cv.getNormalY(), cv.getNormalZ());
        GL11.glVertex3f(x+cv.getX(), y+cv.getY(), z+cv.getZ());

        cv = v[2];
        GL11.glNormal3f(cv.getNormalX(), cv.getNormalY(), cv.getNormalZ());
        GL11.glVertex3f(x+cv.getX(), y+cv.getY(), z+cv.getZ());

        GL11.glEnd();
    }
    public void renderQuad(Face f, float x, float y, float z)
    {
        Vertex[] v = f.getVerts();

        GL11.glBegin(GL11.GL_QUADS);

        Vertex cv = v[0];
        GL11.glNormal3f(cv.getNormalX(), cv.getNormalY(), cv.getNormalZ());
        GL11.glVertex3f(x+cv.getX(), y+cv.getY(), z+cv.getZ());

        cv = v[2];
        GL11.glNormal3f(cv.getNormalX(), cv.getNormalY(), cv.getNormalZ());
        GL11.glVertex3f(x+cv.getX(), y+cv.getY(), z+cv.getZ());

        cv = v[2];
        GL11.glNormal3f(cv.getNormalX(), cv.getNormalY(), cv.getNormalZ());
        GL11.glVertex3f(x+cv.getX(), y+cv.getY(), z+cv.getZ());

        cv = v[3];
        GL11.glNormal3f(cv.getNormalX(), cv.getNormalY(), cv.getNormalZ());
        GL11.glVertex3f(x+cv.getX(), y+cv.getY(), z+cv.getZ());

        GL11.glEnd();
    }
    public void render(float x, float y, float z)
    {
        GL11.glPushMatrix();
        for(Face f : faces)
        {
            if(f==null)
            {
                GL11.glPopMatrix();
                return;
            }
            else
            {
                switch(f.getType())
                {
                    case(3):
                    {
                        renderTri(f, x, y, z);
                    }
                    case(4):
                    {
                        renderQuad(f, x, y, z);
                    }
                }
            }
        }
        GL11.glPopMatrix();
    }
    public int listid=0;
    public Face[] faces = new Face[15000];
    public class Face
    {
        /**
         * Create a new Face object, Faces Hold 3 or 4 Vertex Objects, Polygons not accepted.
         * @param shape
         * @param verts
         * @throws FaceStateException - If the number of vertice in the Vertex[] is not equal to the face type set.
         */
        public Face(int shape, Vertex[] vertlist) throws FaceStateException{

            int vert_n = GL_FACE_NONE-shape;

            if(vertlist.length>vert_n)
            {
                throw new FaceStateException(vert_n+" Vertice faces can not hold "+verts.length+" vertices");
            }
            if(vertlist.length<vert_n)
            {
                throw new FaceStateException(vert_n+" Vertice faces must hold "+vert_n+" vertice, not "+verts.length+" vertices");
            }
            if(vert_n!=3 && vert_n!=4)
            {
                throw new FaceStateException("Faces can only be 3 or 4 vertice. Shapes besides QUAD and TRI are not allowed.");
            }
            type=vert_n;

            verts=vertlist;
        }
        public Vertex[] getVerts()
        {
            return verts;
        }
        public int getType()
        {
            return type;
        }
        public String getType(int i)
        {
            if(i==1)
            {
                return(type==3?"TRI":"QUAD");
            }
            else
            {
                return(type==3?"TRIANGLE":"QUAD");
            }
        }
        private Vertex[] verts;
        public static final int GL_FACE_QUAD = 3;
        public static final int GL_FACE_TRI = 4;
        public static final int GL_FACE_NONE = 7;
        private int type=7;
        public class FaceStateException extends Exception
        {
            public FaceStateException(String s)
            {
                super(s);
            }
            private static final long serialVersionUID = 1L;
        }
    }
    public class Vertex
    {
        public Vertex(float x, float y, float z)
        {
            _x=x;
            _y=y;
            _z=z;
        }
        public void setNormals(float x, float y, float z)
        {
            _nx=x;
            _ny=y;
            _nz=z;
        }
        public float getX()
        {
            return _x;
        }
        public float getY()
        {
            return _y;
        }
        public float getZ()
        {
            return _z;
        }
        public float getNormalX()
        {
            return _nx;
        }
        public float getNormalY()
        {
            return _ny;
        }
        public float getNormalZ()
        {
            return _nz;
        }
        public float[] getNormalXYZ()
        {
            return new float[]{_nx, _ny, _nz};
        }
        public void setXYZ(float x, float y, float z)
        {
            _x=x;
            _y=y;
            _z=z;
        }
        public float[] getXYZ()
        {
            return new float[]{_x, _y, _z};
        }
        private float _x;
        private float _y;
        private float _z;
        private float _nx;
        private float _ny;
        private float _nz;
    }
}

1 Ответ

1 голос
/ 13 декабря 2011

Я считаю, что это довольно простое исправление, GL11.glEnd() действительно не нужно, вы можете запустить другой тип рендеринга, используя begin, даже не заканчивая его первым.Попробуйте вырезать GL11.glEnd() до конца всего скрипта рендеринга, посмотрите, поможет ли это:

public void render()
{
    Object1.render( 5, 0, 5);
    Object1.render(-5, 0,-5);
    Object2.render( 5, 0,-5);
    Object2.render(-5, 0, 5);
    GL11.glEnd();
}
...