Unity中動態繪製圓柱體

問題背景

上次寫了動態繪製立方體,這最近又來了新功能,繪製圓柱(風筒),要求是給了不少節點,根據節點去動態繪製風筒,風筒就是圓柱鏈接而成的,能夠理解爲管道,還有就是拐角處注意倒角,圓潤過分過來。html

實現原理

動態繪製圓柱mesh,注意,圓柱的mesh繪製遠比立方體複雜得多,上節闡述過基本mesh建立立方體,有興趣能夠去看看http://www.javashuo.com/article/p-ynhoctvw-hp.html,頂點以及倒角須要你本身去插值出來,其中倒角是使用貝塞爾曲線插值過分出來的。算法

實現步驟

1.頂點座標ide

2.uv座標函數

3.構建索引測試

4.構建實體this

具體過程

1.準備頂點數據

構建圓柱應當理解爲這是多個圓插值出來的,首先設置圓的頂點座標,首先說第一種方式,我先前考慮,在世界座標空間中,建立一個Gamobject經過它的座標做爲圓上頂點座標,不從本地建立座標了(由於涉及座標轉換,矩陣變換),因此我用了這種方式spa

第一種方式:線程

具體代碼:3d

    /// <summary>
    /// 設置起中間點斷面頂點數據
    /// </summary>
    /// <param name="currPos">當前點座標</param>
    /// <param name="curDirection">朝向</param>
    /// <param name="radius">半徑</param>
    private void SetSectionVertexData(Vector3 currPos, Vector3 curDirection, float radius,float u)
    {
        // 首先計算導線點相對場景中心點的偏移座標
        Vector3 position = currPos - center;

        // 計算direction、right、up向量(注:Unity3d中使用左手座標系)
        Vector3 direction = curDirection.normalized;
        Vector3 right = Vector3.Cross(Vector3.up, direction).normalized;
        Vector3 up = Vector3.Cross(direction, right).normalized;

        angleStep = 360.0f / (float)devide;
        GameObject gameObject = new GameObject();
        gameObject.transform.position = position + radius * right;for (int i = 0; i < 360.0f; i += (int)angleStep)
        {
            gameObject.transform.RotateAround(currPos, direction, angleStep);
            vertices.Add(gameObject.transform.position);
        }
        Destroy(gameObject);
    }

代碼中direction是方向向量(上一點指向下一點座標),構建頂點也須要順序,我這是在右側90度逆時針建立的,gameObject.transform.position = position + radius * right;這是起點頂點,一共十個頂點。code

第二種方式:

我已經用第一種方式功能都作完了,建立好了,完事領導說咱們風筒可能要在子線程建立,哇,一瞬間透心涼,GameObject就意味着淘汰了,矩陣變換是躲不開了。從本地建立圓,這句話的意思是指模型本地座標,即左手座標系(0,0,0)點 找一點爲(0,0,0)點去建立。

具體代碼:

 1     /// <summary>
 2         /// 設置起點圓頂點數據
 3         /// </summary>
 4         /// <param name="startPos">起點座標</param>
 5         /// <param name="nextPos">下一點座標</param>
 6         private void SetStartVertexData(Vector3 startPos, Vector3 nextPos)
 7         {
 8             // 首先計算導線點相對場景中心點的偏移座標
 9             Vector3 position = startPos - center;
10             Vector3 nextPosition = nextPos - center;
11 
12             // 計算direction、right、up向量(注:Unity3d中使用左手座標系)
13             Vector3 direction = (nextPosition - position).normalized;//z軸
14             Vector3 right = Vector3.Cross(Vector3.up, direction).normalized;//x軸,右
15             Vector3 up = Vector3.Cross(direction, right).normalized;//x和z獲得up
16             // 設起點圓定點數據
17             SetSectionVertexData(position, direction, up, right, uvPosU);
18         }
19 
20 
21   /// <summary>
22         /// 設置斷面頂點數據
23         /// </summary>
24         /// <param name="currentPos">當前點座標</param>
25         /// <param name="direction">朝向</param>
26         private void SetSectionVertexData(Vector3 currentPos, Vector3 direction, Vector3 up, Vector3 right, float u)
27         {
28             // 構建旋轉矩陣
29             Matrix4x4 m = Utils.MakeBasis(right, up, direction);
30             for (float i = 0f; i < 360.0f; i += 36.0f)
31             {
32                 // 計算頂點
33                 float rad = Mathf.Deg2Rad * i;
34                 Vector3 targetPos = currentPos + m.MultiplyPoint3x4(new Vector3(Mathf.Cos(rad) * radius, Mathf.Sin(rad) * radius, 0.0f));
35                 // 計算V座標
36                 float v = ((baseValue * 36.0f) / 360.0f);
37                 // 保存頂點座標&紋理座標
38                 vertices.Add(targetPos);
39             }
40         }

