// /****************************************************************************** // * File: CurvedLineRenderer.cs // * Copyright (c) 2023 Qualcomm Technologies, Inc. and/or its subsidiaries. All rights reserved. // * // * // ******************************************************************************/ using System; using System.Collections.Generic; using UnityEngine; namespace QCHT.Samples.Drawing { /// /// Changes the line renderer behaviour to draw a smooth line. /// [RequireComponent(typeof(LineRenderer))] public sealed class CurvedLineRenderer : MonoBehaviour { public float LineSegmentWidth = 0.15f; public float LineWidth = 0.1f; private Vector3[] _positions = Array.Empty(); private static readonly AnimationCurve s_curveX = new AnimationCurve(); private static readonly AnimationCurve s_curveY = new AnimationCurve(); private static readonly AnimationCurve s_curveZ = new AnimationCurve(); #region MonoBehaviour Functions #if UNITY_EDITOR private void OnValidate() { UpdateLine(); } #endif #endregion /// /// Changes the line renderer positions. /// /// the new positions table. public void SetPositions(Vector3[] positions) { _positions = positions; UpdateLine(); } private void UpdateLine() { var smoothedPoints = Smooth(_positions, LineSegmentWidth); var lineRenderer = GetComponent(); lineRenderer.positionCount = smoothedPoints.Length; lineRenderer.SetPositions(smoothedPoints); lineRenderer.startWidth = LineWidth; lineRenderer.endWidth = LineWidth; } private static Vector3[] Smooth(Vector3[] points, float stepSize) { var keysX = new Keyframe[points.Length]; var keysY = new Keyframe[points.Length]; var keysZ = new Keyframe[points.Length]; for (var i = 0; i < points.Length; i++) { keysX[i] = new Keyframe(i, points[i].x); keysY[i] = new Keyframe(i, points[i].y); keysZ[i] = new Keyframe(i, points[i].z); } s_curveX.keys = keysX; s_curveY.keys = keysY; s_curveZ.keys = keysZ; for (var i = 0; i < points.Length; i++) { s_curveX.SmoothTangents(i, 0); s_curveY.SmoothTangents(i, 0); s_curveZ.SmoothTangents(i, 0); } var lineSegments = new List(); for (var i = 0; i < points.Length; i++) { lineSegments.Add(points[i]); if (i + 1 >= points.Length) continue; var distanceToNextPoint = Vector3.Distance(points[i], points[i + 1]); var nbSegments = (int) (distanceToNextPoint / stepSize); for (var j = 1; j < nbSegments; j++) { var t = j / (float) nbSegments + i; var segment = new Vector3( s_curveX.Evaluate(t), s_curveY.Evaluate(t), s_curveZ.Evaluate(t)); lineSegments.Add(segment); } } return lineSegments.ToArray(); } } }