/** * Convert the normals back to cartesian coordinates. */ private float[] restoreNormals(int[] intNormals, float[] vertices, int[] indices, float normalPrecision) { // Calculate smooth normals (nominal normals) float[] smoothNormals = CommonAlgorithm.calcSmoothNormals(vertices, indices); float[] normals = new float[vertices.Length]; int vc = vertices.Length / Mesh.CTM_POSITION_ELEMENT_COUNT; int ne = Mesh.CTM_NORMAL_ELEMENT_COUNT; for (int i = 0; i < vc; ++i) { // Get the normal magnitude from the first of the three normal elements float magn = intNormals[i * ne] * normalPrecision; // Get phi and theta (spherical coordinates, relative to the smooth normal). double thetaScale, theta; int intPhi = intNormals[i * ne + 1]; double phi = intPhi * (0.5 * Math.PI) * normalPrecision; if (intPhi == 0) { thetaScale = 0.0f; } else if (intPhi <= 4) { thetaScale = Math.PI / 2.0f; } else { thetaScale = (2.0f * Math.PI) / intPhi; } theta = intNormals[i * ne + 2] * thetaScale - Math.PI; // Convert the normal from the angular representation (phi, theta) back to // cartesian coordinates double[] n2 = new double[3]; n2[0] = Math.Sin(phi) * Math.Cos(theta); n2[1] = Math.Sin(phi) * Math.Sin(theta); n2[2] = Math.Cos(phi); float[] basisAxes = CommonAlgorithm.makeNormalCoordSys(smoothNormals, i * ne); double[] n = new double[3]; for (int j = 0; j < 3; ++j) { n[j] = basisAxes[j] * n2[0] + basisAxes[3 + j] * n2[1] + basisAxes[6 + j] * n2[2]; } // Apply normal magnitude, and output to the normals array for (int j = 0; j < 3; ++j) { normals[i * ne + j] = (float)(n[j] * magn); } } return(normals); }
/** * Convert the normals to a new coordinate system: magnitude, phi, theta * (relative to predicted smooth normals). */ private int[] makeNormalDeltas(float[] vertices, float[] normals, int[] indices, SortableVertex[] sortVertices) { // Calculate smooth normals (Note: aVertices and aIndices use the sorted // index space, so smoothNormals will too) float[] smoothNormals = CommonAlgorithm.calcSmoothNormals(vertices, indices); // Normal scaling factor float scale = 1.0f / normalPrecision; int vc = vertices.Length / Mesh.CTM_POSITION_ELEMENT_COUNT; int[] intNormals = new int[vc * Mesh.CTM_NORMAL_ELEMENT_COUNT]; for (int i = 0; i < vc; ++i) { // Get old normal index (before vertex sorting) int oldIdx = sortVertices [i].originalIndex; // Calculate normal magnitude (should always be 1.0 for unit length normals) float magn = (float)Math.Sqrt(normals [oldIdx * 3] * normals [oldIdx * 3] + normals [oldIdx * 3 + 1] * normals [oldIdx * 3 + 1] + normals [oldIdx * 3 + 2] * normals [oldIdx * 3 + 2]); if (magn < 1e-10f) { magn = 1.0f; } // Invert magnitude if the normal is negative compared to the predicted // smooth normal if ((smoothNormals [i * 3] * normals [oldIdx * 3] + smoothNormals [i * 3 + 1] * normals [oldIdx * 3 + 1] + smoothNormals [i * 3 + 2] * normals [oldIdx * 3 + 2]) < 0.0f) { magn = -magn; } // Store the magnitude in the first element of the three normal elements intNormals [i * 3] = (int)Math.Floor(scale * magn + 0.5f); // Normalize the normal (1 / magn) - and flip it if magn < 0 magn = 1.0f / magn; float[] n = new float[3]; for (int j = 0; j < 3; ++j) { n [j] = normals [oldIdx * 3 + j] * magn; } // Convert the normal to angular representation (phi, theta) in a coordinate // system where the nominal (smooth) normal is the Z-axis float[] basisAxes = CommonAlgorithm.makeNormalCoordSys(smoothNormals, i * 3); float[] n2 = new float[3]; for (int j = 0; j < 3; ++j) { n2 [j] = basisAxes [j * 3] * n [0] + basisAxes [j * 3 + 1] * n [1] + basisAxes [j * 3 + 2] * n [2]; } double phi, theta, thetaScale; if (n2 [2] >= 1.0f) { phi = 0.0f; } else { phi = Math.Acos(n2 [2]); } theta = Math.Atan2(n2 [1], n2 [0]); // Round phi and theta (spherical coordinates) to integers. Note: We let the // theta resolution vary with the x/y circumference (roughly phi). int intPhi = (int)Math.Floor(phi * (scale / (0.5 * Math.PI)) + 0.5); if (intPhi == 0) { thetaScale = 0.0; } else if (intPhi <= 4) { thetaScale = 2.0 / Math.PI; } else { thetaScale = intPhi / (2.0 * Math.PI); } intNormals [i * 3 + 1] = intPhi; intNormals [i * 3 + 2] = (int)Math.Floor((theta + Math.PI) * thetaScale + 0.5f); } return(intNormals); }