using UnityEngine; using System.Collections.Generic; public struct BezierLineSegment { public Vector3 fromPoint; public Vector3 toPoint; public Vector3 controlPoint; public Quaternion fromDir; public Quaternion toDir; public void CalculateDir() { fromDir = Quaternion.FromToRotation(Vector3.forward, controlPoint - fromPoint); toDir = Quaternion.FromToRotation(Vector3.forward, toPoint - controlPoint); } public bool IsStraight() { return fromDir == toDir; } } [ExecuteInEditMode] public class BezierPipe : MonoBehaviour { public float cornerScale = 1f; [Range(1, 100)] public int cornerStep = 10; [Range(2, 100)] public int circleStep = 10; public float r = 0.1f; public Transform point1; public Vector3 point1Dir = Vector3.up; public Transform point2; public Vector3 point2Dir = Vector3.up; public bool update = false; public Mesh mesh; List verts = new List(); List triangles = new List(); private MeshCollider mc; // Use this for initialization void Start() { mesh = new Mesh(); mesh.name = "Pipe"; MeshFilter mf = GetComponent(); if (mf != null) { mf.sharedMesh = mesh; } mc = GetComponent(); if (mc != null) { mc.sharedMesh = mesh; } BuildMesh(); } // Update is called once per frame void Update() { if (update) { BuildMesh(); } } void GetCirclePoint(Vector3 pos, Quaternion dir, bool draw) { for (int a = 0; a <= circleStep; a++) { float p = 2 * Mathf.PI * a / circleStep; Vector3 cp = new Vector3(r * Mathf.Cos(p), r * Mathf.Sin(p), 0); cp = dir * cp + pos; //if(draw) // Gizmos.DrawSphere(cp, 0.0005f); cp = transform.worldToLocalMatrix.MultiplyPoint(cp); //cp += transform.position; verts.Add(cp); } } void SetTriangles() { triangles.Clear(); for (int i = 0; i < verts.Count - circleStep - 2; i++) { triangles.Add(i); triangles.Add(i + 1); triangles.Add(i + circleStep + 1); triangles.Add(i + circleStep + 1); triangles.Add(i + 1); triangles.Add(i + circleStep + 2); } mesh.triangles = triangles.ToArray(); } public void BuildMesh() { if (point1 != null && point2 != null) { verts.Clear(); float scale = cornerScale; float length = (point1.position - point2.position).magnitude / 4; if (scale > length) { scale = length; } BezierLineSegment[] segments = new BezierLineSegment[3]; segments[0].fromPoint = point1.position; point1Dir.Normalize(); segments[0].controlPoint = point1.position + point1.rotation * point1Dir * scale; segments[2].toPoint = point2.position; point2Dir.Normalize(); segments[2].controlPoint = point2.position + point2.rotation * point2Dir * scale; segments[1].controlPoint = (segments[0].controlPoint + segments[2].controlPoint) / 2; segments[0].toPoint = segments[1].fromPoint = segments[0].controlPoint + (segments[1].controlPoint - segments[0].controlPoint).normalized * scale; segments[1].toPoint = segments[2].fromPoint = segments[2].controlPoint + (segments[1].controlPoint - segments[2].controlPoint).normalized * scale; transform.position = segments[1].controlPoint; segments[1].CalculateDir(); transform.rotation = segments[1].fromDir; // Debug.Log (transform.eulerAngles); foreach (var segment in segments) { segment.CalculateDir(); if (segment.IsStraight()) { GetCirclePoint(segment.fromPoint, segment.fromDir, true); GetCirclePoint(segment.controlPoint, segment.fromDir, false); GetCirclePoint(segment.toPoint, segment.toDir, true); //Gizmos.DrawLine(segment.fromPoint, segment.controlPoint); //Gizmos.DrawLine(segment.controlPoint, segment.toPoint); } else { GetCirclePoint(segment.fromPoint, segment.fromDir, true); Vector3 p1 = segment.fromPoint; for (int s = 1; s < cornerStep; s++) { float t = (float)s / cornerStep; Vector3 p2 = GetBezierPoint(t,segment.fromPoint, segment.controlPoint, segment.toPoint); //Quaternion dir = Quaternion.FromToRotation(Vector3.forward, p2 - p1); Quaternion dir = Quaternion.Lerp(segment.fromDir, segment.toDir, t); GetCirclePoint(p2, dir, false); //Gizmos.DrawLine(p1, p2); p1 = p2; } GetCirclePoint(segment.toPoint, segment.toDir, true); //Gizmos.DrawLine(p1,segment.toPoint); } } mesh.Clear(); mesh.vertices = verts.ToArray(); SetTriangles(); mesh.RecalculateNormals(); if (mc != null) { mc.sharedMesh = mesh; } } } Vector3 GetBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2) { float u = 1f - t; float tt = t * t; float uu = u * u; // 计算二次贝塞尔曲线公式 Vector3 p = uu * p0; // (1 - t)^2 * P0 p += 2 * u * t * p1; // 2 * (1 - t) * t * P1 p += tt * p2; // t^2 * P2 return p; } }