這裏解釋下,過程是這樣的,在本地座標構建圓,經過旋轉矩陣變換到世界座標。Vector3 direction = (nextPosition - position).normalized;,通常將指向方向向量爲座標系Z軸,假設y軸(0,1,0)爲Up方向,那麼Vector3 right = Vector3.Cross(Vector3.up, direction).normalized;Z軸與假設Y軸的叉乘獲得的是X軸的方向向量(即right方向),垂直與zy平面,可是接下來求方向向量(Z軸)與X軸的叉乘,指定是咱們要的Y方向,由於肯定的Z和X(垂直XZ平面)。

Utils.MakeBasis具體邏輯以下:

 1 /// <summary>
 2         /// 經過座標軸構建矩陣
 3         /// </summary>
 4         /// <param name="xAxis">x軸</param>
 5         /// <param name="yAxis">y軸</param>
 6         /// <param name="zAxis">z軸</param>
 7         /// <returns>4x4矩陣</returns>
 8         public static Matrix4x4 MakeBasis(Vector3 xAxis, Vector3 yAxis, Vector3 zAxis)
 9         {
10             Matrix4x4 mat = Matrix4x4.identity;
11 
12             mat.m00 = xAxis.x;
13             mat.m10 = xAxis.y;
14             mat.m20 = xAxis.z;
15 
16             mat.m01 = yAxis.x;
17             mat.m11 = yAxis.y;
18             mat.m21 = yAxis.z;
19 
20             mat.m02 = zAxis.x;
21             mat.m12 = zAxis.y;
22             mat.m22 = zAxis.z;
23 
24             return mat;
25         }

矩陣就不解釋了,本身看吧。Matrix4x4 m = Utils.MakeBasis(right, up, direction);這是在獲得所構建節點的座標系即座標走向。由於要把構建的圓放到該點座標下。m.MultiplyPoint3x4是將構建圓的頂點轉換到當前點座標系下,new Vector3(Mathf.Cos(rad) * radius, Mathf.Sin(rad) * radius, 0.0f)圓上點座標XY平面構建元,Z爲0,到這裏圓心始終是(0,0,0),那麼將這個圓放到目標點下須要再加上目標點在當下座標系的偏移量(即座標值)。因此加currentPos。

到這就將兩種設置頂點座標方式說完了。還有就是拐角處圓的構建,須要用貝塞爾曲線差值出來。

