|
发表于 2011-4-10 16:11:00
|
显示全部楼层
Re: 求解:openGL加载3DS文件的问题
正好在学习,望同大家交流!
使用java写的,请参考!
import com.sun.opengl.util.BufferUtil;
import java.awt.Color;
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.channels.FileChannel;
import java.util.Hashtable;
import java.util.Vector;
public class ThreeDSParser {
public int len = 0;
public Vector<Obj> objs = new Vector<Obj>();
public Hashtable<String,Material> nameMatHt = new Hashtable<String,Material>();
public Material curMat;
public Obj curObj;
public IntBuffer curIndices;
public FloatBuffer curTexsBuff;
public IntBuffer trimeshs;
public int numOfTrimesh;
public int numOfVertices;
public float[] camera = new float[9];
public float[] spot_position = new float[4];
public float[] spot_direction = new float[4];
public float maxCutoff , minCutoff;
public float[] lightColor = new float[4];
public float[][] material = new float[4][4];
public float ou, ov, tu=1f, tv=1f;
public ThreeDSParser(){}
public void parseFile(String filename){
try {
FileInputStream fis = new FileInputStream(filename);
FileChannel fc = fis.getChannel();
ByteBuffer bb = ByteBuffer.allocate((int)fc.size());
bb = bb.order(ByteOrder.LITTLE_ENDIAN);
bb.clear();
fc.read(bb);
bb.flip();
while (bb.hasRemaining()) {
int id = bb.getShort() &0xffff;
int length = bb.getInt();
switch(id) {
case 0x4d4d:
//---------------文件的头部---------------//
break;
case 0x3d3d:
//---------------编辑块头部----------------//
break;
case 0x4000:
//----------------对象头部-----------------//
//----------------6个字节的对象名称-------------//
curObj = new Obj();
byte[] b = new byte[6];
StringBuilder sb = new StringBuilder();
byte t = 0;
while((t=bb.get())!=0){
sb.append((char)t);
}
curObj.objName = sb.toString();
break;
case 0x4100:
break;
case 0x4110:
numOfVertices = bb.getShort();
//一个用于存放所有顶点的坐标x, y, z的数组
curObj.vertsBuff = BufferUtil.newFloatBuffer(3*numOfVertices);
curObj.vertsBuff.clear();
//一个用于存放顶点法线坐标的数组
curObj.normsBuff = BufferUtil.newFloatBuffer(3*numOfVertices);
curObj.normsBuff.clear();
for (int j=0;j<numOfVertices;j++){
//放入x坐标
curObj.vertsBuff.put(bb.getFloat());
curObj.normsBuff.put(0.0f);
//放入y坐标
curObj.vertsBuff.put(bb.getFloat());
curObj.normsBuff.put(0.0f);
//放入z坐标
curObj.vertsBuff.put(bb.getFloat());
curObj.normsBuff.put(0.0f);
}
curObj.vertsBuff.flip();
curObj.normsBuff.flip();
curObj.texsBuff = null;
break;
case 0x4120:
/*================面====================*/
numOfTrimesh = bb.getShort()&0xffff;
curObj.planeNormsBuff = BufferUtil.newFloatBuffer(3*numOfTrimesh);
curObj.planeNormsBuff.clear();
trimeshs = BufferUtil.newIntBuffer(3*numOfTrimesh);
trimeshs.clear();
for (int j=0; j<numOfTrimesh; j++) {
//面三个顶点A, B, C的索引
int ai = bb.getShort()&0xffff; //A
int bi = bb.getShort()&0xffff; //B
int ci = bb.getShort()&0xffff; //C
trimeshs.put(ai);
trimeshs.put(bi);
trimeshs.put(ci);
//面的三个点坐标用于计算面的法线
triNormalVector(ai,bi,ci);
//跳过下面一个2个字节的数据
bb.position(bb.position()+2);
}
curObj.planeNormsBuff.flip();
trimeshs.flip();
break;
case 0x4130:
//----------------面所使用的材质名称-------------------//
//---------------先读一个以0结束的字符串--------------//
//------接下来读2个字节的使用该材质的面数量------------//
//-------------再读2个字节的所有面的索引---------------//
StringBuilder sb2 = new StringBuilder();
byte t2 = 0;
while((t2=bb.get())!=0){
sb2.append((char)t2);
}
String materialName = sb2.toString().trim();
curObj.matNames.add(materialName);
int num = bb.getShort();
curIndices = BufferUtil.newIntBuffer(3*num);
curIndices.clear();
for (int j=0;j<num;j++) {
int i = bb.getShort();
int v1 = trimeshs.get(3*i);
int v2 = trimeshs.get(3*i + 1);
int v3 = trimeshs.get(3*i + 2);
curIndices.put(v1);
curIndices.put(v2);
curIndices.put(v3);
}
curIndices.flip();
curObj.indices.add(curIndices);
break;
case 0x4140:
//-----------------------项点纹理映射坐标----------------//
//-----------------------读取顶点数量---------------------//
numOfVertices = bb.getShort();
//-----------------------用于存放纹理坐标的内存-------------------//
curObj.texsBuff = BufferUtil.newFloatBuffer(2*numOfVertices);
curObj.texsBuff.clear();
//---------------------读纹理坐标--------------//
for (int j=0;j<numOfVertices;j++){
curObj.texsBuff.put(bb.getFloat());
curObj.texsBuff.put(bb.getFloat());
}
curObj.texsBuff.flip();
break;
case 0x4160:
objs.add(curObj);
bb.position(bb.position()+length-6);
break;
case 0xafff:
//-----------------材质头部-----------------//
curMat = new Material();
break;
case 0xa000:
//----------------材质的名称------------------//
b = new byte[length-6];
for (int j=0; j<length-6; j++) {
b[j] = bb.get();
}
String matName = new String(b,"gbk").trim();
if( nameMatHt.get(matName) == null )
nameMatHt.put(matName, curMat);
break;
case 0xa200:
//-------------------纹理头部-----------------//
break;
case 0xa300:
//-------------------纹理的文件名-------------//
b = new byte[length-6];
for (int j=0; j<length-6; j++) {
b[j] = bb.get();
}
curMat.texFileName = new String(b,"gbk").trim().toLowerCase();
break;
case 0xa353:
//---------------------纹理偏移值v--------------//
curMat.ov = bb.getFloat();
break;
case 0xa354:
//------------------纹理平铺u---------------------//
curMat.tu = bb.getFloat();
break;
case 0xa356:
//------------------纹理平铺v---------------------//
curMat.tv = bb.getFloat();
break;
case 0xa358:
//------------------纹理偏移值u---------------------//
curMat.ou = bb.getFloat();
break;
case 0xa010:
//--------------------环境光--------------------//
bb.position(bb.position()+6);
int ar = bb.get()&0xff;
int ag = bb.get()&0xff;
int ab = bb.get()&0xff;
curMat.ambient = new Color(ar,ag,ab, 255).getComponents(null);
break;
case 0xa020:
//---------------------漫射光------------------//
bb.position(bb.position()+6);
int dr = bb.get()&0xff;
int dg = bb.get()&0xff;
int db = bb.get()&0xff;
curMat.diffuse = new Color(dr,dg,db, 255).getComponents(null);
break;
case 0xa030:
//-------------高光反射----------------------//
bb.position(bb.position()+6);
int sr = bb.get()&0xff;
int sg = bb.get()&0xff;
int sbb = bb.get()&0xff;
curMat.specular = new Color(sr,sg,sbb, 255).getComponents(null);
break;
case 0xa041:
//-------------------光泽度--------------------//
bb.position(bb.position()+6);
curMat.shininess = bb.get()&0xff;
bb.position(bb.position()+1);
break;
case 0x4600:
//------------------光源的位置坐标-----------------//
spot_position[0] = bb.getFloat(); //光源的位置x
spot_position[1] = bb.getFloat(); //光源的位置y
spot_position[2] = bb.getFloat(); //光源的位置z
spot_position[3] = 1.0f;
break;
case 0x4610:
//------------------光源的目标位置坐标(xref,yref,zref)-----------------//
spot_direction[0] = bb.getFloat();
spot_direction[1] = bb.getFloat();
spot_direction[2] = bb.getFloat();
// spot_direction[0] -= spot_position[0];
// spot_direction[1] -= spot_position[1];
// spot_direction[2] -= spot_position[2];
spot_direction[3] = 1.0f;
minCutoff = bb.getFloat()/2.0f; //截止角
maxCutoff = bb.getFloat()/2.0f;
bb.position(bb.position()+length-6-20);
break;
case 0x10:
//---------------光源的颜色------------------------//
new Color(bb.getFloat(),bb.getFloat(),bb.getFloat(),1.0f).getComponents(lightColor);
break;
case 0x4700:
camera[0] = bb.getFloat(); //观察点x0
camera[1] = bb.getFloat(); //观察点y0
camera[2] = bb.getFloat(); //观察点z0
camera[3] = bb.getFloat(); //瞄准点xref
camera[4] = bb.getFloat(); //瞄准点yref
camera[5] = bb.getFloat(); //瞄准点zref
//跳过下面一个4个字节的数据
bb.position(bb.position()+4);
camera[6] = bb.getFloat(); //相机的视角
break;
case 0x4720:
camera[7] = bb.getFloat(); //近点
camera[8] = bb.getFloat(); //远点
break;
break;
default:
bb.position(bb.position()+length-6);
}
}
} catch (Exception e){
e.printStackTrace();
System.exit(1);
}
}
public void triNormalVector(int ai, int bi, int ci){
float[] v1 = new float[3];
float[] v2 = new float[3];
float[] v3 = new float[3];
v1[0] = curObj.vertsBuff.get(3*ci) - curObj.vertsBuff.get(3*bi);
v1[1] = curObj.vertsBuff.get(3*ci+1) - curObj.vertsBuff.get(3*bi+1);
v1[2] = curObj.vertsBuff.get(3*ci+2) - curObj.vertsBuff.get(3*bi+2);
v2[0] = curObj.vertsBuff.get(3*ai) - curObj.vertsBuff.get(3*bi);
v2[1] = curObj.vertsBuff.get(3*ai+1) - curObj.vertsBuff.get(3*bi+1);
v2[2] = curObj.vertsBuff.get(3*ai+2) - curObj.vertsBuff.get(3*bi+2);
v3[0] = v1[1]*v2[2] - v1[2]*v2[1];
v3[1] = v1[2]*v2[0] - v1[0]*v2[2];
v3[2] = v1[0]*v2[1] - v1[1]*v2[0];
curObj.planeNormsBuff.put(v3[0]);
curObj.planeNormsBuff.put(v3[1]);
curObj.planeNormsBuff.put(v3[2]);
//同原来这三个顶点的法向量进行矢量和
//a点的法线(x,y,z)
curObj.normsBuff.put(3*ai,curObj.normsBuff.get(3*ai)+v3[0]);
curObj.normsBuff.put(3*ai+1,curObj.normsBuff.get(3*ai+1)+v3[1]);
curObj.normsBuff.put(3*ai+2,curObj.normsBuff.get(3*ai+2)+v3[2]);
//
// b点的法线(x,y,z)
curObj.normsBuff.put(3*bi,curObj.normsBuff.get(3*bi)+v3[0]);
curObj.normsBuff.put(3*bi+1,curObj.normsBuff.get(3*bi+1)+v3[1]);
curObj.normsBuff.put(3*bi+2,curObj.normsBuff.get(3*bi+2)+v3[2]);
//
// c点的法线(x,y,z)
curObj.normsBuff.put(3*ci,curObj.normsBuff.get(3*ci)+v3[0]);
curObj.normsBuff.put(3*ci+1,curObj.normsBuff.get(3*ci+1)+v3[1]);
curObj.normsBuff.put(3*ci+2,curObj.normsBuff.get(3*ci+2)+v3[2]);
}
}
public class Material {
public float[] ambient = new float[3];
public float[] diffuse = new float[3];
public float[] specular = new float[3];
public float shininess;
public String texFileName = null;
float ou = 0f;
float tu = 1.0f;
float ov = 0f;
float tv = 1.0f;
}
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.Vector;
public class Obj {
public String objName;
public Vector<String> matNames = new Vector<String>();
public FloatBuffer vertsBuff;
public FloatBuffer normsBuff;
public FloatBuffer texsBuff;
public Vector<IntBuffer> indices = new Vector<IntBuffer>();
public FloatBuffer planeNormsBuff;
}
public void reshape(GLAutoDrawable drawable, int x, int y, int w, int h){
GL gl = drawable.getGL();
GLU glu = new GLU();
gl.glViewport(x, y, w, h);
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glLoadIdentity();
glu.gluPerspective(p.camera[6], w/h, 0.1, 10000);
gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glLoadIdentity();
glu.gluLookAt(p.camera[0], p.camera[1], p.camera[2], p.camera[3], p.camera[4], p.camera[5], 0, 0, 1);
}
public void display(GLAutoDrawable drawable){
GL gl = drawable.getGL();
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT );
gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, p.spot_position, 0);
renderScene(gl);
gl.glFlush();
}
public void renderScene(GL gl){
for (int i=0; i<p.objs.size(); i++) {
Obj obj = p.objs.elementAt(i);
for (int j=0; j<obj.matNames.size(); j++){
String matName = obj.matNames.elementAt(j);
Material mat = p.nameMatHt.get(matName);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, mat.ambient, 0);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_DIFFUSE, mat.diffuse, 0);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, mat.specular,0);
gl.glMaterialf(GL.GL_FRONT, GL.GL_SHININESS, mat.shininess);
IntBuffer indice = obj.indices.elementAt(j);
if(mat.texFileName == null) {
gl.glDisable(GL.GL_TEXTURE_2D);
gl.glBegin(GL.GL_TRIANGLES);
for (int k=0,l=0; k<indice.capacity(); k+=3,l++) {
int v1 = indice.get(k);
int v2 = indice.get(k+1);
int v3 = indice.get(k+2);
// gl.glNormal3f(obj.planeNormsBuff.get(3*l),obj.planeNormsBuff.get(3*l + 1),obj.planeNormsBuff.get(3*l + 2));
gl.glNormal3f(obj.normsBuff.get(3*v1),obj.normsBuff.get(3*v1 + 1),obj.normsBuff.get(3*v1 + 2));
gl.glVertex3f(obj.vertsBuff.get(3*v1),obj.vertsBuff.get(3*v1 + 1),obj.vertsBuff.get(3*v1 + 2));
gl.glNormal3f(obj.normsBuff.get(3*v2),obj.normsBuff.get(3*v2 + 1),obj.normsBuff.get(3*v2 + 2));
gl.glVertex3f(obj.vertsBuff.get(3*v2),obj.vertsBuff.get(3*v2 + 1),obj.vertsBuff.get(3*v2 + 2));
gl.glNormal3f(obj.normsBuff.get(3*v3),obj.normsBuff.get(3*v3 + 1),obj.normsBuff.get(3*v3 + 2));
gl.glVertex3f(obj.vertsBuff.get(3*v3),obj.vertsBuff.get(3*v3 + 1),obj.vertsBuff.get(3*v3 + 2));
}
gl.glEnd();
}
else {
gl.glEnable(GL.GL_TEXTURE_2D);
try {
t = TextureIO.newTexture(new File("d:/images/"+mat.texFileName), false);
t.setTexParameteri(GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
t.setTexParameteri(GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
t.setTexParameteri(GL.GL_TEXTURE_WRAP_S, GL.GL_REPEAT);
t.setTexParameteri(GL.GL_TEXTURE_WRAP_T, GL.GL_REPEAT);
t.bind();
} catch (Exception e) {
e.printStackTrace();
}
gl.glBegin(GL.GL_TRIANGLES);
for (int k=0, l=0; k<indice.capacity(); k+=3,l++) {
int v1 = indice.get(k);
int v2 = indice.get(k+1);
int v3 = indice.get(k+2);
// gl.glNormal3f(obj.planeNormsBuff.get(3*l),obj.planeNormsBuff.get(3*l + 1),obj.planeNormsBuff.get(3*l + 2));
gl.glNormal3f(obj.normsBuff.get(3*v1),obj.normsBuff.get(3*v1 + 1),obj.normsBuff.get(3*v1 + 2));
float tx1 = (obj.texsBuff.get(2*v1) - mat.ou - 0.5f)*mat.tu + 0.5f;
float ty1 = 1.5f - (obj.texsBuff.get(2*v1 + 1) - mat.ov - 0.5f)*mat.tv;
gl.glTexCoord2f(tx1, ty1);
gl.glVertex3f(obj.vertsBuff.get(3*v1),obj.vertsBuff.get(3*v1 + 1),obj.vertsBuff.get(3*v1 + 2));
gl.glNormal3f(obj.normsBuff.get(3*v2),obj.normsBuff.get(3*v2 + 1),obj.normsBuff.get(3*v2 + 2));
float tx2 = (obj.texsBuff.get(2*v2) - mat.ou - 0.5f)*mat.tu + 0.5f;
float ty2 = 1.5f - (obj.texsBuff.get(2*v2 + 1) - mat.ov - 0.5f)*mat.tv;
gl.glTexCoord2f(tx2, ty2);
gl.glVertex3f(obj.vertsBuff.get(3*v2),obj.vertsBuff.get(3*v2 + 1),obj.vertsBuff.get(3*v2 + 2));
gl.glNormal3f(obj.normsBuff.get(3*v3),obj.normsBuff.get(3*v3 + 1),obj.normsBuff.get(3*v3 + 2));
float tx3 = (obj.texsBuff.get(2*v3) - mat.ou - 0.5f)*mat.tu + 0.5f;
float ty3 = 1.5f - (obj.texsBuff.get(2*v3 + 1) - mat.ov - 0.5f)*mat.tv;
gl.glTexCoord2f(tx3, ty3);
gl.glVertex3f(obj.vertsBuff.get(3*v3),obj.vertsBuff.get(3*v3 + 1),obj.vertsBuff.get(3*v3 + 2));
}
gl.glEnd();
}
}
}
}
|
|