目前,我正在为我的计算机图形课程开发一种高级光线跟踪器 . 之前的光线跟踪器使用简单的形状,如盒子和球体 . 但是,我们希望它与网格一起使用 . 目前,我有代码将读取网格,设置网格的数据,并且可以计算网格的法线 . 我有一些问题 . 首先,一些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);
}
  }
}