Camera Polyline Clipping Algorithm Reference

Camera Polyline Clipping Algorithm Reference

There are two points to note:

1. The method Plane.Raycast will not produce an intersection point when the parameters Ray and Plane are in a parallel state, the return value is false, and the parameter enter is assigned a value of 0. If the parameters Ray and Plane are not in a parallel state, then there will be an intersection point. In this case, if Ray points to the direction of Plane, no matter whether the point product result of Ray's direction and Plane's normal is greater than 0, it will Returns true, and enter is a positive value. If the direction of Ray does not point to the Plane, the opposite direction of Ray's direction will actually intersect with the Plane, but the return value is false at this time, and enter is a negative value.

2. When two points are outside Frustum, if the intersection point between these two points and Frustum is not between these two points, then there is actually no intersection point between these two points and Frustum.

	//折线裁剪
	public static List<Line3D> GetCuttingLines(Line3D line, Camera cam)
	{
		if (line.points == null || line.points.Length < 2) return null;

		List<Line3D> listCuttingLine = new List<Line3D>();

		Plane[] planes = GeometryUtility.CalculateFrustumPlanes(cam);

		List<Vector3> curListPoint = new List<Vector3>();
		bool inPre = true;
		for (int i = 0; i < line.points.Length; i++)
		{
			bool inFrustum = true;
			for (int k = 0; k < 6; k++)
			{
				if (!planes[k].GetSide(line.points[i]))
				{
					inFrustum = false;
					break;
				}
			}

			if (inFrustum)
			{
				if (curListPoint == null)
				{
					curListPoint = new List<Vector3>();
				}

				if (i == 0)
				{
					curListPoint.Add(line.points[i]);
				}
				else
				{
					if (!inPre)
					{
						float enterMin = float.MaxValue;
						Ray ray = new Ray(line.points[i], line.points[i - 1] - line.points[i]);
						foreach (Plane plane in planes)
						{
							if (Vector3.Dot(plane.normal, ray.direction) > 0) continue;
							float enter;
							if (plane.Raycast(ray, out enter))
							{
								if (enterMin > enter) enterMin = enter;
							}
						}
						curListPoint.Add(ray.GetPoint(enterMin));
					}
					curListPoint.Add(line.points[i]);
					if (i >= line.points.Length - 1)
					{
						Line3D lineCutting = new Line3D();
						lineCutting.color = line.color;
						lineCutting.points = curListPoint.ToArray();
						listCuttingLine.Add(lineCutting);
						curListPoint = null;
					}
				}
				//
				inPre = true;
			}
			else
			{
				if (i == 0)
				{
					inPre = false;
				}
				else
				{
					if (inPre)
					{
						if (curListPoint != null)
						{
							float enterMin = float.MaxValue;
							Ray ray = new Ray(line.points[i - 1], line.points[i] - line.points[i - 1]);
							foreach (Plane plane in planes)
							{
								if (Vector3.Dot(plane.normal, ray.direction) > 0) continue;
								float enter;
								if (plane.Raycast(ray, out enter))
								{
									if (enterMin > enter) enterMin = enter;
								}
							}
							curListPoint.Add(ray.GetPoint(enterMin));
							Line3D lineCutting = new Line3D();
							lineCutting.color = line.color;
							lineCutting.points = curListPoint.ToArray();
							listCuttingLine.Add(lineCutting);
							curListPoint = null;
						}
					}
					else
					{
						float enterMin = float.MaxValue;
						Vector3 direction = line.points[i] - line.points[i - 1];
						Ray ray = new Ray(line.points[i - 1], direction);
						Vector3 hitA = Vector3.zero;
						foreach (Plane plane in planes)
						{
							if (Vector3.Dot(plane.normal, ray.direction) > 0) continue;
							float enter;
							if (plane.Raycast(ray, out enter))
							{
								if (enterMin > enter) enterMin = enter;
							}
						}
						if (enterMin * enterMin > direction.sqrMagnitude) continue;

						hitA = ray.GetPoint(enterMin);

						enterMin = float.MaxValue;
						ray = new Ray(line.points[i], -direction);
						Vector3 hitB = Vector3.zero;
						foreach (Plane plane in planes)
						{
							if (Vector3.Dot(plane.normal, ray.direction) > 0) continue;
							float enter;
							if (plane.Raycast(ray, out enter))
							{
								if (enterMin > enter) enterMin = enter;
							}
						}
						if (enterMin * enterMin > direction.sqrMagnitude) continue;

						hitB = ray.GetPoint(enterMin);

						Vector3 hitCenter = (hitA + hitB) * 0.5f;

						bool hitCenterIn = true;
						for (int k = 0; k < 6; k++)
						{
							if (!planes[k].GetSide(hitCenter))
							{
								hitCenterIn = false;
								break;
							}
						}

						if (hitCenterIn)
						{
							Line3D lineCutting = new Line3D();
							lineCutting.color = line.color;
							lineCutting.points = new Vector3[] { hitA, hitB };
							listCuttingLine.Add(lineCutting);
						}
					}
				}
				//
				inPre = false;
			}
		}

		return listCuttingLine;
	}

Add a Line3D class:

using UnityEngine;

public class Line
{
	public Color color = Color.white;
	public bool close = false;
}
public class Line3D : Line
{
	public Vector3[] points = new Vector3[] { };
}

public class Line2D : Line
{
	public Vector2[] points = new Vector2[] { };
	public float width = 2;

	Vector3[] _ps3D;
	public Vector3[] ps3D
	{
		get
		{
			_ps3D = new Vector3[points.Length];
			for (int i = 0; i < points.Length; i++)
			{
				_ps3D[i] = points[i];
			}
			return _ps3D;
		}
	}
}

Guess you like

Origin blog.csdn.net/ttod/article/details/132172988