Unity人物隱身(半透明)處理

2021-02-20 泰鬥社區

本文章只使用到簡單的固定功能shader關閉光照後的效果。

在日常遊戲開發中,一個3D模型需要隱身(半透明),常規步驟需要處理一下幾個問題:

透明Shader處理

模型多部件網格合併

模型多材質合併

需要同時處理圖片的透明和剔除,shader中一個pass是處理不了的。常規做法是進行兩次渲染,一次渲染半透明效果,一次進行透明剔除。

首先,利用AlphaTest進行剔除處理,需要開啟ZWrite選項,渲染一遍。

Pass   

    AlphaTest Greater [_CutOff]

    ZWrite On

    ColorMask 0

        SetTexture [_MainTex] 

        {

            ConstantColor [_Color]

            Combine Texture * constant

        }

}

其次,半透明渲染的時候需要關閉ZWrite選項

Pass

{

    ZWrite Off

    Blend SrcAlpha OneMinusSrcAlpha

    ZTest LEqual

    SetTexture[_MainTex]

    {

        ConstantColor[_Color]

        Combine Texture * constant

    }

}

最終效果,飄帶為半透明,裙邊為剔除效果

模型有些糙,大家湊合看

在一個3D遊戲中,模型的換裝是很常見的功能,沒有換裝也會有簡單的武器,飾品類部件的綁定。這種情況下實現半透明隱身效果,就會出現模型間相互穿插的問題。

模型中支持換發功能,身體和頭髮屬於兩個部件,透明後相互穿插,效果十分不好


出現這種情況是因為兩個部件之間的半透明後,並不知道彼此的深度關係(半透明效果在關閉ZWrite模式下渲染),只有將其合併到同一個Mesh(網格)中才能實現比較完美的透明效果。

unity官方mesh合併文檔

當然只靠官方文檔並沒有什麼卵用,unity官方文檔的一貫風格,你們懂得~~我們還是要自己寫代碼,或者也可以使用像Mesh Baker這樣的現成工具實現,對於Mesh Baker的使用這裡就不累述了,有很詳細的文檔和例子。網格合併的同時還進行了材質合併,代碼在下一部分以前給出。

多個部件一般都是在不同的材質中,這樣在渲染一個3D模型的時候就需要同時處理多個材質球,打開Unity我們就會發現每使用一個材質球就會產生一個drawcall。合併多材質也是unity性能優化的一種方式。

未材質合併下的batches為4

材質合併後的batches為2

在模型的最外層,我掛載了一個Model3D.cs的腳本,用於處理模型和材質的合併,材質合併還需要對UV處理,代碼中也已經包含。

void Combine()

    {

        List<CombineInstance> combineInstances = new List<CombineInstance>(); 

       List<Material> materials = new List<Material>();

        List<Transform> bones = new List<Transform>();

        Transform[] transforms = GetComponentsInChildren<Transform>();        List<Texture2D> textures = new List<Texture2D>();

        int width = 0; 

        int height = 0;

        int uvCount = 0;

        List<Vector2[]> uvList = new List<Vector2[]>();

        //蒙皮模型

        foreach (SkinnedMeshRenderer smr in GetComponentsInChildren<SkinnedMeshRenderer>())

        {

            if (_material == null)

                _material = Instantiate(smr.sharedMaterial) as Material;

            for (int sub = 0; sub < smr.sharedMesh.subMeshCount; sub++)

            {

                CombineInstance ci = new CombineInstance();

                ci.mesh = smr.sharedMesh;

                ci.subMeshIndex = sub;

                ci.transform = smr.transform.localToWorldMatrix;

                combineInstances.Add(ci);

            }

            uvList.Add(smr.sharedMesh.uv);

            uvCount += smr.sharedMesh.uv.Length;

            if (smr.material.mainTexture != null)

            {

                //保存材質

                materials.AddRange(smr.GetComponent<Renderer>().materials);                //保存貼圖

                foreach (var mat in materials)

                {

                    textures.Add(mat.mainTexture as Texture2D);

                }

            }

            //保存骨骼信息

            foreach (Transform bone in smr.bones)

            {

                bones.Add(bone);

            }

            Destroy(smr.gameObject);

        }

        SkinnedMeshRenderer r = GetComponent<SkinnedMeshRenderer>();        if (!r)

            r = gameObject.AddComponent<SkinnedMeshRenderer>();

        r.sharedMesh = new Mesh();

        //合併子網格

        r.sharedMesh.CombineMeshes(combineInstances.ToArray(),  true, false);

        r.bones = bones.ToArray();

        r.material = _material;

        Texture2D skinnedMeshAtlas = new Texture2D(width, height);

        Rect[] packingResult = skinnedMeshAtlas.PackTextures(textures.ToArray(), 0);

        Vector2[] atlasUVs = new Vector2[uvCount];

        //合併材質,處理uv

        int j = 0;

        for (int i = 0; i < uvList.Count; i++)

        {

            foreach (Vector2 uv in uvList[i])

            {

                atlasUVs[j].x = Mathf.Lerp(packingResult[i].xMin, packingResult[i].xMax, uv.x);

                atlasUVs[j].y = Mathf.Lerp(packingResult[i].yMin, packingResult[i].yMax, uv.y);

                j++;

            }

        }

        r.material.mainTexture = skinnedMeshAtlas;

        r.sharedMesh.uv = atlasUVs;

    }

