生活随笔
收集整理的這篇文章主要介紹了
Unity草地/草坪案例分享(完整代码)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
老規矩先上圖
最近又開始繼續操刀我的新獨立游戲啦,網上看了很多草地的案例受益匪淺。但是嘛最近還是選擇用自己的方式去實現。
主要是因為這種方式可以更好的貼合我前后的需求。還有很多有意思的技術點,有時間一點點拿來和大家一起分享吧。
這次先來說說草地的實現方式:
由于草地需要貼合模型表面,所以這里是從附著的模型表面開始的:
一、循環Mesh三角型數值,以三角型為單位記錄一組數據,內容為三個頂點位置及其法線信息。
代碼如下:
private List<GlassPoint> myData
;private RaycastHit Hit
;private List<GameObject> objGlass
;private void __CreateGlass(MeshFilter myTarget
){if (myTarget
!= null && myTarget
.mesh
!= null){int myLength
= myTarget
.mesh
.triangles
.Length
;Vector3[] vector
= myTarget
.mesh
.vertices
;Vector3[] normal
= myTarget
.mesh
.normals
;int[] triangles
= myTarget
.mesh
.triangles
;myData
= new List<GlassPoint>();for (int i
= 0; i
< myLength
; i
+= 3){int index
= triangles
[i
];int index2
= triangles
[i
+ 1];int index3
= triangles
[i
+ 2];Vector3 offset1
= vector
[index
];Vector3 offset2
= vector
[index2
] - offset1
;Vector3 offset3
= vector
[index3
] - offset1
;Vector3 startPos
= offset1
+ (normal
[index
].normalized
*50) + (Vector3
.one
* UnityEngine
.Random
.Range(-10.0f, 10.0f));if (Physics
.Raycast(startPos
, -normal
[index
], out Hit
, 100)){GlassPoint point
= new GlassPoint();point
.pos
= Hit
.point
;point
.pos2
= point
.pos
+ offset2
;point
.pos3
= point
.pos
+ offset3
;point
.norm
= normal
[index
];point
.norm2
= normal
[index2
];point
.norm3
= normal
[index3
];myData
.Add(point
);}}}}
以上即是每組數據記錄了三個點頂及其法線的信息。
值得一提的由于所在位置和法線這不相同,這里用的是頂點沿法線偏移出去,再隨機一定位置后再反射回來找位置的方式找到基點。
二、位置和信息找完后,然后就是創建Mesh將每個草的信息寫進去,由于數量可能非常多,所以可能需要分開幾個Mesh,代碼如下:
private void CreateGlassMesh(List<GlassPoint> data
){for (int i
= 0; i
< 100; i
++){CreateGlass(i
, data
);}}
private void CreateGlass(int index
, List<GlassPoint> myGlassData
){int step
= 9000;int startIndex
= index
* step
;if (startIndex
> myGlassData
.Count
) return;int endIndex
= Mathf
.Min(startIndex
+ step
, myGlassData
.Count
);Mesh mesh
= new Mesh();List<Vector3> vector
= new List<Vector3>();List<int> triangle
= new List<int>();List<Vector2> uv
= new List<Vector2>();int length
= endIndex
- startIndex
;for (int i
= 0; i
< length
; i
++){SingleGlass(i
, ref vector
, ref triangle
, ref uv
, myGlassData
[startIndex
+ i
], UnityEngine
.Random
.Range(0.8f, 1.2f), UnityEngine
.Random
.Range(0.4f, 1f));}mesh
.SetVertices(vector
);mesh
.SetIndices(triangle
.ToArray(), MeshTopology
.Triangles
, 0);mesh
.uv
= uv
.ToArray();GameObject ObjGlass
= new GameObject();ObjGlass
.name
= "MyGlass" + index
;MeshFilter meshFilter
= ObjGlass
.AddComponent<MeshFilter>();MeshRenderer ren
= ObjGlass
.AddComponent<MeshRenderer>();meshFilter
.mesh
= mesh
;ren
.material
= Com
.m_matGlass
;}
這里重點講每個單草是怎么生成的,如圖所示一共四個點頂點型的三個倒三角面,重點關注下UV,上面的X分別為0-0.5和0.5-1的范圍:
代碼如下:
private void SingleGlass(int index
, ref List<Vector3> vert
, ref List<int> triangle
, ref List<Vector2> uv
, GlassPoint data
, float w
, float h
){Vector3 normal
= ((data
.norm
+ data
.norm2
+ data
.norm3
) / 3).normalized
;Vector3 offset
= normal
* h
;Vector3 pos4
= (data
.pos
+ data
.pos2
+ data
.pos3
) / 3 - normal
* 0.3f;Vector3 pos1
= data
.pos
+ offset
;Vector3 pos2
= data
.pos2
+ offset
;Vector3 pos3
= data
.pos3
+ offset
;vert
.Add(pos1
);vert
.Add(pos2
);vert
.Add(pos3
);vert
.Add(pos4
);uv
.Add(new Vector2(0, 1));uv
.Add(new Vector2(0.5f, 1));uv
.Add(new Vector2(1, 1));uv
.Add(new Vector2(0.5f, 0));index
*= 4;triangle
.Add(index
);triangle
.Add(index
+ 1);triangle
.Add(index
+ 3);triangle
.Add(index
+ 1);triangle
.Add(index
+ 2);triangle
.Add(index
+ 3);triangle
.Add(index
+ 2);triangle
.Add(index
);triangle
.Add(index
+ 3);}
下面是材質部分,使用透明度測試的方式裁剪處草的形狀,再用擺動上端UV做出風吹的效果,上代碼:
Shader
"Custom/Glass" {Properties
{[Header(Ground_Base)]_MainTex("RGB:基礎色 A:透明通道",2D) = "white"{}_MainCol("基本色",Color
) = (0.5,0.5,0.5,1.0)_Speed("速度 ",Range(0,10)) = 5_Scope("幅度 ",Range(0,1)) = 0.3}SubShader
{Tags
{"RenderType" = "Opaque"}Pass
{Tags
{"LightMode" = "ForwardBase"}Cull offCGPROGRAM
#pragma vertex vert#pragma fragment frag#include "Lighting.cginc"#include "AutoLight.cginc"#include "UnityCG.cginc"#pragma target 3.0uniform
sampler2D _MainTex
; uniform
half4 _MainTex_ST
;uniform
half3 _MainCol
;uniform
half _Speed
;uniform
fixed _Scope
;struct a2v {float4 vertex
: POSITION
; float2 uv0
: TEXCOORD0
; };struct v2f {float4 pos
:SV_POSITION
; float2 uv0
:TEXCOORD0
; };v2f vert(a2v v
) {v2f o
; o
.pos
= UnityObjectToClipPos(v
.vertex
); o
.uv0
= v
.uv0
*_MainTex_ST
.xy
+ _MainTex_ST
.zw
; o
.uv0
.x
= o
.uv0
.x
+ (sin(_Time
.x
*_Speed
)*_Scope
* o
.uv0
.y
); return o
;}float4 frag(v2f i
) :SV_TARGET
{half4 var_MainTex
= tex2D(_MainTex
, i
.uv0
);clip(var_MainTex
.a
- 0.1);half3 finalRGB
= var_MainTex
* _MainCol
;return half4(finalRGB
,1);}ENDCG
}
草地的貼圖大概是這樣:
中間有個間隔,因為要換面了…嘻嘻.
這或許不是個高明的方式,但是一個符合我項目需求的方式,分享給大家希望對大家有幫助,謝謝。
總結
以上是生活随笔為你收集整理的Unity草地/草坪案例分享(完整代码)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。