private bool TesellateCap(Rect area, bool left, Edge edge, Vector2 verticalNormal, Vector3 offset) { if (!ShouldCloseEdge(edge, left) || area.Equals(default(Rect))) { return(false); } var capUv = Terrain.UvMapping.ToUV(area); var capSize = new Vector2(area.Max.X / Terrain.PixelsPerUnit, area.Max.Y / Terrain.PixelsPerUnit); var top = (left ? edge.Begin : edge.End) + verticalNormal * (capSize.Y / 2) + verticalNormal * offset.Y; var bottom = (left ? edge.Begin : edge.End) - verticalNormal * (capSize.Y / 2) + verticalNormal * offset.Y; var horizontalNormal = (bottom - top).Normal(); top += horizontalNormal * offset.X * (left ? -1 : 1); bottom += horizontalNormal * offset.X * (left ? -1 : 1); var capOffset = horizontalNormal * capSize.X; var otherTop = left ? top - capOffset : top + capOffset; var otherBottom = left ? bottom - capOffset : bottom + capOffset; if (left) { Utils.Swap(ref top, ref otherTop); Utils.Swap(ref bottom, ref otherBottom); } EdgeData.AddQuad( new Vector3(bottom.X, bottom.Y, offset.Z), new Vector3(top.X, top.Y, offset.Z), new Vector3(otherTop.X, otherTop.Y, offset.Z), new Vector3(otherBottom.X, otherBottom.Y, offset.Z), capUv.BottomLeft(), capUv.TopLeft(), capUv.TopRight(), capUv.BottomRight()); return(true); }
private void TesellateEdges(out List <Vector2> centralPoints) { centralPoints = new List <Vector2>(); var normalStart = (Vector2?)null; var firstCapDone = (bool?)null; var pixelsPerUnit = Terrain.PixelsPerUnit; var batches = (IsInverted ? Edges.Reverse() : Edges).BatchOfTakeUntil(e => ShouldCloseEdge(e, false)).ToArray(); var begin = batches[0][0].Begin; foreach (var batch in batches) { if (Terrain.SplitWhenDifferent || batch[0].Split == SplitMode.Left || batch[0].Split == SplitMode.Both || batch[0].PrevSplit == SplitMode.Both || batch[0].PrevSplit == SplitMode.Right) { normalStart = null; batch[0].Prev = null; } var lst = batch.Length - 1; if (Terrain.SplitWhenDifferent || batch[lst].Split == SplitMode.Right || batch[lst].Split == SplitMode.Both || batch[lst].NextSplit == SplitMode.Both || batch[lst].NextSplit == SplitMode.Left) { batch[lst].Next = null; } float[] edgesLengths; var segmentMapping = SegmentFor(batch[0].Direction); var smoothFactor = batch.Length == 1 && batch[0].Prev == null && batch[lst].Next == null ? 1 : Terrain.SmoothFactor; var totalLength = InterpolateLength(Terrain.InterpolationMode, batch, smoothFactor * 5, out edgesLengths); var bodyCount = (float)Math.Max((int)Math.Round(totalLength / (segmentMapping.BodySize.X / pixelsPerUnit) + Terrain.StrechThreshold), 1); var finalBodySize = new Vector2(totalLength / bodyCount, segmentMapping.BodySize.Y / pixelsPerUnit); var halfFinalBodySizeHeight = finalBodySize.Y / 2; var incLength = finalBodySize.X / smoothFactor; var currentLength = incLength; var first = true; var offsets = segmentMapping.Offsets; offsets = new Vector3(offsets.X / pixelsPerUnit, offsets.Y / pixelsPerUnit, offsets.Z / pixelsPerUnit); for (int i = 0; i < bodyCount; i++) { var bodyUV = Terrain.UvMapping.ToUV(new Rect(segmentMapping.Bodies[Math.Abs(begin.GetHashCode() % segmentMapping.Bodies.Count)], segmentMapping.BodySize)); bodyUV.Max.X = bodyUV.Max.X / smoothFactor; for (int j = 0; j < smoothFactor; j++, currentLength += incLength) { var end = Interpolate(Terrain.InterpolationMode, batch, edgesLengths, currentLength); var normalEnd = (end - begin).Normal(); var endOffset = normalEnd * halfFinalBodySizeHeight; var beginOffset = (normalStart ?? normalEnd) * halfFinalBodySizeHeight; var yOffset = (normalStart ?? normalEnd) * offsets.Y; var localBottomLeft = begin - beginOffset + yOffset; var localTopLeft = begin + beginOffset + yOffset; yOffset = normalEnd * offsets.Y; var localBottomRight = end - endOffset + yOffset; var localTopRight = end + endOffset + yOffset; EdgeData.AddQuad( new Vector3(localBottomLeft.X, localBottomLeft.Y, offsets.Z), new Vector3(localTopLeft.X, localTopLeft.Y, offsets.Z), new Vector3(localTopRight.X, localTopRight.Y, offsets.Z), new Vector3(localBottomRight.X, localBottomRight.Y, offsets.Z), bodyUV.BottomLeft(), bodyUV.TopLeft(), bodyUV.TopRight(), bodyUV.BottomRight()); if (first) { first = TesellateCap(new Rect(segmentMapping.LeftCap, segmentMapping.CapSize), true, batch[0], normalStart ?? normalEnd, offsets); firstCapDone = firstCapDone ?? first; first = false; } centralPoints.Add(begin); normalStart = normalEnd; bodyUV.Min.X = bodyUV.Min.X + bodyUV.Max.X; begin = end; } } TesellateCap(new Rect(segmentMapping.RightCap, segmentMapping.CapSize), false, batch[lst], normalStart.Value, offsets); } }