上述代碼中還存在一個問題,就是只合併了SkinnedMeshRenderer類型的網格,在unity中,帶動作的模型FBX檔案導入到項目中的時候,unity會默認導入為SkinnedMeshRenderer類型。

但是如果當前的FBX不帶動作(很多的武器是不需要動作,直接依靠綁點動作的),unity會默認導入為MeshRenderer類型,這時候這段代碼就無法將該模型的網格進行合併。

SkinnedMeshRenderer(帶動作包含骨骼信息)

MeshRenderer(不帶動作不包含骨骼信息)

這種情況有兩種解決辦法:

1、浪費一根骨骼的資源,在所有不含動作的部件中加入一根骨骼,這樣導入到unity中,就會默認統一導入為SkinnedMeshRenderer類型,也就不存在不同類型網格合併問題。


2、實際上SkinnedMeshRenderer和Mesh類型是可以進行合併的,如Mesh Baker中就可以實現,具體的方法我沒有具體研究,有興趣的朋友可以自己看看。

合併後的運行效果,沒有穿幫現象

1、使用該shader渲染的時候,如果是非透明情況,需要將_cutoff的數值調整為接近1,且小於1的數值,如0.95,這樣的顯示效果才正確。
2、修改透明度調低顏色的Alpha值時需要同步調低_cutoff,Alpha值略大於_cutoff值即可,否則會出現模型層級不對問題(渲染先後順序)。

