- Home /
Line drawing: How can I interpolate between points to create a smooth arc?
I'm using the line renderer to create a line on screen based off user input. Think finger drawing.
The problem is that when a user draws too quickly, there isn't enough fidelity captured per frame to create a smooth line - it looks jaggy. I have an array of x,y point values in Javascript.
I'd like to figure out a simple way to take my array and smooth it out before sending the values to the line renderer by interpolating between the points I have. Any ideas?
Here is an example array that I'm working with based off user input:
var user_touch_input = [(16.6, 7.4, 0.0),(15.5, 7.2, 0.0),(14.4, 7.1, 0.0),(13.5, 7.1, 0.0),(12.4, 7.7, 0.0)];
in general, what you're looking for is called a bezier. it is a very basic problem in computer science, and used constantly in Unity and almost all computer system.
Answer by Codetastic · Feb 03, 2013 at 08:41 AM
Thanks to this site, I was able to create the following script:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Curver : MonoBehaviour {
//arrayToCurve is original Vector3 array, smoothness is the number of interpolations.
public static Vector3[] MakeSmoothCurve(Vector3[] arrayToCurve,float smoothness){
List<Vector3> points;
List<Vector3> curvedPoints;
int pointsLength = 0;
int curvedLength = 0;
if(smoothness < 1.0f) smoothness = 1.0f;
pointsLength = arrayToCurve.Length;
curvedLength = (pointsLength*Mathf.RoundToInt(smoothness))-1;
curvedPoints = new List<Vector3>(curvedLength);
float t = 0.0f;
for(int pointInTimeOnCurve = 0;pointInTimeOnCurve < curvedLength+1;pointInTimeOnCurve++){
t = Mathf.InverseLerp(0,curvedLength,pointInTimeOnCurve);
points = new List<Vector3>(arrayToCurve);
for(int j = pointsLength-1; j > 0; j--){
for (int i = 0; i < j; i++){
points[i] = (1-t)*points[i] + t*points[i+1];
}
}
curvedPoints.Add(points[0]);
}
return(curvedPoints.ToArray());
}
}
To use this just call Curver.MakeSmoothCurve(theArrayYouWantToCurve,numberOfInterpolations). Example:
//javascript/unityscript example
#pragma strict
var points : Vector3[];
var lineRenderer : LineRenderer;
var c1 : Color = Color.yellow;
var c2 : Color = Color.red;
function Start () {
points = Curver.MakeSmoothCurve(points,3.0);
lineRenderer.SetColors(c1, c2);
lineRenderer.SetWidth(0.5,0.5);
lineRenderer.SetVertexCount(points.Length);
var counter : int = 0;
for(var i : Vector3 in points){
lineRenderer.SetPosition(counter, i);
++counter;
}
}
Notes:
Place in a folder that will be compiled earlier than your scripts if you are using unityscript/javascript. A "Plugins" folder will probably work.
smoothness is rounded.
Wow, such an amazingly detailed & thoughtful answer. This code is flawless. Thanks to your help, my lines are smooth at last. Can't thank you enough for providing such a great answer.
Well I figured a detailed question deserved a decent answer. But the real thanks should go to Evgeny Demidov and Paul de Casteljau. All I did was put it into code.
While this is nice code, it doesn't seem to behave exactly like the question describes above. In his illustration, the smoothed path includes the original points -- this code doesn't produce smooth paths that do this
Thank you! I have been trying to get this for a very long time and this works 100% great!
I am trying to figure out how to use this, is this c# or javastcript?
Nice script, but it's performance is very weak, over 70 points i get fps lag, can yoz help pls?
Answer by robertbu · Feb 03, 2013 at 06:25 AM
There is a lot of spline algorithms and spline code on the net you could adapt. If you are looking for something easier, iTween comes with smoothed Path that you could use to calculate the positions for additional points. There are also packages at the Asset store. Vectrosity will handle both the smoothing and line drawing. I've never used it, but I've read some good things about SuperSplines.
This is a much better answer than the checked solution. iTween (now?) also includes a command for simply doing what you want. In essence there's iTween.PointOnPath(Vector3[], float) which returns a point along the smoothed path formed by the positions (there's also a version that takes an array of transforms and does the same thing).
I'm not sure I agree that adding an entire library to a project in order to accomplish one relatively simple task is a better solution than 40 lines of specific, tailored code.
Hey, sorry to come back on an old thread but could you maybe explain a little bit more how we would use this?
Answer by ercion · Feb 17, 2017 at 09:12 AM
Codetastic's answer provides Bezier curves which don't reach middle points. Using iTween.PointOnPath gives you Catmull-Rom spline which is better in some situations.
Answer by surajdico · Jun 07, 2018 at 05:29 AM
Am new to line renderer and is it possible I can use this code and assign to the device's x y z motion to draw like a graph thing. @ensomniac. thanks in advance.