package glmodel; import java.util.ArrayList; /** * Describes a triangular face. Holds references to three vertices, * their normals and texture coodinates. Vertex normals are stored * here and not in the Vertex object because a vertex may be shared * between two or more faces, and the faces may have very different * normals (ie. if the faces are at a 90 degree angle and make a * sharp edge). * * To smooth normals and preserve sharp edges, the Triangle object * holds the neighboring triangles for each vert. Based on the * angles between this triangle and its neighbors, the smoothing * algorithm can decide whether to smooth the normals across the * triangles, or to use the face normal to create a hard edge. * * jun 2006: added makeClone() */ public class GL_Triangle { public GL_Vertex p1; // first vertex public GL_Vertex p2; // second vertex public GL_Vertex p3; // third vertex public GL_Vector norm1; // normal at vert 1 public GL_Vector norm2; // normal at vert 2 public GL_Vector norm3; // normal at vert 3 public GL_Vector uvw1 = new GL_Vector();; // texture coord at vert 1 public GL_Vector uvw2 = new GL_Vector();; // texture coord at vert 2 public GL_Vector uvw3 = new GL_Vector();; // texture coord at vert 3 public ArrayList neighborsP1 = new ArrayList(); // Neighbor triangles of vertex1 public ArrayList neighborsP2 = new ArrayList(); // Neighbor triangles of vertex2 public ArrayList neighborsP3 = new ArrayList(); // Neighbor triangles of vertex3 public GL_Vector n = new GL_Vector(); // Normal vector of flat triangle public float Zdepth = 0f; // screen Z depth public int ID = 0; public int groupID = 0; int materialID; // index into materials array public GL_Triangle(GL_Vertex a, GL_Vertex b, GL_Vertex c) { p1=a; p2=b; p3=c; } /** * Calculate the face normal for this triangle */ public void recalcFaceNormal() { n = GL_Vector.getNormal(p1.pos,p2.pos,p3.pos); } /** * Recalculate the vertex normal, by averagin the normals * of the neighboring triangles. The neighbor list holds * only triangles that we want to average with this vertex. * * @see GL_Object.registerNeighbors() * @param neighbors neighboring triangles for this vert * @return vertex normal */ public GL_Vector recalcVertexNormal(ArrayList neighbors) { float nx = 0; float ny = 0; float nz = 0; GL_Triangle tri; GL_Vector wn = new GL_Vector(); // for each neighbor triangle, average the normals for (int i=0; i < neighbors.size(); i++) { tri = (GL_Triangle) neighbors.get(i); wn = tri.getWeightedNormal(); nx += wn.x; ny += wn.y; nz += wn.z; } GL_Vector vertn = new GL_Vector(nx, ny, nz); vertn.normalize(); return vertn; } public GL_Vector getWeightedNormal() { return GL_Vector.vectorProduct(p1.pos,p2.pos,p3.pos); } public GL_Vector getCenter() { float cx=(p1.pos.x+p2.pos.x+p3.pos.x)/3; float cy=(p1.pos.y+p2.pos.y+p3.pos.y)/3; float cz=(p1.pos.z+p2.pos.z+p3.pos.z)/3; return new GL_Vector(cx,cy,cz); } public void resetNeighbors() { neighborsP1.clear(); neighborsP2.clear(); neighborsP3.clear(); } /** * Calculate average screen Z depth of this triangle. This * function requires that the vertex screen positions have been * set (vertex.posS). * @see GL_Mesh.project() */ public void calcZdepth() { Zdepth = (p1.posS.z + p2.posS.z + p3.posS.z)/3f; } /** * Return true if two triangles should be smoothed as one * surface. cos_angle is the minumum angle for smoothing. * If the angle between the faces is > cos_angle, then the * faces are considered to be a continuous surface. Ie. * 90 degrees is a sharp corner, 180 degrees is a flat surface. */ public static boolean onSameSurface(GL_Triangle t1, GL_Triangle t2, float cos_angle) { float dot = GL_Vector.dotProduct(t1.n, t2.n); //System.out.println("surface: compare dot=" +dot + " cos-angle=" + cos_angle + " return " + (dot > cos_angle)); return (dot > cos_angle); } // MJN: have to clone the vertices, otherwise the cloned triangle // points back to the same verts as the original triangle. // WARNING: this means that the triangle verts aren't references to the // verts in the vertex array. The triangle verts are copies, so if // changes are made to the verts (ie. rebuild() assigns ids to them), // these copies won't be affected. public GL_Triangle makeClone() { GL_Triangle clone = new GL_Triangle(p1.makeClone(),p2.makeClone(),p3.makeClone()); clone.norm1 = norm1.getClone(); clone.norm2 = norm2.getClone(); clone.norm3 = norm3.getClone(); clone.uvw1 = uvw1.getClone(); clone.uvw2 = uvw2.getClone(); clone.uvw3 = uvw3.getClone(); clone.neighborsP1 = (ArrayList)neighborsP1.clone(); clone.neighborsP2 = (ArrayList)neighborsP2.clone(); clone.neighborsP3 = (ArrayList)neighborsP3.clone(); return clone; } }