我正和一些朋友一起开展游戏,为了让生活更轻松,我决定使用.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;
}
}
答案 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();
}