public static void SoftNormalsInTangents(Mesh mesh) { var mVerts = mesh.vertices; var mTangents = new Vector4[mVerts.Length]; var mTris = mesh.triangles; Dictionary <Vector3, SoftNormal> vertDict = new Dictionary <Vector3, SoftNormal>(); for (int i = 0; i < mTris.Length; i += 3) { int i0 = mTris[i]; int i1 = mTris[i + 1]; int i2 = mTris[i + 2]; var v0 = mVerts[i0]; var v1 = mVerts[i1]; var v2 = mVerts[i2]; Vector3 dir = v1 - v0; Vector3 tan = v2 - v0; if (dir == Vector3.zero) { continue; } if (tan == Vector3.zero) { continue; } var normal = Vector3.Cross(tan, dir).normalized; float dirLength = dir.magnitude; float height = Vector3.Dot(tan, Vector3.Cross(dir / dirLength, normal)); float area = (dirLength * height) / 2f; normal *= area; Vector4 tangent = new Vector4(normal.x, normal.y, normal.z, 0); for (int j = 0; j < 3; j++) { SoftNormal softNormal; int vertIndex = mTris[i + j]; Vector3 vert = mVerts[vertIndex]; if (!vertDict.TryGetValue(mVerts[mTris[i + j]], out softNormal)) { softNormal = new SoftNormal(); vertDict.Add(vert, softNormal); } if (!softNormal.indexs.Contains(vertIndex)) { softNormal.indexs.Add(vertIndex); } softNormal.normal += tangent; } } var softNormals = vertDict.Values; foreach (var softNormal in softNormals) { for (int i = 0; i < softNormal.indexs.Count; i++) { mTangents[softNormal.indexs[i]] += softNormal.normal; } } for (int i = 0; i < mTangents.Length; i++) { mTangents[i] = -mTangents[i].normalized; } mesh.tangents = mTangents; }
/// Credit to: /// · https://stackoverflow.com/questions/45477806/general-method-for-calculating-smooth-vertex-normals-with-100-smoothness /// · Oskar Stålberg (@OskSta) public static void SoftNormalsAsColors(this Mesh mesh) { var tris = mesh.triangles; var verts = mesh.vertices; var tans = new Vector4[verts.Length]; var dicVerts = new Dictionary <Vector3, SoftNormal> (); for (var v = 0; v < tris.Length; v += 3) { int i1 = tris[v + 0]; int i2 = tris[v + 1]; int i3 = tris[v + 2]; // p1, p2 and p3 are the points in the face var p1 = verts[i1]; var p2 = verts[i2]; var p3 = verts[i3]; // Calculate normal of the surface using edges var edge1 = p2 - p1; var edge2 = p3 - p1; if (edge1 == Vector3.zero) { continue; } if (edge2 == Vector3.zero) { continue; } var n = Vector3.Cross(edge1, edge2).normalized; // Get the angle between the two other points for each point var angles = new float[3]; angles[0] = Vector3.Angle(p2 - p1, p3 - p1); // p1 is the 'base' here angles[1] = Vector3.Angle(p3 - p2, p1 - p2); // p2 is the 'base' here angles[2] = Vector3.Angle(p1 - p3, p2 - p3); // p3 is the 'base' here // Store the weighted normal in an structured array var tangent = new Vector4(n.x, n.y, n.z, 0f); for (var i = 0; i != 3; i++) { SoftNormal softNormal; int vertIndex = tris[v + i]; var vert = verts[vertIndex]; if (!dicVerts.TryGetValue(vert, out softNormal)) { softNormal = new SoftNormal(); dicVerts.Add(vert, softNormal); } if (!softNormal.indexs.Contains(vertIndex)) { softNormal.indexs.Add(vertIndex); } softNormal.normal += tangent * angles[i]; } } //okay foreach (var softNormal in dicVerts.Values) { foreach (var index in softNormal.indexs) { tans[index] += softNormal.normal; } } var colors = new Color32[tans.Length]; // Normalize sum for (int i = 0; i != tans.Length; i++) { tans[i] = tans[i].normalized; // Get corresponding color var color = new Color32 ( // Tranform to range [0,1] and then [0,255] (byte)(((tans[i].x + 1) / 2) * 255), (byte)(((tans[i].y + 1) / 2) * 255), (byte)(((tans[i].z + 1) / 2) * 255), 1); colors[i] = color; } // Save to mesh mesh.colors32 = colors; }