最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Unity實現(xiàn)噴漆效果

 更新時間:2020年07月12日 17:19:27   作者:無跡浪子  
這篇文章主要為大家詳細介紹了Unity實現(xiàn)噴漆效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下

本文實例為大家分享了Unity實現(xiàn)噴漆效果展示的具體代碼,供大家參考,具體內(nèi)容如下

噴漆功能

**應(yīng)用場景:**如墻上的標語貼花,汽車上的噴漆等。

選擇方案:

1、當然實現(xiàn)方法各式各異,最最最簡單,也是最“不堪入目”的方法是直接給一個面片,然后獲取噴漆位置,加上一個要噴漆表面法線方向的偏移,作為最終面片放置位置,當然,不要忘了設(shè)置面片的方向。這種方法雖然說簡單,但是效果并不理想,會出經(jīng)?,F(xiàn)與其他物體穿插的情況,如果游戲中曲面太多,那么這個方案基本沒法看。
2、對于個別特殊的需求來講,比如說人物身上的紋身,完全可以用一個shader里實現(xiàn),此方法僅限于一個貼花對應(yīng)一個物體,如果是一對多的情況,請看后邊這兩種。
3、有一種簡易的方法是用Projector,這種方法實現(xiàn)較為簡單,不多說。
4、接下來說一種動態(tài)生成網(wǎng)格方案,也較為常用,接下來就詳細說說這種方案。

實現(xiàn)思路:

噴漆的網(wǎng)格是根據(jù)場景中所噴位置的物體的網(wǎng)格動態(tài)生成的,噴漆的時候,獲取規(guī)定范圍內(nèi)的物體,再用一個立方體(也可以用球體)去截取這些物體的Mesh,從而構(gòu)造新的網(wǎng)格,將噴漆渲染在這個Mesh就OK了。

代碼實現(xiàn):

首先,我們需要一個獲取規(guī)定范圍內(nèi)MeshRenderer的函數(shù):

public GameObject[] GetAffectedObjects(Bounds bounds, LayerMask affectedLayers)
{
 MeshRenderer[] renderers = FindObjectsOfType<MeshRenderer>();
 List<GameObject> objects = new List<GameObject>();
 foreach (Renderer r in renderers)
 {
 if (!r.enabled) continue;
 if ((1 << r.gameObject.layer & affectedLayers.value) == 0) continue;
 if (r.GetComponent<Decal>() != null) continue;

 if (bounds.Intersects(r.bounds))
 {
 objects.Add(r.gameObject);
 }
 }
 return objects.ToArray();
}

然后拿到這些GameObject去做裁剪,裁剪函數(shù):

public void BuildDecal(GameObject affectedObject, bool isLast)
{
 Mesh affectedMesh = affectedObject.GetComponent<MeshFilter>().sharedMesh;
 if (affectedMesh == null) return;

 //這里預(yù)存了已獲取物體的vertices和triangles,減少了不必要的GC
 Vector3[] vertices = GetVertexList(affectedObject);
 int[] triangles = GetTriangleList(affectedObject);

 //目標頂點轉(zhuǎn)換到當前物體的模型空間
 Matrix4x4 matrix = this.transform.worldToLocalMatrix*affectedObject.transform.localToWorldMatrix;
 //將主要計算移入異步
 Loom.RunAsync(() =>
 {
 for (int i = 0; i < triangles.Length; i += 3)
 {
 int i1 = triangles[i];
 int i2 = triangles[i + 1];
 int i3 = triangles[i + 2];

 Vector3 v1 = matrix.MultiplyPoint(vertices[i1]);
 Vector3 v2 = matrix.MultiplyPoint(vertices[i2]);
 Vector3 v3 = matrix.MultiplyPoint(vertices[i3]);

 Vector3 side1 = v2 - v1;
 Vector3 side2 = v3 - v1;
 Vector3 normal = Vector3.Cross(side1, side2).normalized;

 if (Vector3.Angle(-Vector3.forward, normal) >= maxAngle) continue;

 DecalPolygon poly = new DecalPolygon(v1, v2, v3);

 //用立方體裁剪
 poly = DecalPolygon.ClipPolygon(poly, right);
 if (poly == null) continue;
 poly = DecalPolygon.ClipPolygon(poly, left);
 if (poly == null) continue;
 poly = DecalPolygon.ClipPolygon(poly, top);
 if (poly == null) continue;
 poly = DecalPolygon.ClipPolygon(poly, bottom);
 if (poly == null) continue;
 poly = DecalPolygon.ClipPolygon(poly, front);
 if (poly == null) continue;
 poly = DecalPolygon.ClipPolygon(poly, back);
 if (poly == null) continue;

 AddPolygon(poly, normal);
 }

 if (isLast)
 {
 RenderDecal();
 }
 });
}

