public void CycleSpriteIndex() { ISelection selection = ShapeEditorCache.GetSelection(); if (selection.single == -1) { return; } int nextIndex = SplineUtility.NextIndex(selection.single, m_Spline.GetPointCount()); float angle = SpriteShapeHandleUtility.PosToAngle(m_Spline.GetPosition(selection.single), m_Spline.GetPosition(nextIndex), 0f); int angleRangeIndex = SpriteShapeEditorUtility.GetRangeIndexFromAngle(m_SpriteShape, angle); if (angleRangeIndex == -1) { return; } AngleRange angleRange = m_SpriteShape.angleRanges[angleRangeIndex]; int spriteIndex = (m_Spline.GetSpriteIndex(selection.single) + 1) % angleRange.sprites.Count; Undo.RecordObject(m_CurrentEditor.target, "Edit Sprite Index"); m_Spline.SetSpriteIndex(selection.single, spriteIndex); EditorUtility.SetDirty(m_CurrentEditor.target); }
private void ResetTangents(int pointIndex) { Vector3 position = GetPosition(pointIndex); Vector3 positionNext = GetPosition(SplineUtility.NextIndex(pointIndex, GetPointCount())); Vector3 positionPrev = GetPosition(SplineUtility.PreviousIndex(pointIndex, GetPointCount())); Vector3 forward = Vector3.forward; if (SplineEditorCache.IsValid() && SplineEditorCache.GetTarget() != null) { forward = SplineEditorCache.GetTarget().transform.forward; } float scale = Mathf.Min((positionNext - position).magnitude, (positionPrev - position).magnitude) * 0.33f; Vector3 leftTangent = (positionPrev - position).normalized * scale; Vector3 rightTangent = (positionNext - position).normalized * scale; if (GetTangentMode(pointIndex) == TangentMode.Continuous) { SplineUtility.CalculateTangents(position, positionPrev, positionNext, forward, scale, out rightTangent, out leftTangent); } SetLeftTangent(pointIndex, leftTangent); SetRightTangent(pointIndex, rightTangent); }
public static NativeArray <RigidTransform> IntPointsToRigidTransforms(List <IntPoint> points, bool looped, Allocator allocator) { var path = IntPointListToFloat3Array(points, allocator); var splinePath = SplineUtility.Float3PathToRigidTransformPath(path, looped, allocator); path.Dispose(); return(splinePath); }
public void Execute(int index) { var roadEntity = RoadEntities[index]; var sampleBuffer = RoadSampleBuffers[roadEntity].Reinterpret <RigidTransform>().AsNativeArray(); var length = SplineUtility.SplineLength(sampleBuffer); NumDecalsPerRoad[index] = math.max(0, (int)(length * Density)); }
public void SwitchSides() { SplineUtility.ReverseArray(Surfaces.AsArray()); SplineUtility.ReverseArray(Samples.AsArray()); InvertSamples(); m_NumLeftSurfaces = Surfaces.Length; m_NumLeftSamples = Samples.Length; }
void AddSolidLaneLine( NativeArray <RigidTransform> samples, float xOffset, RoadMarking marking, DynamicBuffer <CombinedVertex> vertexBuffer, DynamicBuffer <Triangle> triangleBuffer, DynamicBuffer <SubMesh> subMeshBuffer) { var newSubMesh = new SubMesh(); var markingWidth = marking.Width / 2; var leftOffsetSpline = SplineUtility.OffsetSpline(samples, new float3(-markingWidth + xOffset, 0f, 0f), Allocator.Temp); var rightOffsetSpline = SplineUtility.OffsetSpline(samples, new float3(markingWidth + xOffset, 0f, 0f), Allocator.Temp); newSubMesh.VertexStartIndex = vertexBuffer.Length; newSubMesh.VertexCount = samples.Length * 2; vertexBuffer.ResizeUninitialized(vertexBuffer.Length + samples.Length * 2); var upVector = new float3(0f, 1f, 0f); for (int i = 0, j = newSubMesh.VertexStartIndex; i < samples.Length; i++) { var leftPoint = leftOffsetSpline[i]; vertexBuffer[j++] = new CombinedVertex { Vertex = leftPoint.pos, Normal = math.mul(leftPoint.rot, upVector), Uv = leftPoint.pos.xz }; var rightPoint = rightOffsetSpline[i]; vertexBuffer[j++] = new CombinedVertex { Vertex = rightPoint.pos, Normal = math.mul(rightPoint.rot, upVector), Uv = rightPoint.pos.xz }; } leftOffsetSpline.Dispose(); rightOffsetSpline.Dispose(); newSubMesh.TriangleStartIndex = triangleBuffer.Length; newSubMesh.TriangleCount = (samples.Length - 1) * 6; triangleBuffer.ResizeUninitialized(triangleBuffer.Length + newSubMesh.TriangleCount); for (int i = 0, j = newSubMesh.TriangleStartIndex; i < newSubMesh.VertexCount - 2; i += 2) { triangleBuffer[j++] = i; triangleBuffer[j++] = i + 3; triangleBuffer[j++] = i + 1; triangleBuffer[j++] = i; triangleBuffer[j++] = i + 2; triangleBuffer[j++] = i + 3; } newSubMesh.Material = marking.Material; subMeshBuffer.Add(newSubMesh); }
public Vector2 GetEdgeWindowPosition(int edgeIndex) { int nextIndex = SplineUtility.NextIndex(edgeIndex, m_Points.Count); Vector2 start = m_Points[edgeIndex].m_Position; Vector2 startTangent = (Vector2)m_Points[edgeIndex].m_RightTangent + start; Vector2 end = m_Points[nextIndex].m_Position; Vector2 endTangent = (Vector2)m_Points[nextIndex].m_LeftTangent + end; return(BezierUtility.BezierPoint(start, startTangent, endTangent, end, 0.5f) + Vector3.up * kWindowHeaderHeight); }
public void Execute(int index) { var numDecals = NumDecalsPerRoad[index]; if (numDecals == 0) { return; } var random = RandomUtility.ParallelForRandom(RandomSeed, index); var roadEntity = RoadEntities[index]; var sampleBuffer = RoadSampleBuffers[roadEntity].Reinterpret <RigidTransform>().AsNativeArray(); var startIndex = DecalStartIndices[index]; var decalPositions = DecalPoses.GetSubArray(startIndex, numDecals); var decalTrackDistances = new NativeArray <float>(numDecals, Allocator.Temp); var distancePerDecal = SplineUtility.SplineLength(sampleBuffer) / (numDecals); // Offset the decals by a third instead of a half of the separation dist to decrease the chances of // overlapping decals being generated. var thirdDistPerDecal = distancePerDecal / 3f; var currDist = distancePerDecal / 2f; for (var i = 0; i < numDecals; i++) { decalTrackDistances[i] = currDist + random.NextFloat(-thirdDistPerDecal, thirdDistPerDecal); currDist += distancePerDecal; } var remappedSpline = SplineUtility.SampleSplineAtDistances(sampleBuffer, decalTrackDistances, Allocator.Temp); var lateralProfile = Profiles[ProfileBuffers[roadEntity].Reinterpret <Entity>()[0]]; var minLateralRange = lateralProfile.LeftDrivableOffset.x; var maxLateralRange = lateralProfile.RightDrivableOffset.x; minLateralRange = math.clamp(minLateralRange, minLateralRange + 1, 0); maxLateralRange = math.clamp(maxLateralRange, 0, maxLateralRange - 1); for (var i = 0; i < remappedSpline.Length; i++) { var pose = remappedSpline[i]; var randOffset = random.NextFloat(minLateralRange, maxLateralRange); var randRotation = quaternion.RotateY(random.NextFloat(0, math.PI * 2f)); var offset = new float3(randOffset, 0f, 0f); decalPositions[i] = new RigidTransform { pos = math.transform(pose, offset), rot = math.mul(pose.rot, randRotation) }; } remappedSpline.Dispose(); }
private void LayoutEdges() { if (currentEvent.type != EventType.Layout) { return; } PrepareEdgePoints(); int pointCount = GetPointCount(); int edgeCount = OpenEnded() ? pointCount - 1 : pointCount; float minDistance = float.MaxValue; for (int index = 0; index < edgeCount; ++index) { int id = GUIUtility.GetControlID("Edge".GetHashCode(), FocusType.Passive); if (currentEvent.type == EventType.Layout) { int nextIndex = SplineUtility.NextIndex(index, pointCount); Vector3 position0 = GetPosition(index); Vector3 position1 = GetPosition(nextIndex); Vector3 tangent0 = GetRightTangent(index) + position0; Vector3 tangent1 = GetLeftTangent(nextIndex) + position1; float t; Vector3 closestPoint = BezierUtility.ClosestPointOnCurve(ScreenToWorld(currentEvent.mousePosition), position0, position1, tangent0, tangent1, out t); Vector2 guiPosition = HandleUtility.WorldToGUIPoint(closestPoint); float distance = (currentEvent.mousePosition - guiPosition).magnitude; if (m_HoveredPointIndex == -1) { HandleUtility.AddControl(id, distance); if (HandleUtility.nearestControl == id) { m_HoveredEdgeIndex = index; m_HoveredPointIndex = -1; m_HoveredTangentPoint = -1; } } if (distance < minDistance) { m_ClosestPoint = closestPoint; m_ClosestPointT = t; minDistance = distance; } } } }
private int GetAngleRangeLocal(int index) { var selection = SplineEditorCache.GetSelection(); var spriteShape = SplineEditorCache.GetTarget().spriteShape; var nextIndex = SplineUtility.NextIndex(selection.single, GetPointCount()); var pos1 = GetLocalPosition(selection.single); var pos2 = GetLocalPosition(nextIndex); var angle = SplineUtility.SlopeAngle(pos1, pos2) + 90; var angleRangeIndex = SpriteShapeEditorUtility.GetRangeIndexFromAngle(spriteShape, angle); return(angleRangeIndex); }
void AppendRightTurnCornerSamples(NativeList <RigidTransform> samples, Entity cornerEntity) { var cornerSamples = RoadCenterLineSamples[cornerEntity] .Reinterpret <RigidTransform>().AsNativeArray(); var offset = new float3(-OffsetFromCurb, 0f, 0f); var offsetSamples = SplineUtility.OffsetSpline(cornerSamples, offset, Allocator.Temp); samples.AddRange(offsetSamples); offsetSamples.Dispose(); }
public void Execute(int index) { var splineEntity = SplineEntities[index]; var sampleBuffer = SplineSampleBuffers[splineEntity].Reinterpret <RigidTransform>(); var range = Ranges[index]; var samples = SplineSamples.GetSubArray(range.StartIndex, range.Length); sampleBuffer.ResizeUninitialized(samples.Length); SplineUtility.Float3PathToRigidTransformPath( samples, sampleBuffer.Reinterpret <RigidTransform>().AsNativeArray(), false); }
void AppendRightTurnCornerSamples(NativeList <RigidTransform> samples, Entity cornerEntity) { var cornerSamples = RoadCenterLineSamples[cornerEntity] .Reinterpret <RigidTransform>().AsNativeArray(); var lateralProfileEntity = LateralProfileEntityRefs[cornerEntity].Reinterpret <Entity>()[0]; var lateralProfileSamples = LateralProfileSampleBuffers[lateralProfileEntity].Reinterpret <float2>(); var lateralOffset = lateralProfileSamples[lateralProfileSamples.Length - 1].x; var offset = new float3(lateralOffset, 0f, 0f); var offsetSamples = SplineUtility.OffsetSpline(cornerSamples, offset, Allocator.Temp); samples.AddRange(offsetSamples); offsetSamples.Dispose(); }
public static void ReverseSplineQuaternionTest(float3 source) { source = math.normalize(source); var upVector = new float3(0f, 1f, 0f); var forward = quaternion.LookRotation(source, upVector); var reverseCheck = quaternion.LookRotation(-source, upVector); var reverse = SplineUtility.ReverseSplineQuaternion(forward); var p1 = math.normalize(new float3(1f, 1f, 1f)); var p2 = math.normalize(new float3(-1f, -1f, -1f)); Assert.True(Utilities.GeometryUtility.ApproximatelyEqual( math.mul(reverseCheck, p1), math.mul(reverse, p1))); Assert.True(Utilities.GeometryUtility.ApproximatelyEqual( math.mul(reverseCheck, p2), math.mul(reverse, p2))); }
public void Execute(int index) { var offsetPathEntity = OffsetPathEntities[index]; var rangeBuffer = OffsetPathRangeBuffers[offsetPathEntity]; var offsetPathBuffer = OffsetPathSampleBuffers[offsetPathEntity] .Reinterpret <RigidTransform>().AsNativeArray(); var placementPointBuffer = PlacementPointBuffers[offsetPathEntity].Reinterpret <RigidTransform>(); for (var i = 0; i < rangeBuffer.Length; i++) { var range = rangeBuffer[i]; var offsetPath = offsetPathBuffer.GetSubArray(range.StartIndex, range.SampleCount); var uniformSamples = SplineUtility.EvenlyDistributeSpline(offsetPath, Spacing, true, Allocator.Temp); placementPointBuffer.AddRange(uniformSamples); uniformSamples.Dispose(); } }
// Start is called before the first frame update private void Smoothen(SpriteShapeController sc, int pointIndex) { Vector3 position = sc.spline.GetPosition(pointIndex); Vector3 positionNext = sc.spline.GetPosition(SplineUtility.NextIndex(pointIndex, sc.spline.GetPointCount())); Vector3 positionPrev = sc.spline.GetPosition(SplineUtility.PreviousIndex(pointIndex, sc.spline.GetPointCount())); Vector3 forward = gameObject.transform.forward; float scale = Mathf.Min((positionNext - position).magnitude, (positionPrev - position).magnitude) * 0.33f; Vector3 leftTangent = (positionPrev - position).normalized * scale; Vector3 rightTangent = (positionNext - position).normalized * scale; sc.spline.SetTangentMode(pointIndex, ShapeTangentMode.Continuous); SplineUtility.CalculateTangents(position, positionPrev, positionNext, forward, scale, out rightTangent, out leftTangent); sc.spline.SetLeftTangent(pointIndex, leftTangent); sc.spline.SetRightTangent(pointIndex, rightTangent); }
public void Execute(int index) { var range = RoadSplineRanges[index]; var roadEntity = RoadEntities[index]; RoadCenterLineDataComponents[roadEntity] = new RoadCenterLineData { StreetId = range.StreetId, StartIntersection = range.StartIntersectionEntity, EndIntersection = range.EndIntersectionEntity }; var splineBuffer = RoadSplineSampleBuffers[range.SplineEntity].Reinterpret <RigidTransform>(); var roadBuffer = RoadCenterLineSampleBuffers[roadEntity].Reinterpret <RigidTransform>(); // Get nearest integer spline indices var firstIntegerIdx = (int)math.floor(range.StartIndex + 1f); var lastIntegerIdx = (int)math.ceil(range.EndIndex - 1f); // Add first point if between spline indices if (!Utilities.GeometryUtility.ApproximatelyEqual(range.StartIndex, firstIntegerIdx)) { roadBuffer.Add(SplineUtility.LerpTransform( splineBuffer[firstIntegerIdx - 1], splineBuffer[firstIntegerIdx], range.StartIndex - (firstIntegerIdx - 1))); } // Intermediate points for (var i = firstIntegerIdx; i <= lastIntegerIdx; i++) { roadBuffer.Add(splineBuffer[i]); } // Add last point if between spline indices if (!Utilities.GeometryUtility.ApproximatelyEqual(range.EndIndex, lastIntegerIdx)) { roadBuffer.Add(SplineUtility.LerpTransform( splineBuffer[lastIntegerIdx], splineBuffer[lastIntegerIdx + 1], range.EndIndex - lastIntegerIdx)); } }
private void HandleDragEdge() { EventType eventType = currentEvent.GetTypeForControl(m_DragEdgeControlId); if ((m_HoveredEdgeIndex != -1 && GUIUtility.hotControl == 0 && EdgeDragModifiersActive()) || GUIUtility.hotControl == m_DragEdgeControlId) { if (eventType == EventType.MouseDown && currentEvent.button == 0) { m_ActiveEdgeIndex = m_HoveredEdgeIndex; m_SliderPosition = GetPosition(m_HoveredEdgeIndex); } if (eventType == EventType.MouseUp && currentEvent.button == 0) { m_ActiveEdgeIndex = -1; } if (eventType == EventType.Layout && GUIUtility.hotControl == 0) { HandleUtility.AddControl(m_DragEdgeControlId, 0f); } EditorGUI.BeginChangeCheck(); var newPosition = DoSlider(m_DragEdgeControlId, m_SliderPosition, GetUpVector(), GetRightVector(), GetHandleSize(m_SliderPosition), (int cid, Vector3 p, Quaternion q, float s, EventType et) => { }); if (EditorGUI.EndChangeCheck()) { RegisterUndoOnSliderChangedOnce(); var snappedDelta = Snap(newPosition) - m_SliderPosition; var nextIndex = SplineUtility.NextIndex(m_ActiveEdgeIndex, GetPointCount()); SetPosition(m_ActiveEdgeIndex, GetPosition(m_ActiveEdgeIndex) + snappedDelta); SetPosition(nextIndex, GetPosition(nextIndex) + snappedDelta); m_EdgePointsDirty = true; } m_SliderPosition = newPosition; } }
private void ResetTangents(int pointIndex) { Vector3 position = m_Spline.GetPosition(pointIndex); Vector3 positionNext = m_Spline.GetPosition(SplineUtility.NextIndex(pointIndex, m_Spline.GetPointCount())); Vector3 positionPrev = m_Spline.GetPosition(SplineUtility.PreviousIndex(pointIndex, m_Spline.GetPointCount())); Vector3 forward = (m_CurrentEditor.target as SpriteShapeController).transform.forward; float scale = Mathf.Min((positionNext - position).magnitude, (positionPrev - position).magnitude) * 0.33f; Vector3 leftTangent = (positionPrev - position).normalized * scale; Vector3 rightTangent = (positionNext - position).normalized * scale; if (m_Spline.GetTangentMode(pointIndex) == ShapeTangentMode.Continuous) { SplineUtility.CalculateTangents(position, positionPrev, positionNext, forward, scale, out rightTangent, out leftTangent); } m_Spline.SetLeftTangent(pointIndex, leftTangent); m_Spline.SetRightTangent(pointIndex, rightTangent); }
public void Execute() { LongestPath[0] = Entity.Null; if (CameraPathEntities.Length == 0) { return; } var longestPathLength = 0f; for (var i = 0; i < CameraPathEntities.Length; i++) { var entity = CameraPathEntities[i]; var samples = CameraPathSampleBuffers[entity].Reinterpret <RigidTransform>().AsNativeArray(); var length = SplineUtility.SplineLength(samples); if (length > longestPathLength) { longestPathLength = length; LongestPath[0] = entity; } } }
private void PrepareEdgePoints() { int pointCount = GetPointCount(); int edgeCount = OpenEnded() ? pointCount - 1 : pointCount; if (m_EdgePoints.Count != edgeCount) { m_EdgePointsDirty = true; } if (!m_EdgePointsDirty) { return; } m_EdgePoints.Clear(); for (int index = 0; index < edgeCount; ++index) { int nextIndex = SplineUtility.NextIndex(index, pointCount); Vector3 position0 = GetPosition(index); Vector3 position1 = GetPosition(nextIndex); if (GetTangentMode(index) == TangentMode.Linear && GetTangentMode(nextIndex) == TangentMode.Linear) { m_EdgePoints.Add(new Vector3[] { position0, position1 }); } else { var tangent0 = GetRightTangent(index) + position0; var tangent1 = GetLeftTangent(nextIndex) + position1; m_EdgePoints.Add(Handles.MakeBezierPoints(position0, position1, tangent0, tangent1, kBezierPatch)); } } m_EdgePointsDirty = false; }
void AppendRoadSamples(NativeList <RigidTransform> samples, IntersectionRoadConnection connection) { var centerLineSamples = RoadCenterLineSamples[connection.Road] .Reinterpret <RigidTransform>().AsNativeArray(); var lateralProfileEntity = LateralProfileEntityRefs[connection.Road].Reinterpret <Entity>()[0]; var lateralProfile = LateralProfileComponents[lateralProfileEntity]; var lateralOffset = connection.Direction == IntersectionRoadDirection.Incoming ? lateralProfile.LeftDrivableOffset.x + OffsetFromCurb : lateralProfile.RightDrivableOffset.x - OffsetFromCurb; var offset = new float3(lateralOffset, 0f, 0f); var offsetSamples = SplineUtility.OffsetSpline(centerLineSamples, offset, Allocator.Temp); if (connection.Direction == IntersectionRoadDirection.Incoming) { SplineUtility.ReverseSpline(offsetSamples); } samples.AddRange(offsetSamples); offsetSamples.Dispose(); }
void AppendRoadSamples(NativeList <RigidTransform> samples, IntersectionRoadConnection connection) { var centerLineSamples = RoadCenterLineSamples[connection.Road] .Reinterpret <RigidTransform>().AsNativeArray(); var lateralProfileEntity = LateralProfileEntityRefs[connection.Road].Reinterpret <Entity>()[0]; var lateralProfileSamples = LateralProfileSampleBuffers[lateralProfileEntity].Reinterpret <float2>(); var lateralOffset = connection.Direction == IntersectionRoadDirection.Incoming ? lateralProfileSamples[0].x : lateralProfileSamples[lateralProfileSamples.Length - 1].x; var offset = new float3(lateralOffset, 0f, 0f); var offsetSamples = SplineUtility.OffsetSpline(centerLineSamples, offset, Allocator.Temp); if (connection.Direction == IntersectionRoadDirection.Incoming) { SplineUtility.ReverseSpline(offsetSamples); } samples.AddRange(offsetSamples); offsetSamples.Dispose(); }
private void HandleInsertPointToEdge() { EventType eventType = currentEvent.GetTypeForControl(m_DragPointControlId); if (m_HoveredPointIndex == -1 && m_HoveredEdgeIndex != -1 && GUIUtility.hotControl == 0 && eventType == EventType.MouseDown && currentEvent.button == 0 && !currentEvent.shift) { RecordUndo(); ClearSelection(); int nextIndex = SplineUtility.NextIndex(m_HoveredEdgeIndex, GetPointCount()); TangentMode leftTangentMode = GetTangentMode(m_HoveredEdgeIndex); TangentMode rightTangentMode = GetTangentMode(nextIndex); Vector3 leftStartPosition; Vector3 leftEndPosition; Vector3 leftStartTangent; Vector3 leftEndTangent; Vector3 rightStartPosition; Vector3 rightEndPosition; Vector3 rightStartTangent; Vector3 rightEndTangent; Vector3 position0 = GetPosition(m_HoveredEdgeIndex); Vector3 position1 = GetPosition(nextIndex); Vector3 tangent0 = GetRightTangent(m_HoveredEdgeIndex) + position0; Vector3 tangent1 = GetLeftTangent(nextIndex) + position1; BezierUtility.SplitBezier(m_ClosestPointT, position0, position1, tangent0, tangent1, out leftStartPosition, out leftEndPosition, out leftStartTangent, out leftEndTangent, out rightStartPosition, out rightEndPosition, out rightStartTangent, out rightEndTangent); if (leftTangentMode != TangentMode.Linear) { SetTangentMode(m_HoveredEdgeIndex, TangentMode.Broken); SetRightTangent(m_HoveredEdgeIndex, leftStartTangent - leftStartPosition); } if (rightTangentMode != TangentMode.Linear) { SetTangentMode(nextIndex, TangentMode.Broken); SetLeftTangent(nextIndex, rightEndTangent - rightEndPosition); } InsertPointAt(nextIndex, m_ClosestPoint); if (leftTangentMode != TangentMode.Linear || rightTangentMode != TangentMode.Linear) { SetTangentMode(nextIndex, TangentMode.Broken); if (m_ClosestPointT == 0.5f) { SetTangentMode(nextIndex, TangentMode.Continuous); } SetLeftTangent(nextIndex, leftEndTangent - leftEndPosition); SetRightTangent(nextIndex, rightStartTangent - rightStartPosition); } m_HoveredPointIndex = nextIndex; m_HoveredEdgeIndex = -1; HandleUtility.nearestControl = m_DragPointControlId; } }
private void GenerateSegments(SpriteShapeController sc, List <ShapeAngleRange> angleRanges) { var controlPointCount = sc.spline.GetPointCount(); var angleRangeIndices = new int[controlPointCount]; ShapeSegment activeSegment = new ShapeSegment() { start = -1, end = -1, angleRange = -1 }; m_ShapeSegments.Clear(); for (int i = 0; i < controlPointCount; ++i) { var actv = i; var next = SplineUtility.NextIndex(actv, controlPointCount); var pos1 = sc.spline.GetPosition(actv); var pos2 = sc.spline.GetPosition(next); bool continueStrip = (sc.spline.GetTangentMode(actv) == ShapeTangentMode.Continuous), edgeUpdated = false; float angle = 0; if (false == continueStrip || activeSegment.start == -1) { angle = SplineUtility.SlopeAngle(pos1, pos2) + 90.0f; } next = (!sc.spline.isOpenEnded && next == 0) ? (actv + 1) : next; int mn = (actv < next) ? actv : next; int mx = (actv > next) ? actv : next; var anglerange = RangeFromAngle(angleRanges, angle); angleRangeIndices[actv] = anglerange; if (anglerange == -1) { activeSegment = new ShapeSegment() { start = mn, end = mx, angleRange = anglerange }; m_ShapeSegments.Add(activeSegment); continue; } // Check for Segments. Also check if the Segment Start has been resolved. Otherwise simply start with the next one if (activeSegment.start != -1) { continueStrip = continueStrip && (angleRangeIndices[activeSegment.start] != -1); } bool canContinue = (actv != (controlPointCount - 1)) || (!sc.spline.isOpenEnded && (actv == (controlPointCount - 1))); if (continueStrip && canContinue) { for (int s = 0; s < m_ShapeSegments.Count; ++s) { activeSegment = m_ShapeSegments[s]; if (activeSegment.start - mn == 1) { edgeUpdated = true; activeSegment.start = mn; m_ShapeSegments[s] = activeSegment; break; } if (mx - activeSegment.end == 1) { edgeUpdated = true; activeSegment.end = mx; m_ShapeSegments[s] = activeSegment; break; } } } if (!edgeUpdated) { activeSegment.start = mn; activeSegment.end = mx; activeSegment.angleRange = anglerange; m_ShapeSegments.Add(activeSegment); } } }
void DashSamples( NativeArray <RigidTransform> samples, RoadMarking marking, out NativeList <RigidTransform> dashSamples, out NativeList <DashPoint> dashPoints) { var sampleDistances = SplineUtility.SplineDistanceArray(samples, Allocator.Temp); var totalDist = sampleDistances[sampleDistances.Length - 1]; marking.BeginningOffset %= marking.DashLength; var patternDist = marking.DashLength + marking.SeparationDistance; var numPatterns = (int)(totalDist / patternDist) + 2; var patternPoints = new NativeArray <DashPoint>(numPatterns * 2, Allocator.Temp); var accumulatedDist = marking.BeginningOffset; for (var i = 0; i < patternPoints.Length;) { patternPoints[i++] = new DashPoint { Distance = accumulatedDist, Cap = DashCap.Start }; accumulatedDist += marking.DashLength; patternPoints[i++] = new DashPoint { Distance = accumulatedDist, Cap = DashCap.End }; accumulatedDist += marking.SeparationDistance; } dashSamples = new NativeList <RigidTransform>(patternPoints.Length + sampleDistances.Length, Allocator.Temp); dashPoints = new NativeList <DashPoint>(patternPoints.Length + sampleDistances.Length, Allocator.Temp); dashSamples.Add(samples[0]); dashPoints.Add(new DashPoint { Distance = 0f, Cap = DashCap.End }); for (int i = 1, j = 0; i < samples.Length; i++) { var prevSample = samples[i - 1]; var nextSample = samples[i]; var prevDist = sampleDistances[i - 1]; var nextDist = sampleDistances[i]; var betweenDist = nextDist - prevDist; while (patternPoints[j].Distance < nextDist) { var t = (patternPoints[j].Distance - prevDist) / betweenDist; dashSamples.Add(SplineUtility.LerpTransform(prevSample, nextSample, t)); dashPoints.Add(new DashPoint { Distance = i - 1 + t, Cap = patternPoints[j].Cap }); j++; } dashSamples.Add(nextSample); dashPoints.Add(new DashPoint { Distance = i, Cap = dashPoints[dashPoints.Length - 1].Cap }); } sampleDistances.Dispose(); patternPoints.Dispose(); }
void AddDashedLaneLine( NativeArray <RigidTransform> samples, float xOffset, RoadMarking marking, DynamicBuffer <CombinedVertex> vertexBuffer, DynamicBuffer <Triangle> triangleBuffer, DynamicBuffer <SubMesh> subMeshBuffer, DynamicBuffer <RigidTransform> roadMarkingSamples, DynamicBuffer <DashPoint> dashPoints) { DashSamples(samples, marking, out var dashSamples, out var dashCaps); roadMarkingSamples.AddRange(dashSamples); dashPoints.AddRange(dashCaps); var markingWidth = marking.Width / 2; var leftOffsetSpline = SplineUtility.OffsetSpline(dashSamples, new float3(-markingWidth + xOffset, 0f, 0f), Allocator.Temp); var rightOffsetSpline = SplineUtility.OffsetSpline(dashSamples, new float3(markingWidth + xOffset, 0f, 0f), Allocator.Temp); var dashVertices = new NativeList <CombinedVertex>(leftOffsetSpline.Length / 2, Allocator.Temp); var nonDashVertices = new NativeList <CombinedVertex>(leftOffsetSpline.Length / 2, Allocator.Temp); var upVector = new float3(0f, 1f, 0f); for (var i = 0; i < dashSamples.Length - 1; i++) { if (dashCaps[i].Cap == DashCap.Start) { var leftPoint = leftOffsetSpline[i]; dashVertices.Add(new CombinedVertex { Vertex = leftPoint.pos, Normal = math.mul(leftPoint.rot, upVector), Uv = leftPoint.pos.xz }); var rightPoint = rightOffsetSpline[i]; dashVertices.Add(new CombinedVertex { Vertex = rightPoint.pos, Normal = math.mul(rightPoint.rot, upVector), Uv = rightPoint.pos.xz }); leftPoint = leftOffsetSpline[i + 1]; dashVertices.Add(new CombinedVertex { Vertex = leftPoint.pos, Normal = math.mul(leftPoint.rot, upVector), Uv = leftPoint.pos.xz }); rightPoint = rightOffsetSpline[i + 1]; dashVertices.Add(new CombinedVertex { Vertex = rightPoint.pos, Normal = math.mul(rightPoint.rot, upVector), Uv = rightPoint.pos.xz }); } else { var leftPoint = leftOffsetSpline[i]; nonDashVertices.Add(new CombinedVertex { Vertex = leftPoint.pos, Normal = math.mul(leftPoint.rot, upVector), Uv = leftPoint.pos.xz }); var rightPoint = rightOffsetSpline[i]; nonDashVertices.Add(new CombinedVertex { Vertex = rightPoint.pos, Normal = math.mul(rightPoint.rot, upVector), Uv = rightPoint.pos.xz }); leftPoint = leftOffsetSpline[i + 1]; nonDashVertices.Add(new CombinedVertex { Vertex = leftPoint.pos, Normal = math.mul(leftPoint.rot, upVector), Uv = leftPoint.pos.xz }); rightPoint = rightOffsetSpline[i + 1]; nonDashVertices.Add(new CombinedVertex { Vertex = rightPoint.pos, Normal = math.mul(rightPoint.rot, upVector), Uv = rightPoint.pos.xz }); } } leftOffsetSpline.Dispose(); rightOffsetSpline.Dispose(); dashSamples.Dispose(); dashCaps.Dispose(); var dashSubMesh = new SubMesh { VertexCount = dashVertices.Length, VertexStartIndex = vertexBuffer.Length, TriangleCount = (dashVertices.Length * 3) / 2, TriangleStartIndex = triangleBuffer.Length, Material = marking.Material }; var nonDashSubMesh = new SubMesh { VertexCount = nonDashVertices.Length, VertexStartIndex = dashSubMesh.VertexStartIndex + dashSubMesh.VertexCount, TriangleCount = (nonDashVertices.Length * 3) / 2, TriangleStartIndex = dashSubMesh.TriangleStartIndex + dashSubMesh.TriangleCount, Material = RoadMaterial.RoadSurface }; vertexBuffer.AddRange(dashVertices); vertexBuffer.AddRange(nonDashVertices); triangleBuffer.ResizeUninitialized(triangleBuffer.Length + dashSubMesh.TriangleCount + nonDashSubMesh.TriangleCount); for (int i = 0, j = dashSubMesh.TriangleStartIndex; i < dashSubMesh.VertexCount; i += 4) { triangleBuffer[j++] = i; triangleBuffer[j++] = i + 3; triangleBuffer[j++] = i + 1; triangleBuffer[j++] = i; triangleBuffer[j++] = i + 2; triangleBuffer[j++] = i + 3; } for (int i = 0, j = nonDashSubMesh.TriangleStartIndex; i < nonDashSubMesh.VertexCount; i += 4) { triangleBuffer[j++] = i; triangleBuffer[j++] = i + 3; triangleBuffer[j++] = i + 1; triangleBuffer[j++] = i; triangleBuffer[j++] = i + 2; triangleBuffer[j++] = i + 3; } subMeshBuffer.Add(dashSubMesh); subMeshBuffer.Add(nonDashSubMesh); dashVertices.Dispose(); nonDashVertices.Dispose(); }
public static void Bake(GameObject go, bool forced) { var sc = go.GetComponent <SpriteShapeController>(); var lc = go.GetComponent <LegacyCollider>(); if (sc != null) { List <IntPoint> path = new List <IntPoint>(); int splinePointCount = sc.spline.GetPointCount(); int pathPointCount = splinePointCount; ColliderCornerType cct = ColliderCornerType.Square; float co = 1.0f; if (lc != null) { int hashCode = sc.spline.GetHashCode() + lc.m_ColliderCornerType.GetHashCode() + lc.m_ColliderOffset.GetHashCode(); if (lc.m_HashCode == hashCode && !forced) { return; } lc.m_HashCode = hashCode; cct = lc.m_ColliderCornerType; co = lc.m_ColliderOffset; } if (sc.spline.isOpenEnded) { pathPointCount--; } for (int i = 0; i < pathPointCount; ++i) { int nextIndex = SplineUtility.NextIndex(i, splinePointCount); SampleCurve(sc.colliderDetail, sc.spline.GetPosition(i), sc.spline.GetRightTangent(i), sc.spline.GetPosition(nextIndex), sc.spline.GetLeftTangent(nextIndex), ref path); } if (co != 0f) { List <List <IntPoint> > solution = new List <List <IntPoint> >(); ClipperOffset clipOffset = new ClipperOffset(); EndType endType = EndType.etClosedPolygon; if (sc.spline.isOpenEnded) { endType = EndType.etOpenSquare; if (cct == ColliderCornerType.Round) { endType = EndType.etOpenRound; } } clipOffset.ArcTolerance = 200f / sc.colliderDetail; clipOffset.AddPath(path, (ExtrasClipperLib.JoinType)cct, endType); clipOffset.Execute(ref solution, s_ClipperScale * co); if (solution.Count > 0) { path = solution[0]; } } List <Vector2> pathPoints = new List <Vector2>(path.Count); for (int i = 0; i < path.Count; ++i) { IntPoint ip = path[i]; pathPoints.Add(new Vector2(ip.X / s_ClipperScale, ip.Y / s_ClipperScale)); } var pc = go.GetComponent <PolygonCollider2D>(); if (pc) { pc.pathCount = 0; pc.SetPath(0, pathPoints.ToArray()); } var ec = go.GetComponent <EdgeCollider2D>(); if (ec) { if (co > 0f || co < 0f && !sc.spline.isOpenEnded) { pathPoints.Add(pathPoints[0]); } ec.points = pathPoints.ToArray(); } } }
// Update is called once per frame void Update() { var mouseWorldPos = Camera.main.ScreenToWorldPoint(Input.mousePosition); var mousePos = new Vector2(mouseWorldPos.x, mouseWorldPos.y); if (state == DragState.None && Input.GetMouseButton(0)) { var hits = new List <RaycastHit2D>(); var cf = new ContactFilter2D(); cf.NoFilter(); int hitCount = Physics2D.CircleCast(mousePos, 0.1f, Vector2.zero, cf, hits); Vector2 startPoint = Vector2.zero; GameObject obj = null; PlantSectionType?plantType = null; // Find the highest priority growth thing (seed > medium) for (int i = 0; i < hitCount; i++) { var hit = hits[i]; var iObj = hit.collider.gameObject; var growable = iObj.GetComponent <Growable>(); if (growable && !obj) { obj = iObj; startPoint = hit.point; plantType = growable.rootType; } else if (growable) { if (growable.rootType == PlantSectionType.Seed || plantType != PlantSectionType.Seed) { obj = iObj; startPoint = hit.point; plantType = growable.rootType; } } } if (obj != null && plantType != null) { // First, check if it's the end point var spline = obj.GetComponent <SpriteShapeController>()?.spline; if (spline != null) { var pointCount = spline.GetPointCount(); var lastWorld = obj.transform.position + spline.GetPosition(pointCount - 1); var last = new Vector2(lastWorld.x, lastWorld.y); if ((last - mousePos).magnitude < 0.4f) { // We're close enough to the end, we should just continue growing this one state = DragState.Dragging; currentlyGrowing = obj; return; } } switch (plantType) { case PlantSectionType.Seed: { // Unlock the camera if this is the first time we've clicked on a seed focus.startupLock = false; // If we're clicking on a seed, drop into the deciding state state = DragState.Deciding_Seed; dragStart = startPoint; dragParent = obj.GetComponent <Growable>(); obj.GetComponent <Animator>().SetTrigger("StopWiggle"); } break; case PlantSectionType.MediumRoot: { state = DragState.Deciding_Medium_Root; dragStart = startPoint; dragParent = obj.GetComponent <Growable>(); } break; default: { } break; } } return; } if (state == DragState.Deciding_Seed && Input.GetMouseButton(0)) { var delta = mousePos - dragStart; if (delta.sqrMagnitude < .5f) { // Update the indicator position, or something? } else { // Decide what to spawn based on whether you went up or down if (delta.y <= 0) { // They went down, spawn a root! currentlyGrowing = SpawnOffshoot(dragParent, PlantSectionType.MediumRoot, dragStart, mousePos); state = DragState.Dragging; } else { currentlyGrowing = SpawnOffshoot(dragParent, PlantSectionType.SkinnyPlant, dragStart, mousePos); state = DragState.Dragging; } } return; } if (state == DragState.Deciding_Medium_Root && Input.GetMouseButton(0)) { var delta = mousePos - dragStart; if (delta.sqrMagnitude < .5f) { // Update the indicator position, or something? } else { currentlyGrowing = SpawnOffshoot(dragParent, PlantSectionType.SkinnyRoot, dragStart, mousePos); state = DragState.Dragging; } } if (state == DragState.Dragging && Input.GetMouseButton(0)) { var growable = currentlyGrowing.GetComponent <Growable>().growable; if (!growable) { return; } var currentType = currentlyGrowing.GetComponent <Growable>().rootType; var spline = currentlyGrowing.GetComponent <SpriteShapeController>().spline; var pointCount = spline.GetPointCount(); // Check the length of the last segment var basePosWorld = currentlyGrowing.transform.position; var lastWorld = spline.GetPosition(pointCount - 1); var prevWorld = spline.GetPosition(pointCount - 2); var basePos = new Vector2(basePosWorld.x, basePosWorld.y); var last = new Vector2(lastWorld.x, lastWorld.y); var prev = new Vector2(prevWorld.x, prevWorld.y); // Grow the spline slightly var growDir = mousePos - (basePos + last); segmentTime += Time.deltaTime; var currentCost = currentType == PlantSectionType.MediumRoot ? 30 : 5; if (growDir.sqrMagnitude > .001) { var growDirN = growDir.normalized; var growSpeed = currentType == PlantSectionType.MediumRoot ? 0.5f : 1.5f; var newPos = last + growDirN * growSpeed * Time.deltaTime; var newPosWorld = basePos + newPos; // Check for rocks bool blocked = false; foreach (var rock in impassables) { var collider = rock.GetComponent <Collider2D>(); if (collider.OverlapPoint(newPosWorld)) { newPosWorld = collider.ClosestPoint(basePos + last); newPos = newPosWorld - basePos; } } // If roots, make sure we stay below ground if (currentType == PlantSectionType.SkinnyRoot || currentType == PlantSectionType.MediumRoot ) { newPosWorld = dirt.GetComponent <Collider2D>().ClosestPoint(basePos + newPos); newPos = newPosWorld - basePos; } var newPosRel = new Vector3(newPos.x, newPos.y, 0.0f); if (newPosWorld.y > focus.plantHeight) { focus.plantHeight = newPosWorld.y; } if (newPosWorld.y < focus.plantDepth) { focus.plantDepth = newPosWorld.y; } var turningRadius = currentType == PlantSectionType.MediumRoot ? 0.7f : 0.3f; if ((last - prev).sqrMagnitude < turningRadius && segmentTime < 2) { spline.SetPosition(pointCount - 1, newPosRel); } else if (currentCost <= minerals) { segmentTime = 0.0f; var midpoint = (lastWorld + prevWorld) / 2; spline.SetPosition(pointCount - 1, midpoint); spline.InsertPointAt(pointCount, newPosRel); // we just added something to the spline, so pointCount now refers to the last minerals -= currentCost; switch (currentType) { case PlantSectionType.MediumRoot: { spline.SetHeight(pointCount, .3f); } break; case PlantSectionType.SkinnyRoot: { spline.SetHeight(pointCount, .1f); } break; case PlantSectionType.SkinnyPlant: { spline.SetHeight(pointCount, .2f); } break; } // pointCount - 1 is the second-to-last spline.SetTangentMode(pointCount - 1, ShapeTangentMode.Continuous); Vector3 right; Vector3 left; SplineUtility.CalculateTangents( lastWorld, prevWorld, newPosRel, Vector2.zero, .2f, out right, out left ); spline.SetLeftTangent(pointCount - 1, left); spline.SetRightTangent(pointCount - 1, right); float length = 0; for (var i = 0; i < pointCount - 1; i++) { if (i > 0) { length += (spline.GetPosition(i) - spline.GetPosition(i - 1)).magnitude; } var maxH = currentType == PlantSectionType.MediumRoot ? 0.7f : 0.5f; var h = spline.GetHeight(i); var dH = (maxH - h) / 50f; var newH = h + dH; spline.SetHeight(i, newH); } var maxLength = currentType == PlantSectionType.SkinnyPlant ? 75 : 25; if (length > maxLength) { currentlyGrowing.GetComponent <Growable>().growable = false; } } } } if (!Input.GetMouseButton(0)) { state = DragState.None; dragStart = Vector2.zero; currentlyGrowing = null; } }
void SolveCorner() { if (m_ParentObj != null) { DestroyImmediate(m_ParentObj); } m_ParentObj = new GameObject("RoundedCornerVisualizer"); NativeArray <float2> leftBuffer, rightBuffer; switch (testCase) { case TestCase.BetweenBothSegments: BetweenBothSegments(out leftBuffer, out rightBuffer); break; case TestCase.PivotLeftSegment: PivotNextLeftSegment(out leftBuffer, out rightBuffer); break; case TestCase.PivotRightSegment: PivotNextRightSegment(out leftBuffer, out rightBuffer); break; case TestCase.PivotBothSegments: PivotBothSegments(out leftBuffer, out rightBuffer); break; case TestCase.InwardInput: InwardInput(out leftBuffer, out rightBuffer); break; case TestCase.OutwardInput: OutwardInput(out leftBuffer, out rightBuffer); break; default: throw new ArgumentOutOfRangeException(); } SplineUtility.ReverseArray(rightBuffer); var leftBufferTransform = Float2ToRigidTransform(leftBuffer); var rightBufferTransform = Float2ToRigidTransform(rightBuffer); var roundedCornerSolver = new RoundedCornerSolver { LeftBuffer = leftBufferTransform, RightBuffer = rightBufferTransform, CornerRadius = radius }; if (roundedCornerSolver.Solve(out var results)) { var leftTangent = Utilities.GeometryUtility.SwizzleX0Z(results.LeftTangent); var rightTangent = Utilities.GeometryUtility.SwizzleX0Z(results.RightTangent); CreateLine(leftBufferTransform, Color.green); CreateLine(rightBufferTransform, Color.green); CreateLine(new Vector3[] { leftTangent, results.Center3 }, Color.red); CreateLine(new Vector3[] { rightTangent, results.Center3 }, Color.blue); CreateCircle(results.Center3, radius, Color.cyan); } else { CreateLine(leftBufferTransform, Color.magenta); CreateLine(rightBufferTransform, Color.magenta); } CreateNormals(leftBuffer); CreateNormals(rightBuffer); leftBuffer.Dispose(); rightBuffer.Dispose(); leftBufferTransform.Dispose(); rightBufferTransform.Dispose(); }