代碼:

 1         /// <summary>
 2         /// 設置中間點頂點數據
 3         /// </summary>
 4         /// <param name="currentPos"></param>
 5         /// <param name="prevPos"></param>
 6         /// <param name="nextPos"></param>
 7         private void SetPrepareVertexData(Vector3 currentPos, Vector3 prevPos, Vector3 nextPos)
 8         {
 9             // 首先計算導線點相對場景中心點的偏移座標
10             Vector3 prevPosition = prevPos - center;
11             Vector3 position = currentPos - center;
12             Vector3 anitherposition = nextPos - center;
13 
14             // 計算前一段巷道的direction、right、up向量(注:Unity3d中使用左手座標系)
15             Vector3 prevDirection = (position - prevPosition).normalized;
16             Vector3 prevRight = Vector3.Cross(Vector3.up, prevDirection).normalized;
17             Vector3 prevUp = Vector3.Cross(prevDirection, prevRight).normalized;
18 
19             // 計算後一段巷道的direction、right、up向量(注:Unity3d中使用左手座標系)
20             Vector3 anitherDirection = (anitherposition - position).normalized;
21             Vector3 anitherlRight = Vector3.Cross(Vector3.up, anitherDirection).normalized;
22             Vector3 anitherUp = Vector3.Cross(anitherDirection, anitherlRight).normalized;
23 
24             float angle = Vector3.Angle(-prevDirection, anitherDirection);
25 
26             if (angle >= 179.0)
27             {
28                 //生成斷面數據不倒角處理
29                 uvPosU += (GetPointDistance(position, prevPosition) / textureSizeL);
30                 SetSectionVertexData(position, prevDirection, prevUp, prevRight, uvPosU);
31                 return;
32             }
33             //倒角處理
34 
35             //先後兩段風筒長度
36             float PrevLength = Vector3.Distance(position, prevPosition);
37             float anithorLength = Vector3.Distance(position, anitherposition);
38 
39             indentationValue = PrevLength > anithorLength ? (anithorLength * 0.25f) : (PrevLength * 0.25f);//縮進爲短風筒的1/4
40 
41             // 計算縮進後的位置
42             Vector3 prevEnd = position - prevDirection * indentationValue;//
43             Vector3 behindStart = position + anitherDirection * indentationValue;//
44 
45             uvPosU += (GetPointDistance(prevPosition, prevEnd) / textureSizeL);
46             // 生成前段結束斷面頂點數據
47             SetSectionVertexData(prevEnd, prevDirection, prevUp, prevRight, uvPosU);
48 
49             // 生成中間倒角斷面頂點數據
50             //插值0-1
51             float timer = 0.1f;
52             Vector3 prevpos = prevEnd;
53             for (float i = 1.0f; i <= 9.0f; i++)
54             {
55                 Vector3 pos = Utils.CalculateCubicBezierPoint(timer, prevEnd, position, behindStart);
56                 // 計算斷面方向
57                 Vector3 direction = (pos - prevpos).normalized;
58                 Vector3 right = Vector3.Cross(Vector3.up, direction).normalized;
59                 Vector3 up = Vector3.Cross(direction, right).normalized;
60                 uvPosU += (GetPointDistance(pos, prevpos) / textureSizeL);
61                 // 生成斷面頂點數據
62                 SetSectionVertexData(pos, direction, up, right, uvPosU);
63                 //遞增插值時間
64                 timer += 0.1f;
65                 //更新前一個點座標
66                 prevpos = pos;
67             }
68             // 生成後段起始斷面頂點數據
69             SetSectionVertexData(behindStart, anitherDirection, anitherUp, anitherlRight, ++uvPosU);
70         }

1到9插10個圓。須要找拐角處先後兩個點分別爲開始和結束插值點,Utils.CalculateCubicBezierPoint(timer, prevEnd, position, behindStart);timer爲每次插值(可理解爲時刻)。此函數(三階貝塞爾曲線)具體邏輯:

 1 /// <summary>
 2         /// 計算三階貝塞爾曲線點座標
 3         /// </summary>
 4         /// <param name="t">時刻(0.0~1.0)</param>
 5         /// <param name="p0">起點座標</param>
 6         /// <param name="p1">中間點座標</param>
 7         /// <param name="p2">終點座標</param>
 8         /// <returns>座標點</returns>
 9         public static Vector3 CalculateCubicBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2)
10         {
11             float u = 1.0f - t;
12             float tt = t * t;
13             float uu = u * u;
14 
15             return (p0 * uu + p1 * 2 * u * t + p2 * tt);
16         }

這樣準備頂點座標就結束了。

2.uv座標

UV座標是與頂點一一對應的,因此在建立頂點時最好一塊兒計算出來,我這裏的要求是,上下面貼想同紋理,並且是重複帖,因此V向基本就貼1次上下兩面貼,就要從圓上10個點分紅兩半,或者按角度角度分,通常從0-1後一半從1-0這樣就能夠實現,重點是U方向座標值的計算,每一個橫向重複帖不少次紋理,須要根據貼圖比例以及長度去設置,可是U的值應該是累加的。一次從起點到終點貼。知道這一點就好辦了。

代碼:

//橫向代碼,U是累加的,根據圓柱長度去設置計算。
 uvPosU += (GetPointDistance(pos, prevpos) / textureSizeL);

