points | 组成原始线条的点。 |
tolerance | 此值用于评估应从线条中删除哪些点。较高的值将导致更简单的线条(更少的点)。接近零的正值将导致线条几乎或完全不减少。值为零或负值没有任何效果。 |
pointsToKeep | 由该函数填充。包含应生成简化版本的点的索引。 |
simplifiedPoints | 由该函数填充。包含构成简化线条的点。 |
通过删除位于指定容差范围内的点,生成原始线条的简化版本。
例如,你可以使用此函数缩减由数千个点构成的复杂线条。可以将该线条缩减至数百个甚至更少的点,同时仍然保持与原始线条非常接近的形状。你可以通过调整容差(较高的容差值会导致生成线条中的点较少)来生成同一线条的多个不同细节级别的版本。然后,可以使用 LODGroup 系统显示生成的线条。
Simplify 算法基于Ramer Douglas Peucker 算法;它创建一条非常接近所提供线条但点较少的线条(由容差值确定)。
注释:该函数能够处理大量的点,因为它是非递归的。此函数的 2D 版本比此函数的性能要好,因为它使用了一种更简单的点评估方式。
其他资源:LineRenderer.Simplify。
以下示例演示如何将线简化应用到现有的线中。
using System.Collections.Generic; using System.Linq; using UnityEngine;
// This example shows how to apply line simplification to a line that already contains points. [RequireComponent(typeof(LineRenderer))] public class SimpleExampleLineUtility : MonoBehaviour { public float tolerance = 1; void Start() { // Get the points. var lineRenderer = GetComponent<LineRenderer>(); int pointsBefore = lineRenderer.positionCount; var points = new Vector3[pointsBefore]; lineRenderer.GetPositions(points);
// Simplify. var simplifiedPoints = new List<Vector3>(); LineUtility.Simplify(points.ToList(), tolerance, simplifiedPoints);
// Assign back to the line renderer. lineRenderer.positionCount = simplifiedPoints.Count; lineRenderer.SetPositions(simplifiedPoints.ToArray());
Debug.Log("Line reduced from " + pointsBefore + " to " + lineRenderer.positionCount); } }
以下示例演示如何使用 pointsToKeep 参数返回索引列表。该列表随后可用于简化保留该列表中点的线段。仍可向所得简化线段中添加其他点。
using System.Collections.Generic; using System.Linq; using UnityEngine;
// This example shows how to use the pointsToKeep parameter to generate a new simplified version of the line. [RequireComponent(typeof(LineRenderer))] public class SimpleExampleLineUtilityPointsToKeep : MonoBehaviour { public float tolerance = 1; void Start() { // Get the points. var lineRenderer = GetComponent<LineRenderer>(); int pointsBefore = lineRenderer.positionCount; var points = new Vector3[pointsBefore]; lineRenderer.GetPositions(points);
// Simplify. var pointsToKeep = new List<int>(); LineUtility.Simplify(points.ToList(), tolerance, pointsToKeep);
var simplifiedPoints = new Vector3[pointsToKeep.Count]; for (int i = 0; i < simplifiedPoints.Length; ++i) { simplifiedPoints[i] = points[pointsToKeep[i]]; }
// Assign back to the line renderer. lineRenderer.positionCount = simplifiedPoints.Length; lineRenderer.SetPositions(simplifiedPoints);
Debug.Log("Line reduced from " + pointsBefore + " to " + lineRenderer.positionCount); } }
本示例生成一条正弦波形状的线段,并提供一个 GUI 来自定义线段生成和简化参数。
using System.Collections.Generic; using UnityEngine;
// This example creates a sine wave and then simplifies it using the LineUtility. // The parameters can be adjusted through an in game GUI to allow for experimentation. [RequireComponent(typeof(LineRenderer))] public class LineUtilityExample : MonoBehaviour { public int numberOfPoints = 1000; public float length = 50; public float waveHeight = 10; public float tolerance = 0.1f;
private LineRenderer lineRenderer; private List<Vector3> points = new List<Vector3>(); // Generated points before LineOptimizer is used. private List<Vector3> simplifiedPoints = new List<Vector3>(); // Simplified points after LineOptimizer is used.
public void Start() { lineRenderer = GetComponent<LineRenderer>(); }
// Generates the sine wave points. public void GeneratePoints() { points.Clear(); float halfWaveHeight = waveHeight * 0.5f; float step = length / numberOfPoints; for (int i = 0; i < numberOfPoints; ++i) { points.Add(new Vector3(i * step, Mathf.Sin(i * step) * halfWaveHeight, 0)); } }
// Simplify the line using the LineOptimizer. public void SimplifyLine() { simplifiedPoints.Clear(); LineUtility.Simplify(points, tolerance, simplifiedPoints); lineRenderer.positionCount = simplifiedPoints.Count; lineRenderer.SetPositions(simplifiedPoints.ToArray()); }
// Draw a simple GUI slider with a label. private static float GUISlider(string label, float value, float min, float max) { GUILayout.BeginHorizontal(GUILayout.Width(Screen.width / 2.0f)); GUILayout.Label(label + "(" + value + ") :", GUILayout.Width(150)); var val = GUILayout.HorizontalSlider(value, min, max); GUILayout.EndHorizontal(); return val; }
public void OnGUI() { GUILayout.Label("LineUtility.Simplify", GUI.skin.box);
// We use GUI.changed to detect if a value was changed via the GUI, if it has we can then re-generate the points and simplify the line again. GUI.changed = false;
numberOfPoints = (int)GUISlider("Number of Points", numberOfPoints, 0, 1000); length = GUISlider("Length", length, 0, 100); waveHeight = GUISlider("Wave Height", waveHeight, 0, 100); if (GUI.changed) GeneratePoints();
tolerance = GUISlider("Simplify Tolerance", tolerance, 0, 2); if (GUI.changed) SimplifyLine();
float percentRemoved = 100.0f - ((float)lineRenderer.positionCount / numberOfPoints) * 100.0f; if (tolerance > 0.0f) GUILayout.Label("Points after simplification: " + lineRenderer.positionCount + "(Removed " + percentRemoved.ToString("##.##") + "%)"); } }