DecalPolygon構(gòu)建了新的三角形(這里注意頂點的空間變換),然后分別用立方體的每一個面去做裁剪,轉(zhuǎn)換成數(shù)學(xué)算法,其實是判面與面的關(guān)系,具體實現(xiàn):

/// <summary>
/// 兩面相交裁剪
/// </summary>
public static DecalPolygon ClipPolygon(DecalPolygon polygon, Plane plane)
{
 //相交為True
 bool[] positive = new bool[9];
 int positiveCount = 0;

 for (int i = 0; i < polygon.vertices.Count; i++)
 {
 positive[i] = !plane.GetSide(polygon.vertices[i]); //不在裁剪面正面,說明有相交
 if (positive[i]) positiveCount++;
 }

 if (positiveCount == 0)
 return null; //全都在裁剪面正面面,不相交
 if (positiveCount == polygon.vertices.Count) return polygon; //全都在裁剪面反面,完全相交

 DecalPolygon tempPolygon = new DecalPolygon();

 for (int i = 0; i < polygon.vertices.Count; i++)
 {
 int next = i + 1;
 next %= polygon.vertices.Count;

 if (positive[i])
 {
 tempPolygon.vertices.Add(polygon.vertices[i]);
 }

 if (positive[i] != positive[next])
 {
 Vector3 v1 = polygon.vertices[next];
 Vector3 v2 = polygon.vertices[i];

 Vector3 v = LineCast(plane, v1, v2);
 tempPolygon.vertices.Add(v);
 }
 }

 return tempPolygon;
}

OK,到這里已經(jīng)為新的Mesh準備好了所有的數(shù)據(jù),接下來將計算好的數(shù)據(jù)移步到主線程做渲染:

public void RenderDecal()
{
 //主線程渲染
 Loom.QueueOnMainThread(() =>
 {
 if (sprite == null || Renderer == null||filter==null)
  {
   return;
  }
  //生成uv信息
  GenerateTexCoords(0, sprite);
  //距離偏移
 Push(pushDistance);

 Mesh mesh = CreateMesh();
 if (mesh != null) {
 mesh.name = "DecalMesh";
 filter.mesh = mesh;
 Renderer.material = material;
 Renderer.enabled = true;
 }
 });
}

這樣,一個噴漆功能就做好了,有幾點需要注意是的是:

1.GC的控制

示例:Vector3[] vertices = mesh.vertices;
注意這里不是簡單的內(nèi)存引用,而是會申請新的內(nèi)存,所以這樣的臨時變量會造成GC,當物體的頂點上十幾K,甚至幾十K的時候,這樣的GC是吃不消的!為了盡量避免這樣的情況,可以做一次預(yù)存處理,對沒有檢測過物體的頂點和三角形數(shù)據(jù)進行保存,下次用的時候直接取,從而取代mesh.vertices;

2.計算量的問題

還是出于性能的考慮,當與之裁剪的Mesh頂點數(shù)太多,在主線程for循環(huán)幾十K次,不出意外PC端也會卡頓,所以異步是一個較好的選擇。復(fù)雜的裁剪計算交給其他線程,計算好主線程直接拿數(shù)據(jù)做渲染;

3.效果問題

