LWJGL .OBJ文件阅读器有时会变形或不渲染文件

时间:2011-12-10 15:38:09

标签: java render lwjgl object-files

我正和一些朋友一起开展游戏,为了让生活更轻松,我决定使用.obj文件制作所有3D模型,并在3DSMax,Maya和Blender3D等程序中导出。

所以我编写了一个.obj文件阅读器并在一个简单的场景中尝试了它,一些.obj文件渲染得很好(就像一个简单的立方体),有些渲染真的很奇怪,然后有些根本没有渲染。我希望有人可以向我指出我做错了什么,下面的代码包含一个类,其中包含2个嵌入式类,其中一个包含另一个嵌入类。它可能会让人感到困惑,因此您可以复制并粘贴到文件中,以便在需要时更容易阅读。

脚本在文件中逐行读取,如果以“v”(顶点)开头,则按空格分割行,并获取索引1 2和3(xy和z)并将整数值存储在类中称为Vertex,并将其添加到Vertex对象数组中。顶点对象就像一个向量,只有它包含两个向量,一个用于位置,一个用于法线。

如果该行以“vn”(顶点法线)开头,则将该行拆分为“”,并将索引1 2和3添加到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 个答案:

答案 0 :(得分:1)

我相信这是一个相当简单的修复,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();
}