📄 normalgenerator.java
字号:
// The original data was in quads. We converted it to triangles to // calculate normals. Now we need to convert it back to quads. private void convertTriToQuad(GeometryInfo geom) { // Create the new arrays geom.setCoordinateIndices( triToQuadIndices(geom.getCoordinateIndices())); geom.setColorIndices(triToQuadIndices(geom.getColorIndices())); geom.setNormalIndices(triToQuadIndices(geom.getNormalIndices())); int num = geom.getTexCoordSetCount(); for (int i = 0 ; i < num ; i++) { geom.setTextureCoordinateIndices(i, triToQuadIndices(geom.getTextureCoordinateIndices(i))); } geom.setPrimitive(gi.QUAD_ARRAY); } // End of convertTriToQuad() // The original data was in fans and we converted it to triangles to // calculate the normals. Now we are converting it back to fans. // We have already calculated the new stripCounts, so now we need // to change the index lists so they match up with the stripCounts. // It's a very simple algorithm. The paramater oldList is the // index list being compressed back into fans (could be coordinate, // color, normal, or texCoord indices) and numVerts is the pre- // calculated total of all entries of the stripCounts array. private int[] triToFanIndices(int sc[], int oldList[], int numVerts) { if (oldList == null) return null; int newList[] = new int[numVerts]; // index list to pass back int vert1 = 0; // 1st vertex of triangle int n = 0; // index into newList // Cycle through each fan in the new list for (int f = 0 ; f < sc.length ; f++) { // Copy entire first triangle into new array newList[n++] = oldList[vert1++]; newList[n++] = oldList[vert1++]; newList[n++] = oldList[vert1++]; // Each additional triangle in the fan only needs one vertex for (int t = 3 ; t < sc[f] ; t++) { newList[n++] = oldList[vert1 + 2]; vert1 += 3; } } return newList; } // End of triToFanIndices // // The original data was in fans. We converted it to triangles to // calculate normals. Now we need to convert it back to fans. // The hard part is that, if we found a hard edge in the middle of // a fan, we need to split the fan into two. To tell if there's // a hard edge there, we compare the normal indices of both // vertices comprising the edge. private void convertTriToFan(GeometryInfo geom, int oldStripCounts[]) { int ni[] = geom.getNormalIndices(); // // Calculate new stripCounts array // int tri = 0; // Which triangle currently being converted ArrayList newStripCounts; newStripCounts = new ArrayList(oldStripCounts.length + 100); // Use the original stripCounts array for (int f = 0 ; f < oldStripCounts.length ; f++) { int stripCount = 3; // Cycle through each triangle in the fan, comparing to the // next triangle in the fan. Compare the normal indices of // both vertices of the edge to see if the two triangles // can be mated for (int t = 0 ; t < oldStripCounts[f] - 3 ; t++) { // The first vertex of this triangle must match the first // vertex of the next, AND the third vertex of this // triangle must match the second vertex of the next. if ((ni[tri * 3] == ni[(tri+1) * 3]) && (ni[tri * 3 + 2] == ni[(tri+1) * 3 + 1])) { // OK to extend fan stripCount++; } else { // hard edge within fan newStripCounts.add(new Integer(stripCount)); stripCount = 3; } tri++; } tri++; newStripCounts.add(new Integer(stripCount)); } // Convert from ArrayList to int[] int sc[] = new int[newStripCounts.size()]; for (int i = 0 ; i < sc.length ; i++) sc[i] = ((Integer)newStripCounts.get(i)).intValue(); newStripCounts = null; // // Change the index lists so they match up with the new stripCounts // // See how many vertices we'll need int c = 0; for (int i = 0 ; i < sc.length ; i++) c += sc[i]; // Create the new arrays geom.setCoordinateIndices( triToFanIndices(sc, geom.getCoordinateIndices(), c)); geom.setColorIndices(triToFanIndices(sc, geom.getColorIndices(), c)); geom.setNormalIndices(triToFanIndices(sc, geom.getNormalIndices(), c)); int num = geom.getTexCoordSetCount(); for (int i = 0 ; i < num ; i++) { geom.setTextureCoordinateIndices(i, triToFanIndices(sc, geom.getTextureCoordinateIndices(i), c)); } if ((DEBUG & 8) != 0) { System.out.print("Old stripCounts:"); for (int i = 0 ; i < oldStripCounts.length ; i++) { System.out.print(" " + oldStripCounts[i]); } System.out.println(); System.out.print("New stripCounts:"); for (int i = 0 ; i < sc.length ; i++) { System.out.print(" " + sc[i]); } System.out.println(); } geom.setStripCounts(sc); geom.setPrimitive(gi.TRIANGLE_FAN_ARRAY); } // End of convertTriToFan() // The original data was in strips and we converted it to triangles to // calculate the normals. Now we are converting it back to strips. // We have already calculated the new stripCounts, so now we need // to change the index lists so they match up with the stripCounts. // It's a very simple algorithm. The paramater oldList is the // index list being compressed back into strips (could be coordinate, // color, normal, or texCoord indices) and numVerts is the pre- // calculated total of all entries of the stripCounts array. private int[] triToStripIndices(int sc[], int oldList[], int numVerts) { if (oldList == null) return null; int newList[] = new int[numVerts]; // index list to pass back int vert1 = 0; // 1st vertex of triangle int n = 0; // index into newList // Cycle through each strip in the new list for (int f = 0 ; f < sc.length ; f++) { // Copy entire first triangle into new array newList[n++] = oldList[vert1++]; newList[n++] = oldList[vert1++]; newList[n++] = oldList[vert1++]; // Each additional triangle in the fan only needs one vertex for (int t = 3 ; t < sc[f] ; t++) { // Every other triangle has been reversed to preserve winding newList[n++] = oldList[vert1 + 2 - (t % 2)]; vert1 += 3; } } return newList; } // End of triToStripIndices private void convertTriToStrip(GeometryInfo geom, int oldStripCounts[]) { int ni[] = geom.getNormalIndices(); // // Calculate new stripCounts array // int tri = 0; // Which triangle currently being converted ArrayList newStripCounts; newStripCounts = new ArrayList(oldStripCounts.length + 100); // Use the original stripCounts array for (int f = 0 ; f < oldStripCounts.length ; f++) { int stripCount = 3; // Cycle through each triangle in the strip, comparing to the // next triangle in the strip. Compare the normal indices of // both vertices of the edge to see if the two triangles // can be mated. for (int t = 0 ; t < oldStripCounts[f] - 3 ; t++) { // Every other triangle has been reversed to preserve winding if (t % 2 == 0) { // The middle vertex of this triangle needs to match the // first vertex of the next, AND the third vertices of // the two triangles must match if ((ni[tri * 3 + 1] == ni[(tri+1) * 3]) && (ni[tri * 3 + 2] == ni[(tri+1) * 3 + 2])) { // OK to extend strip stripCount++; } else { // hard edge within strip newStripCounts.add(new Integer(stripCount)); stripCount = 3; // Can't start a new strip on an odd edge so output // isolated triangle if (t < oldStripCounts[f] - 4) { newStripCounts.add(new Integer(3)); t++; } } } else { // The middle vertex of this triangle must match the middle // vertex of the next, AND the third vertex of this triangle // must match the first vertex of the next if ((ni[tri * 3 + 1] == ni[(tri+1) * 3 + 1]) && (ni[tri * 3 + 2] == ni[(tri+1) * 3])) { // OK to extend strip stripCount++; } else { // hard edge within strip newStripCounts.add(new Integer(stripCount)); stripCount = 3; } } tri++; } tri++; newStripCounts.add(new Integer(stripCount)); } // Convert from ArrayList to int[] int sc[] = new int[newStripCounts.size()]; for (int i = 0 ; i < sc.length ; i++) sc[i] = ((Integer)newStripCounts.get(i)).intValue(); newStripCounts = null; // // Change the index lists so they match up with the new stripCounts // // See how many vertices we'll need int c = 0; for (int i = 0 ; i < sc.length ; i++) c += sc[i]; // Create the new arrays geom.setCoordinateIndices( triToStripIndices(sc, geom.getCoordinateIndices(), c)); geom.setColorIndices(triToStripIndices(sc, geom.getColorIndices(), c)); geom.setNormalIndices(triToStripIndices(sc, geom.getNormalIndices(), c)); int num = geom.getTexCoordSetCount(); for (int i = 0 ; i < num ; i++) { geom.setTextureCoordinateIndices(i, triToStripIndices(sc, geom.getTextureCoordinateIndices(i), c)); } if ((DEBUG & 8) != 0) { System.out.print("Old stripCounts:"); for (int i = 0 ; i < oldStripCounts.length ; i++) { System.out.print(" " + oldStripCounts[i]); } System.out.println(); System.out.print("New stripCounts:"); for (int i = 0 ; i < sc.length ; i++) { System.out.print(" " + sc[i]); } System.out.println(); } geom.setStripCounts(sc); geom.setPrimitive(gi.TRIANGLE_STRIP_ARRAY); }// End of convertTriToStrip() /** * Used when the user calls the NormalGenerator and not * the Stripifier or Triangulator. We had to convert * the user's data to indexed triangles before we could * generate normals, so now we need to switch back to * the original format. */ void convertBackToOldPrim(GeometryInfo geom, int oldPrim, int oldStripCounts[]) { if (oldPrim == geom.TRIANGLE_ARRAY) return; switch (oldPrim) { case GeometryInfo.QUAD_ARRAY: convertTriToQuad(geom); break; case GeometryInfo.TRIANGLE_FAN_ARRAY: convertTriToFan(geom, oldStripCounts); break; case GeometryInfo.TRIANGLE_STRIP_ARRAY: convertTriToStrip(geom, oldStripCounts); break; } if ((DEBUG & 64) != 0) { System.out.println("Coordinate and normal indices (original):"); for (int i = 0 ; i < coordInds.length ; i++) { System.out.println(i + " " + coordInds[i] + " " + normalInds[i]); } } } // End of convertBackToOldPrim /** * Generate normals for the GeometryInfo object. If the GeometryInfo * object didn't previously contain indexed data, indexes are made * by collapsing identical positions into a single index. Any * normal information previously contained in the GeometryInfo * object is lost. Strips and Fans are converted into individual * triangles for Normal generation, but are stitched back together * if GeometryInfo.getGeometryArray() (or getIndexedGeometryArray()) * is called without stripifying first. */ public void generateNormals(GeometryInfo geom) { gi = geom; gi.setNormals((Vector3f[])null); gi.setNormalIndices(null); long time = 0L; if ((DEBUG & 16) != 0) { time = System.currentTimeMillis(); } if (gi.getPrimitive() == gi.POLYGON_ARRAY) { if (tr == null) tr = new Triangulator(); tr.triangulate(gi); } else { // NOTE: We should calculate facet normals before converting to // triangles. gi.rememberOldPrim(); gi.convertToIndexedTriangles(); } // Cache some of the GeometryInfo fields coordInds = gi.getCoordinateIndices(); colorInds = gi.getColorIndices(); normalInds = gi.getNormalIndices(); numTexSets = gi.getTexCoordSetCount(); texInds = new int[numTexSets][]; for (int i = 0 ; i < numTexSets ; i++) { texInds[i] = gi.getTextureCoordinateIndices(i); } stripCounts = gi.getStripCounts(); if ((DEBUG & 16) != 0) { t1 += System.currentTimeMillis() - time; System.out.println("Convert to triangles: " + t1 + " ms"); time = System.currentTimeMillis(); } calculatefacetNorms(); if ((DEBUG & 16) != 0) { t2 += System.currentTimeMillis() - time; System.out.println("Calculate Facet Normals: " + t2 + " ms"); time = System.currentTimeMillis(); } int maxShare = createHardEdges(); if ((DEBUG & 16) != 0) { t3 += System.currentTimeMillis() - time; System.out.println("Hard Edges: " + t3 + " ms"); time = System.currentTimeMillis(); } calculateVertexNormals(maxShare); if ((DEBUG & 16) != 0) { t5 += System.currentTimeMillis() - time; System.out.println("Vertex Normals: " + t5 + " ms"); time = System.currentTimeMillis(); } if ((DEBUG & 64) != 0) { System.out.println("Coordinate and normal indices (triangles):"); for (int i = 0 ; i < coordInds.length ; i++) { System.out.println(i + " " + coordInds[i] + " " + normalInds[i]); } } // We have been caching some info from the GeometryInfo, so we need // to update it. gi.setCoordinateIndices(coordInds); gi.setColorIndices(colorInds); gi.setNormalIndices(normalInds); for (int i = 0 ; i < numTexSets ; i++) { gi.setTextureCoordinateIndices(i, texInds[i]); } gi.setStripCounts(stripCounts); } // End of generateNormals /** * Set the crease angle. * If two triangles' normals differ by more than * creaseAngle, then the vertex will get two separate normals, creating a * discontinuous crease in the model. This is perfect for the edge * of a table or the corner of a cube, for instance. Clamped to * 0 <= creaseAngle <= PI. Optimizations are made for creaseAngle == 0 * (facet normals) and creaseAngle == PI (smooth shading). */ public void setCreaseAngle(double radians) { if (radians > Math.PI) radians = Math.PI; if (radians < 0.0) radians = 0.0; creaseAngle = radians; } // End of setCreaseAngle /** * Returns the current value of the crease angle, in radians. */ public double getCreaseAngle() { return creaseAngle; } // End of getCreaseAngle /** * Constructor. Construct a NormalGenerator object with creaseAngle * set to the given value. */ public NormalGenerator(double radians) { creaseAngle = radians; } // End of NormalGenerator(double) /** * Constructor. Construct a NormalGenerator object with creaseAngle * set to 44 degrees (0.767944871 radians). */ public NormalGenerator() { this(44.0 * Math.PI / 180.0); } // End of NormalGenerator()} // End of class NormalGenerator// End of file NormalGenerator.java
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -