📄 filemesh.java
字号:
package org.sunflow.core.tesselatable;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import org.sunflow.SunflowAPI;
import org.sunflow.core.ParameterList;
import org.sunflow.core.PrimitiveList;
import org.sunflow.core.Tesselatable;
import org.sunflow.core.ParameterList.InterpolationType;
import org.sunflow.core.primitive.TriangleMesh;
import org.sunflow.math.BoundingBox;
import org.sunflow.math.Matrix4;
import org.sunflow.math.Point3;
import org.sunflow.math.Vector3;
import org.sunflow.system.Memory;
import org.sunflow.system.UI;
import org.sunflow.system.UI.Module;
import org.sunflow.util.FloatArray;
import org.sunflow.util.IntArray;
public class FileMesh implements Tesselatable {
private String filename = null;
private boolean smoothNormals = false;
public BoundingBox getWorldBounds(Matrix4 o2w) {
// world bounds can't be computed without reading file
// return null so the mesh will be loaded right away
return null;
}
public PrimitiveList tesselate() {
if (filename.endsWith(".ra3")) {
try {
UI.printInfo(Module.GEOM, "RA3 - Reading geometry: \"%s\" ...", filename);
File file = new File(filename);
FileInputStream stream = new FileInputStream(filename);
MappedByteBuffer map = stream.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length());
map.order(ByteOrder.LITTLE_ENDIAN);
IntBuffer ints = map.asIntBuffer();
FloatBuffer buffer = map.asFloatBuffer();
int numVerts = ints.get(0);
int numTris = ints.get(1);
UI.printInfo(Module.GEOM, "RA3 - * Reading %d vertices ...", numVerts);
float[] verts = new float[3 * numVerts];
for (int i = 0; i < verts.length; i++)
verts[i] = buffer.get(2 + i);
UI.printInfo(Module.GEOM, "RA3 - * Reading %d triangles ...", numTris);
int[] tris = new int[3 * numTris];
for (int i = 0; i < tris.length; i++)
tris[i] = ints.get(2 + verts.length + i);
stream.close();
UI.printInfo(Module.GEOM, "RA3 - * Creating mesh ...");
return generate(tris, verts, smoothNormals);
} catch (FileNotFoundException e) {
e.printStackTrace();
UI.printError(Module.GEOM, "Unable to read mesh file \"%s\" - file not found", filename);
} catch (IOException e) {
e.printStackTrace();
UI.printError(Module.GEOM, "Unable to read mesh file \"%s\" - I/O error occured", filename);
}
} else if (filename.endsWith(".obj")) {
int lineNumber = 1;
try {
UI.printInfo(Module.GEOM, "OBJ - Reading geometry: \"%s\" ...", filename);
FloatArray verts = new FloatArray();
IntArray tris = new IntArray();
FileReader file = new FileReader(filename);
BufferedReader bf = new BufferedReader(file);
String line;
while ((line = bf.readLine()) != null) {
if (line.startsWith("v")) {
String[] v = line.split("\\s+");
verts.add(Float.parseFloat(v[1]));
verts.add(Float.parseFloat(v[2]));
verts.add(Float.parseFloat(v[3]));
} else if (line.startsWith("f")) {
String[] f = line.split("\\s+");
if (f.length == 5) {
tris.add(Integer.parseInt(f[1]) - 1);
tris.add(Integer.parseInt(f[2]) - 1);
tris.add(Integer.parseInt(f[3]) - 1);
tris.add(Integer.parseInt(f[1]) - 1);
tris.add(Integer.parseInt(f[3]) - 1);
tris.add(Integer.parseInt(f[4]) - 1);
} else if (f.length == 4) {
tris.add(Integer.parseInt(f[1]) - 1);
tris.add(Integer.parseInt(f[2]) - 1);
tris.add(Integer.parseInt(f[3]) - 1);
}
}
if (lineNumber % 100000 == 0)
UI.printInfo(Module.GEOM, "OBJ - * Parsed %7d lines ...", lineNumber);
lineNumber++;
}
file.close();
UI.printInfo(Module.GEOM, "OBJ - * Creating mesh ...");
return generate(tris.trim(), verts.trim(), smoothNormals);
} catch (FileNotFoundException e) {
e.printStackTrace();
UI.printError(Module.GEOM, "Unable to read mesh file \"%s\" - file not found", filename);
} catch (NumberFormatException e) {
e.printStackTrace();
UI.printError(Module.GEOM, "Unable to read mesh file \"%s\" - syntax error at line %d", lineNumber);
} catch (IOException e) {
e.printStackTrace();
UI.printError(Module.GEOM, "Unable to read mesh file \"%s\" - I/O error occured", filename);
}
} else if (filename.endsWith(".stl")) {
try {
UI.printInfo(Module.GEOM, "STL - Reading geometry: \"%s\" ...", filename);
FileInputStream file = new FileInputStream(filename);
DataInputStream stream = new DataInputStream(new BufferedInputStream(file));
file.skip(80);
int numTris = getLittleEndianInt(stream.readInt());
UI.printInfo(Module.GEOM, "STL - * Reading %d triangles ...", numTris);
long filesize = new File(filename).length();
if (filesize != (84 + 50 * numTris)) {
UI.printWarning(Module.GEOM, "STL - Size of file mismatch (expecting %s, found %s)", Memory.bytesToString(84 + 14 * numTris), Memory.bytesToString(filesize));
return null;
}
int[] tris = new int[3 * numTris];
float[] verts = new float[9 * numTris];
for (int i = 0, i3 = 0, index = 0; i < numTris; i++, i3 += 3) {
// skip normal
stream.readInt();
stream.readInt();
stream.readInt();
for (int j = 0; j < 3; j++, index += 3) {
tris[i3 + j] = i3 + j;
// get xyz
verts[index + 0] = getLittleEndianFloat(stream.readInt());
verts[index + 1] = getLittleEndianFloat(stream.readInt());
verts[index + 2] = getLittleEndianFloat(stream.readInt());
}
stream.readShort();
if ((i + 1) % 100000 == 0)
UI.printInfo(Module.GEOM, "STL - * Parsed %7d triangles ...", i + 1);
}
file.close();
// create geometry
UI.printInfo(Module.GEOM, "STL - * Creating mesh ...");
if (smoothNormals)
UI.printWarning(Module.GEOM, "STL - format does not support shared vertices - normal smoothing disabled");
return generate(tris, verts, false);
} catch (FileNotFoundException e) {
e.printStackTrace();
UI.printError(Module.GEOM, "Unable to read mesh file \"%s\" - file not found", filename);
} catch (IOException e) {
e.printStackTrace();
UI.printError(Module.GEOM, "Unable to read mesh file \"%s\" - I/O error occured", filename);
}
} else
UI.printWarning(Module.GEOM, "Unable to read mesh file \"%s\" - unrecognized format", filename);
return null;
}
private TriangleMesh generate(int[] tris, float[] verts, boolean smoothNormals) {
ParameterList pl = new ParameterList();
pl.addIntegerArray("triangles", tris);
pl.addPoints("points", InterpolationType.VERTEX, verts);
if (smoothNormals) {
float[] normals = new float[verts.length]; // filled with 0's
Point3 p0 = new Point3();
Point3 p1 = new Point3();
Point3 p2 = new Point3();
Vector3 n = new Vector3();
for (int i3 = 0; i3 < tris.length; i3 += 3) {
int v0 = tris[i3 + 0];
int v1 = tris[i3 + 1];
int v2 = tris[i3 + 2];
p0.set(verts[3 * v0 + 0], verts[3 * v0 + 1], verts[3 * v0 + 2]);
p1.set(verts[3 * v1 + 0], verts[3 * v1 + 1], verts[3 * v1 + 2]);
p2.set(verts[3 * v2 + 0], verts[3 * v2 + 1], verts[3 * v2 + 2]);
Point3.normal(p0, p1, p2, n); // compute normal
// add face normal to each vertex
// note that these are not normalized so this in fact weights
// each normal by the area of the triangle
normals[3 * v0 + 0] += n.x;
normals[3 * v0 + 1] += n.y;
normals[3 * v0 + 2] += n.z;
normals[3 * v1 + 0] += n.x;
normals[3 * v1 + 1] += n.y;
normals[3 * v1 + 2] += n.z;
normals[3 * v2 + 0] += n.x;
normals[3 * v2 + 1] += n.y;
normals[3 * v2 + 2] += n.z;
}
// normalize all the vectors
for (int i3 = 0; i3 < normals.length; i3 += 3) {
n.set(normals[i3 + 0], normals[i3 + 1], normals[i3 + 2]);
n.normalize();
normals[i3 + 0] = n.x;
normals[i3 + 1] = n.y;
normals[i3 + 2] = n.z;
}
pl.addVectors("normals", InterpolationType.VERTEX, normals);
}
TriangleMesh m = new TriangleMesh();
if (m.update(pl, null))
return m;
// something failed in creating the mesh, the error message will be
// printed by the mesh itself - no need to repeat it here
return null;
}
public boolean update(ParameterList pl, SunflowAPI api) {
String file = pl.getString("filename", null);
if (file != null)
filename = api.resolveIncludeFilename(file);
smoothNormals = pl.getBoolean("smooth_normals", smoothNormals);
return filename != null;
}
private int getLittleEndianInt(int i) {
// input integer has its bytes in big endian byte order
// swap them around
return (i >>> 24) | ((i >>> 8) & 0xFF00) | ((i << 8) & 0xFF0000) | (i << 24);
}
private float getLittleEndianFloat(int i) {
// input integer has its bytes in big endian byte order
// swap them around and interpret data as floating point
return Float.intBitsToFloat(getLittleEndianInt(i));
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -