1. 程式人生 > >【Unity】Mesh網格程式設計(二)流體

【Unity】Mesh網格程式設計(二)流體

通過Mesh網格隨Sin函式實時變化模擬液體的流動,從而達到動態水的效果。

原文:

by 涅凡塵

對,你沒有看錯。這是本部落格的一個系列,但同時也是一篇轉載。

原文已經做得很棒了!不做重複工作,直接轉入本系列中。

也歡迎大家支援這位技術部落格新人和數學奇才,多粉多瀏覽。

Mesh網格程式設計(一) 流體水

通過Mesh網格隨Sin函式實時變化模擬液體的流動,從而達到動態水的效果。

效果圖:

Mesh網格程式設計步驟:

一:確定數量

確定該幾何圖形應有多少個三角形面,頂點座標、頂點序列、UV貼圖、法線向量皆為三角形面數的三倍。

二:根據三角形面確定頂點座標

這裡我習慣把一個面的頂點確定好之後再去找下一個面,這樣做可以是法線和頂點序列確定起來很容易。但是要注意的是在確定頂點時要按照順時針順序確定,否則會導致三角形面相反。

三:確定法線

法線大致分為兩種: 其一是稜角分明的幾何體,這種幾何體的法線可以用確定好的頂點座標兩兩相減,得到的向量做叉乘並賦值給三個頂點上的法線。 其二是圓滑的幾何體,這種幾何體需要求出該點在曲面上的切線,從而確定垂直於切線的法線。如果是圓形。可以使用頂點減圓心所得的向量。 此外,求得的法線儘量單位化,否則可能出現一個面上的顏色不同。

四:確定頂點序列

若三角形頂點按照面數去確定,頂點序列就會變得非常簡單,按順序賦值即可。

五:確定UV貼圖

根據所做幾何體的不同,貼圖左邊也會有所改變,並不固定。

六:建立網格

實現程式碼如下:

  1. using UnityEngine;  
  2. using System.Collections;  
  3. publicclass Water : MonoBehaviour {  
  4.     Mesh mesh;  
  5.     publicint tier = 10;           //長度分段
  6.     privatefloat length = 10;      //長
  7.     privateint width = 3;          //寬
  8.     privateint hight = 10;         //高
  9.     private Vector3[] vs;           //頂點座標
  10.     privateint[] ts;               //頂點序列
  11.     private Vector2[] newUVs;       
    //UV貼圖
  12.     private Vector3[] newNormals;   //法線
  13.     void Update () {  
  14.         int temp = ((tier + 1) * 8 + 4) * 3;    //確定頂點數量
  15.         vs = new Vector3[temp];  
  16.         ts = newint[temp];  
  17.         newUVs = new Vector2[temp];  
  18.         newNormals = new Vector3[temp];  
  19.         float dis = 2 * Mathf.PI / tier;        //兩段之差的橫座標
  20.         int count = 0;  
  21.         for (int i = 0; i < tier; i++) {  
  22.             float pos1 = i * length / tier - length / 2;  
  23.             float pos2 = (i + 1) * length / tier - length / 2;  
  24.             //頂面頂點座標
  25.             vs[count] = new Vector3(pos1,Mathf.Sin(Time.time + i * dis), width);  
  26.             vs[count + 1] = new Vector3(pos2,Mathf.Sin(Time.time + (i + 1) * dis), -width);  
  27.             vs[count + 2] = new Vector3(pos1,Mathf.Sin(Time.time + i * dis), -width);  
  28.             vs[count + 3] = new Vector3(pos1,Mathf.Sin(Time.time + i * dis), width);  
  29.             vs[count + 4] = new Vector3(pos2,Mathf.Sin(Time.time + (i + 1) * dis), width);  
  30.             vs[count + 5] = new Vector3(pos2,Mathf.Sin(Time.time + (i + 1) * dis), -width);  
  31.             //頂面法線
  32.             newNormals[count] = Vector3.Normalize(new Vector3(1,Mathf.Cos(Time.time + i * dis), 0));  
  33.             newNormals[count + 1] = Vector3.Normalize(new Vector3(1,Mathf.Cos(Time.time + (i + 1) * dis), 0));  
  34.             newNormals[count + 2] = Vector3.Normalize(new Vector3(1,Mathf.Cos(Time.time + i * dis), 0));  
  35.             newNormals[count + 3] = Vector3.Normalize(new Vector3(1,Mathf.Cos(Time.time + i * dis), 0));  
  36.             newNormals[count + 4] = Vector3.Normalize(new Vector3(1,Mathf.Cos(Time.time + (i + 1) * dis), 0));  
  37.             newNormals[count + 5] = Vector3.Normalize(new Vector3(1,Mathf.Cos(Time.time + (i + 1) * dis), 0));  
  38.             //前面頂點座標
  39.             vs[count + 6] = new Vector3(pos1,Mathf.Sin(Time.time + i * dis), -width);  
  40.             vs[count + 7] = new Vector3(pos2,-hight, -width);  
  41.             vs[count + 8] = new Vector3(pos1,-hight, -width);  
  42.             vs[count + 9] = new Vector3(pos1,Mathf.Sin(Time.time + i * dis), -width);  
  43.             vs[count + 10] = new Vector3(pos2,Mathf.Sin(Time.time + (i + 1) * dis), -width);  
  44.             vs[count + 11] = new Vector3(pos2,-hight, -width);  
  45.             //前面法線
  46.             for (int j = 0; j < 6; j++) {  
  47.                 newNormals[count + 6 + j] = Vector3.back;  
  48.             }  
  49.             //後面頂點座標
  50.             vs[count + 12] = new Vector3(pos1,Mathf.Sin(Time.time + i * dis), width);  
  51.             vs[count + 13] = new Vector3(pos1,-hight, width);  
  52.             vs[count + 14] = new Vector3(pos2,-hight, width);  
  53.             vs[count + 15] = new Vector3(pos1,Mathf.Sin(Time.time + i * dis), width);  
  54.             vs[count + 16] = new Vector3(pos2,-hight, width);  
  55.             vs[count + 17] = new Vector3(pos2,Mathf.Sin(Time.time + (i + 1) * dis), width);  
  56.             //後面法線
  57.             for (int j = 0; j < 6; j++) {  
  58.                 newNormals[count + 12 + j] = Vector3.forward;  
  59.             }  
  60.             //下面頂點座標
  61.             vs[count + 18] = new Vector3(pos1,-hight, width);  
  62.             vs[count + 19] = new Vector3(pos1,-hight, -width);  
  63.             vs[count + 20] = new Vector3(pos2,-hight, -width);  
  64.             vs[count + 21] = new Vector3(pos1,-hight, width);  
  65.             vs[count + 22] = new Vector3(pos2,-hight, -width);  
  66.             vs[count + 23] = new Vector3(pos2,-hight, width);  
  67.             //下面法線
  68.             for (int j = 0; j < 6; j++) {  
  69.                 newNormals[count + 18 + j] = Vector3.down;  
  70.             }  
  71.             count += 24;  
  72.         }  
  73.         //兩側頂點座標及法線
  74.         vs [vs.Length - 12] = new Vector3 (-length / 2, Mathf.Sin (Time.time), width);  
  75.         vs [vs.Length - 11] = new Vector3 (-length / 2, -hight, -width);  
  76.         vs [vs.Length - 10] = new Vector3 (-length / 2, -hight, width);  
  77.         vs [vs.Length - 9] = new Vector3 (-length / 2, Mathf.Sin (Time.time), width);  
  78.         vs [vs.Length - 8] = new Vector3 (-length / 2, Mathf.Sin (Time.time), -width);  
  79.         vs [vs.Length - 7] = new Vector3 (-length / 2, -hight, -width);  
  80.         for (int j = 0; j < 6; j++) {  
  81.             newNormals[vs.Length - 12 + j] = Vector3.left;  
  82.         }  
  83.         vs [vs.Length - 6] = new Vector3 (length / 2, Mathf.Sin (Time.time + tier * dis), width);  
  84.         vs [vs.Length - 5] = new Vector3 (length / 2, -hight, width);  
  85.         vs [vs.Length - 4] = new Vector3 (length / 2, -hight, -width);  
  86.         vs [vs.Length - 3] = new Vector3 (length / 2, Mathf.Sin (Time.time + tier * dis), width);  
  87.         vs [vs.Length - 2] = new Vector3 (length / 2, -hight, -width);  
  88.         vs [vs.Length - 1] = new Vector3 (length / 2, Mathf.Sin (Time.time + tier * dis), -width);  
  89.         for (int j = 0; j < 6; j++) {  
  90.             newNormals[vs.Length - 6 + j] = Vector3.right;  
  91.         }  
  92.         for (int i = 0; i < ts.Length; i++) {    //頂點序列賦值
  93.             ts[i] = i;  
  94.         }  
  95.         mesh = new Mesh();  
  96.         GetComponent<MeshFilter>().mesh = mesh;  
  97.         mesh.vertices = vs;  
  98.         mesh.uv = newUVs;  
  99.         mesh.triangles = ts;  
  100.         mesh.normals = newNormals;  
  101.     }  
  102. }  

注:波浪上方的面為曲面,故使用切線求法線。其他面很有規則,並沒有使用叉乘的方法。
幾何體沒有使用UV貼圖,newUVs沒有賦值。