Version: 2022.2
public static void Simplify (List<Vector3> points, float tolerance, List<int> pointsToKeep);
public static void Simplify (List<Vector3> points, float tolerance, List<Vector3> simplifiedPoints);
public static void Simplify (List<Vector2> points, float tolerance, List<int> pointsToKeep);
public static void Simplify (List<Vector2> points, float tolerance, List<Vector2> simplifiedPoints);

参数

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("##.##") + "%)"); } }