【Unity】Mesh网格编程(二)流体
2015-03-14 19:28
337 查看
通过Mesh网格随Sin函数实时变化模拟液体的流动,从而达到动态水的效果。
原文:
Mesh网格编程(一) 流体
http://blog.csdn.net/qq_18408937/article/details/44161229
by 涅凡尘
对,你没有看错。这是本博客的一个系列,但同时也是一篇转载。
原文已经做得很棒了!不做重复工作,直接转入本系列中。
也欢迎大家支持这位技术博客新人和数学奇才,多粉多浏览。
通过Mesh网格随Sin函数实时变化模拟液体的流动,从而达到动态水的效果。
其一是棱角分明的几何体,这种几何体的法线可以用确定好的顶点坐标两两相减,得到的向量做叉乘并赋值给三个顶点上的法线。
其二是圆滑的几何体,这种几何体需要求出该点在曲面上的切线,从而确定垂直于切线的法线。如果是圆形。可以使用顶点减圆心所得的向量。
此外,求得的法线尽量单位化,否则可能出现一个面上的颜色不同。
plaincopy
using UnityEngine;
using System.Collections;
public class Water : MonoBehaviour {
Mesh mesh;
public int tier = 10; //长度分段
private float length = 10; //长
private int width = 3; //宽
private int hight = 10; //高
private Vector3[] vs; //顶点坐标
private int[] ts; //顶点序列
private Vector2[] newUVs; //UV贴图
private Vector3[] newNormals; //法线
void Update () {
int temp = ((tier + 1) * 8 + 4) * 3; //确定顶点数量
vs = new Vector3[temp];
ts = new int[temp];
newUVs = new Vector2[temp];
newNormals = new Vector3[temp];
float dis = 2 * Mathf.PI / tier; //两段之差的横坐标
int count = 0;
for (int i = 0; i < tier; i++) {
float pos1 = i * length / tier - length / 2;
float pos2 = (i + 1) * length / tier - length / 2;
//顶面顶点坐标
vs[count] = new Vector3(pos1,Mathf.Sin(Time.time + i * dis), width);
vs[count + 1] = new Vector3(pos2,Mathf.Sin(Time.time + (i + 1) * dis), -width);
vs[count + 2] = new Vector3(pos1,Mathf.Sin(Time.time + i * dis), -width);
vs[count + 3] = new Vector3(pos1,Mathf.Sin(Time.time + i * dis), width);
vs[count + 4] = new Vector3(pos2,Mathf.Sin(Time.time + (i + 1) * dis), width);
vs[count + 5] = new Vector3(pos2,Mathf.Sin(Time.time + (i + 1) * dis), -width);
//顶面法线
newNormals[count] = Vector3.Normalize(new Vector3(1,Mathf.Cos(Time.time + i * dis), 0));
newNormals[count + 1] = Vector3.Normalize(new Vector3(1,Mathf.Cos(Time.time + (i + 1) * dis), 0));
newNormals[count + 2] = Vector3.Normalize(new Vector3(1,Mathf.Cos(Time.time + i * dis), 0));
newNormals[count + 3] = Vector3.Normalize(new Vector3(1,Mathf.Cos(Time.time + i * dis), 0));
newNormals[count + 4] = Vector3.Normalize(new Vector3(1,Mathf.Cos(Time.time + (i + 1) * dis), 0));
newNormals[count + 5] = Vector3.Normalize(new Vector3(1,Mathf.Cos(Time.time + (i + 1) * dis), 0));
//前面顶点坐标
vs[count + 6] = new Vector3(pos1,Mathf.Sin(Time.time + i * dis), -width);
vs[count + 7] = new Vector3(pos2,-hight, -width);
vs[count + 8] = new Vector3(pos1,-hight, -width);
vs[count + 9] = new Vector3(pos1,Mathf.Sin(Time.time + i * dis), -width);
vs[count + 10] = new Vector3(pos2,Mathf.Sin(Time.time + (i + 1) * dis), -width);
vs[count + 11] = new Vector3(pos2,-hight, -width);
//前面法线
for (int j = 0; j < 6; j++) {
newNormals[count + 6 + j] = Vector3.back;
}
//后面顶点坐标
vs[count + 12] = new Vector3(pos1,Mathf.Sin(Time.time + i * dis), width);
vs[count + 13] = new Vector3(pos1,-hight, width);
vs[count + 14] = new Vector3(pos2,-hight, width);
vs[count + 15] = new Vector3(pos1,Mathf.Sin(Time.time + i * dis), width);
vs[count + 16] = new Vector3(pos2,-hight, width);
vs[count + 17] = new Vector3(pos2,Mathf.Sin(Time.time + (i + 1) * dis), width);
//后面法线
for (int j = 0; j < 6; j++) {
newNormals[count + 12 + j] = Vector3.forward;
}
//下面顶点坐标
vs[count + 18] = new Vector3(pos1,-hight, width);
vs[count + 19] = new Vector3(pos1,-hight, -width);
vs[count + 20] = new Vector3(pos2,-hight, -width);
vs[count + 21] = new Vector3(pos1,-hight, width);
vs[count + 22] = new Vector3(pos2,-hight, -width);
vs[count + 23] = new Vector3(pos2,-hight, width);
//下面法线
for (int j = 0; j < 6; j++) {
newNormals[count + 18 + j] = Vector3.down;
}
count += 24;
}
//两侧顶点坐标及法线
vs [vs.Length - 12] = new Vector3 (-length / 2, Mathf.Sin (Time.time), width);
vs [vs.Length - 11] = new Vector3 (-length / 2, -hight, -width);
vs [vs.Length - 10] = new Vector3 (-length / 2, -hight, width);
vs [vs.Length - 9] = new Vector3 (-length / 2, Mathf.Sin (Time.time), width);
vs [vs.Length - 8] = new Vector3 (-length / 2, Mathf.Sin (Time.time), -width);
vs [vs.Length - 7] = new Vector3 (-length / 2, -hight, -width);
for (int j = 0; j < 6; j++) {
newNormals[vs.Length - 12 + j] = Vector3.left;
}
vs [vs.Length - 6] = new Vector3 (length / 2, Mathf.Sin (Time.time + tier * dis), width);
vs [vs.Length - 5] = new Vector3 (length / 2, -hight, width);
vs [vs.Length - 4] = new Vector3 (length / 2, -hight, -width);
vs [vs.Length - 3] = new Vector3 (length / 2, Mathf.Sin (Time.time + tier * dis), width);
vs [vs.Length - 2] = new Vector3 (length / 2, -hight, -width);
vs [vs.Length - 1] = new Vector3 (length / 2, Mathf.Sin (Time.time + tier * dis), -width);
for (int j = 0; j < 6; j++) {
newNormals[vs.Length - 6 + j] = Vector3.right;
}
for (int i = 0; i < ts.Length; i++) { //顶点序列赋值
ts[i] = i;
}
mesh = new Mesh();
GetComponent<MeshFilter>().mesh = mesh;
mesh.vertices = vs;
mesh.uv = newUVs;
mesh.triangles = ts;
mesh.normals = newNormals;
}
}
注:波浪上方的面为曲面,故使用切线求法线。其他面很有规则,并没有使用叉乘的方法。
原文:
Mesh网格编程(一) 流体
http://blog.csdn.net/qq_18408937/article/details/44161229
by 涅凡尘
对,你没有看错。这是本博客的一个系列,但同时也是一篇转载。
原文已经做得很棒了!不做重复工作,直接转入本系列中。
也欢迎大家支持这位技术博客新人和数学奇才,多粉多浏览。
Mesh网格编程(一) 流体水
通过Mesh网格随Sin函数实时变化模拟液体的流动,从而达到动态水的效果。效果图:
Mesh网格编程步骤:
一:确定数量
确定该几何图形应有多少个三角形面,顶点坐标、顶点序列、UV贴图、法线向量皆为三角形面数的三倍。二:根据三角形面确定顶点坐标
这里我习惯把一个面的顶点确定好之后再去找下一个面,这样做可以是法线和顶点序列确定起来很容易。但是要注意的是在确定顶点时要按照顺时针顺序确定,否则会导致三角形面相反。三:确定法线
法线大致分为两种:其一是棱角分明的几何体,这种几何体的法线可以用确定好的顶点坐标两两相减,得到的向量做叉乘并赋值给三个顶点上的法线。
其二是圆滑的几何体,这种几何体需要求出该点在曲面上的切线,从而确定垂直于切线的法线。如果是圆形。可以使用顶点减圆心所得的向量。
此外,求得的法线尽量单位化,否则可能出现一个面上的颜色不同。
四:确定顶点序列
若三角形顶点按照面数去确定,顶点序列就会变得非常简单,按顺序赋值即可。五:确定UV贴图
根据所做几何体的不同,贴图左边也会有所改变,并不固定。六:创建网格
实现代码如下:
[csharp] viewplaincopy
using UnityEngine;
using System.Collections;
public class Water : MonoBehaviour {
Mesh mesh;
public int tier = 10; //长度分段
private float length = 10; //长
private int width = 3; //宽
private int hight = 10; //高
private Vector3[] vs; //顶点坐标
private int[] ts; //顶点序列
private Vector2[] newUVs; //UV贴图
private Vector3[] newNormals; //法线
void Update () {
int temp = ((tier + 1) * 8 + 4) * 3; //确定顶点数量
vs = new Vector3[temp];
ts = new int[temp];
newUVs = new Vector2[temp];
newNormals = new Vector3[temp];
float dis = 2 * Mathf.PI / tier; //两段之差的横坐标
int count = 0;
for (int i = 0; i < tier; i++) {
float pos1 = i * length / tier - length / 2;
float pos2 = (i + 1) * length / tier - length / 2;
//顶面顶点坐标
vs[count] = new Vector3(pos1,Mathf.Sin(Time.time + i * dis), width);
vs[count + 1] = new Vector3(pos2,Mathf.Sin(Time.time + (i + 1) * dis), -width);
vs[count + 2] = new Vector3(pos1,Mathf.Sin(Time.time + i * dis), -width);
vs[count + 3] = new Vector3(pos1,Mathf.Sin(Time.time + i * dis), width);
vs[count + 4] = new Vector3(pos2,Mathf.Sin(Time.time + (i + 1) * dis), width);
vs[count + 5] = new Vector3(pos2,Mathf.Sin(Time.time + (i + 1) * dis), -width);
//顶面法线
newNormals[count] = Vector3.Normalize(new Vector3(1,Mathf.Cos(Time.time + i * dis), 0));
newNormals[count + 1] = Vector3.Normalize(new Vector3(1,Mathf.Cos(Time.time + (i + 1) * dis), 0));
newNormals[count + 2] = Vector3.Normalize(new Vector3(1,Mathf.Cos(Time.time + i * dis), 0));
newNormals[count + 3] = Vector3.Normalize(new Vector3(1,Mathf.Cos(Time.time + i * dis), 0));
newNormals[count + 4] = Vector3.Normalize(new Vector3(1,Mathf.Cos(Time.time + (i + 1) * dis), 0));
newNormals[count + 5] = Vector3.Normalize(new Vector3(1,Mathf.Cos(Time.time + (i + 1) * dis), 0));
//前面顶点坐标
vs[count + 6] = new Vector3(pos1,Mathf.Sin(Time.time + i * dis), -width);
vs[count + 7] = new Vector3(pos2,-hight, -width);
vs[count + 8] = new Vector3(pos1,-hight, -width);
vs[count + 9] = new Vector3(pos1,Mathf.Sin(Time.time + i * dis), -width);
vs[count + 10] = new Vector3(pos2,Mathf.Sin(Time.time + (i + 1) * dis), -width);
vs[count + 11] = new Vector3(pos2,-hight, -width);
//前面法线
for (int j = 0; j < 6; j++) {
newNormals[count + 6 + j] = Vector3.back;
}
//后面顶点坐标
vs[count + 12] = new Vector3(pos1,Mathf.Sin(Time.time + i * dis), width);
vs[count + 13] = new Vector3(pos1,-hight, width);
vs[count + 14] = new Vector3(pos2,-hight, width);
vs[count + 15] = new Vector3(pos1,Mathf.Sin(Time.time + i * dis), width);
vs[count + 16] = new Vector3(pos2,-hight, width);
vs[count + 17] = new Vector3(pos2,Mathf.Sin(Time.time + (i + 1) * dis), width);
//后面法线
for (int j = 0; j < 6; j++) {
newNormals[count + 12 + j] = Vector3.forward;
}
//下面顶点坐标
vs[count + 18] = new Vector3(pos1,-hight, width);
vs[count + 19] = new Vector3(pos1,-hight, -width);
vs[count + 20] = new Vector3(pos2,-hight, -width);
vs[count + 21] = new Vector3(pos1,-hight, width);
vs[count + 22] = new Vector3(pos2,-hight, -width);
vs[count + 23] = new Vector3(pos2,-hight, width);
//下面法线
for (int j = 0; j < 6; j++) {
newNormals[count + 18 + j] = Vector3.down;
}
count += 24;
}
//两侧顶点坐标及法线
vs [vs.Length - 12] = new Vector3 (-length / 2, Mathf.Sin (Time.time), width);
vs [vs.Length - 11] = new Vector3 (-length / 2, -hight, -width);
vs [vs.Length - 10] = new Vector3 (-length / 2, -hight, width);
vs [vs.Length - 9] = new Vector3 (-length / 2, Mathf.Sin (Time.time), width);
vs [vs.Length - 8] = new Vector3 (-length / 2, Mathf.Sin (Time.time), -width);
vs [vs.Length - 7] = new Vector3 (-length / 2, -hight, -width);
for (int j = 0; j < 6; j++) {
newNormals[vs.Length - 12 + j] = Vector3.left;
}
vs [vs.Length - 6] = new Vector3 (length / 2, Mathf.Sin (Time.time + tier * dis), width);
vs [vs.Length - 5] = new Vector3 (length / 2, -hight, width);
vs [vs.Length - 4] = new Vector3 (length / 2, -hight, -width);
vs [vs.Length - 3] = new Vector3 (length / 2, Mathf.Sin (Time.time + tier * dis), width);
vs [vs.Length - 2] = new Vector3 (length / 2, -hight, -width);
vs [vs.Length - 1] = new Vector3 (length / 2, Mathf.Sin (Time.time + tier * dis), -width);
for (int j = 0; j < 6; j++) {
newNormals[vs.Length - 6 + j] = Vector3.right;
}
for (int i = 0; i < ts.Length; i++) { //顶点序列赋值
ts[i] = i;
}
mesh = new Mesh();
GetComponent<MeshFilter>().mesh = mesh;
mesh.vertices = vs;
mesh.uv = newUVs;
mesh.triangles = ts;
mesh.normals = newNormals;
}
}
注:波浪上方的面为曲面,故使用切线求法线。其他面很有规则,并没有使用叉乘的方法。
几何体没有使用UV贴图,newUVs没有赋值。
相关文章推荐
- Mesh网格编程(一) 流体水
- Mesh网格编程(一) 流体
- Unity网格编程篇(二) 非常详细的Mesh编程入门文章
- 【Unity】Mesh网格编程(一)正二十面体
- 【Unity】Mesh网格编程(三)万能网格几何形体
- 【Unity】Mesh网格编程(四)麦比乌斯环
- 【Unity】Mesh网格编程(一)正二十面体
- Mesh网格编程(一) 流体
- Unity 通过Mesh网格渲染绘制图形与字体
- unity5之导航网格寻路系统-4Nav Mesh Obstacle(导航障碍物)
- 关于Unity中Mesh网格的详解
- Mesh网格编程(二) 万能网格几何体
- Mesh网格编程(四) 正6面体
- Unity MeshBaker 合并网格和材质
- Mesh网格编程(三) 正12面体
- Unity MeshBaker 合并网格和材质
- Mesh网格编程(二) 万能网格几何体
- unity之mesh renderer网格渲染器
- unity 脚本创建 MESH(网格)
- Mesh网格编程 正6面体