相關焦點

  • [TA]Unity Shader:半透明、渲染、透明度測試和混合...
    綠色代表材質1,黃色代表材質2,因此分為兩個DrawCall從cpu發送渲染命令(批處理技術為了優化渲染減少drawcall會將材質1的兩個物體分為一個Batch一起處理,暫時看成同一個物體即可);在每一次Drawcall中,也就是處理每一個物體映射到屏幕上的像素的過程中,物體經過幾何階段變換、光柵化、片元著色器後會得到一堆片元序列(屏幕輸出像素的候選者),片元可簡單理解成攜帶各種數據的像素
  • Unity高級知識點總結:性能優化與圖形渲染進階
    = DecodeHDR(rgbm, unity_SpecCube0_HDR);3.4、我們額外做了一個把漫反射的lightmap合併到specular上的操作,防止金屬丟失lightmap信息。3、延遲渲染的好處是可以處理多光源的情況。缺點是無法正確處理半透明,且會消耗更多的顯存帶寬。4、還有一種 Forward+ 渲染。思路是將屏幕劃分為一個一個的塊兒,控制每個塊兒的影響燈光數量,從而減輕運算壓力,讓前向渲染也可以處理多光源的情況。不過這個貌似並沒有被廣泛應用。主流遊戲引擎還都是延遲渲染+前向渲染。5、在移動平臺下,我們都是使用前向渲染。
  • 漫步VR——Unity語音聊天室開發
    安裝:https://unity3d.com/cn/get-unity/download/archive。編譯Support包:unity可以很方便移植到多個平臺上,依賴的即是下載安裝對應unity版本的Support-for-Editor。
  • Unity圖片資源處理
    Editor GUI…: Use this if your texture is going to be used on any HUD/GUI Controls.Sprite:2D中的貼圖或者UI一般使用這種格式,這種貼圖會提供UI坐標偏移和九宮格之類的高級圖片處理效果,且通常需要進行打包來降低 drawcall。
  • Unity2018.3中文更新日誌詳解
    新的Hub v1.2版本包括通過Unity下載歸檔(https://unity3d.com/get-unity/download/archive) URL 直接在Hub中下載和安裝舊版Unity Editor版本的功能。依賴特定(較舊)版本的編輯器的用戶現在只需單擊一下即可輕鬆地從Hub訪問它們。
  • Unity URP/SRP 渲染管線淺入深出【匠】
    光照處理(包括陰影)2. SRP Bacher (SRP 批處理)(重點)其他可以看看官網圖,下面是官網的對比表連結和圖。docs.unity3d.com/Packages/com.unity.render-pipelines.universal%408.2/manual/universalrp-builtin-feature-comparison.html
  • Unity Android Plugin開發指南
    為了方便起見,後文將前者稱為Unity,後者稱為Android如上圖所示,Unity通過UnityEngine提供的API調用Android的方法;Android藉助com.unity.player包提供的API調用Unity的方法。
  • 實戰 用Unity快速開發太空飛機大戰(上)
    1、新建打飛機unity工程,建好資源分類目錄,導入飛機FBX模型文件以及貼圖,射擊和爆炸等聲音文件等等。如圖:2、新建場景game.unity,下面大部分工作都在這個場景裡完成!7、上面步驟,已經將遊戲需要模擬太空背景的效果處理差不多了,接下來需要調整試圖角度,我們需要從上向下展望火星和星空。我調整了下攝像機視角和視野大小。
  • unity篇(2):在Unity中協程的各種使用
    這樣說有點難懂,其實unity中的協程其實就是為一個方法開闢多個入口。StopCoroutine()方法只能終止以字符串形式啟動(開始)的協程;多個協程可以同時運行,它們會根據各自的啟動順序來更新協程可以嵌套任意多層如果你想讓多個腳本訪問一個協程,那麼你可以定義靜態的協程;協程不是多線程,它們運行在同一線程中,跟普通的腳本一樣;如果你的程序需要進行大量的計算,那麼可以考慮在一個隨時間進行的協程中處理它們
  • 如何利用Unity快速搭建訓練機器人數字孿生?
    OAK-D 攝像機由兩個立體深度攝像機、一個帶有內置處理功能(由英特爾 MyriadX VPU 驅動)、可自動識別多種特徵的 4K 彩色攝像機組成。在參賽期間,我們為 OAK 設備創建了一個 Unity 插件,並且也想在 Unity 中為其製作一個數字孿生。
  • 使用Unity感知工具大批量生成、分析合成數據,高效地訓練ML模型
    經過處理的真值會與相關度量衡一起儲存到JSON文件中。我們計劃在未來添加更多的貼標器,比如實例分隔,來支持其它常見的計算機視覺任務;場景生成工具;配置、管理大批domain randomization(域隨機化)參數的功能,以及雲服務的規模擴展。任何ML從業者都明白查看、分析帶標註數據的重要性。
  • Unity 基於excel2json批處理讀取Excel表並反序列化
    excel2json是一款將Excel表格文件快速生成json和C#數據類的高效插件,詳情了解如下:https://neil3d.github.io/coding/excel2json.html該插件有兩種模式,分別是命令行和圖像界面;為了更方便愉快的進行大規模轉換,可以寫兩個批處理文件來實現
  • Unity Demo教程系列——Unity塔防遊戲(三)塔(Shooting Enemies)
    有許多種方法可以可視化它,但是我們僅使用拉伸後的半透明立方體來形成光束。每個塔將需要一個自己的光束,因此將其添加到塔的預製件中。將其放置在塔內,以便默認情況下處於隱藏狀態,並使其較小,例如0.2。使它成為預製根的子節點,而不是轉塔立方體的子節點。
  • 如何運用Unity製作VR全景漫遊?
    Unity5.3.1 X64: http://unity3d.com/cn/get-unity/download/archivePTGui[可選]: 把全景圖轉成6個立方小圖 http://www.ptgui.com/download.htmlGoogle VR SDK For Unity: https://github.com/googlevr
  • Unity2019.3中學習並實踐光追原理(一)基本原理與硬編碼場景
    _CameraInverseProjection", _camera.projectionMatrix.inverse); //向CS中傳遞天空紋理 RayTracingShader.SetTexture(0, "_SkyboxTexture", SkyboxTexture); } //完成所有渲染之後調用,通常用於後處理
  • 遊戲士兵人形角色3D模型Unity遊戲素材資源
    人人素材社區-最專業的CG藝術交流網站今天小生為大家帶來的是遊戲士兵人形角色3D模型Unity遊戲素材資源一說到士兵是不是很快腦海裡就浮現出了反恐精英裡面的畫面想起了裡面的人物甚至想要趕快打開這個遊戲玩上一把呢不要著急哦還是先看看小生推薦的角色模型吧你會有不一樣的收穫哦
  • 隱身戰鬥機是如何實現隱身的?詳解隱身技術原理
    隱身技術 畢竟咱們要知其然,也要知其所以然嘛! 我從三個方面分別跟大家聊聊啊。 第一個是外形設計。 第二個是機身吸波材料。 第三個是特殊部位的隱身處理技術。
  • 小技巧:在Ubuntu 14.04中重置Unity和Compiz設置
    重置Ubuntu 14.04中的Unity和Compiz打開終端(Ctrl+Alt+T),並使用以下命令來重置compiz:dconf reset -f /org/compiz/重置compiz後,重啟Unity:setsid unity此外,如果你想將Unity圖標也進行重置,試試以下的命令吧:
  • Made with Unity | 這款衝出地表的SLG手遊,用URP渲染了整個銀河系
    自從Unity發布URP之後,新一代的管線架構體系帶來的畫質飛躍和性能提升,尤其是URP為行動裝置在渲染方面帶來的諸多可能性,引起了我們深切的關注。數據編輯頁面在實際推進過程中,我們也遇到了不少意料之外的問題,例如由於建模方面缺乏經驗,導致某些表情產生誤差,甚至難以想像的扭曲;包括一些錄製下來的數據導入之後,發現往往難以表演得一步到位,往往每一條或多或少都存在一些瑕疵,諸如情緒不到位、眼神躲閃等等。
  • [專欄精選]Unity中的Git最佳實踐
    這也是基於Git的一些原則:通常Unity中需要設置的內容有以下幾項:設置Asset Serialization為Force Text上面提到了,Git無法處理二進位文件的合併,只能處理文本文件的合併。如果二進位文件出現了衝突,那只能選擇一個文件保留,無法將兩個文件進行合併。對於Unity中的文件,我們需要儘量避免這種情況。