// Triangulate Bone Samplers. todo: Burst it. internal static void TriangulateSamplers(Vector2[] samplers, List <Vector2> triVertices, List <int> triIndices) { foreach (var v in samplers) { var vertexCount = triVertices.Count; for (int i = 0; i < triIndices.Count / 3; ++i) { int i1 = triIndices[0 + (i * 3)]; int i2 = triIndices[1 + (i * 3)]; int i3 = triIndices[2 + (i * 3)]; float2 v1 = triVertices[i1]; float2 v2 = triVertices[i2]; float2 v3 = triVertices[i3]; var inside = ModuleHandle.IsInsideTriangle(v, v1, v2, v3); if (inside) { triVertices.Add(v); triIndices.Add(i1); triIndices.Add(i2); triIndices.Add(vertexCount); triIndices.Add(i2); triIndices.Add(i3); triIndices.Add(vertexCount); triIndices.Add(i3); triIndices.Add(i1); triIndices.Add(vertexCount); break; } } } }
private static bool SubdivideSafe(NativeArray <float2> points, NativeArray <int2> edges, ref NativeArray <float2> outVertices, ref int outVertexCount, ref NativeArray <int> outIndices, ref int outIndexCount, ref NativeArray <int2> outEdges, ref int outEdgeCount, float areaFactor, float areaThreshold, int refineIterations, int smoothenIterations) { try { ModuleHandle.Subdivide(Allocator.Persistent, points, edges, ref outVertices, ref outVertexCount, ref outIndices, ref outIndexCount, ref outEdges, ref outEdgeCount, areaFactor, areaThreshold, refineIterations, smoothenIterations); } catch (Exception) { return(false); } return(true); }
private static bool TessellateSafe(NativeArray <float2> points, NativeArray <int2> edges, ref NativeArray <float2> outVertices, ref int outVertexCount, ref NativeArray <int> outIndices, ref int outIndexCount, ref NativeArray <int2> outEdges, ref int outEdgeCount) { try { ModuleHandle.Tessellate(Allocator.Persistent, points, edges, ref outVertices, ref outVertexCount, ref outIndices, ref outIndexCount, ref outEdges, ref outEdgeCount); } catch (Exception) { return(false); } return(true); }
private static unsafe void TessellateBurst(Allocator allocator, float2 *points, int pointCount, int2 *edges, int edgeCount, float2 *outVertices, int *outIndices, int2 *outEdges, int arrayCount, int3 *result) { NativeArray <int2> _edges = new NativeArray <int2>(edgeCount, allocator); for (int i = 0; i < _edges.Length; ++i) { _edges[i] = edges[i]; } NativeArray <float2> _points = new NativeArray <float2>(pointCount, allocator); for (int i = 0; i < _points.Length; ++i) { _points[i] = points[i]; } NativeArray <int> _outIndices = new NativeArray <int>(arrayCount, allocator); NativeArray <int2> _outEdges = new NativeArray <int2>(arrayCount, allocator); NativeArray <float2> _outVertices = new NativeArray <float2>(arrayCount, allocator); int outEdgeCount = 0; int outIndexCount = 0; int outVertexCount = 0; ModuleHandle.Tessellate(allocator, _points, _edges, ref _outVertices, ref outVertexCount, ref _outIndices, ref outIndexCount, ref _outEdges, ref outEdgeCount); for (int i = 0; i < outEdgeCount; ++i) { outEdges[i] = _outEdges[i]; } for (int i = 0; i < outIndexCount; ++i) { outIndices[i] = _outIndices[i]; } for (int i = 0; i < outVertexCount; ++i) { outVertices[i] = _outVertices[i]; } result->x = outVertexCount; result->y = outIndexCount; result->z = outEdgeCount; _outVertices.Dispose(); _outEdges.Dispose(); _outIndices.Dispose(); _points.Dispose(); _edges.Dispose(); }
private static unsafe void SubdivideBurst(Allocator allocator, float2 *points, int pointCount, int2 *edges, int edgeCount, float2 *outVertices, int *outIndices, int2 *outEdges, int arrayCount, float areaFactor, float areaThreshold, int refineIterations, int smoothenIterations, int3 *result) { NativeArray <int2> _edges = new NativeArray <int2>(edgeCount, allocator); for (int i = 0; i < _edges.Length; ++i) { _edges[i] = edges[i]; } NativeArray <float2> _points = new NativeArray <float2>(pointCount, allocator); for (int i = 0; i < _points.Length; ++i) { _points[i] = points[i]; } NativeArray <int> _outIndices = new NativeArray <int>(arrayCount, allocator); NativeArray <int2> _outEdges = new NativeArray <int2>(arrayCount, allocator); NativeArray <float2> _outVertices = new NativeArray <float2>(arrayCount, allocator); int outEdgeCount = 0; int outIndexCount = 0; int outVertexCount = 0; ModuleHandle.Subdivide(allocator, _points, _edges, ref _outVertices, ref outVertexCount, ref _outIndices, ref outIndexCount, ref _outEdges, ref outEdgeCount, areaFactor, areaThreshold, refineIterations, smoothenIterations); for (int i = 0; i < outEdgeCount; ++i) { outEdges[i] = _outEdges[i]; } for (int i = 0; i < outIndexCount; ++i) { outIndices[i] = _outIndices[i]; } for (int i = 0; i < outVertexCount; ++i) { outVertices[i] = _outVertices[i]; } result->x = outVertexCount; result->y = outIndexCount; result->z = outEdgeCount; _outVertices.Dispose(); _outEdges.Dispose(); _outIndices.Dispose(); _points.Dispose(); _edges.Dispose(); }
// Find Target Area to Subdivide for BBW. todo: Burst it. internal static float FindTargetAreaForWeightMesh(List <Vector2> triVertices, List <int> triIndices, float meshAreaFactor, float largestTriangleFactor) { float totalArea = 0, largestArea = 0, targetArea = 0; for (int i = 0; i < triIndices.Count / 3; ++i) { int i1 = triIndices[0 + (i * 3)]; int i2 = triIndices[1 + (i * 3)]; int i3 = triIndices[2 + (i * 3)]; float2 v1 = triVertices[i1]; float2 v2 = triVertices[i2]; float2 v3 = triVertices[i3]; float area = ModuleHandle.TriangleArea(v1, v2, v3); totalArea = totalArea + area; largestArea = largestArea > area ? largestArea : area; } targetArea = Mathf.Max(meshAreaFactor * totalArea, largestTriangleFactor * largestArea); return(targetArea); }
// Triangulate Skipped Original Points. These points are discarded during PlanarGrapg cleanup. But bbw only cares if these are part of any geometry. So just insert them. todo: Burst it. internal static void TriangulateInternal(int[] internalIndices, List <Vector2> triVertices, List <int> triIndices) { foreach (var index in internalIndices) { var v = triVertices[index]; var triangleCount = triIndices.Count / 3; for (int i = 0; i < triangleCount; ++i) { int i1 = triIndices[0 + (i * 3)]; int i2 = triIndices[1 + (i * 3)]; int i3 = triIndices[2 + (i * 3)]; float2 v1 = triVertices[i1]; float2 v2 = triVertices[i2]; float2 v3 = triVertices[i3]; var c1 = (float)Math.Round(ModuleHandle.OrientFast(v1, v2, v), 2); if (c1 == 0) { triIndices[0 + (i * 3)] = i1; triIndices[1 + (i * 3)] = index; triIndices[2 + (i * 3)] = i3; triIndices.Add(index); triIndices.Add(i2); triIndices.Add(i3); } else { var c2 = (float)Math.Round(ModuleHandle.OrientFast(v2, v3, v), 2); if (c2 == 0) { triIndices[0 + (i * 3)] = i2; triIndices[1 + (i * 3)] = index; triIndices[2 + (i * 3)] = i1; triIndices.Add(index); triIndices.Add(i3); triIndices.Add(i1); } else { var c3 = (float)Math.Round(ModuleHandle.OrientFast(v3, v1, v), 2); if (c3 == 0) { triIndices[0 + (i * 3)] = i3; triIndices[1 + (i * 3)] = index; triIndices[2 + (i * 3)] = i2; triIndices.Add(index); triIndices.Add(i1); triIndices.Add(i2); } } } } } }
internal BoneWeight[] CalculateInternal(string name, Vector2[] vertices, int[] indices, Edge[] edges, Vector2[] controlPoints, Edge[] bones, int[] pins, int numSamples, bool subdivide, ref bool done) { done = false; var weights = new BoneWeight[vertices.Length]; for (var i = 0; i < weights.Length; ++i) { weights[i] = defaultWeight; } if (vertices.Length < 3) { return(weights); } var boneSamples = SampleBones(controlPoints, bones, numSamples); var verticesList = new List <Vector2>(vertices.Length + controlPoints.Length + boneSamples.Length); Round(vertices); Round(controlPoints); Round(boneSamples); verticesList.AddRange(vertices); verticesList.AddRange(controlPoints); verticesList.AddRange(boneSamples); var utEdges = new List <Edge>(edges); var utIndices = new List <int>(); var utVertices = new List <Vector2>(vertices); // Input Vertices are well refined and smoothed, just triangulate with bones and cages. bool ok = TriangulationUtility.TriangulateSafe(utVertices, utEdges, utIndices); if (!ok || utIndices.Count == 0) { utIndices.AddRange(indices); utVertices.AddRange(vertices); } else if (subdivide) { var targetArea = TriangulationUtility.FindTargetAreaForWeightMesh(utVertices, utIndices, kMeshAreaFactor, kLargestTriangleAreaFactor); TriangulationUtility.TessellateSafe(0, 0, 0, 0, targetArea, 1, 0, utVertices, utEdges, utIndices); } if (utIndices.Count == 0) { return(weights); } // Copy Original Indices. var coIndices = new List <int>(utIndices); utIndices.Clear(); for (int i = 0; i < coIndices.Count / 3; ++i) { int i1 = coIndices[0 + (i * 3)]; int i2 = coIndices[1 + (i * 3)]; int i3 = coIndices[2 + (i * 3)]; float2 v1 = utVertices[i1]; float2 v2 = utVertices[i2]; float2 v3 = utVertices[i3]; var rt = (float)Math.Round(ModuleHandle.OrientFast(v1, v2, v3), 2); if (rt != 0) { utIndices.Add(i1); utIndices.Add(i2); utIndices.Add(i3); } } // Insert Samplers. var internalPoints = new List <int>(); for (int i = 0; i < utVertices.Count; ++i) { if (utIndices.Count(x => x == i) == 0) { internalPoints.Add(i); } } TriangulationUtility.TriangulateInternal(internalPoints.ToArray(), utVertices, utIndices); TriangulationUtility.TriangulateSamplers(boneSamples, utVertices, utIndices); TriangulationUtility.TriangulateSamplers(controlPoints, utVertices, utIndices); var tessellatedIndices = utIndices.ToArray(); var tessellatedVertices = utVertices.ToArray(); GCHandle verticesHandle = GCHandle.Alloc(tessellatedVertices, GCHandleType.Pinned); GCHandle indicesHandle = GCHandle.Alloc(tessellatedIndices, GCHandleType.Pinned); GCHandle controlPointsHandle = GCHandle.Alloc(controlPoints, GCHandleType.Pinned); GCHandle bonesHandle = GCHandle.Alloc(bones, GCHandleType.Pinned); GCHandle pinsHandle = GCHandle.Alloc(pins, GCHandleType.Pinned); GCHandle weightsHandle = GCHandle.Alloc(weights, GCHandleType.Pinned); int result = Bbw(kNumIterations, verticesHandle.AddrOfPinnedObject(), tessellatedVertices.Length, vertices.Length, indicesHandle.AddrOfPinnedObject(), tessellatedIndices.Length, controlPointsHandle.AddrOfPinnedObject(), controlPoints.Length, bonesHandle.AddrOfPinnedObject(), bones.Length, pinsHandle.AddrOfPinnedObject(), pins.Length, weightsHandle.AddrOfPinnedObject()); switch (result) { case 1: case 2: Debug.LogWarning($"Weight generation failure due to unexpected mesh input. Re-generate the mesh with a different Outline Detail value to resolve the issue. Error Code: {result}"); break; case 3: if (!PlayerSettings.suppressCommonWarnings) { Debug.LogWarning($"Internal weight generation error. Error Code: {result}"); } break; } verticesHandle.Free(); indicesHandle.Free(); controlPointsHandle.Free(); bonesHandle.Free(); pinsHandle.Free(); weightsHandle.Free(); // OhmDebugger.WriteStatisticsText(verticesList.ToArray(), edges, bones, boneSamples, weights, tessellatedVertices, tessellatedIndices, vertices.Length, controlPoints.Length, boneSamples.Length, "UTess", 1000); for (var i = 0; i < weights.Length; ++i) { var weight = weights[i]; if (weight.Sum() == 0f) { weights[i] = defaultWeight; } else if (!done) { done = (weight.boneIndex0 != 0 || weight.boneIndex1 != 0 || weight.boneIndex2 != 0 || weight.boneIndex3 != 0); } } return(weights); }