日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Unity草地/草坪案例分享(完整代码)

發布時間:2024/8/1 编程问答 61 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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"}//ZWrite offCull offCGPROGRAM#pragma vertex vert#pragma fragment frag#include "Lighting.cginc"#include "AutoLight.cginc"#include "UnityCG.cginc"#pragma target 3.0//地面參數uniform sampler2D _MainTex; uniform half4 _MainTex_ST;uniform half3 _MainCol;uniform half _Speed;uniform fixed _Scope;//輸入結構struct a2v {float4 vertex: POSITION; //頂點信息float2 uv0: TEXCOORD0; //UV信息};//輸出結構struct v2f {float4 pos:SV_POSITION; //屏幕定點位置float2 uv0:TEXCOORD0; //UV};v2f vert(a2v v) {v2f o; //新輸出結構o.pos = UnityObjectToClipPos(v.vertex); //頂點位置 OS>CSo.uv0 = v.uv0 *_MainTex_ST.xy + _MainTex_ST.zw; //傳弟UVo.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草地/草坪案例分享(完整代码)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。