【厚積薄發】如何在Editor中監聽Prefab修改後Auto Save的事件

1)如何在Editor中監聽Prefab修改後Auto Save的事件
2)關於動畫文件的Optimal選項的開啓優勢
3)一個大地形拆成多個Mesh Collider,對性能有幫助嗎
4)Camera.SetReplacementShader和Projector顯示問題
5)FMOD在安卓機上插拔耳機聲音不會切換git


這是第207篇UWA技術知識分享的推送。今天咱們繼續爲你們精選了若干和開發、優化相關的問題,建議閱讀時間10分鐘,認真讀完必有收穫。github

UWA 問答社區:answer.uwa4d.com
UWA QQ羣2:793972859(原羣已滿員)網絡

Editor

Q:如圖,在新的Prefab機制中多了Auto Save,沒找到監聽方法。app

原來的Apply是能夠監聽的,可是若是勾選了Auto Save,就不須要點擊Apply,因此會監聽不到。求問Auto Save的保存能夠監聽嗎? 編輯器

A:PrefabStage類負責管理Prefab的編輯操做,並提供了豐富的回調,參考 PrefabStage源碼能夠輕鬆實現監聽各個階段:
#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using UnityEditor.Experimental.SceneManagement;

[InitializeOnLoad]
public static class PrefabStageListener
{
    static PrefabStageListener()
    {
        // 打開Prefab編輯界面回調
        PrefabStage.prefabStageOpened += OnPrefabStageOpened;
        // Prefab被保存以前回調
        PrefabStage.prefabSaving += OnPrefabSaving;
        // Prefab被保存以後回調
        PrefabStage.prefabSaved += OnPrefabSaved;
        // 關閉Prefab編輯界面回調
        PrefabStage.prefabStageClosing += OnPrefabStageClosing;
    }

    //....
}
#endif

PS:若是常常要查找一些編輯器私有的字段方法,建議下載dnSpy直接打開UnityEditor.dll搜索關鍵字進行查找,例如想經過代碼實現界面按鈕的某個功能卻找不到API,這時候就能夠查看相關DLL裏的方法嘗試反射調用。ide

感謝張迪@UWA問答社區提供了回答。性能


Animation

Q:項目中的動畫文件開啓了Optimal選項,會有哪些實質性的優勢能夠講一下嗎?開啓Optimal選項是對項目中的哪一部分起到了做用?測試

A:Unity的官方文檔對這個選項的描述確實並不清楚:
Let Unity decide how to compress, either by keyframe reduction or by using dense format. If enabled, the Inspector displays Animation Compression Errors options.
Only for Generic and Humanoid Animation Type rigs.

推薦看這篇文章,對於Unity動畫文件裏的曲線保存方式和相關選項作了細緻的描述。整體來講,Optimal就是讓Unity自動選擇最優的曲線表達方式,從而佔用最小的存儲空間。優化

該回答由UWA提供。動畫


Physics

Q:請問下你們的項目裏,地形部分是直接用的MeshCollider嗎?若是把一個大地形拆成多個MeshCollider性能上會不會好一些?不知道你們有沒有這方面的優化經驗?
A:按以前的優化經驗來看,物理的contacts數(有接觸的物體對)對於物理的開銷影響會比較大。而計算MeshCollider與其餘物體是否有接觸的時候,是用的AABB包圍盒,因此對於彎曲的、狹長的MeshCollider仍是建議作一下拆分,避免其包圍盒過大,致使過多的contacts產生。但對於方方正正的地形塊來講,是否須要拆分、拆分到什麼粒度就不太好判斷了,這方面的文檔或者經驗分享確實很少。

該回答由UWA提供。


Rendering

Q:如圖,爲了作雪地場景的效果,我使用Camera.SetReplacementShader這個方法來替換場景中的Shader,場景物體和粒子這些都正常的替換了,可是惟獨Projector沒有正常顯示,不知道Projector的處理和其餘Shader不同(也給它寫了個替換用的Shader,可是沒有效果,也不知道是否是替換成功了,只是被覆蓋了)。

爲了測試,我作了一個更加簡單的場景:

用FrameDebug能夠看到它的渲染信息:

而後執行替換邏輯後:

相應的,它的渲染信息以下圖:

能夠看到好像替換成功了,可是Blend和ZWrite這些不對應,原始Projector Shader中 爲Blend SrcAlpha OneMinusSrcAlpha,ZWrite Off,在替換的Shader中也是同樣設置,可是在FrameDebug中看到的倒是Blend One Zero,ZWrite On。

本身對這一塊也不是很瞭解,但願有前輩能夠指點指點,解答一下疑惑,哪裏作的不對。附上個人測試腳本(簡單點,替換的Projector Shader中就直接複製過去了)。

public class ReplaceShader : MonoBehaviour
{
    public Camera Camera;
    public Shader replaceShader;

    bool isOn;

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space)) {
            ToggleEffect();
        }
    }

    void ToggleEffect()
    {
        isOn = !isOn;
        if (isOn)
        {
            Camera.SetReplacementShader(replaceShader, "RenderType");
        }
        else {
            Camera.ResetReplacementShader();
        }

    }
}

投影Shader:

