/// <summary> /// Updates the MeshRenderer's sharedMaterial based on extrusion results. /// </summary> /// <param name="lineExtrusionConfiguration">The line extrusion configuration</param> /// <param name="lineExtrusionResults">The line extrusion results</param> protected override void DoUpdateMaterialBasedOnExtrusionResults(LineExtrusionConfiguration lineExtrusionConfiguration, LineExtrusionResults lineExtrusionResults) { var connectedSegmentsResults = lineExtrusionResults.ConnectedSegmentsExtrusionResults; var singleContourConnectedSegments = connectedSegmentsResults.SegmentwiseCoverageOfSingleContour; if (singleContourConnectedSegments != null) { var firstVector4 = Vector2WithUVToLocalVector4(singleContourConnectedSegments.FirstPoint); var lastVector4 = Vector2WithUVToLocalVector4(singleContourConnectedSegments.LastPoint); var increasingChunkPackedArrays = ConvertMonotonicChunkPointsToLocalVector4Array(singleContourConnectedSegments.IncreasingPortionSegmentPoints); var decreasingChunkPackedArrays = ConvertMonotonicChunkPointsToLocalVector4Array(singleContourConnectedSegments.DecreasingPortionSegmentPoints); var renderer = MeshRenderer; var mpb = MaterialPropertyBlock; mpb.SetFloat("_ExtrusionLength", Mathf.Abs(lineExtrusionConfiguration.ExtrusionAmount)); //TODO Set connected segments floats using textures, not uniforms, to help alleviate uniform limits. The best choice may be platform dependent. mpb.SetVector("_connectedSegmentFirstPoint", firstVector4); mpb.SetVector("_connectedSegmentLastPoint", lastVector4); mpb.SetVectorArray("_increasingChunkConnectedSegmentPoints", increasingChunkPackedArrays.PackedPoints); mpb.SetVectorArray("_increasingChunkConnectedSegmentUvs", increasingChunkPackedArrays.PackedUvs); mpb.SetVectorArray("_decreasingChunkConnectedSegmentPoints", decreasingChunkPackedArrays.PackedPoints); mpb.SetVectorArray("_decreasingChunkConnectedSegmentUvs", decreasingChunkPackedArrays.PackedUvs); mpb.SetFloat("_numberOfConnectedSegments", Mathf.Min(increasingChunkPackedArrays.NumberOfPoints, decreasingChunkPackedArrays.NumberOfPoints)); renderer.SetPropertyBlock(mpb); } }
/// <summary> /// Updates the extrusion with the given <see cref="_discretization"/> and <see cref="Extrusion"/> values. /// Updates the <see cref="MeshFilter"/> component with the resulting Mesh. /// </summary> public void UpdateExtrusion() { if (_meshFilter == null) { _meshFilter = GetComponent <MeshFilter>(); } if (_meshRenderer == null) { _meshRenderer = GetComponent <MeshRenderer>(); } bool doExtrusion = Math.Abs(_extrusion) > ExtrusionNumericalPrecision.MinimumExtrusionDistanceExclusive; if (doExtrusion) { try { _lineExtrusionConfiguration = GetLineExtrusionConfiguration(_extrusion); _extrusionResults = SegmentedLineExtrusionFromIntersection.ExtrudeSegmentedLineBothDirections(this, _lineExtrusionConfiguration); var linePointsWithUVs = LineSegmentation.GetLinePointsUV(this); var segmentwiseLinePointList = new SegmentwiseLinePointListUV(linePointsWithUVs); _extrudedMesh = ExtrusionTriangulator2D.TriangulatePolygon(_extrusionResults, segmentwiseLinePointList, _lineExtrusionConfiguration); var verts = _extrudedMesh.vertices; for (int i = 0; i < verts.Length; i++) { verts[i] = transform.InverseTransformPoint(verts[i]); } _extrudedMesh.vertices = verts; _meshFilter.mesh = _extrudedMesh; bool singleContour = _extrusionResults.Contours.Count <= 1; _meshRenderer.material = singleContour ? _singleContourMaterial : _multipleContourMaterial; (singleContour ? OnSingleContourExtrusionUpdated : OnMultipleContourExtrusionUpdated).Invoke(); } catch (Exception e) { Debug.LogWarning(string.Format("Error in extrusion of amount {0}: {1}\n{2}.", _extrusion, e.Message, e.StackTrace)); _extrudedMesh = new Mesh(); _meshFilter.mesh = _extrudedMesh; } finally { } } else { _extrudedMesh = new Mesh(); _meshFilter.mesh = _extrudedMesh; } }
/// <summary> /// Updates the MeshRenderer's sharedMaterial based on extrusion results. /// </summary> /// <param name="lineExtrusionConfiguration">The line extrusion configuration</param> /// <param name="lineExtrusionResults">The line extrusion results</param> protected abstract void DoUpdateMaterialBasedOnExtrusionResults(LineExtrusionConfiguration lineExtrusionConfiguration, LineExtrusionResults lineExtrusionResults);
public ExtrusionConfigurationAndResults(LineExtrusionConfiguration lineExtrusionConfiguration, LineExtrusionResults lineExtrusionResults) { LineExtrusionConfiguration = lineExtrusionConfiguration; LineExtrusionResults = lineExtrusionResults; }
/// <summary> /// Triangulate a line based on a single closed contour of extruded points, by creating quads connecting points of the the same u-parameter on opposite sides of the original line. /// </summary> /// <param name="lineExtrusionResults">Line extrusion results</param> /// <param name="extrusionConfiguration">The extrusion configuration parameters</param> private static Mesh TriangulateLine_ConnectExtrudedPointsOfSameUParameter(LineExtrusionResults lineExtrusionResults, LineExtrusionConfiguration extrusionConfiguration) { var mesh = new Mesh(); var originalLinePointsList = lineExtrusionResults.OriginalLinePointList; //NB Setting closest original segment index is not even needed in this implementation, but it's a reasonable choice to sent as the second half of the addition uv we're sending. var extrusionAmountAbs = Mathf.Abs(extrusionConfiguration.ExtrusionAmount); var connectedSegmentsResults = lineExtrusionResults.ConnectedSegmentsExtrusionResults; var contourConnectedSegmentsResults = connectedSegmentsResults.SegmentwiseCoverageOfSingleContour; if (contourConnectedSegmentsResults != null) { var firstPoint = contourConnectedSegmentsResults.FirstPoint; var lastPoint = contourConnectedSegmentsResults.LastPoint; var increasingSegmentPoints = contourConnectedSegmentsResults.IncreasingPortionSegmentPoints; var decreasingSegmentPoints = contourConnectedSegmentsResults.DecreasingPortionSegmentPoints; if (increasingSegmentPoints.Count == decreasingSegmentPoints.Count && increasingSegmentPoints.Count >= 1) { int numInBetweenUParameters = decreasingSegmentPoints.Count; Vector3[] vertices = new Vector3[numInBetweenUParameters * 2 + 2]; Vector2[] uvs = new Vector2[numInBetweenUParameters * 2 + 2]; Vector2[] indexUvs = new Vector2[numInBetweenUParameters * 2 + 2]; int[] trindices = new int[(numInBetweenUParameters - 1) * 6 + 6]; vertices[0] = firstPoint.Vector; uvs[0] = firstPoint.UV; int closestOriginalSegmentIndex = SegmentedLineUtil.ClosestIndexAlongSegmentwiseLine(firstPoint.Vector, originalLinePointsList, extrusionAmountAbs); indexUvs[0] = new Vector2(-1, closestOriginalSegmentIndex); vertices[numInBetweenUParameters * 2 + 1] = lastPoint.Vector; uvs[numInBetweenUParameters * 2 + 1] = lastPoint.UV; closestOriginalSegmentIndex = SegmentedLineUtil.ClosestIndexAlongSegmentwiseLine(lastPoint.Vector, originalLinePointsList, extrusionAmountAbs); indexUvs[numInBetweenUParameters * 2 + 1] = new Vector2(numInBetweenUParameters, closestOriginalSegmentIndex); for (int i = 0; i < numInBetweenUParameters; i++) { var increasingPoint = increasingSegmentPoints[i]; var decreasingPoint = decreasingSegmentPoints[i]; vertices[i * 2 + 1] = increasingPoint.Vector; uvs[i * 2 + 1] = increasingPoint.UV; closestOriginalSegmentIndex = SegmentedLineUtil.ClosestIndexAlongSegmentwiseLine(increasingPoint.Vector, originalLinePointsList, extrusionAmountAbs); indexUvs[i * 2 + 1] = new Vector2(i, closestOriginalSegmentIndex); vertices[i * 2 + 2] = decreasingPoint.Vector; uvs[i * 2 + 2] = decreasingPoint.UV; closestOriginalSegmentIndex = SegmentedLineUtil.ClosestIndexAlongSegmentwiseLine(decreasingPoint.Vector, originalLinePointsList, extrusionAmountAbs); indexUvs[i * 2 + 2] = new Vector2(i, closestOriginalSegmentIndex); } //NB This order of triangle indices is consistent with our direction of extrusion points winding around the original line trindices[0] = 0; trindices[1] = 1; trindices[2] = 2; trindices[numInBetweenUParameters * 6 - 3] = numInBetweenUParameters * 2 + 0; trindices[numInBetweenUParameters * 6 - 2] = numInBetweenUParameters * 2 - 1; trindices[numInBetweenUParameters * 6 - 1] = numInBetweenUParameters * 2 + 1; for (int j = 0; j < numInBetweenUParameters - 1; j++) { trindices[3 + j * 6 + 0] = 1 + j * 2 + 1; trindices[3 + j * 6 + 1] = 1 + j * 2 + 0; trindices[3 + j * 6 + 2] = 1 + j * 2 + 2; trindices[3 + j * 6 + 3] = 1 + j * 2 + 2; trindices[3 + j * 6 + 4] = 1 + j * 2 + 3; trindices[3 + j * 6 + 5] = 1 + j * 2 + 1; } mesh.vertices = vertices; mesh.uv = uvs; mesh.triangles = trindices; mesh.uv4 = indexUvs; } else { Debug.LogError("Not enough connected extruded points to create mesh."); } } else { Debug.LogError("Single contour connected segments results are not calculated."); } return(mesh); }
/// <summary> /// Triangulate a line based on a single closed contour of extruded points by connecting points of equal u-parameter. /// </summary> /// <param name="originalLinePointList">Original line points</param> /// <param name="lineExtrusionResults">Line extrusion results</param> /// <param name="extrusionConfiguration">The extrusion configuration parameters</param> public Mesh TriangulateClosedContour(LineExtrusionResults lineExtrusionResults, SegmentwiseLinePointListUV originalLinePointList, LineExtrusionConfiguration extrusionConfiguration) { return(TriangulateLine_ConnectExtrudedPointsOfSameUParameter(lineExtrusionResults, extrusionConfiguration)); }
/// <summary> /// Extract <see cref="LineExtrusionResults"/> containing contiguous chunks of extruded points, after first determining intersection points and removing chunks too close to the original <paramref name="linePoints"/>. /// </summary> /// <param name="linePoints">The line against which chunks are compared by distance.</param> /// <param name="initiallyExtrudedPointList">The initially extruded points list.</param> /// <param name="lineExtrusionConfiguration">The extrusion configuration.</param> /// <param name="intersectionPoints">All intersection points between extruded segments.</param> /// <param name="chunkIntersectionEndpoints">Pairs of neighbouring intersection points, acting as chunk endpoints.</param> private static LineExtrusionResults ExtractLineExtrusionResults_FindContinuousLast(SegmentwiseLinePointListUV linePoints, SegmentwiseExtrudedPointListUV initiallyExtrudedPointList, LineExtrusionConfiguration lineExtrusionConfiguration, List <IntersectionPoint> intersectionPoints, List <IntersectionPointPair> chunkIntersectionEndpoints) { var extrudedChunksBetweenIntersections = ExtractChunksBetweenIntersections(initiallyExtrudedPointList, chunkIntersectionEndpoints); var removedChunks = SegmentedExtrudedChunkRemoval.RemoveChunksThatAreTooClose(extrudedChunksBetweenIntersections, linePoints, lineExtrusionConfiguration.ExtrusionAmount, intersectionPoints); var chunkCollectionList = ConnectExtrudedChunksBetweenIntersections(extrudedChunksBetweenIntersections); var removedChunksConnected = ConnectExtrudedChunksBetweenIntersections(removedChunks); var chunkConnector = lineExtrusionConfiguration.GetExtrudedChunkContourConnector(); List <Vector2WithUV[]> contours = chunkConnector.ConnnectChunksBetweenIntersectionsIntoPointsLists(chunkCollectionList); List <Vector2WithUV[]> removedContours = chunkConnector.ConnnectChunksBetweenIntersectionsIntoPointsLists(removedChunksConnected); return(new LineExtrusionResults(linePoints, contours, removedContours, chunkCollectionList, removedChunksConnected, intersectionPoints, initiallyExtrudedPointList, lineExtrusionConfiguration)); }
/// <summary> /// Extract a list of <see cref="Vector2WithUV[]"/> representing contiguous lines of extruded points. /// </summary> /// <param name="linePoints">The line from which extruded points came from.</param> /// <param name="extrudedPoints">The extruded points.</param> /// <param name="lineExtrusionConfiguration">The extrusion configuration.</param> private static LineExtrusionResults GetExtrudedLines(IList <LinePointUV> linePoints, IList <ExtrudedPointUV> extrudedPoints, LineExtrusionConfiguration lineExtrusionConfiguration) { SegmentwiseLinePointListUV linePointList = new SegmentwiseLinePointListUV(linePoints); SegmentwiseExtrudedPointListUV extrudedPointList = new SegmentwiseExtrudedPointListUV(extrudedPoints); //Note that the extruded maximum segment distance can be large (order of extrusion distance) when the original line has a kink (discontinuous derivative) List <IntersectionPoint> intersectionPoints; List <IntersectionPointPair> chunkIntersectionEndpoints; SegmentedIntersectionDetermination.FindIntersectionPointsAndChunkEndpoints(extrudedPointList, out intersectionPoints, out chunkIntersectionEndpoints); return(ExtractLineExtrusionResults_FindContinuousLast(linePointList, extrudedPointList, lineExtrusionConfiguration, intersectionPoints, chunkIntersectionEndpoints)); }
/// <summary> /// Return <see cref="LineExtrusionResults"/> containing contiguous lines of extruded points. /// </summary> /// <param name="originalLine">The line points to be extruded.</param> /// <param name="lineExtrusionConfiguration">The extrusion configuration.</param> public static LineExtrusionResults ExtrudeSegmentedLineBothDirections(ILineSegmentation originalLine, LineExtrusionConfiguration lineExtrusionConfiguration) { var originalLinePointsUV = LineSegmentation.GetLinePointsUV(originalLine); LineExtrusionResults results; if (originalLinePointsUV.Count >= 2) { var extrudedSubspaceTotal = SegmentedLineExtrusionFromSegments.GetExtrudedSubspaceAllSides(originalLinePointsUV, lineExtrusionConfiguration.ExtrusionAmount); results = GetExtrudedLines(originalLinePointsUV, extrudedSubspaceTotal, lineExtrusionConfiguration); } else { results = LineExtrusionResults.Empty; } return(results); }
/// <summary> /// Generates UV values for triangulated points on the interior of an extruded surface. /// </summary> /// <param name="triangulatedPoints">The triangulated points</param> /// <param name="lineExtrusionResults">Line extrusion resulting contours.</param> /// <param name="originalLinePointsList">Original line points</param> /// <param name="extrusionConfiguration">The extrusion configuration parameters</param> protected abstract Vector2[] GenerateTriangulatedPointUVs(Vector3[] triangulatedPoints, LineExtrusionResults lineExtrusionResults, SegmentwiseLinePointListUV originalLinePointsList, LineExtrusionConfiguration extrusionConfiguration);
/// <summary> /// Triangulate a polygon based on an outer closed contour of extruded points, further inner hole contours of extruded points, and the original line points from which they were extruded. /// </summary> /// <param name="originalLinePointList">Original line points</param> /// <param name="lineExtrusionResults">Line extrusion results</param> /// <param name="extrusionConfiguration">The extrusion configuration parameters</param> public Mesh TriangulatePolygonWithHoleContours(LineExtrusionResults lineExtrusionResults, SegmentwiseLinePointListUV originalLinePointList, LineExtrusionConfiguration extrusionConfiguration) { var polygon = new Polygon(); var outerThenAllInnerPointsList = lineExtrusionResults.Contours; var originalLinePoints = originalLinePointList.Points; int marker = 0; AddContourToPolygon(polygon, outerThenAllInnerPointsList[0], ref marker, contourIsHole: false); if (IncludeOriginalLinePoints) { AddOriginalLinePointsVerticesAndSegmentsToPolygon(originalLinePoints, polygon, ref marker); } if (IncludeRemovedContours) { List <Vector2WithUV[]> removedContours = lineExtrusionResults.RemovedContours; for (int i = 0; i < removedContours.Count; i++) { AddContourToPolygon(polygon, removedContours[i], ref marker, contourIsHole: false); } } for (int i = 1; i < outerThenAllInnerPointsList.Count; i++) { AddContourToPolygon(polygon, outerThenAllInnerPointsList[i], ref marker, contourIsHole: true); } var options = ConstraintOptions; var quality = QualityOptions; var iMesh = polygon.Triangulate(options, quality); var unityMesh = new Mesh(); Vector3[] vectorArray; Dictionary <int, int> vertexIdToArrayIndexDictionary; GetVector3ArrayAndIndexIdDictionaryFromVertices(iMesh.Vertices, out vectorArray, out vertexIdToArrayIndexDictionary); var trindicesArray = GetTrindicesArrayFromTriangles(iMesh.Triangles, vertexIdToArrayIndexDictionary); Vector2[] uvArray = GenerateTriangulatedPointUVs(vectorArray, lineExtrusionResults, originalLinePointList, extrusionConfiguration); unityMesh.vertices = vectorArray; unityMesh.triangles = trindicesArray; unityMesh.uv = uvArray; return(unityMesh); }
/// <summary> /// Creates a new instance of <see cref="LineExtrusionResults"/> with values for its public fields. /// </summary> /// <param name="originalLinePointList">The original line points</param> /// <param name="contours">List of connected contours resulting from line extrusion.</param> /// <param name="removedContours">List of contours removed from initially-extruded surface because they were too close to the original line.</param> /// <param name="contourChunkCollections">List of connected contours resulting from line extrusion, as <see cref="ChunkBetweenIntersectionsCollection"/>.</param> /// <param name="removedContourChunkCollections">List of contours removed from initially-extruded surface because they were too close to the original line, as <see cref="ChunkBetweenIntersectionsCollection"/>.</param> /// <param name="intersectionPoints">The intersection points of extruded segments.</param> /// <param name="initiallyExtrudedPoints">Set of initially-extruded points, before contours removed for being too close to the original line.</param> /// <param name="lineExtrusionConfiguration">Line extrusion configuration.</param> public LineExtrusionResults(SegmentwiseLinePointListUV originalLinePointList, List <Vector2WithUV[]> contours, List <Vector2WithUV[]> removedContours, List <ChunkBetweenIntersectionsCollection> contourChunkCollections, List <ChunkBetweenIntersectionsCollection> removedContourChunkCollections, List <IntersectionPoint> intersectionPoints, SegmentwiseExtrudedPointListUV initiallyExtrudedPoints, LineExtrusionConfiguration lineExtrusionConfiguration) { OriginalLinePointList = originalLinePointList; Contours = contours; ContoursWithAlteredUParameters = GetContoursWithAlteredUParameters(contours, lineExtrusionConfiguration); RemovedContours = removedContours; ContourChunkCollections = contourChunkCollections; RemovedContourChunkCollections = removedContourChunkCollections; IntersectionPoints = intersectionPoints; InitiallyExtrudedPoints = initiallyExtrudedPoints; ConnectedSegmentsExtrusionResults = new ConnectedSegmentsExtrusionResults(ContoursWithAlteredUParameters); }
/// <summary> /// Returns a set of connected contours resulting from line extrusion with altered texture u parameters based on <paramref name="lineExtrusionConfiguration"/>. /// </summary> /// <param name="contours">List of connected contours resulting from line extrusion.</param> /// <param name="lineExtrusionConfiguration">Line extrusion configuration.</param> private static List <Vector2WithUV[]> GetContoursWithAlteredUParameters(List <Vector2WithUV[]> contours, LineExtrusionConfiguration lineExtrusionConfiguration) { List <Vector2WithUV[]> uvAlteredContours; int numContours = contours.Count; bool multipleContours = numContours > 1; bool performAlteration = multipleContours ? lineExtrusionConfiguration.GetMultipleContourTriangulation().HasUvAlteration : lineExtrusionConfiguration.GetSingleContourTriangulation().HasUvAlteration; var alteration = multipleContours ? lineExtrusionConfiguration.GetMultipleContourUVAlteration() : lineExtrusionConfiguration.GetSingleContourUVAlteration(); if (performAlteration && alteration != null) { uvAlteredContours = new List <Vector2WithUV[]>(); for (int i = 0; i < numContours; i++) { var contour = contours[i]; var altered = alteration.GetUvAlteredExtrudedContour(contours[i], lineExtrusionConfiguration.ExtrusionAmount); uvAlteredContours.Add(altered); } } else { uvAlteredContours = new List <Vector2WithUV[]>(contours); } return(uvAlteredContours); }
/// <summary> /// Triangulate a polygon based on line extrusion results and original line points from which extrusion occured. /// </summary> /// <param name="lineExtrusionResults">Results of line extrusion.</param> /// <param name="originalLinePointList">Original line points</param> /// <param name="extrusionConfiguration">The extrusion configuration parameters</param> public static Mesh TriangulatePolygon(LineExtrusionResults lineExtrusionResults, SegmentwiseLinePointListUV originalLinePointList, LineExtrusionConfiguration extrusionConfiguration) { PolygonHelper.OrderContourByAreaDescending(lineExtrusionResults.Contours); PolygonHelper.OrderContourByAreaDescending(lineExtrusionResults.ContoursWithAlteredUParameters); var outerThenAllInnerPointsListWithAlteredUVs = lineExtrusionResults.ContoursWithAlteredUParameters; Mesh mesh; if (outerThenAllInnerPointsListWithAlteredUVs.Count == 1) { mesh = extrusionConfiguration.GetSingleContourTriangulation().TriangulateClosedContour(lineExtrusionResults, originalLinePointList, extrusionConfiguration); } else if (outerThenAllInnerPointsListWithAlteredUVs.Count >= 1) { mesh = extrusionConfiguration.GetMultipleContourTriangulation().TriangulatePolygonWithHoleContours(lineExtrusionResults, originalLinePointList, extrusionConfiguration); } else { mesh = new Mesh(); } return(mesh); }
/// <summary> /// Generates empty UV values for triangulated points on the interior of an extruded surface. /// </summary> /// <param name="triangulatedPoints">The triangulated points</param> /// <param name="lineExtrusionResults">Line extrusion resulting contours.</param> /// <param name="originalLinePointsList">Original line points</param> /// <param name="extrusionConfiguration">The extrusion configuration parameters</param> protected override Vector2[] GenerateTriangulatedPointUVs(Vector3[] triangulatedPoints, LineExtrusionResults lineExtrusionResults, SegmentwiseLinePointListUV originalLinePointsList, LineExtrusionConfiguration extrusionConfiguration) { return(new Vector2[triangulatedPoints.Length]); }