我正在和一些朋友一起玩遊戲,爲了讓生活更輕鬆我決定全部使用.obj文件製作3D模型,並導出到程序中3DSMax,Maya和Blender3D。LWJGL .OBJ文件讀取器有時會影響或不渲染文件
因此,我寫了一個.obj文件閱讀器,並在簡單的場景中嘗試過,一些.obj文件呈現良好(如簡單的多維數據集),一些渲染得非常奇怪,然後一些渲染完全沒有。我希望有人能指出我做錯了什麼,下面的代碼包含一個類,其中2個嵌入類,其中一個包含另一個嵌入類。它可能會引起混淆,因此如果需要,您可以複製並粘貼到文件中以便於閱讀。
腳本在文件中逐行讀取,如果它以「v」(頂點)開頭,則按空格分割該行,並採用索引1 2和3(xy和z),並將整數值存儲在稱爲頂點的類,並將其添加到頂點對象的數組中。頂點對象就像一個矢量一樣,只有它包含兩個矢量,一個用於位置,另一個用於法線。
如果行以「vn」(Vertex Normal)開頭,則它將行分割爲「」,並採用索引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;
}
}
我不知道你有沒有遇到過,但在使用代碼時,我不得不遞減索引查找當建立的面孔,以使其發揮作用。 –