Shader "Custom/ProjectorFX_CharacterRing"
{
  Properties {
    _MainColor ("Main Color", Color) = (1,1,1,1)
    _ProjectTex ("Shape", 2D) = "" {}
  }

  Subshader {
    Tags {"Queue"="Transparent+1" "RenderType"="Projector" "ProjectorFX"="Normal"}
    Pass {
      ZWrite Off
      AlphaTest Greater 0
      ColorMask RGB
      Blend SrcAlpha OneMinusSrcAlpha
      Offset -1, -1

      CGPROGRAM

      #pragma vertex vert
      #pragma fragment frag
      #pragma multi_compile_fog

      #include "UnityCG.cginc"

      fixed4 _MainColor;      
      fixed4 _MainTex_ST;
      float4x4 unity_Projector;
      sampler2D _ProjectTex;

      struct vInput {
        float4 vertex : POSITION;
      };

      struct vOutput {
        float4 uvMain : TEXCOORD0;
        UNITY_FOG_COORDS(2)
        float4 pos : SV_POSITION;
      };

      vOutput vert (vInput v)
      {
        vOutput o;
        o.pos = UnityObjectToClipPos(v.vertex);
        o.uvMain = mul(unity_Projector, v.vertex);        

        UNITY_TRANSFER_FOG(o,o.pos);
        return o;
      }

      fixed4 frag (vOutput i) : SV_Target
      {
        fixed4 main = tex2Dproj(_ProjectTex, UNITY_PROJ_COORD(i.uvMain));       
        main *= _MainColor;


        UNITY_APPLY_FOG_COLOR(i.fogCoord, main, fixed4(0,0,0,0));

        return main;
      }
      ENDCG
    }
  }
}

使用的替換Shader:

Shader "Unlit/TestRed"
{  
     Subshader {
    Tags {"Queue"="Transparent+1" "RenderType"="Projector"}
    Pass {
      ZWrite Off
      AlphaTest Greater 0
      ColorMask RGB
      Blend SrcAlpha OneMinusSrcAlpha
      Offset -1, -1

      CGPROGRAM

      #pragma vertex vert
      #pragma fragment frag
      #pragma multi_compile_fog

      #include "UnityCG.cginc"

      fixed4 _MainColor;      
      fixed4 _MainTex_ST;
      float4x4 unity_Projector;
      sampler2D _ProjectTex;

      struct vInput {
        float4 vertex : POSITION;
      };

      struct vOutput {
        float4 uvMain : TEXCOORD0;
        UNITY_FOG_COORDS(2)
        float4 pos : SV_POSITION;
      };

      vOutput vert (vInput v)
      {
        vOutput o;
        o.pos = UnityObjectToClipPos(v.vertex);
        o.uvMain = mul(unity_Projector, v.vertex);        

        UNITY_TRANSFER_FOG(o,o.pos);
        return o;
      }

      fixed4 frag (vOutput i) : SV_Target
      {
        fixed4 main = tex2Dproj(_ProjectTex, UNITY_PROJ_COORD(i.uvMain));       
        main *= _MainColor;


        UNITY_APPLY_FOG_COLOR(i.fogCoord, main, fixed4(0,0,0,0));

        return main;
      }
      ENDCG
    }
  }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = fixed4(1,0,0,1);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
        }
    }

}
A:從題主的截圖中能夠看到,在沒有使用Replace Shader的時候,Plane渲染了兩次,一次是自身Shader,一次是Projector Shader。在使用了Replace Shader以後,FrameDebugger裏面看到Plane只渲染了一次,應該是Projector沒有生效。由於只有Opaque的那個SubShader起做用了,因此FrameDebugger裏面看到的是「 Blend One Zero , ZWrite On」,這個是正常的,只是跑到半透明渲染隊列裏面去了,這個不太正常。我嘗試把題主的Replace Shader裏面的兩個SubShader調換了一下順序,結果又跑到不透明渲染隊列裏面去了。

在Google裏面搜索了一下,發現Unity論壇裏面有2個帖子跟題主的問題比較相關,這個帖子裏有提到說Unity 5.6.4使用了Replace Shader就不支持Projector。

這個帖子說是由於以前有個Bug,Replace Shader會使受到Projector影響的物體即便Tag不匹配也進行渲染,因此Unity修Bug把Projector改爲使用了Replace Shader就不起做用了。

感謝Xuan@UWA問答社區提供了回答。


Audio

Q:咱們用FMOD播放的音樂和音效,在安卓設備上,手機功放BGM,這個時候插入耳機,手機依然在功放,並不能切換到耳機播放,另外切換到藍牙也是一樣的問題,有沒有人遇到過,蘋果設備是沒問題的。

A:在RuntimeManager.cs的Initialize()方法裏把Android平臺的OutputType改爲FMOD.OUTPUTTYPE.AUDIOTRACK就能夠了。

感謝題主徐蓮一蒙@UWA問答社區提供了回答。

封面圖來源於網絡


今天的分享就到這裏。固然,生有涯而知無涯。在漫漫的開發週期中,您看到的這些問題也許都只是冰山一角,咱們早已在UWA問答網站上準備了更多的技術話題等你一塊兒來探索和分享。歡迎熱愛進步的你加入,也許你的方法恰能解別人的燃眉之急;而他山之「石」,也能攻你之「玉」。

官網:www.uwa4d.com
官方技術博客:blog.uwa4d.com
官方問答社區:answer.uwa4d.com
UWA學堂:edu.uwa4d.com 官方技術QQ羣:793972859(原羣已滿員)

相關文章
相關標籤/搜索