//V方向按上述規律貼
   /// <summary>
        /// 設置斷面頂點數據
        /// </summary>
        /// <param name="currentPos">當前點座標</param>
        /// <param name="direction">朝向</param>
        private void SetSectionVertexData(Vector3 currentPos, Vector3 direction, Vector3 up, Vector3 right, float u)
        {
            // 構建旋轉矩陣
            Matrix4x4 m = Utils.MakeBasis(right, up, direction);
            int baseValue = 2;
            for (float i = 0f; i < 360.0f; i += 36.0f)
            {
                // 計算頂點
                float rad = Mathf.Deg2Rad * i;
                Vector3 targetPos = currentPos + m.MultiplyPoint3x4(new Vector3(Mathf.Cos(rad) * radius, Mathf.Sin(rad) * radius, 0.0f));
                // 計算V座標
                float v = ((baseValue * 36.0f) / 360.0f);
                // 保存頂點座標&紋理座標
                vertices.Add(targetPos);
                uvs.Add(new Vector2(u, v));
                if (i > 108)
                {
                    baseValue -= 2;
                }
                else
                {
                    baseValue += 2;
                }
            }
        }

這float v = ((baseValue * 36.0f) / 360.0f);算法須要按要求設置。

3.構建索引

構建索引就要按照定點順序去構建,鏈接圓與圓之間的曲面,索引值也是累加的好比這裏十個點,第一個圓是0-9/第二個10-19/以此類推。

 1   /// <summary>
 2         /// 設置索引數據
 3         /// </summary>
 4         private void SetIndexData()
 5         {
 6             int faceCount = (vertices.Count / devide) - 1;
 7             int baseValue;
 8             for (int i = 0; i < faceCount; i++)
 9             {
10                 baseValue = 0;
11                 for (int j = 1; j <= 10; j++)
12                 {
13                     if (j < 10)
14                     {
15                         triangles.Add(i * 10 + baseValue);
16                         triangles.Add(i * 10 + 11 + baseValue);
17                         triangles.Add(i * 10 + baseValue + 10);
18 
19                         triangles.Add(i * 10 + baseValue);
20                         triangles.Add(i * 10 + baseValue + 1);
21                         triangles.Add(i * 10 + 11 + baseValue);
22                     }
23                     else
24                     {
25                         triangles.Add(i * 10 + baseValue);
26                         triangles.Add(i * 10 + 10);
27                         triangles.Add(i * 10 + baseValue + 10);
28 
29                         triangles.Add(i * 10 + baseValue);
30                         triangles.Add(i * 10);
31                         triangles.Add(i * 10 + 10);
32                     }
33                     baseValue++;
34                 }
35             }
36         }

注意構建順序否則順逆時針容易反了。

4.構建實體

這裏解釋最後一步了,也是最簡單的一步了,不解釋上代碼:

 1   /// <summary>
 2         /// 繪製風筒實體
 3         /// </summary>
 4         /// <param name="posList">風筒節點數據集合</param>
 5         /// <param name="radius">風筒半徑</param>
 6         public void DrawAirDuct(List<Vector3> posList, float radius)
 7         {
 8             this.radius = radius;
 9             PrepareVertexData(posList);
10             SetIndexData();
11             Mesh mesh = new Mesh
12             {
13                 vertices = vertices.ToArray(),
14                 triangles = triangles.ToArray(),
15                 uv = uvs.ToArray(),
16             };
17             mesh.RecalculateNormals();
18             GameObject airDuctObj = new GameObject(name);
19             airDuctObj.AddComponent<MeshFilter>().mesh = mesh;
20             airDuctObj.AddComponent<MeshRenderer>().material = new Material(Resources.Load<Material>("Materials/Mine/LanewayColor"));
21 
22             // 添加碰撞器MeshCollider
23             airDuctObj.AddComponent<MeshCollider>();
24         }

切記別忘了從新計算法線mesh.RecalculateNormals();這纔出預期效果。

