Is it really so difficult to draw smooth lines in Unity?
I had this issue with Unity 2017.2. I tried changing my AA settings to max to get rid of line render jaggies. Didn't work and it was frustrating.
My solution was resolving the problem that MSAA was turned off on the camera because rendering was deferred. The camera has a setting for "use graphics settings" which should have never messed up in the first place, but I'm a beginner - I don't know much. I changed the setting to "forward" and my jaggies disappeared into the mist.
If I was more industrious, I would post before and after images.
Thanks to @Iggy 's inspiration and tutorials on catlikecoding.com (where the spline code I'm using comes from), I created a component that will create a mesh based on a spline given a width and sample frequency. Higher sample frequency = smoother curve of course.
using UnityEngine;
[ExecuteInEditMode]
[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer), typeof(BezierSpline))]
public class SplineMesh : MonoBehaviour {
[Range(1, 20)]
public int sampleFrequency = 5;
[Range(0, 5f)]
public float lineWidth = 0.3f;
BezierSpline spline;
Mesh mesh;
private void Awake () {
spline = GetComponent<BezierSpline>();
mesh = GetComponent<Mesh>();
}
/*
void Update()
{
for(int i = 0; i <= sampleFrequency; i++){
float interval = i / (float)sampleFrequency;
var point = spline.GetPoint(interval);
var direction = spline.GetDirection(interval);
var perpendicularLeftVec = PerpendicularLeft(direction) * lineWidth;
var perpendicularRightVec = PerpendicularRight(direction) * lineWidth;
Debug.DrawLine(point, point + (Vector3)perpendicularLeftVec, Color.magenta, 0.5f, false);
Debug.DrawLine(point, point + (Vector3)perpendicularRightVec, Color.cyan, 0.5f, false);
}
}
*/
Vector2 PerpendicularRight(Vector2 orig){
var vec = new Vector2(orig.y, -orig.x);
vec.Normalize();
return vec;
}
Vector2 PerpendicularLeft(Vector2 orig){
var vec = new Vector2(orig.y, -orig.x);
vec.Normalize();
return vec * -1;
}
private Vector3[] vertices;
public void GenerateMesh(){
vertices = new Vector3[(sampleFrequency + 1) * 2];
//iterate over our samples adding two vertices for each one
for(int s = 0, i = 0; s <= sampleFrequency; s++, i += 2){
float interval = s / (float)sampleFrequency;
//get point along spline, and translate to local coords from world
var point = transform.InverseTransformPoint(spline.GetPoint(interval));
var direction = spline.GetDirection(interval);
var perpendicularLeftVec = PerpendicularLeft(direction) * lineWidth;
var perpendicularRightVec = PerpendicularRight(direction) * lineWidth;
// var perpendicularVec = turnLeft ? PerpendicularLeft(diffVector) : PerpendicularRight(diffVector);
vertices[i] = point + (Vector3)perpendicularLeftVec;
vertices[i + 1] = point + (Vector3)perpendicularRightVec;
}
GetComponent<MeshFilter>().mesh = mesh = new Mesh();
mesh.name = "Spline Mesh";
mesh.vertices = vertices;
//now figure out our triangles
int [] triangles = new int[sampleFrequency * 6];
for(int s = 0, ti = 0, vi = 0; s < sampleFrequency; s++, ti += 6, vi += 2){
//first tri
triangles[ti] = vi;
triangles[ti + 1] = vi + 3;
triangles[ti + 2] = vi + 1;
//second matching tri
triangles[ti + 3] = vi;
triangles[ti + 4] = vi + 2;
triangles[ti + 5] = vi + 3;
}
mesh.triangles = triangles;
mesh.RecalculateNormals();
Debug.Log("Generated Spline Mesh");
}
}
You can get some good results by generating a mesh from a set of points.
The algorithm for it is as follows:
- You have a set of points, could be generated with bezier curve.
- For each point, take a directional vector to the next point
v = (p2 - p1)
(marked in blue). Then rotate that vector by 90 degreesnormal = v.y, -v.x
marked in red.
- This illustrates that we will use each normal from the point position. You can now multiply this vector in both directions by the desired width of the line.
- Create the vertices at those positions.
- Add indices to form triangles. It will be something like
[i, w/2 + i, w/2 + i + 1]
wherei
is the current index, andw
is the total number of vertices.
- Create the other triangles. Again something like
[i, w/2 * i + 1, i + 1]
- And the final result. You can add more points to make the line smoother.
I obtained only jagged lines with the corners not rounded, in particular when the angle of curvature is really small .
This was a problem in Unity 5.4 and below. This problem has been fixed in Unity 5.5 and above after LineRenderer
was completely re-designed.
All you have to do is update to Unity 5.5 or version above and this problem should go away.
There is a new variable called LineRenderer.numCornerVertices
. You can use that to set how smooth you want the line to be. The value of 5 seems fine for this.
There is also another new variable called LineRenderer.numCapVertices
that can be used to set how smooth the end of the line should be.
This is a screenshot that demonstrate between 5.4 and 5.5 the changes: