private uint GenerateVertex(ref List <TVertex> verts, int a, int b) { Int64 key1 = Geometry.Topology.CreateEdgeKey(indices[a], indices[b]); uint middlePt; if (!subDivideEdgeCache.TryGetValue(key1, out middlePt)) { Vector3 pos1 = MeshAttr.GetPosition(ref mesh.vertices[indices[a]]); Vector3 pos2 = MeshAttr.GetPosition(ref mesh.vertices[indices[b]]); Vector3 e1 = Vector3.Normalize(pos1 + (pos2 - pos1) * 0.5f); TVertex v1 = mesh.vertices[indices[a]]; MeshAttr.SetPosition(ref v1, ref e1); middlePt = (uint)verts.Count; subDivideEdgeCache.Add(key1, middlePt); verts.Add(v1); } return(middlePt); }
/// <summary> /// Adds a triangle with vertex format Position, Normal and UV, calculating the normal from the origin, and /// using a defined UV of top center, bottom left, bottom right. /// </summary> /// <typeparam name="AltVertex"></typeparam> /// <param name="newVerts"></param> /// <param name="newIndices"></param> /// <param name="v1"></param> /// <param name="v2"></param> /// <param name="v3"></param> /// <param name="isAnticlockwise"></param> public void AddTriangle <AltVertex>(ref List <AltVertex> newVerts, ref List <uint> newIndices, ref Vector3 v1, ref Vector3 v2, ref Vector3 v3, bool isAnticlockwise) where AltVertex : struct, IVertex { AltVertex[] triVerts = new AltVertex[3]; triVerts.Initialize(); MeshAttr.SetPosition(ref triVerts[0], ref v1); MeshAttr.SetPosition(ref triVerts[1], ref v2); MeshAttr.SetPosition(ref triVerts[2], ref v3); Vector3 v1N = v1; v1N.Normalize(); for (int i = 0; i < 3; i++) { MeshAttr.SetNormal(ref triVerts[i], ref v1N); } Vector2 uv0 = new Vector2(0.5f, 1); Vector2 uv1 = new Vector2(0, 0); Vector2 uv2 = new Vector2(1, 0); MeshAttr.SetUV(ref triVerts[0], ref uv0); MeshAttr.SetUV(ref triVerts[1], ref uv1); MeshAttr.SetUV(ref triVerts[2], ref uv2); int index = newVerts.Count; for (int i = 0; i < 3; i++) { newVerts.Add(triVerts[i]); } if (isAnticlockwise) { newIndices.Add((uint)index); newIndices.Add((uint)index + 1); newIndices.Add((uint)index + 2); } else { newIndices.Add((uint)index); newIndices.Add((uint)index + 2); newIndices.Add((uint)index + 1); } }
/// <summary> /// Adds a triangle based on the current mesh with the vertex format Position, Normal, UV and Color. /// It sets the normal for each vertex to the original position vector, /// UV is set to top center, bottom left, bottom right, with original vert being top center /// It sets color of all verts to the color of the original vertex. /// </summary> /// <typeparam name="AltVertex"></typeparam> /// <param name="newVerts">The new set of vertices</param> /// <param name="newIndices">The new set of indices</param> /// <param name="v1index">The index of the vertex in the original mesh</param> /// <param name="v2">the position of the first new vertex</param> /// <param name="v3">the position of the second new vertex</param> /// <param name="color">The new vertex color</param>" public void AddTriangle2 <AltVertex>(ref List <AltVertex> newVerts, ref List <uint> newIndices, int v1index, ref Vector3 v2, ref Vector3 v3, Vector4 color) where AltVertex : struct, IVertex { AltVertex[] triVerts = new AltVertex[3]; triVerts.Initialize(); Vector3 v1Pos = MeshAttr.GetPosition(ref mesh.vertices[v1index]); MeshAttr.SetPosition(ref triVerts[0], ref v1Pos); MeshAttr.SetPosition(ref triVerts[1], ref v2); MeshAttr.SetPosition(ref triVerts[2], ref v3); v1Pos.Normalize(); for (int i = 0; i < 3; i++) { MeshAttr.SetNormal(ref triVerts[i], ref v1Pos); } Vector2 uv0 = new Vector2(0.5f, 1); Vector2 uv1 = new Vector2(0, 0); Vector2 uv2 = new Vector2(1, 0); MeshAttr.SetUV(ref triVerts[0], ref uv0); MeshAttr.SetUV(ref triVerts[1], ref uv1); MeshAttr.SetUV(ref triVerts[2], ref uv2); MeshAttr.SetColor(ref triVerts[0], ref color); MeshAttr.SetColor(ref triVerts[1], ref color); MeshAttr.SetColor(ref triVerts[2], ref color); newVerts[v1index] = triVerts[0]; int index = newVerts.Count; newVerts.Add(triVerts[1]); newVerts.Add(triVerts[2]); newIndices.Add((uint)v1index); newIndices.Add((uint)index++); newIndices.Add((uint)index++); }
public IGeometry ClonePosition <TVertex2>() where TVertex2 : struct, IVertex { TVertex2[] newVerts = new TVertex2[mesh.vertices.Length]; int index = 0; foreach (var iter in mesh.vertices) { TVertex vertex = iter; Vector3 pos = MeshAttr.GetPosition(ref vertex); newVerts[index] = new TVertex2(); MeshAttr.SetPosition(ref newVerts[index], ref pos); index++; } Mesh <TVertex2> newMesh = new Mesh <TVertex2>(newVerts); Indices newIndices = null; if (indices != null) { newIndices = indices.Clone(); } Geometry <TVertex2> newGeom = new Geometry <TVertex2>(newMesh, newIndices); return(newGeom); }
public float RelaxTriangles(float multiplier) { NeedsUpdate = true; double totalSurfaceArea = 4.0 * Math.PI; double idealFaceArea = totalSurfaceArea / (indices.Length / 3); double idealEdgeLength = Math.Sqrt(idealFaceArea * 4.0 / Math.Sqrt(3.0)); double idealDistanceToCentroid = idealEdgeLength * Math.Sqrt(3) / 3.0 * 0.9; Vector3[] shiftPositions = new Vector3[mesh.vertices.Length]; for (int i = 0; i < mesh.vertices.Length; ++i) { shiftPositions[i] = new Vector3(Vector3.Zero); } int numIndices = indices.Length; TVertex[] centroidVerts = new TVertex[numIndices / 3]; TVertex centroidVertex = new TVertex(); for (int i = 0; i < numIndices; i += 3) { Vector3 centroid = Topology.CalculateCentroid(i / 3); centroid.Normalize(); MeshAttr.SetPosition(ref centroidVertex, ref centroid); Vector3[] oldPositions = new Vector3[3] { new Vector3(MeshAttr.GetPosition(ref mesh.vertices[indices[i]])), new Vector3(MeshAttr.GetPosition(ref mesh.vertices[indices[i + 1]])), new Vector3(MeshAttr.GetPosition(ref mesh.vertices[indices[i + 2]])), }; for (int j = 0; j < 3; ++j) { Vector3 midLine = centroid - oldPositions[j]; float midLength = midLine.Length; midLine *= (float)(multiplier * (midLength - idealDistanceToCentroid) / midLength); shiftPositions[indices[i + j]] += midLine; } } var origin = Vector3.Zero; Plane p = new Plane(Vector3.UnitY, Vector3.Zero); for (int i = 0; i < mesh.vertices.Length; ++i) { Vector3 vertexPosition = MeshAttr.GetPosition(ref mesh.vertices[i]); p.Redefine(vertexPosition, origin); shiftPositions[i] = vertexPosition + p.ProjectPoint(shiftPositions[i]); shiftPositions[i].Normalize(); } // Stop poylgons rotating about their centroid. // Doesn't stop triangles flipping. float[] rotationSuppressions = new float[mesh.vertices.Length]; rotationSuppressions.Initialize(); Topology.GenerateEdges(); float minEdgeLength = (float)idealEdgeLength * 0.8f; float maxEdgeLength = (float)idealEdgeLength * 1.2f; foreach (var iter in Topology.Edges) { Int64 key = iter.Key; int index1 = (int)(key & 0xffffffff); int index2 = (int)((key >> 32) & 0xffffffff); Vector3 oldPos1 = MeshAttr.GetPosition(ref mesh.vertices[index1]); Vector3 oldPos2 = MeshAttr.GetPosition(ref mesh.vertices[index2]); Vector3 newPos1 = shiftPositions[index1]; Vector3 newPos2 = shiftPositions[index2]; Vector3 oldEdge = oldPos2 - oldPos1; Vector3 newEdge = newPos2 - newPos1; if (newEdge.Length < minEdgeLength) { // Move shift positions back out to ensure that the edge is never too small. Vector3 midPt = newPos1 + 0.5f * newEdge; newEdge.Normalize(); newEdge *= minEdgeLength * 0.5f; shiftPositions[index1] = midPt - newEdge; shiftPositions[index2] = midPt + newEdge; newEdge = shiftPositions[index2] - shiftPositions[index1]; } if (newEdge.Length > maxEdgeLength) { // Move shift positions back in to ensure that the edge is never too large. Vector3 midPt = newPos1 + 0.5f * newEdge; newEdge.Normalize(); newEdge *= (maxEdgeLength * 0.5f); shiftPositions[index1] = midPt - newEdge; shiftPositions[index2] = midPt + newEdge; newEdge = shiftPositions[index2] - shiftPositions[index1]; } oldEdge.Normalize(); newEdge.Normalize(); float suppression = (1.0f - Vector3.Dot(oldEdge, newEdge)) * 0.5f; rotationSuppressions[index1] = Math.Max(suppression, rotationSuppressions[index1]); rotationSuppressions[index2] = Math.Max(suppression, rotationSuppressions[index2]); } for (int i = 0; i < mesh.vertices.Length; ++i) { Vector3 pos = MeshAttr.GetPosition(ref mesh.vertices[i]); Vector3 delta = pos; pos = Math2.Lerp(pos, shiftPositions[i], (float)(1.0f - Math.Sqrt(rotationSuppressions[i]))); pos.Normalize(); shiftPositions[i] = pos; } float totalShift = 0; for (int i = 0; i < mesh.vertices.Length; ++i) { Vector3 delta = MeshAttr.GetPosition(ref mesh.vertices[i]); MeshAttr.SetPosition(ref mesh.vertices[i], ref shiftPositions[i]); delta -= shiftPositions[i]; totalShift += delta.Length; } Topology.Regenerate(); return(totalShift); }
// Alternative algorithm // for each triangle // find normal // find centroid radius // Tilt triangle towards centroid radius // moving edges towards symmetry. // generate new point for each tri vert // for each vert, calc average of all new verts, normalise and apply // Algorithm is nearly there, but on some triangles, there is a potential that converging on // centroid tilts through random moves away from centroidal radius, and they become thin / start overlapping. public float RelaxTriangles1(float multiplier) { NeedsUpdate = true; double totalSurfaceArea = 4.0 * Math.PI; double idealFaceArea = totalSurfaceArea / (indices.Length / 3); double idealEdgeLength = Math.Sqrt(idealFaceArea * 4.0 / Math.Sqrt(3.0)); double idealDistanceToCentroid = idealEdgeLength * Math.Sqrt(3) / 3.0 * 0.9; int numIndices = indices.Length; Vector3[] shiftPositions = new Vector3[mesh.vertices.Length]; for (int i = 0; i < mesh.vertices.Length; ++i) { shiftPositions[i] = new Vector3(Vector3.Zero); } for (int i = 0; i < numIndices; i += 3) { if (1 == 1)//TooThin(i)) { Vector3 centroid = Topology.CalculateCentroid(i / 3); centroid.Normalize(); // Compare each corner to the centroid // if too far off some ideal length ( the centroid of an equilateral triangle ), // pull vertex closer to centroid, (without buggering up the other triangles using // this point.) Vector3[] oldPositions = new Vector3[3] { new Vector3(MeshAttr.GetPosition(ref mesh.vertices[indices[i]])), new Vector3(MeshAttr.GetPosition(ref mesh.vertices[indices[i + 1]])), new Vector3(MeshAttr.GetPosition(ref mesh.vertices[indices[i + 2]])), }; Vector3[] newPositions = new Vector3[3]; for (int j = 0; j < 3; ++j) { TVertex v1 = mesh.vertices[indices[i + j]]; Vector3 v1Pos = MeshAttr.GetPosition(ref v1); Vector3 e1 = centroid - v1Pos; if (e1.Length > idealDistanceToCentroid * 1.1) { // Move vertex closer to centroid float factor = 1.0f - (float)idealDistanceToCentroid / e1.Length; float fraction = (multiplier * (1.0f - (float)idealDistanceToCentroid / e1.Length)); factor = factor * fraction; v1Pos = Vector3.Normalize(v1Pos + e1 * factor); } else if (e1.Length < idealDistanceToCentroid * 0.9) { // Move vertex away from the centroid float factor = 1 - e1.Length / (float)idealDistanceToCentroid; float fraction = (multiplier * (e1.Length / (float)idealDistanceToCentroid)); factor = factor * fraction; v1Pos = Vector3.Normalize(v1Pos - e1 * factor); } newPositions[j] = v1Pos; } // If this makes the triangle less parallel to the sphere, don't do it. Vector3 a = newPositions[1] - newPositions[0]; Vector3 b = newPositions[2] - newPositions[1]; Vector3 normal = Vector3.Cross(a, b); normal.Normalize(); float dot = Vector3.Dot(centroid, normal); double phi = Math.Acos(dot); a = oldPositions[1] - oldPositions[0]; b = oldPositions[2] - oldPositions[1]; normal = Vector3.Cross(a, b); normal.Normalize(); dot = Vector3.Dot(centroid, normal); double theta = Math.Acos(dot); if (phi < dot) { for (int j = 0; j < 3; ++j) { //SetPosition(ref mesh.vertices[indices[i + j]], ref newPositions[j]); shiftPositions[indices[i + j]] = newPositions[j]; } } // If any surrounding triangles would be less parallel to the sphere than // this is more parallel, don't do it. } } TVertex[] vertices = new TVertex[mesh.vertices.Length]; float totalShift = 0; for (int i = 0; i < mesh.vertices.Length; ++i) { Vector3 delta = shiftPositions[i] - MeshAttr.GetPosition(ref mesh.vertices[i]); MeshAttr.SetPosition(ref mesh.vertices[i], ref shiftPositions[i]); totalShift += delta.Length; } Topology.Regenerate(); return(totalShift); }
public void SetPosition(int index, ref Vector3 position) { MeshAttr.SetPosition(ref vertices[index], ref position); }