public override IEnumerator BeginGeneration() { var topology = topologyInputSlot.GetAsset <Topology>(); var vertexNormals = Vector3VertexAttribute.Create(new Vector3[topology.vertices.Count]).SetName("Vertex Normals"); yield return(executive.GenerateConcurrently(() => { switch (calculationMethod) { case CalculationMethod.FromSurfaceNormal: VertexAttributeUtility.CalculateVertexNormalsFromSurface(topology.vertices, surfaceInputSlot.GetAsset <Surface>(), vertexPositionsInputSlot.GetAsset <IVertexAttribute <Vector3> >(), vertexNormals); break; case CalculationMethod.FromVertexPositions: VertexAttributeUtility.CalculateVertexNormalsFromVertexPositions(topology.vertices, vertexPositionsInputSlot.GetAsset <IVertexAttribute <Vector3> >(), vertexNormals); break; case CalculationMethod.FromFacePositions: VertexAttributeUtility.CalculateVertexNormalsFromFacePositions(topology.vertices, facePositionsInputSlot.GetAsset <IFaceAttribute <Vector3> >(), vertexNormals); break; case CalculationMethod.FromFaceNormals: VertexAttributeUtility.CalculateVertexNormalsFromFaceNormals(topology.vertices, faceNormalsInputSlot.GetAsset <IFaceAttribute <Vector3> >(), vertexNormals); break; default: throw new System.NotImplementedException(); } })); vertexNormalsOutputSlot.SetAsset(vertexNormals); yield break; }
/// <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="surface">The spherical surface describing the overall shape of the manifold.</param> /// <param name="topology">The topology to relax.</param> /// <param name="vertexPositions">The original positions of the vertices to relax.</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> /// <param name="faceCentroidAngles">A pre-allocated collection in which the intermediate face centroid angles will be stored.</param> /// <returns>The relaxed vertex positions.</returns> public static IVertexAttribute <Vector3> RelaxVertexPositionsForEqualArea(SphericalSurface surface, Topology topology, IVertexAttribute <Vector3> vertexPositions, bool lockBoundaryPositions, IVertexAttribute <Vector3> relaxedVertexPositions, IFaceAttribute <Vector3> faceCentroids, IEdgeAttribute <float> faceCentroidAngles, IVertexAttribute <float> vertexAreas) { var idealArea = surface.radius * surface.radius * 4f * Mathf.PI / topology.vertices.Count; FaceAttributeUtility.CalculateSphericalFaceCentroidsFromVertexPositions(topology.internalFaces, surface, vertexPositions, faceCentroids); EdgeAttributeUtility.CalculateSphericalFaceCentroidAnglesFromFaceCentroids(topology.faceEdges, surface, faceCentroids, faceCentroidAngles); VertexAttributeUtility.CalculateSphericalVertexAreasFromFaceCentroidAngles(topology.vertices, surface, faceCentroidAngles, 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] = relaxedVertexPositions[vertex].WithMagnitude(surface.radius); } else { relaxedVertexPositions[vertex] = vertexPositions[vertex]; } } return(relaxedVertexPositions); }
/// <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; }