由于新生成的噴漆Mesh是由原有物體的mesh裁剪所得的,而這兩個Mesh位置是重疊在一起的,兩個完全重疊的面,如果其他因變量也相同的情況下,讓計算機渲染,計算機也不知道該先渲染哪個,這樣就出現(xiàn)z-fighting的問題。所以加一個Push()方法,將新Mesh的頂點沿當前頂點的法線方向擠出一點距離,這樣就實現(xiàn)了一個噴漆功能。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Unity?UGUI的StandaloneInputModule標準輸入模塊組件使用示例

    Unity?UGUI的StandaloneInputModule標準輸入模塊組件使用示例

    這篇文章主要為大家介紹了Unity?UGUI的StandaloneInputModule標準輸入模塊組件使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-08-08
  • C#中閉包的實現(xiàn)和注意事項詳解

    C#中閉包的實現(xiàn)和注意事項詳解

    閉包并不是某一個語言中特有的概念,在主流的編程語言中都有這個特性,閉包可以讓一個內(nèi)部方法可以訪問它所在外部方法中的變量,并可以對變量的值進行修改,即使在外部方法的生命周期已經(jīng)結(jié)束后,本文給大家介紹了C#中閉包的實現(xiàn)和注意事項,需要的朋友可以參考下
    2025-01-01
  • C#集成DeepSeek模型實現(xiàn)AI私有化的流程步驟(本地部署與API調(diào)用教程)

    C#集成DeepSeek模型實現(xiàn)AI私有化的流程步驟(本地部署與API調(diào)用教程)

    本文主要介紹了C#集成DeepSeek模型實現(xiàn)AI私有化的方法,包括搭建基礎(chǔ)環(huán)境,如安裝Ollama和下載DeepSeek?R1模型,客戶端?ChatBox?AI?接入?DeepSeek?的步驟,以及?C#?調(diào)用?DeepSeek?API?的示例代碼,并總結(jié)了其在實際項目中的應(yīng)用價值,需要的朋友可以參考下
    2025-03-03
  • Unity中的RegisterPlugins實用案例深入解析

    Unity中的RegisterPlugins實用案例深入解析

    這篇文章主要為大家介紹了Unity中的RegisterPlugins實用案例深入解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-05-05
  • C# 獲取進程退出代碼的實現(xiàn)示例

    C# 獲取進程退出代碼的實現(xiàn)示例

    這篇文章主要介紹了C# 獲取進程退出代碼的實現(xiàn)示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-02-02
  • C#實現(xiàn)漂亮的數(shù)字時鐘效果

    C#實現(xiàn)漂亮的數(shù)字時鐘效果

    這篇文章主要介紹了C#實現(xiàn)漂亮的數(shù)字時鐘效果,涉及時間函數(shù)的應(yīng)用及繪圖的方法,需要的朋友可以參考下
    2014-10-10
  • C#?模式匹配完全指南

    C#?模式匹配完全指南

    模式匹配是一種高端的使用機制,它允許程序員在開發(fā)的時候以對象的類型作為條件篩選和分情況處理的一種手段,本文給大家介紹C#?模式匹配完全指南,感興趣的朋友跟隨小編一起看看吧
    2022-03-03
  • 在C#中調(diào)用Python代碼的兩種實現(xiàn)方式

    在C#中調(diào)用Python代碼的兩種實現(xiàn)方式

    這篇文章主要介紹了在C#中調(diào)用Python代碼的兩種實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-03-03
  • C# 大數(shù)據(jù)導(dǎo)出word的假死報錯的處理方法

    C# 大數(shù)據(jù)導(dǎo)出word的假死報錯的處理方法

    C# 大數(shù)據(jù)導(dǎo)出word的假死報錯的處理方法,需要的朋友可以參考一下
    2013-03-03
  • c#模擬js escape方法的簡單實例

    c#模擬js escape方法的簡單實例

    這篇文章主要介紹了c#模擬js escape方法的簡單實例,有需要的朋友可以參考一下
    2013-11-11

最新評論

紫金县| 凌海市| 阳城县| 荆州市| 丰县| 乡城县| 日照市| 阿克苏市| 常熟市| 孙吴县| 霞浦县| 宽甸| 曲阳县| 绥棱县| 阿克苏市| 和田县| 深水埗区| 大城县| 土默特右旗| 辽宁省| 高要市| 株洲县| 漯河市| 黄浦区| 望奎县| 略阳县| 黔江区| 昆明市| 忻城县| 隆安县| 方城县| 瑞金市| 长乐市| 洪泽县| 双城市| 交城县| 通榆县| 吉林省| 丘北县| 华坪县| 桂林市|