目前,我正在为我的计算机图形课程开发一种高级光线跟踪器 . 之前的光线跟踪器使用简单的形状,如盒子和球体 . 但是,我们希望它与网格一起使用 . 目前,我有代码将读取网格,设置网格的数据,并且可以计算网格的法线 . 我有一些问题 . 首先,一些xml文件包含这些网格的法线,而某些xml文件则不包含 . 首先,我想知道如何解释这一点,以便我可以在需要时计算法线 . 其次,有一种交叉方法,因为它从Surface延伸 . 但是,交叉方法需要光线,最小点和最大点;但是对于网格,你可以根据它的顶点来计算t值;那我该怎么办呢?
package ray.surface;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.PrintWriter;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import javax.vecmath.Matrix4f;
import javax.vecmath.Point3f;
import javax.vecmath.Vector3f;
import ray.Ray;
import ray.math.Point3;
import ray.math.Vector3;
import com.jogamp.opengl.GL2;
import com.jogamp.common.nio.Buffers;
public class Mesh extends Surface{
/** The number of vertices in the mesh * */
protected int numVertices;
/** The number of triangles in the mesh * */
protected int numTriangles;
/** The vertex array -- always present in each mesh * */
protected FloatBuffer verts;
/** The normal coordinate array -- may be null * */
protected FloatBuffer normals;
/** Mesh triangle objects for each triangle. */
protected IntBuffer triangles = null;
static float[] vertices;
static float[] normal;
static int[] triangle;
public Mesh() { }
public Mesh(float[] verts, int[] tris, float[] normals) {
// check the inputs
if (verts.length % 3 != 0)
throw new Error("Vertex array for a triangle mesh is not a multiple of 3.");
if (tris.length % 3 != 0)
throw new Error("Triangle array for a triangle mesh is not a multiple of 3.");
setMeshData(verts, tris, normals);
}
public FloatBuffer getNormals() {
return normals;
}
public FloatBuffer getVerts() {
return verts;
}
private void setMeshData(float[] verts, int[] tris, float[] normals) {
this.verts = Buffers.newDirectFloatBuffer(verts.length);
this.triangles = Buffers.newDirectIntBuffer(tris.length);
this.normals = Buffers.newDirectFloatBuffer(normals.length);
this.numVertices = verts.length / 3;
this.numTriangles = tris.length / 3;
this.verts.put(verts);
this.triangles.put(tris);
this.normals.put(normals);
}
public int getNumTriangles() {
return numTriangles;
}
public int getNumVertices() {
return numVertices;
}
public void setData(String fileName) {
readMesh(this, "./scenes/" + fileName);
}
/**
* Draws this mesh
* @param glD
*/
public void render(GL2 gl) {
verts.rewind();
normals.rewind();
triangles.rewind();
gl.glBegin(GL2.GL_TRIANGLES);
gl.glEnable(GL2.GL_TRIANGLES);
gl.glCullFace(GL2.GL_BACK);
gl.glFrontFace(GL2.GL_CW);
while (triangles.hasRemaining())
{
int[] vertices = new int[3];
triangles.get(vertices);
for (int i = 0; i < 3; i++)
{
float[] vertex = new float[3];
float[] normal = new float[3];
int offset = 3 * vertices[i];
vertex[0] = verts.get(offset);
vertex[1] = verts.get(offset+1);
vertex[2] = verts.get(offset+2);
normal[0] = normals.get(offset);
normal[1] = normals.get(offset+1);
normal[2] = normals.get(offset+2);
gl.glNormal3fv(normal, 0);
gl.glVertex3fv(vertex, 0);
}
}
gl.glEnd();
// TODO: draw the mesh using OpenGL calls
}
/**
* Write this mesh to the supplied print writer under the given transform
* @param currMat
*/
public void writeMesh(Matrix4f currMat, PrintWriter pw) {
pw.println(numVertices);
pw.println(numTriangles);
//Write the vertices
Point3f currVert = new Point3f();
pw.println("vertices");
for(int i = 0; i < numVertices; i++) {
currVert.x = verts.get(3*i);
currVert.y = verts.get(3*i+1);
currVert.z = verts.get(3*i+2);
currMat.transform(currVert);
pw.println(currVert.x);
pw.println(currVert.y);
pw.println(currVert.z);
}
//Triangles
pw.println("triangles");
for(int i = 0; i < triangles.capacity(); i++) {
pw.println(triangles.get(i));
}
//Normals
Vector3f currNorm = new Vector3f();
Matrix4f invTrans = new Matrix4f(currMat);
invTrans.transpose();
invTrans.invert();
pw.println("normals");
for(int i = 0; i < numVertices; i++) {
currNorm.x = normals.get(3*i);
currNorm.y = normals.get(3*i+1);
currNorm.z = normals.get(3*i+2);
invTrans.transform(currNorm);
currNorm.normalize();
pw.println(currNorm.x);
pw.println(currNorm.y);
pw.println(currNorm.z);
}
}
public static final void readMesh(Mesh outputMesh, String fileName) {
float[] vertices;
int[] triangles;
float[] normals;
try {
// Create a buffered reader for the mesh file
BufferedReader fr = new BufferedReader(new FileReader(fileName));
// Read the size of the file
int nPoints = Integer.parseInt(fr.readLine());
int nPolys = Integer.parseInt(fr.readLine());
// Create arrays for mesh data
vertices = new float[nPoints*3];
triangles = new int[nPolys*3];
normals = null;
// read vertices
if (!fr.readLine().equals("vertices")) {
fr.close();
throw new RuntimeException("Broken file - vertices expected");
}
for (int i=0; i<vertices.length; ++i) {
vertices[i] = Float.parseFloat(fr.readLine());
}
// read triangles
if (!fr.readLine().equals("triangles")) {
fr.close();
throw new RuntimeException("Broken file - triangles expected.");
}
for (int i=0; i<triangles.length; ++i) {
triangles[i] = Integer.parseInt(fr.readLine());
}
String line = fr.readLine();
if (line != null && line.equals("normals")) {
normals = new float[nPoints*3];
for (int i=0; i<normals.length; ++i) {
normals[i] = Float.parseFloat(fr.readLine());
}
}
fr.close();
}
catch (Exception e) {
throw new Error("Error reading mesh file: "+fileName);
}
if(normals == null)
{
SceneMesh(fileName);
outputMesh.setMeshData(vertices, triangle, normal);
}
else
{
//Set the data in the output Mesh
outputMesh.setMeshData(vertices, triangles, normals);
}
System.out.println("Read mesh of " + vertices.length + " verts");
}
@Override
public double intersect(Ray ray, double min, double max)
{
Point3 p = ray.p;
Vector3 d = ray.d;
// TODO Auto-generated method stub
return 1;
}
@Override
public Vector3 getNormal(Point3 p)
{
// TODO Auto-generated method stub
return null;
}
protected static void computeNormals(int nPolys) {
// compute normals
normal = new float[nPolys * 3]; // one normal per triangle. To heck with
// smoothed meshes
Vector3f v0 = new Vector3f();
Vector3f v1 = new Vector3f();
Vector3f v2 = new Vector3f();
Vector3f normall = new Vector3f();
int v0i, v1i, v2i;
for (int i = 0; i < nPolys; ++i) {
v0i = 3 * triangle[3 * i + 0];
v1i = 3 * triangle[3 * i + 1];
v2i = 3 * triangle[3 * i + 2];
v0.set(vertices[v0i], vertices[v0i + 1], vertices[v0i + 2]);
v1.set(vertices[v1i], vertices[v1i + 1], vertices[v1i + 2]);
v2.set(vertices[v2i], vertices[v2i + 1], vertices[v2i + 2]);
v1.sub(v1, v0);
v2.sub(v2, v0);
normall.cross(v1, v2);
normall.normalize();
normal[3 * i + 0] = normall.x;
normal[3 * i + 1] = normall.y;
normal[3 * i + 2] = normall.z;
}
}
public static void SceneMesh(String meshFile) {
try {
BufferedReader fr = new BufferedReader(new FileReader(meshFile));
int nPoints = Integer.parseInt(fr.readLine());
int nPolys = Integer.parseInt(fr.readLine());
vertices = new float[nPoints * 3];
triangle = new int[nPolys * 3];
boolean vertsRead = false;
boolean trisRead = false;
String line = fr.readLine();
while(line != null) {
if(line.equals("vertices")) {
for (int i = 0; i < vertices.length; ++i) {
vertices[i] = Float.parseFloat(fr.readLine());
}
vertsRead = true;
}
else if( line.equals("triangles")) {
for (int i = 0; i < triangle.length; ++i) {
triangle[i] = Integer.parseInt(fr.readLine());
}
trisRead = true;
}
line = fr.readLine();
}
// sanity checks
if( !vertsRead )
throw new Exception("Broken file - vertices expected");
if( !trisRead )
throw new Exception("Broken file - triangles expected.");
computeNormals(nPolys);
}
catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}