我一直试图在Unity中绘制平滑的线条,但是使用线条渲染器我只获得锯齿状线条,其边角不圆,特别是当曲率角非常小时。我在质量设置中增加了抗锯齿的值并尝试了不同的材料,但没有任何改变。我还尝试在每次鼠标移动时实例化一个球体,但它会在各个球体之间产生一些间隙,特别是当鼠标快速移动时。我知道有一个名为Vectrosity的插件,但有一种方法可以实现这一点吗?
答案 0 :(得分:21)
通过从一组点生成网格,可以获得一些好的结果。
它的算法如下:
答案 1 :(得分:8)
我只获得锯齿状的线条,其中的圆角没有圆角 特别是当曲率角非常小时。
这是 Unity 5.4 及以下的问题。在完全重新设计LineRenderer
后, Unity 5.5 及以上版本已修复此问题。
您所要做的就是更新到 Unity 5.5 或上面的版本,这个问题就会消失。
有一个名为LineRenderer.numCornerVertices
的新变量。您可以使用它来设置您希望线条的平滑程度。 5 的值似乎很好。
还有另一个名为LineRenderer.numCapVertices
的新变量,可用于设置该行的 end 的平滑程度。
这是在 5.4 和 5.5 之间演示更改的屏幕截图:
答案 2 :(得分:2)
由于@Iggy在catlikecoding.com上的灵感和教程(我使用的样条代码来自此),我创建了一个组件,该组件将根据给定宽度和采样频率的样条创建网格。更高的采样频率=当然曲线更平滑。
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");
}
}
答案 3 :(得分:0)
我在Unity 2017.2中遇到过这个问题。我尝试将我的AA设置更改为最大值以摆脱线条渲染锯齿。没有工作,这令人沮丧。
我的解决方案是解决了相机关闭MSAA的问题,因为渲染延迟了。相机有一个“使用图形设置”的设置,它应该从来没有搞砸过,但我是初学者 - 我不太了解。我将设置改为“前进”,我的锯齿消失在雾中。
如果我更勤奋,我会在图像之前和之后发布。
答案 4 :(得分:0)
由于@Iggy的出色回答,我终于可以工作了。
在画布上创建一个新图像,删除图像脚本并将其替换为UICubicBezier。
提供:
using UnityEngine;
using UnityEngine.UI;
[ExecuteInEditMode]
public class UiCubicBezier : MaskableGraphic
{
public float thickness = 2;
public int anchors = 20;
protected override void OnPopulateMesh(VertexHelper vh)
{
// draws a cubic bezier curve from the lower left hand corner (start)
// to the upper right hand corner (end).
vh.Clear();
var rt = this.rectTransform;
var rect = rt.rect;
var start = new Vector2(-rect.width / 2, -rect.height / 2);
var cp1 = new Vector2(-rect.width / 6, -rect.height / 2);
var cp2 = new Vector2(rect.width / 6, rect.height / 2);
var end = new Vector2(rect.width / 2, rect.height / 2);
var data = new BezierData(start, cp1, cp2, end);
// all you need to know is that data.GetPoint generates a sequence of points
// between the start and end points.
var points = new Vector2[this.anchors];
for (var anchor = 0; anchor < points.Length; anchor++)
{
var t = (float)anchor / this.anchors;
points[anchor] = data.GetPoint(t);
}
// because the normals are at the mid-points between vertexes the start and end
// points don't touch the bounding box. to fix this some vertexes are added to
// the start and end that touch the bounding box.
this.DrawStartVertexes(vh, start);
for (var anchor = 0; anchor < points.Length - 1; anchor++)
{
this.DrawVertexes(vh, points[anchor], points[anchor + 1]);
}
this.DrawEndVertexes(vh, end);
for (var v = 0; v + 2 < vh.currentVertCount; v += 2)
{
vh.AddTriangle(v, v + 1, v + 2);
}
for (var v = 0; v + 3 < vh.currentVertCount; v += 2)
{
vh.AddTriangle(v + 1, v + 2, v + 3);
}
}
private void DrawStartVertexes(VertexHelper vh, Vector2 start)
{
// d = thickness * \sqrt{2}, so the distance between the vertexes
// is equal to the thickness (https://en.wikipedia.org/wiki/Triangle#Right_triangles)
var d = this.thickness * 0.70710678118f;
var vertex = UIVertex.simpleVert;
vertex.color = this.color;
vertex.position = new Vector2(start.x, start.y + d);
vh.AddVert(vertex);
vertex.position = new Vector2(start.x + d, start.y);
vh.AddVert(vertex);
}
private void DrawEndVertexes(VertexHelper vh, Vector2 end)
{
// d = thickness * \sqrt{2}, so the distance between the vertexes
// is equal to the thickness (https://en.wikipedia.org/wiki/Triangle#Right_triangles)
var d = this.thickness * 0.70710678118f;
var vertex = UIVertex.simpleVert;
vertex.color = this.color;
vertex.position = new Vector2(end.x - d, end.y);
vh.AddVert(vertex);
vertex.position = new Vector2(end.x, end.y - d);
vh.AddVert(vertex);
}
private void DrawVertexes(VertexHelper vh, Vector2 start, Vector2 end)
{
var v = end - start;
var mid = start + v / 2; // the mid-point between start and end.
var perp = Vector2.Perpendicular(v.normalized); // vector of length 1 perpendicular to v.
var vertex = UIVertex.simpleVert;
vertex.color = this.color;
// move half the thickness away from the mid-point.
vertex.position = mid + (perp * this.thickness / 2);
vh.AddVert(vertex);
// move half the thickness away from the mid-point in the opposite direction.
vertex.position = mid - (perp * this.thickness / 2);
vh.AddVert(vertex);
}
private struct BezierData
{
private readonly Vector2 start;
private readonly float cx;
private readonly float bx;
private readonly float ax;
private readonly float cy;
private readonly float by;
private readonly float ay;
public BezierData(Vector2 start, Vector2 cp1, Vector2 cp2, Vector2 end)
{
// cribbed from here: https://www.codeproject.com/articles/25237/bezier-curves-made-simple
this.start = start;
this.cx = 3 * (cp1.x - start.x);
this.bx = 3 * (cp2.x - cp1.x) - this.cx;
this.ax = end.x - start.x - this.cx - this.bx;
this.cy = 3 * (cp1.y - start.y);
this.by = 3 * (cp2.y - cp1.y) - this.cy;
this.ay = end.y - start.y - this.cy - this.by;
}
public Vector2 GetPoint(float t)
{
var tSquared = t * t;
var tCubed = tSquared * t;
return new Vector2(
(this.ax * tCubed) + (this.bx * tSquared) + (this.cx * t) + this.start.x,
(this.ay * tCubed) + (this.by * tSquared) + (this.cy * t) + this.start.y);
}
}
}
答案 5 :(得分:0)
TLDR: 考虑使用Shapes的Freya Holmér
免责声明:我还没有尝试过,但是结果看起来很棒。
过去,我创建了自定义解决方案,其中将创建自定义网格(类似于此处描述的其他解决方案),用于抵消屏幕空间中的顶点的顶点着色器和具有alpha混合功能的片段着色器,以实现出色的AA。我从来没有时间来创建一个合适的,可重复使用的程序包,但是Freya的解决方案似乎要先进得多。
如果我再次需要类似的东西,我会先检查她的图书馆。