/// <summary> /// Attempts to move the positions of vertices such that they have roughly uniform density, with a bias towards also making sure that the surface areas of the faces also become more uniform. /// </summary> /// <param name="topology">The topology to relax.</param> /// <param name="vertexPositions">The original positions of the vertices to relax.</param> /// <param name="totalArea">The total surface area of the internal faces of the topology.</param> /// <param name="lockBoundaryPositions">Indicates that vertices with an external neighboring face should not have their positions altered.</param> /// <param name="relaxedVertexPositions">A pre-allocated collection in which the relaxed vertex positions will be stored. Should not be the same collection as <paramref name="vertexPositions"/>.</param> /// <param name="faceCentroids">A pre-allocated collection in which the intermediate face centroid positions will be stored.</param> /// <param name="vertexAreas">A pre-allocated collection in which the intermediate nearby surface areas of vertices will be stored.</param> /// <returns>The relaxed vertex positions.</returns> public static IVertexAttribute <Vector3> RelaxVertexPositionsForEqualArea(Topology topology, IVertexAttribute <Vector3> vertexPositions, float totalArea, bool lockBoundaryPositions, IVertexAttribute <Vector3> relaxedVertexPositions, IFaceAttribute <Vector3> faceCentroids, IVertexAttribute <float> vertexAreas) { var idealArea = totalArea / topology.vertices.Count; FaceAttributeUtility.CalculateFaceCentroidsFromVertexPositions(topology.internalFaces, vertexPositions, faceCentroids); VertexAttributeUtility.CalculateVertexAreasFromVertexPositionsAndFaceCentroids(topology.vertices, vertexPositions, faceCentroids, vertexAreas); for (int i = 0; i < topology.vertices.Count; ++i) { relaxedVertexPositions[i] = new Vector3(0f, 0f, 0f); } foreach (var vertex in topology.vertices) { var multiplier = Mathf.Sqrt(idealArea / vertexAreas[vertex]); foreach (var edge in vertex.edges) { var neighborVertex = edge.vertex; var neighborRelativeCenter = vertexPositions[edge.twin]; relaxedVertexPositions[neighborVertex] += (vertexPositions[neighborVertex] - neighborRelativeCenter) * multiplier + neighborRelativeCenter; } } foreach (var vertex in topology.vertices) { if (!lockBoundaryPositions || !vertex.hasExternalFaceNeighbor) { relaxedVertexPositions[vertex] /= vertex.neighborCount; } else { relaxedVertexPositions[vertex] = vertexPositions[vertex]; } } return(relaxedVertexPositions); }
public override IEnumerator BeginGeneration() { var surface = surfaceInputSlot.GetAsset <Surface>(); var topology = topologyInputSlot.GetAsset <Topology>(); var vertexPositions = vertexPositionsInputSlot.source != null?vertexPositionsInputSlot.GetAsset <IVertexAttribute <Vector3> >() : null; var random = randomness.GetRandom(); System.Func <float> relaxIterationFunction = null; System.Func <bool> repairFunction = null; System.Action relaxationLoopFunction = null; if (vertexPositions != null) { if (surface is QuadrilateralSurface) { if (relaxForRegularityWeight >= 1.0f) { var relaxedVertexPositions = new Vector3[topology.vertices.Count].AsVertexAttribute(); relaxIterationFunction = () => { PlanarManifoldUtility.RelaxVertexPositionsForRegularity(topology, vertexPositions, lockBoundaryPositions, relaxedVertexPositions); var relaxationAmount = PlanarManifoldUtility.CalculateRelaxationAmount(vertexPositions, relaxedVertexPositions); for (int i = 0; i < vertexPositions.Count; ++i) { vertexPositions[i] = relaxedVertexPositions[i]; } return(relaxationAmount); }; } else if (relaxForRegularityWeight <= 0.0f) { var relaxedVertexPositions = new Vector3[topology.vertices.Count].AsVertexAttribute(); var faceCentroids = PositionalFaceAttribute.Create(surface, topology.internalFaces.Count); var vertexAreas = new float[topology.vertices.Count].AsVertexAttribute(); FaceAttributeUtility.CalculateFaceCentroidsFromVertexPositions(topology.internalFaces, vertexPositions, faceCentroids); VertexAttributeUtility.CalculateVertexAreasFromVertexPositionsAndFaceCentroids(topology.vertices, vertexPositions, faceCentroids, vertexAreas); var totalArea = 0f; foreach (var vertexArea in vertexAreas) { totalArea += vertexArea; } relaxIterationFunction = () => { PlanarManifoldUtility.RelaxVertexPositionsForEqualArea(topology, vertexPositions, totalArea, lockBoundaryPositions, relaxedVertexPositions, faceCentroids, vertexAreas); var relaxationAmount = PlanarManifoldUtility.CalculateRelaxationAmount(vertexPositions, relaxedVertexPositions); for (int i = 0; i < vertexPositions.Count; ++i) { vertexPositions[i] = relaxedVertexPositions[i]; } return(relaxationAmount); }; } else { var regularityWeight = Mathf.Clamp01(relaxForRegularityWeight); var equalAreaWeight = 1f - regularityWeight; var regularityRelaxedVertexPositions = new Vector3[topology.vertices.Count].AsVertexAttribute(); var equalAreaRelaxedVertexPositions = new Vector3[topology.vertices.Count].AsVertexAttribute(); var relaxedVertexPositions = regularityRelaxedVertexPositions; var faceCentroids = PositionalFaceAttribute.Create(surface, topology.internalFaces.Count); var vertexAreas = new float[topology.vertices.Count].AsVertexAttribute(); FaceAttributeUtility.CalculateFaceCentroidsFromVertexPositions(topology.internalFaces, vertexPositions, faceCentroids); VertexAttributeUtility.CalculateVertexAreasFromVertexPositionsAndFaceCentroids(topology.vertices, vertexPositions, faceCentroids, vertexAreas); var totalArea = 0f; foreach (var vertexArea in vertexAreas) { totalArea += vertexArea; } relaxIterationFunction = () => { PlanarManifoldUtility.RelaxVertexPositionsForRegularity(topology, vertexPositions, lockBoundaryPositions, regularityRelaxedVertexPositions); PlanarManifoldUtility.RelaxVertexPositionsForEqualArea(topology, vertexPositions, totalArea, lockBoundaryPositions, equalAreaRelaxedVertexPositions, faceCentroids, vertexAreas); for (int i = 0; i < relaxedVertexPositions.Count; ++i) { relaxedVertexPositions[i] = regularityRelaxedVertexPositions[i] * regularityWeight + equalAreaRelaxedVertexPositions[i] * equalAreaWeight; } var relaxationAmount = PlanarManifoldUtility.CalculateRelaxationAmount(vertexPositions, relaxedVertexPositions); for (int i = 0; i < vertexPositions.Count; ++i) { vertexPositions[i] = relaxedVertexPositions[i]; } return(relaxationAmount); }; } repairFunction = () => { return(PlanarManifoldUtility.ValidateAndRepair(topology, ((QuadrilateralSurface)surface).normal, vertexPositions, repairRate, lockBoundaryPositions)); }; relaxationLoopFunction = TopologyRandomizer.CreateRelaxationLoopFunction(maxRelaxIterations, maxRepairIterations, relaxRelativePrecision, relaxIterationFunction, repairFunction); } else if (surface is SphericalSurface) { var sphericalSurface = (SphericalSurface)surface; if (relaxForRegularityWeight >= 1.0f) { var relaxedVertexPositions = new Vector3[topology.vertices.Count].AsVertexAttribute(); relaxIterationFunction = () => { SphericalManifoldUtility.RelaxVertexPositionsForRegularity(sphericalSurface, topology, vertexPositions, lockBoundaryPositions, relaxedVertexPositions); var relaxationAmount = SphericalManifoldUtility.CalculateRelaxationAmount(vertexPositions, relaxedVertexPositions); for (int i = 0; i < vertexPositions.Count; ++i) { vertexPositions[i] = relaxedVertexPositions[i]; } return(relaxationAmount); }; } else if (relaxForRegularityWeight <= 0.0f) { var relaxedVertexPositions = new Vector3[topology.vertices.Count].AsVertexAttribute(); var faceCentroids = PositionalFaceAttribute.Create(surface, topology.internalFaces.Count); var faceCentroidAngles = new float[topology.faceEdges.Count].AsEdgeAttribute(); var vertexAreas = new float[topology.vertices.Count].AsVertexAttribute(); relaxIterationFunction = () => { SphericalManifoldUtility.RelaxVertexPositionsForEqualArea(sphericalSurface, topology, vertexPositions, lockBoundaryPositions, relaxedVertexPositions, faceCentroids, faceCentroidAngles, vertexAreas); var relaxationAmount = SphericalManifoldUtility.CalculateRelaxationAmount(vertexPositions, relaxedVertexPositions); for (int i = 0; i < vertexPositions.Count; ++i) { vertexPositions[i] = relaxedVertexPositions[i]; } return(relaxationAmount); }; } else { var regularityWeight = Mathf.Clamp01(relaxForRegularityWeight); var equalAreaWeight = 1f - regularityWeight; var regularityRelaxedVertexPositions = new Vector3[topology.vertices.Count].AsVertexAttribute(); var equalAreaRelaxedVertexPositions = new Vector3[topology.vertices.Count].AsVertexAttribute(); var relaxedVertexPositions = regularityRelaxedVertexPositions; var faceCentroids = PositionalFaceAttribute.Create(surface, topology.internalFaces.Count); var faceCentroidAngles = new float[topology.faceEdges.Count].AsEdgeAttribute(); var vertexAreas = new float[topology.vertices.Count].AsVertexAttribute(); relaxIterationFunction = () => { SphericalManifoldUtility.RelaxVertexPositionsForRegularity(sphericalSurface, topology, vertexPositions, lockBoundaryPositions, regularityRelaxedVertexPositions); SphericalManifoldUtility.RelaxVertexPositionsForEqualArea(sphericalSurface, topology, vertexPositions, lockBoundaryPositions, equalAreaRelaxedVertexPositions, faceCentroids, faceCentroidAngles, vertexAreas); for (int i = 0; i < relaxedVertexPositions.Count; ++i) { relaxedVertexPositions[i] = regularityRelaxedVertexPositions[i] * regularityWeight + equalAreaRelaxedVertexPositions[i] * equalAreaWeight; } var relaxationAmount = SphericalManifoldUtility.CalculateRelaxationAmount(vertexPositions, relaxedVertexPositions); for (int i = 0; i < vertexPositions.Count; ++i) { vertexPositions[i] = relaxedVertexPositions[i]; } return(relaxationAmount); }; } repairFunction = () => { return(SphericalManifoldUtility.ValidateAndRepair(sphericalSurface, topology, vertexPositions, repairRate, lockBoundaryPositions)); }; relaxationLoopFunction = TopologyRandomizer.CreateRelaxationLoopFunction(maxRelaxIterations, maxRepairIterations, relaxRelativePrecision, relaxIterationFunction, repairFunction); } } yield return(executive.GenerateConcurrently(() => { TopologyRandomizer.Randomize(topology, passCount, frequency, minVertexNeighbors, maxVertexNeighbors, minFaceNeighbors, maxFaceNeighbors, lockBoundaryPositions, random, relaxationLoopFunction); })); EditorUtility.SetDirty(topology); if (vertexPositions != null) { EditorUtility.SetDirty((Object)vertexPositions); } yield break; }