public override IEnumerator BeginGeneration() { var topology = topologyInputSlot.GetAsset <Topology>(); var faceNormals = Vector3FaceAttribute.Create(new Vector3[topology.internalFaces.Count]).SetName("Face Normals"); yield return(executive.GenerateConcurrently(() => { switch (calculationMethod) { case CalculationMethod.FromSurfaceNormal: FaceAttributeUtility.CalculateFaceNormalsFromSurface(topology.internalFaces, surfaceInputSlot.GetAsset <Surface>(), facePositionsInputSlot.GetAsset <IFaceAttribute <Vector3> >(), faceNormals); break; case CalculationMethod.FromVertexPositions: FaceAttributeUtility.CalculateFaceNormalsFromVertexPositions(topology.internalFaces, vertexPositionsInputSlot.GetAsset <IVertexAttribute <Vector3> >(), faceNormals); break; case CalculationMethod.FromVertexNormals: FaceAttributeUtility.CalculateFaceNormalsFromVertexNormals(topology.internalFaces, vertexNormalsInputSlot.GetAsset <IVertexAttribute <Vector3> >(), faceNormals); break; case CalculationMethod.FromFacePositions: FaceAttributeUtility.CalculateFaceNormalsFromFacePositions(topology.internalFaces, facePositionsInputSlot.GetAsset <IFaceAttribute <Vector3> >(), faceNormals); break; default: throw new System.NotImplementedException(); } })); faceNormalsOutputSlot.SetAsset(faceNormals); yield break; }
public override IEnumerator BeginGeneration() { var surface = surfaceInputSlot.GetAsset <Surface>(); var topology = topologyInputSlot.GetAsset <Topology>(); var vertexPositions = vertexPositionsInputSlot.GetAsset <IVertexAttribute <Vector3> >(); var faceCentroids = PositionalFaceAttribute.Create(surface, new Vector3[topology.internalFaces.Count]).SetName("Face Centroids"); yield return(executive.GenerateConcurrently(() => { if (flatten || surface is QuadrilateralSurface) { FaceAttributeUtility.CalculateFaceCentroidsFromVertexPositions(topology.internalFaces, vertexPositions, faceCentroids); } else if (surface is SphericalSurface) { var sphericalSurface = (SphericalSurface)surface; FaceAttributeUtility.CalculateSphericalFaceCentroidsFromVertexPositions(topology.internalFaces, sphericalSurface, vertexPositions, faceCentroids); } else { throw new System.NotImplementedException(); } })); faceCentroidsOutputSlot.SetAsset(faceCentroids); yield break; }
public void CreateIcosahedron(float radius) { surface = SphericalSurface.Create(Vector3.up, Vector3.right, radius); Vector3[] vertexPositionsArray; SphericalManifoldUtility.CreateIcosahedron((SphericalSurface)surface, out topology, out vertexPositionsArray); vertexPositions = vertexPositionsArray.AsVertexAttribute(); facePositions = FaceAttributeUtility.CalculateFaceCentroidsFromVertexPositions(topology.internalFaces, vertexPositions); partitioning = UniversalFaceSpatialPartitioning.Create(surface, topology, vertexPositions); }
protected void Start() { var hexGridSurface = RectangularHexGrid.Create( HexGridDescriptor.CreateSideUp(true, HexGridAxisStyles.StaggeredSymmetric), Vector3.zero, Quaternion.Euler(90f, 0f, 0f), false, false, new IntVector2(topologyWidth, topologyHeight)); _surface = hexGridSurface; Vector3[] vertexPositionsArray; _topology = hexGridSurface.CreateManifold(out vertexPositionsArray); _vertexPositions = vertexPositionsArray.AsVertexAttribute(); _facePositions = FaceAttributeUtility.CalculateFaceCentroidsFromVertexPositions(_topology.internalFaces, _vertexPositions); _faceCornerBisectors = EdgeAttributeUtility.CalculateFaceEdgeBisectorsFromVertexPositions(_topology.internalFaces, _vertexPositions, _facePositions); _faceBlockedStates = new bool[_topology.internalFaces.Count].AsFaceAttribute(); var triangulation = new SeparatedFacesUmbrellaTriangulation(2, (Topology.FaceEdge edge, DynamicMesh.IIndexedVertexAttributes vertexAttributes) => { vertexAttributes.position = _vertexPositions[edge]; vertexAttributes.normal = Vector3.up; vertexAttributes.color = borderColor; vertexAttributes.Advance(); vertexAttributes.position = _vertexPositions[edge] + _faceCornerBisectors[edge] * 0.05f; vertexAttributes.normal = (vertexAttributes.position + Vector3.up - _facePositions[edge.nearFace]).normalized; vertexAttributes.color = normalColor; vertexAttributes.Advance(); }, (Topology.Face face, DynamicMesh.IIndexedVertexAttributes vertexAttributes) => { vertexAttributes.position = _facePositions[face]; vertexAttributes.normal = Vector3.up; vertexAttributes.color = normalColor; vertexAttributes.Advance(); }); _dynamicMesh = DynamicMesh.Create( _topology.enumerableInternalFaces, DynamicMesh.VertexAttributes.Position | DynamicMesh.VertexAttributes.Normal | DynamicMesh.VertexAttributes.Color, triangulation); foreach (var mesh in _dynamicMesh.submeshes) { var meshFilter = Instantiate(submeshPrefab); meshFilter.mesh = mesh; meshFilter.transform.SetParent(transform, false); } var partioning = UniversalFaceSpatialPartitioning.Create(_surface, _topology, _vertexPositions); var picker = GetComponent <FaceSpatialPartitioningPicker>(); picker.partitioning = partioning; }
public void CreateHexGrid(int width, int height) { surface = RectangularHexGrid.Create(HexGridDescriptor.standardCornerUp, Vector3.zero, Quaternion.identity, false, false, new IntVector2(width, height)); Vector3[] vertexPositionsArray; topology = ((RectangularHexGrid)surface).CreateManifold(out vertexPositionsArray); vertexPositions = vertexPositionsArray.AsVertexAttribute(); facePositions = FaceAttributeUtility.CalculateFaceCentroidsFromVertexPositions(topology.internalFaces, vertexPositions); partitioning = UniversalFaceSpatialPartitioning.Create(surface, topology, vertexPositions); }
public void CreateDistortedQuadGrid(int width, int height, int seed) { var quadGrid = RectangularQuadGrid.Create(Vector2.right, Vector2.up, Vector3.zero, Quaternion.identity, false, false, new IntVector2(width, height)); surface = quadGrid; Vector3[] vertexPositionsArray; topology = quadGrid.CreateManifold(out vertexPositionsArray); vertexPositions = vertexPositionsArray.AsVertexAttribute(); var random = XorShift128Plus.Create(seed); var maxOffsetRadius = Mathf.Sqrt(2f) / 5f; for (int y = 1; y < height; ++y) { for (int x = 1; x < width; ++x) { vertexPositions[quadGrid.GetVertexIndex(x, y)] += (Vector3)random.PointWithinCircle(maxOffsetRadius); } } facePositions = FaceAttributeUtility.CalculateFaceCentroidsFromVertexPositions(topology.internalFaces, vertexPositions); partitioning = UniversalFaceSpatialPartitioning.Create(surface, topology, vertexPositions); }
public void CreateDistortedHexGrid(int width, int height, int seed) { var hexGrid = RectangularHexGrid.Create(HexGridDescriptor.standardCornerUp, Vector3.zero, Quaternion.identity, false, false, new IntVector2(width, height)); surface = hexGrid; Vector3[] vertexPositionsArray; topology = hexGrid.CreateManifold(out vertexPositionsArray); vertexPositions = vertexPositionsArray.AsVertexAttribute(); var random = XorShift128Plus.Create(seed); var maxOffsetRadius = Mathf.Sqrt(3f) / 8f; foreach (var vertex in topology.vertices) { if (!vertex.hasExternalFaceNeighbor) { vertexPositions[vertex] += (Vector3)random.PointWithinCircle(maxOffsetRadius); } } facePositions = FaceAttributeUtility.CalculateFaceCentroidsFromVertexPositions(topology.internalFaces, vertexPositions); partitioning = UniversalFaceSpatialPartitioning.Create(surface, topology, vertexPositions); }
/// <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); }
private void CreateGrid(out Topology topology, out IVertexAttribute <Vector3> vertexPositions, out IFaceAttribute <Vector3> facePositions) { if (squareGridToggle.isOn) { CreateSquareGrid(out topology, out vertexPositions); } else if (hexGrid1Toggle.isOn) { CreateHexGrid1(out topology, out vertexPositions); } else if (hexGrid2Toggle.isOn) { CreateHexGrid2(out topology, out vertexPositions); } else { CreateJumbledGrid(out topology, out vertexPositions); } _topology = topology; _vertexPositions = vertexPositions; facePositions = FaceAttributeUtility.CalculateFaceCentroidsFromVertexPositions(topology.internalFaces, vertexPositions); }
/// <summary> /// Reverses the roles of vertices and faces, as when taking the dual of a polyhedron. /// </summary> /// <param name="topology">The topology containing the vertices and faces to swap.</param> /// <param name="vertexPositions">The original positions of the vertices.</param> /// <param name="dualVertexPositions">The positions of the vertices after the swap, calculated as the face centroids of the original topology.</param> public static void MakeDual(Topology topology, IVertexAttribute <Vector3> vertexPositions, out Vector3[] dualVertexPositions) { ManifoldUtility.MakeDual(topology, FaceAttributeUtility.CalculateFaceCentroidsFromVertexPositions(topology.faces, vertexPositions), out dualVertexPositions); }
public void StartNewGame() { DestroyOldGame(); Vector3[] vertexPositionsArray; if (squaresToggle.isOn) { IntVector2 boardSize; if (smallToggle.isOn) { boardSize = new IntVector2(9, 9); } else if (mediumToggle.isOn) { boardSize = new IntVector2(13, 13); } else { boardSize = new IntVector2(19, 19); } _surface = RectangularQuadGrid.Create(Vector2.right, Vector2.up, Vector3.zero, Quaternion.identity, false, false, boardSize); _topology = ((RectangularQuadGrid)_surface).CreateManifold(out vertexPositionsArray); _vertexPositions = PositionalVertexAttribute.Create(_surface, vertexPositionsArray); } else if (hexesToggle.isOn) { IntVector2 boardSize; if (smallToggle.isOn) { boardSize = new IntVector2(9, 9); } else if (mediumToggle.isOn) { boardSize = new IntVector2(13, 13); } else { boardSize = new IntVector2(19, 19); } _surface = RectangularHexGrid.Create( HexGridDescriptor.CreateCornerUp(true, HexGridAxisStyles.StaggeredSymmetric), Vector3.zero, Quaternion.identity, false, false, boardSize); _topology = ((RectangularHexGrid)_surface).CreateManifold(out vertexPositionsArray); _vertexPositions = PositionalVertexAttribute.Create(_surface, vertexPositionsArray); } else { IntVector2 boardSize; if (smallToggle.isOn) { boardSize = new IntVector2(9, 9); } else if (mediumToggle.isOn) { boardSize = new IntVector2(13, 13); } else { boardSize = new IntVector2(19, 19); } _surface = RectangularHexGrid.Create( HexGridDescriptor.CreateCornerUp(true, HexGridAxisStyles.StaggeredSymmetric), Vector3.zero, Quaternion.identity, false, false, boardSize); _topology = ((RectangularHexGrid)_surface).CreateManifold(out vertexPositionsArray); _vertexPositions = PositionalVertexAttribute.Create(_surface, vertexPositionsArray); var regularityWeight = 0.5f; 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; } Func <float> relaxIterationFunction = () => { PlanarManifoldUtility.RelaxVertexPositionsForRegularity(_topology, _vertexPositions, true, regularityRelaxedVertexPositions); PlanarManifoldUtility.RelaxVertexPositionsForEqualArea(_topology, _vertexPositions, totalArea, true, 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); }; Func <bool> repairFunction = () => { return(PlanarManifoldUtility.ValidateAndRepair(_topology, _surface.normal, _vertexPositions, 0.5f, true)); }; Action relaxationLoopFunction = TopologyRandomizer.CreateRelaxationLoopFunction(20, 20, 0.95f, relaxIterationFunction, repairFunction); TopologyRandomizer.Randomize( _topology, 1, 0.1f, 3, 3, 5, 7, true, _random, relaxationLoopFunction); } _facePositions = PositionalFaceAttribute.Create(_surface, _topology.internalFaces.Count); FaceAttributeUtility.CalculateFaceCentroidsFromVertexPositions(_topology.internalFaces, _vertexPositions, _facePositions); _innerAngleBisectors = EdgeAttributeUtility.CalculateFaceEdgeBisectorsFromVertexPositions(_topology.internalFaces, PlanarSurface.Create(Vector3.zero, Quaternion.identity), _vertexPositions); _faceBoardStates = new BoardState[_topology.internalFaces.Count].AsFaceAttribute(); foreach (var face in _topology.internalFaces) { _faceBoardStates[face] = BoardState.Empty; } _facePieces = new Transform[_topology.internalFaces.Count].AsFaceAttribute(); _partitioning = UniversalFaceSpatialPartitioning.Create(_surface, _topology, _vertexPositions); _picker.partitioning = _partitioning; _picker.enabled = true; var centerVertexNormal = _surface.normal.normalized; var triangulation = new SeparatedFacesUmbrellaTriangulation(2, (Topology.FaceEdge edge, DynamicMesh.IIndexedVertexAttributes vertexAttributes) => { vertexAttributes.position = _vertexPositions[edge]; vertexAttributes.normal = (_vertexPositions[edge] + _surface.normal * 5f - _facePositions[edge.nearFace]).normalized; vertexAttributes.uv = new Vector2(0.25f, 0f); vertexAttributes.Advance(); vertexAttributes.position = _vertexPositions[edge] + _innerAngleBisectors[edge] * 0.05f; vertexAttributes.normal = (vertexAttributes.position + _surface.normal * 5f - _facePositions[edge.nearFace]).normalized; vertexAttributes.uv = new Vector2(0.25f, 0.5f); vertexAttributes.Advance(); }, (Topology.Face face, DynamicMesh.IIndexedVertexAttributes vertexAttributes) => { vertexAttributes.position = _facePositions[face]; vertexAttributes.normal = centerVertexNormal; vertexAttributes.uv = new Vector2(0.25f, 1f); vertexAttributes.Advance(); }); _dynamicMesh = DynamicMesh.Create( _topology.enumerableInternalFaces, DynamicMesh.VertexAttributes.Position | DynamicMesh.VertexAttributes.Normal | DynamicMesh.VertexAttributes.UV, triangulation); foreach (var mesh in _dynamicMesh.submeshes) { var meshObject = Instantiate(meshFilterRendererPrefab); meshObject.mesh = mesh; meshObject.transform.SetParent(gameBoardMeshes); } _gameBoardBounds = new Bounds(Vector3.zero, Vector3.zero); foreach (var vertex in _topology.vertices) { _gameBoardBounds.Encapsulate(_vertexPositions[vertex]); } AdjustCamera(); var pickerCollider = GetComponent <BoxCollider>(); pickerCollider.center = _gameBoardBounds.center; pickerCollider.size = _gameBoardBounds.size; _whiteCount = 0; _blackCount = 0; _moveCount = 0; whiteCountText.text = _whiteCount.ToString(); blackCountText.text = _blackCount.ToString(); _gameActive = true; _turn = BoardState.Black; }
/// <summary> /// Exports the given manifold to SVG format with the given style, flattening it onto a plane if necessary. /// </summary> /// <param name="writer">The writer to which the SVG-formatted manifold will be written.</param> /// <param name="surface">The surface describing the manifold.</param> /// <param name="topology">The topology of the manifold.</param> /// <param name="orientation">The orientation of the plane to which the manifold will be flattened.</param> /// <param name="scale">The scale which will be applied to the manifold while writing out SVG positions.</param> /// <param name="vertexPositions">The vertex positions of the manifold.</param> /// <param name="numericFormat">The format specifier to use for each number written to <paramref name="writer"/>.</param> /// <param name="style">The style details to apply to the SVG content.</param> public static void ExportToSVG(System.IO.TextWriter writer, ISurface surface, Topology topology, Quaternion orientation, Vector3 scale, IVertexAttribute <Vector3> vertexPositions, string numericFormat, SVGStyle style) { var inverseOrientation = Quaternion.Inverse(orientation); var plane = new Plane(orientation * Vector3.back, 0f); var transform = Matrix4x4.TRS(Vector3.zero, inverseOrientation, scale); Vector2 transformedVertexDotRadius = new Vector2(style.vertexCircleRadius * transform.m00, style.vertexCircleRadius * transform.m11); Func <Vector3, Vector2> flatten = (Vector3 point) => transform *plane.ClosestPoint(point); Vector2 min = new Vector2(float.PositiveInfinity, float.PositiveInfinity); Vector2 max = new Vector2(float.NegativeInfinity, float.NegativeInfinity); foreach (var face in topology.faces) { foreach (var edge in face.edges) { var p = flatten(vertexPositions[edge]); min = Geometry.AxisAlignedMin(min, p); max = Geometry.AxisAlignedMax(max, p); } } var range = max - min; flatten = (Vector3 point) => { Vector2 p = transform * plane.ClosestPoint(point); p.y = max.y - p.y + min.y; return(p); }; writer.WriteLine("<svg viewBox=\"{0} {1} {2} {3}\" xmlns=\"http://www.w3.org/2000/svg\">", (min.x - style.padding.x).ToString(numericFormat), (min.y - style.padding.y).ToString(numericFormat), (range.x + style.padding.x * 2f).ToString(numericFormat), (range.y + style.padding.y * 2f).ToString(numericFormat)); writer.WriteLine("\t<style>"); writer.WriteLine("\t\tsvg"); writer.WriteLine("\t\t{"); if (!style.svg.ContainsKey("width")) { writer.WriteLine("\t\t\twidth: 100%;"); } if (!style.svg.ContainsKey("height")) { writer.WriteLine("\t\t\theight: 100%;"); } foreach (var keyValue in style.svg) { writer.WriteLine("\t\t\t{0}: {1};", keyValue.Key, keyValue.Value); } writer.WriteLine("\t\t}"); writer.WriteLine("\t\ttext.index"); writer.WriteLine("\t\t{"); foreach (var keyValue in style.index) { writer.WriteLine("\t\t\t{0}: {1};", keyValue.Key, keyValue.Value); } writer.WriteLine("\t\t}"); writer.WriteLine("\t\tellipse.vertex"); writer.WriteLine("\t\t{"); if (!style.vertexCircle.ContainsKey("stroke")) { writer.WriteLine("\t\t\tstroke: black;"); } if (!style.vertexCircle.ContainsKey("stroke-width")) { writer.WriteLine("\t\t\tstroke-width: 1;"); } if (!style.vertexCircle.ContainsKey("fill")) { writer.WriteLine("\t\t\tfill: none;"); } foreach (var keyValue in style.vertexCircle) { writer.WriteLine("\t\t\t{0}: {1};", keyValue.Key, keyValue.Value); } writer.WriteLine("\t\t}"); writer.WriteLine("\t\ttext.vertex.index"); writer.WriteLine("\t\t{"); if (!style.vertexIndex.ContainsKey("fill")) { writer.WriteLine("\t\t\tfill: black;"); } if (!style.vertexIndex.ContainsKey("font-size")) { writer.WriteLine("\t\t\tfont-size: {0:F0}px;", transformedVertexDotRadius.x); } if (!style.vertexIndex.ContainsKey("text-anchor")) { writer.WriteLine("\t\t\ttext-anchor: middle;"); } if (!style.vertexIndex.ContainsKey("dominant-baseline")) { writer.WriteLine("\t\t\tdominant-baseline: central;"); } foreach (var keyValue in style.vertexIndex) { writer.WriteLine("\t\t\t{0}: {1};", keyValue.Key, keyValue.Value); } writer.WriteLine("\t\t}"); writer.WriteLine("\t\tpolygon.face"); writer.WriteLine("\t\t{"); if (!style.facePolygon.ContainsKey("fill")) { writer.WriteLine("\t\t\tfill: #CCC;"); } if (!style.facePolygon.ContainsKey("stroke")) { writer.WriteLine("\t\t\tstroke: none;"); } foreach (var keyValue in style.facePolygon) { writer.WriteLine("\t\t\t{0}: {1};", keyValue.Key, keyValue.Value); } writer.WriteLine("\t\t}"); writer.WriteLine("\t\ttext.face.index"); writer.WriteLine("\t\t{"); if (!style.faceIndex.ContainsKey("fill")) { writer.WriteLine("\t\t\tfill: black;"); } if (!style.faceIndex.ContainsKey("font-size")) { writer.WriteLine("\t\t\tfont-size: {0:F0}px;", transformedVertexDotRadius.x * 2f); } if (!style.faceIndex.ContainsKey("text-anchor")) { writer.WriteLine("\t\t\ttext-anchor: middle;"); } if (!style.faceIndex.ContainsKey("dominant-baseline")) { writer.WriteLine("\t\t\tdominant-baseline: central;"); } foreach (var keyValue in style.faceIndex) { writer.WriteLine("\t\t\t{0}: {1};", keyValue.Key, keyValue.Value); } writer.WriteLine("\t\t}"); writer.WriteLine("\t\tpolyline.edge"); writer.WriteLine("\t\t{"); if (!style.edgePath.ContainsKey("stroke")) { writer.WriteLine("\t\t\tstroke: black;"); } if (!style.edgePath.ContainsKey("stroke-width")) { writer.WriteLine("\t\t\tstroke-width: 1;"); } if (!style.edgePath.ContainsKey("stroke-linecap")) { writer.WriteLine("\t\t\tstroke-linecap: square;"); } if (!style.edgePath.ContainsKey("stroke-linejoin")) { writer.WriteLine("\t\t\tstroke-linejoin: miter;"); } if (!style.edgePath.ContainsKey("fill")) { writer.WriteLine("\t\t\tfill: none;"); } foreach (var keyValue in style.edgePath) { writer.WriteLine("\t\t\t{0}: {1};", keyValue.Key, keyValue.Value); } writer.WriteLine("\t\t}"); writer.WriteLine("\t\ttext.edge.index"); writer.WriteLine("\t\t{"); if (!style.edgeIndex.ContainsKey("fill")) { writer.WriteLine("\t\t\tfill: black;"); } if (!style.edgeIndex.ContainsKey("font-size")) { writer.WriteLine("\t\t\tfont-size: {0:F0}px;", style.edgeIndexOffset * Mathf.Sqrt(transform.m00 * transform.m11)); } if (!style.edgeIndex.ContainsKey("text-anchor")) { writer.WriteLine("\t\t\ttext-anchor: middle;"); } if (!style.edgeIndex.ContainsKey("dominant-baseline")) { writer.WriteLine("\t\t\tdominant-baseline: central;"); } foreach (var keyValue in style.edgeIndex) { writer.WriteLine("\t\t\t{0}: {1};", keyValue.Key, keyValue.Value); } writer.WriteLine("\t\t}"); writer.WriteLine("\t</style>"); var facePointFormat = string.Format("{{0:{0}}},{{1:{0}}}", numericFormat); var faceIndexFormat = string.Format("\t<text class=\"face index\" x=\"{{0:{0}}}\" y=\"{{1:{0}}}\">{{2}}</text>", numericFormat); var arrowFormat = string.Format("\t<polyline class=\"edge{{6}}\" points=\"{{0:{0}}},{{1:{0}}} {{2:{0}}},{{3:{0}}} {{4:{0}}},{{5:{0}}}\" />", numericFormat); var edgeIndexFormat = string.Format("\t<text class=\"edge index{{3}}\" x=\"{{0:{0}}}\" y=\"{{1:{0}}}\">{{2}}</text>", numericFormat); var vertexFormat = string.Format("\t<ellipse class=\"vertex{{4}}\" cx=\"{{0:{0}}}\" cy=\"{{1:{0}}}\" rx=\"{{2:{0}}}\" ry=\"{{3:{0}}}\" />", numericFormat); var vertexIndexFormat = string.Format("\t<text class=\"vertex index{{3}}\" x=\"{{0:{0}}}\" y=\"{{1:{0}}}\">{{2}}</text>", numericFormat); var centroids = FaceAttributeUtility.CalculateFaceCentroidsFromVertexPositions(topology.internalFaces, vertexPositions); var bisectors = EdgeAttributeUtility.CalculateFaceEdgeBisectorsFromVertexPositions(topology.internalFaces, surface, vertexPositions, centroids); writer.WriteLine(); writer.WriteLine("\t<!-- Faces -->"); foreach (var face in topology.internalFaces) { writer.Write("\t<polygon class=\"face\" points=\""); foreach (var edge in face.edges) { if (edge != face.firstEdge) { writer.Write(" "); } var p = flatten(vertexPositions[edge] + bisectors[edge] * style.faceInset); writer.Write(facePointFormat, p.x, p.y); } writer.WriteLine("\" />"); if (style.showFaceIndices) { var p = flatten(centroids[face]); writer.WriteLine(faceIndexFormat, p.x, p.y, face.index); } } writer.WriteLine(); writer.WriteLine("\t<!-- Edges -->"); foreach (var face in topology.faces) { foreach (var edge in face.edges) { ExportEdgeToSVG(writer, surface, edge, edge.prev, edge, flatten, vertexPositions, arrowFormat, edgeIndexFormat, style, " not-wrapped"); if ((edge.wrap & EdgeWrap.FaceToFace) != EdgeWrap.None) { ExportEdgeToSVG(writer, surface, edge, edge.twin, edge.twin.vertexEdge.next.twin.faceEdge, flatten, vertexPositions, arrowFormat, edgeIndexFormat, style, " wrapped"); } } } writer.WriteLine(); writer.WriteLine("\t<!-- Vertices -->"); foreach (var vertex in topology.vertices) { bool neitherAxis = false; bool axis0 = false; bool axis1 = false; bool bothAxes = false; foreach (var edge in vertex.edges) { var faceEdge = edge.twin.faceEdge; var wrap = faceEdge.wrap & EdgeWrap.FaceToVert; if (EdgeWrapUtility.WrapsOnNeitherAxis(wrap)) { if (!neitherAxis) { neitherAxis = true; ExportVertexToSVG(writer, vertex, faceEdge, flatten, vertexPositions, transformedVertexDotRadius, vertexFormat, vertexIndexFormat, style, " wrapped-neither"); } } else if (EdgeWrapUtility.WrapsOnOnlyAxis0(wrap)) { if (!axis0) { axis0 = true; ExportVertexToSVG(writer, vertex, faceEdge, flatten, vertexPositions, transformedVertexDotRadius, vertexFormat, vertexIndexFormat, style, " wrapped-axis-0"); } } else if (EdgeWrapUtility.WrapsOnOnlyAxis1(wrap)) { if (!axis1) { axis1 = true; ExportVertexToSVG(writer, vertex, faceEdge, flatten, vertexPositions, transformedVertexDotRadius, vertexFormat, vertexIndexFormat, style, " wrapped-axis-1"); } } else { if (!bothAxes) { bothAxes = true; ExportVertexToSVG(writer, vertex, faceEdge, flatten, vertexPositions, transformedVertexDotRadius, vertexFormat, vertexIndexFormat, style, " wrapped-both"); } } } } writer.WriteLine("</svg>"); }
protected void Start() { orbitalCamera.enabled = !isInverted; pivotalCamera.enabled = isInverted; exteriorLight.enabled = !isInverted; interiorLight.enabled = isInverted; _lightVector = (isInverted ? interiorLight : exteriorLight).transform.position; _lightAxis = Vector3.Cross(Vector3.Cross(Vector3.up, _lightVector), _lightVector); RenderSettings.ambientLight = new Color(0.3f, 0.4f, 0.5f); RenderSettings.ambientIntensity = 0.25f; RenderSettings.customReflection = whiteCubeMap; RenderSettings.reflectionIntensity = 0.125f; RenderSettings.defaultReflectionMode = UnityEngine.Rendering.DefaultReflectionMode.Custom; _picker = GetComponent <FaceSpatialPartitioningPicker>(); _surface = SphericalSurface.Create(Vector3.up, Vector3.right, 10f, isInverted); Vector3[] baseVertexPositionsArray; Topology baseTopology; SphericalManifoldUtility.CreateIcosahedron(_surface, out baseTopology, out baseVertexPositionsArray); Vector3[] vertexPositionsArray; SphericalManifoldUtility.Subdivide(_surface, baseTopology, baseVertexPositionsArray.AsVertexAttribute(), topologySubdivision, out _topology, out vertexPositionsArray); _vertexPositions = PositionalVertexAttribute.Create(_surface, vertexPositionsArray); SphericalManifoldUtility.MakeDual(_surface, _topology, _vertexPositions, out vertexPositionsArray); _vertexPositions = PositionalVertexAttribute.Create(_surface, vertexPositionsArray); var regularityWeight = 0.5f; 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(); FaceAttributeUtility.CalculateFaceCentroidsFromVertexPositions(_topology.internalFaces, _vertexPositions, faceCentroids); VertexAttributeUtility.CalculateVertexAreasFromVertexPositionsAndFaceCentroids(_topology.vertices, _vertexPositions, faceCentroids, vertexAreas); Func <float> relaxIterationFunction = () => { SphericalManifoldUtility.RelaxVertexPositionsForRegularity(_surface, _topology, _vertexPositions, true, regularityRelaxedVertexPositions); SphericalManifoldUtility.RelaxVertexPositionsForEqualArea(_surface, _topology, _vertexPositions, true, 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); }; Func <bool> repairFunction = () => { return(SphericalManifoldUtility.ValidateAndRepair(_surface, _topology, _vertexPositions, 0.5f, true)); }; Action relaxationLoopFunction = TopologyRandomizer.CreateRelaxationLoopFunction(20, 20, 0.95f, relaxIterationFunction, repairFunction); TopologyRandomizer.Randomize( _topology, 1, 0.1f, 3, 3, 5, 7, true, _random, relaxationLoopFunction); _facePositions = PositionalFaceAttribute.Create(_surface, _topology.internalFaces.Count); FaceAttributeUtility.CalculateFaceCentroidsFromVertexPositions(_topology.internalFaces, _vertexPositions, _facePositions); _maximumFaceDistance = 0f; foreach (var edge in _topology.faceEdges) { var distance = Geometry.AngleBetweenVectors(_facePositions[edge.nearFace], _facePositions[edge.farFace]) * _surface.radius; _maximumFaceDistance = Mathf.Max(_maximumFaceDistance, distance); } _innerAngleBisectors = EdgeAttributeUtility.CalculateFaceEdgeBisectorsFromVertexPositions(_topology.internalFaces, _vertexPositions, _facePositions); _innerVertexPositions = new Vector3[_topology.faceEdges.Count].AsEdgeAttribute(); foreach (var edge in _topology.faceEdges) { _innerVertexPositions[edge] = _vertexPositions[edge] + _innerAngleBisectors[edge] * 0.03f; } _faceNormals = FaceAttributeUtility.CalculateFaceNormalsFromSurface(_topology.faces, _surface, _facePositions); _faceUVFrames = FaceAttributeUtility.CalculatePerFaceSphericalUVFramesFromFaceNormals(_topology.faces, _faceNormals, Quaternion.identity); _faceOuterEdgeUVs = EdgeAttributeUtility.CalculatePerFaceUnnormalizedUVsFromVertexPositions(_topology.faces, _vertexPositions, _faceUVFrames); _faceInnerEdgeUVs = EdgeAttributeUtility.CalculatePerFaceUnnormalizedUVsFromVertexPositions(_topology.faces, _innerVertexPositions, _faceUVFrames); _faceCenterUVs = FaceAttributeUtility.CalculateUnnormalizedUVsFromFacePositions(_topology.faces, _facePositions, _faceUVFrames); var faceMinUVs = new Vector2[_topology.faces.Count].AsFaceAttribute(); var faceRangeUVs = new Vector2[_topology.faces.Count].AsFaceAttribute(); FaceAttributeUtility.CalculateFaceEdgeMinAndRangeValues(_topology.faces, _faceOuterEdgeUVs, faceMinUVs, faceRangeUVs); foreach (var face in _topology.faces) { var uvMin = faceMinUVs[face]; var uvRange = faceRangeUVs[face]; var adjusted = AspectRatioUtility.Expand(new Rect(uvMin.x, uvMin.y, uvRange.x, uvRange.y), 1f); faceMinUVs[face] = adjusted.min; faceRangeUVs[face] = adjusted.size; } _faceOuterEdgeUVs = EdgeAttributeUtility.CalculatePerFaceUniformlyNormalizedUVsFromFaceUVMinAndRange(_topology.faces, faceMinUVs, faceRangeUVs, _faceOuterEdgeUVs); _faceInnerEdgeUVs = EdgeAttributeUtility.CalculatePerFaceUniformlyNormalizedUVsFromFaceUVMinAndRange(_topology.faces, faceMinUVs, faceRangeUVs, _faceInnerEdgeUVs); _faceCenterUVs = FaceAttributeUtility.CalculateUniformlyNormalizedUVsFromFaceUVMinAndRange(_topology.faces, faceMinUVs, faceRangeUVs, _faceCenterUVs); _partitioning = UniversalFaceSpatialPartitioning.Create(_surface, _topology, _vertexPositions); _picker.partitioning = _partitioning; _picker.enabled = true; _faceTerrainIndices = new int[_topology.faces.Count].AsFaceAttribute(); var terrainWeights = new int[] { grassWeight, waterWeight, desertWeight, mountainWeight }; int terrainWeightSum = 0; foreach (var weight in terrainWeights) { terrainWeightSum += weight; } var rootFaces = new List <Topology.Face>(); var rootFaceEdges = new List <Topology.FaceEdge>(); for (int regionIndex = 0; regionIndex < geographicalRegionCount; ++regionIndex) { Topology.Face face; do { face = _topology.internalFaces[_random.Index(_topology.internalFaces.Count)]; } while (rootFaces.Contains(face)); rootFaces.Add(face); foreach (var edge in face.edges) { rootFaceEdges.Add(edge); } _faceTerrainIndices[face] = _random.WeightedIndex(terrainWeights, terrainWeightSum); } TopologyVisitor.VisitFacesInRandomOrder(rootFaceEdges, (FaceEdgeVisitor visitor) => { _faceTerrainIndices[visitor.edge.farFace] = _faceTerrainIndices[visitor.edge.nearFace]; visitor.VisitInternalNeighborsExceptSource(); }, _random); _faceSeenStates = new bool[_topology.faces.Count].AsFaceAttribute(); _faceSightCounts = new int[_topology.faces.Count].AsFaceAttribute(); var triangulation = new SeparatedFacesUmbrellaTriangulation(2, (Topology.FaceEdge edge, DynamicMesh.IIndexedVertexAttributes vertexAttributes) => { var face = edge.nearFace; var faceNormal = _faceNormals[face]; var gridOverlayU = GetGridOverlayU(false, _faceSeenStates[face], _faceSightCounts[face]); vertexAttributes.position = _vertexPositions[edge]; vertexAttributes.normal = faceNormal; vertexAttributes.uv1 = AdjustSurfaceUV(_faceOuterEdgeUVs[edge], _faceTerrainIndices[face]); vertexAttributes.uv2 = new Vector2(gridOverlayU, 0f); vertexAttributes.Advance(); vertexAttributes.position = _innerVertexPositions[edge]; vertexAttributes.normal = faceNormal; vertexAttributes.uv1 = AdjustSurfaceUV(_faceInnerEdgeUVs[edge], _faceTerrainIndices[face]); vertexAttributes.uv2 = new Vector2(gridOverlayU, 0.5f); vertexAttributes.Advance(); }, (Topology.Face face, DynamicMesh.IIndexedVertexAttributes vertexAttributes) => { vertexAttributes.position = _facePositions[face]; vertexAttributes.normal = _faceNormals[face]; vertexAttributes.uv1 = AdjustSurfaceUV(_faceCenterUVs[face], _faceTerrainIndices[face]); vertexAttributes.uv2 = new Vector2(GetGridOverlayU(false, _faceSeenStates[face], _faceSightCounts[face]), 1f); vertexAttributes.Advance(); }); _dynamicMesh = DynamicMesh.Create( _topology.enumerableInternalFaces, DynamicMesh.VertexAttributes.Position | DynamicMesh.VertexAttributes.Normal | DynamicMesh.VertexAttributes.UV1 | DynamicMesh.VertexAttributes.UV2, triangulation); foreach (var mesh in _dynamicMesh.submeshes) { var meshObject = Instantiate(planetMeshPrefab); meshObject.mesh = mesh; meshObject.transform.SetParent(planetMeshes, false); } _faceUnits = new Transform[_topology.faces.Count].AsFaceAttribute(); for (int i = 0; i < unitCount; ++i) { Topology.Face face; do { face = _topology.internalFaces[_random.Index(_topology.internalFaces.Count)]; } while (_faceTerrainIndices[face] == 1 || _faceUnits[face] != null); var unit = Instantiate(unitPrefab); unit.SetParent(units, false); unit.transform.position = _facePositions[face] + _faceNormals[face] * 0.15f; _faceUnits[face] = unit; RevealUnitVicinity(face); } _dynamicMesh.RebuildMesh(DynamicMesh.VertexAttributes.UV2); }
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; }
private void CreateJumbledGrid(out Topology topology, out IVertexAttribute <Vector3> vertexPositions) { Vector3[] vertexPositionsArray; var surface = RectangularHexGrid.Create( HexGridDescriptor.CreateSideUp(true, HexGridAxisStyles.StaggeredSymmetric), Vector3.zero, Quaternion.identity, false, false, new IntVector2(11, 10)); topology = surface.CreateManifold(out vertexPositionsArray); vertexPositions = PositionalVertexAttribute.Create(surface, vertexPositionsArray); var regularityWeight = 0.5f; 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; } var localTopology = topology; var localVertexPositions = vertexPositions; Func <float> relaxIterationFunction = () => { PlanarManifoldUtility.RelaxVertexPositionsForRegularity(localTopology, localVertexPositions, false, regularityRelaxedVertexPositions); PlanarManifoldUtility.RelaxVertexPositionsForEqualArea(localTopology, localVertexPositions, totalArea, false, equalAreaRelaxedVertexPositions, faceCentroids, vertexAreas); for (int i = 0; i < relaxedVertexPositions.Count; ++i) { relaxedVertexPositions[i] = regularityRelaxedVertexPositions[i] * regularityWeight + equalAreaRelaxedVertexPositions[i] * equalAreaWeight; } var relaxationAmount = PlanarManifoldUtility.CalculateRelaxationAmount(localVertexPositions, relaxedVertexPositions); for (int i = 0; i < localVertexPositions.Count; ++i) { localVertexPositions[i] = relaxedVertexPositions[i]; } return(relaxationAmount); }; Func <bool> repairFunction = () => { return(PlanarManifoldUtility.ValidateAndRepair(localTopology, surface.normal, localVertexPositions, 0.5f, false)); }; Action relaxationLoopFunction = TopologyRandomizer.CreateRelaxationLoopFunction(20, 20, 0.95f, relaxIterationFunction, repairFunction); TopologyRandomizer.Randomize( topology, 1, 0.2f, 3, 3, 5, 7, false, XorShift128Plus.Create(23478), relaxationLoopFunction); }
/// <summary> /// Reverses the roles of vertices and faces, as when taking the dual of a polyhedron. /// </summary> /// <param name="topology">The topology containing the vertices and faces to swap.</param> /// <param name="vertexPositions">The positions of the vertices, which will become the new positions after the call is complete, calculated as the face centroids of the original topology.</param> public static void MakeDual(Topology topology, ref Vector3[] vertexPositions) { ManifoldUtility.MakeDual(topology, FaceAttributeUtility.CalculateFaceCentroidsFromVertexPositions(topology.faces, vertexPositions.AsVertexAttribute()), out vertexPositions); }