完整代碼:

  1 using System;
  2 using System.Collections.Generic;
  3 using UnityEngine;
  4 
  5 namespace Tx3d.Framework
  6 {
  7     /// <summary>
  8     /// 繪製風筒實體
  9     /// </summary>
 10     public class AirDuct : Entity
 11     {
 12         #region Fields
 13 
 14         //計算圓角的縮進值
 15         private float indentationValue;
 16 
 17         //圓劃分爲多少等份
 18         private int devide = 10;
 19 
 20         //中心點座標
 21         private Vector3 center = Vector3.zero;
 22 
 23         //頂點座標集合
 24         private List<Vector3> vertices = new List<Vector3>();
 25 
 26         //uv座標集合
 27         private List<Vector2> uvs = new List<Vector2>();
 28 
 29         //索引集合
 30         private List<int> triangles = new List<int>();
 31 
 32         //半徑
 33         private float radius;
 34 
 35         //貼圖長度縮放尺寸
 36         private float textureSizeL = 10.24f;
 37 
 38         //uv座標的u座標值
 39         private float uvPosU = 0;
 40 
 41         #endregion
 42 
 43         #region Public Methods
 44 
 45         /// <summary>
 46         /// 風筒實體
 47         /// </summary>
 48         /// <param name="name">實體名</param>
 49         public AirDuct(string name) : base(name)
 50         {
 51 
 52         }
 53 
 54         /// <summary>
 55         /// 繪製風筒實體
 56         /// </summary>
 57         /// <param name="posList">風筒節點數據集合</param>
 58         /// <param name="radius">風筒半徑</param>
 59         public void DrawAirDuct(List<Vector3> posList, float radius)
 60         {
 61             this.radius = radius;
 62             PrepareVertexData(posList);
 63             SetIndexData();
 64             Mesh mesh = new Mesh
 65             {
 66                 vertices = vertices.ToArray(),
 67                 triangles = triangles.ToArray(),
 68                 uv = uvs.ToArray(),
 69             };
 70             mesh.RecalculateNormals();
 71             GameObject airDuctObj = new GameObject(name);
 72             airDuctObj.AddComponent<MeshFilter>().mesh = mesh;
 73             airDuctObj.AddComponent<MeshRenderer>().material = new Material(Resources.Load<Material>("Materials/Mine/LanewayColor"));
 74 
 75             // 添加碰撞器MeshCollider
 76             airDuctObj.AddComponent<MeshCollider>();
 77         }
 78 
 79         /// <summary>
 80         /// 釋放風筒實體
 81         /// </summary>
 82         public override void Dispose()
 83         {
 84 
 85         }
 86 
 87         /// <summary>
 88         /// 射線查詢
 89         /// </summary>
 90         /// <param name="ray">射線</param>
 91         /// <param name="hit">拾取結果</param>
 92         /// <param name="maxDistance">最大拾取距離</param>
 93         /// <returns>拾取成功返回true,不然返回false</returns>
 94         public override bool Raycast(Ray ray, out RaycastHit hit, float maxDistance)
 95         {
 96             var collider = gameObject.GetComponent<MeshCollider>();
 97             return collider.Raycast(ray, out hit, maxDistance);
 98         }
 99 
100         /// <summary>
101         /// 體積查詢 <see cref="Entity.VolumeQuery(PlaneBoundedVolume)"/>
102         /// </summary>
103         /// <param name="volume">查詢體</param>
104         /// <returns>查詢成功返回true,不然返回false</returns>
105         public override bool VolumeQuery(PlaneBoundedVolume volume)
106         {
107             throw new NotImplementedException();
108         }
109 
110         #endregion
111 
112         #region Private Methods
113 
114         /// <summary>
115         /// 準備頂點數據
116         /// </summary>
117         private void PrepareVertexData(List<Vector3> posList)
118         {
119             for (int i = 0; i < posList.Count; i++)
120             {   
121                 //起點圓面
122                 if (i == 0)
123                 {
124                     SetStartVertexData(posList[i], posList[i + 1]);
125                 }
126                 else if (i != posList.Count - 1)
127                 {
128                     ////中間點(求縮進點設置圓角)
129                     SetPrepareVertexData(posList[i], posList[i - 1], posList[i + 1]);
130                 }
131                 else
132                 {
133                     //終點圓面
134                     SetEndVertexData(posList[i], posList[i - 1]);
135                 }
136             }
137         }
138 
139         /// <summary>
140         /// 設置起點圓頂點數據
141         /// </summary>
142         /// <param name="startPos">起點座標</param>
143         /// <param name="nextPos">下一點座標</param>
144         private void SetStartVertexData(Vector3 startPos, Vector3 nextPos)
145         {
146             // 首先計算導線點相對場景中心點的偏移座標
147             Vector3 position = startPos - center;
148             Vector3 nextPosition = nextPos - center;
149 
150             // 計算direction、right、up向量(注:Unity3d中使用左手座標系)
151             Vector3 direction = (nextPosition - position).normalized;//z軸
152             Vector3 right = Vector3.Cross(Vector3.up, direction).normalized;//x軸,右
153             Vector3 up = Vector3.Cross(direction, right).normalized;//x和z獲得up
154             // 設起點圓定點數據
155             SetSectionVertexData(position, direction, up, right, uvPosU);
156         }
157 
158         /// <summary>
159         /// 設置終點圓頂點數據
160         /// </summary>
161         /// <param name="endPos">終點座標</param>
162         /// <param name="previousPos">上一點座標</param>
163         private void SetEndVertexData(Vector3 endPos, Vector3 previousPos)
164         {
165             // 首先計算導線點相對場景中心點的偏移座標
166             Vector3 position = endPos - center;
167             Vector3 PreviousPosition = previousPos - center;
168 
169             // 計算direction、right、up向量(注:Unity3d中使用左手座標系)
170             Vector3 direction = (position - PreviousPosition).normalized;//指向下一點(結束)方向向量
171             Vector3 right = Vector3.Cross(Vector3.up, direction).normalized;
172             Vector3 up = Vector3.Cross(direction, right).normalized;
173             //計算U值
174             uvPosU += (GetPointDistance(position, PreviousPosition) / textureSizeL);
175             SetSectionVertexData(position, direction, up, right, uvPosU);
176         }
177 
178         /// <summary>
179         /// 設置斷面頂點數據
180         /// </summary>
181         /// <param name="currentPos">當前點座標</param>
182         /// <param name="direction">朝向</param>
183         private void SetSectionVertexData(Vector3 currentPos, Vector3 direction, Vector3 up, Vector3 right, float u)
184         {
185             // 構建旋轉矩陣
186             Matrix4x4 m = Utils.MakeBasis(right, up, direction);
187             int baseValue = 2;
188             for (float i = 0f; i < 360.0f; i += 36.0f)
189             {
190                 // 計算頂點
191                 float rad = Mathf.Deg2Rad * i;
192                 Vector3 targetPos = currentPos + m.MultiplyPoint3x4(new Vector3(Mathf.Cos(rad) * radius, Mathf.Sin(rad) * radius, 0.0f));
193                 // 計算V座標
194                 float v = ((baseValue * 36.0f) / 360.0f);
195                 // 保存頂點座標&紋理座標
196                 vertices.Add(targetPos);
197                 uvs.Add(new Vector2(u, v));
198                 if (i > 108)
199                 {
200                     baseValue -= 2;
201                 }
202                 else
203                 {
204                     baseValue += 2;
205                 }
206             }
207         }
208 
209         /// <summary>
210         /// 設置中間點頂點數據
211         /// </summary>
212         /// <param name="currentPos"></param>
213         /// <param name="prevPos"></param>
214         /// <param name="nextPos"></param>
215         private void SetPrepareVertexData(Vector3 currentPos, Vector3 prevPos, Vector3 nextPos)
216         {
217             // 首先計算導線點相對場景中心點的偏移座標
218             Vector3 prevPosition = prevPos - center;
219             Vector3 position = currentPos - center;
220             Vector3 anitherposition = nextPos - center;
221 
222             // 計算前一段巷道的direction、right、up向量(注:Unity3d中使用左手座標系)
223             Vector3 prevDirection = (position - prevPosition).normalized;
224             Vector3 prevRight = Vector3.Cross(Vector3.up, prevDirection).normalized;
225             Vector3 prevUp = Vector3.Cross(prevDirection, prevRight).normalized;
226 
227             // 計算後一段巷道的direction、right、up向量(注:Unity3d中使用左手座標系)
228             Vector3 anitherDirection = (anitherposition - position).normalized;
229             Vector3 anitherlRight = Vector3.Cross(Vector3.up, anitherDirection).normalized;
230             Vector3 anitherUp = Vector3.Cross(anitherDirection, anitherlRight).normalized;
231 
232             float angle = Vector3.Angle(-prevDirection, anitherDirection);
233 
234             if (angle >= 179.0)
235             {
236                 //生成斷面數據不倒角處理
237                 uvPosU += (GetPointDistance(position, prevPosition) / textureSizeL);
238                 SetSectionVertexData(position, prevDirection, prevUp, prevRight, uvPosU);
239                 return;
240             }
241             //倒角處理
242 
243             //先後兩段風筒長度
244             float PrevLength = Vector3.Distance(position, prevPosition);
245             float anithorLength = Vector3.Distance(position, anitherposition);
246 
247             indentationValue = PrevLength > anithorLength ? (anithorLength * 0.25f) : (PrevLength * 0.25f);//縮進爲短風筒的1/4
248 
249             // 計算縮進後的位置
250             Vector3 prevEnd = position - prevDirection * indentationValue;//
251             Vector3 behindStart = position + anitherDirection * indentationValue;//
252 
253             uvPosU += (GetPointDistance(prevPosition, prevEnd) / textureSizeL);
254             // 生成前段結束斷面頂點數據
255             SetSectionVertexData(prevEnd, prevDirection, prevUp, prevRight, uvPosU);
256 
257             // 生成中間倒角斷面頂點數據
258             //插值0-1
259             float timer = 0.1f;
260             Vector3 prevpos = prevEnd;
261             for (float i = 1.0f; i <= 9.0f; i++)
262             {
263                 Vector3 pos = Utils.CalculateCubicBezierPoint(timer, prevEnd, position, behindStart);
264                 // 計算斷面方向
265                 Vector3 direction = (pos - prevpos).normalized;
266                 Vector3 right = Vector3.Cross(Vector3.up, direction).normalized;
267                 Vector3 up = Vector3.Cross(direction, right).normalized;
268                 uvPosU += (GetPointDistance(pos, prevpos) / textureSizeL);
269                 // 生成斷面頂點數據
270                 SetSectionVertexData(pos, direction, up, right, uvPosU);
271                 //遞增插值時間
272                 timer += 0.1f;
273                 //更新前一個點座標
274                 prevpos = pos;
275             }
276             // 生成後段起始斷面頂點數據
277             SetSectionVertexData(behindStart, anitherDirection, anitherUp, anitherlRight, ++uvPosU);
278         }
279 
280         /// <summary>
281         /// 設置索引數據
282         /// </summary>
283         private void SetIndexData()
284         {
285             int faceCount = (vertices.Count / devide) - 1;
286             int baseValue;
287             for (int i = 0; i < faceCount; i++)
288             {
289                 baseValue = 0;
290                 for (int j = 1; j <= 10; j++)
291                 {
292                     if (j < 10)
293                     {
294                         triangles.Add(i * 10 + baseValue);
295                         triangles.Add(i * 10 + 11 + baseValue);
296                         triangles.Add(i * 10 + baseValue + 10);
297 
298                         triangles.Add(i * 10 + baseValue);
299                         triangles.Add(i * 10 + baseValue + 1);
300                         triangles.Add(i * 10 + 11 + baseValue);
301                     }
302                     else
303                     {
304                         triangles.Add(i * 10 + baseValue);
305                         triangles.Add(i * 10 + 10);
306                         triangles.Add(i * 10 + baseValue + 10);
307 
308                         triangles.Add(i * 10 + baseValue);
309                         triangles.Add(i * 10);
310                         triangles.Add(i * 10 + 10);
311                     }
312                     baseValue++;
313                 }
314             }
315         }
316 
317         /// <summary>
318         /// 求兩點距離
319         /// </summary>
320         /// <param name="prevPos">前一點座標</param>
321         /// <param name="nextPos">後一點座標</param>
322         /// <returns></returns>
323         private float GetPointDistance(Vector3 prevPos, Vector3 nextPos)
324         {
325             return Vector3.Distance(prevPos, nextPos);
326         }
327 
328         #endregion
329     }
330 }
View Code

 

這裏定了五個測試點,

效果以下:

到這基本結束了,可是這期間計算思考過程仍是仍是有點東西的,這玩意也是會的不難難的不會,作過一次了就好辦了,這裏給沒搞過的小朋友啓發一下。

渴望指正交流。

相關文章
相關標籤/搜索