如何在Editor中監聽Prefab修改後Auto Save的事件

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


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

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

Editor

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

原來的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裏的方法嘗試反射調用。

感謝張迪@UWA問答社區提供了回答,歡迎大家轉至社區交流:
https://answer.uwa4d.com/question/5ee0aecaa45e13073a5710ea


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提供,歡迎大家轉至社區交流:
https://answer.uwa4d.com/question/5eb905a04d93790618e0ed25


Physics

Q:請問下大家的項目裏,地形部分是直接用的MeshCollider嗎?如果把一個大地形拆成多個MeshCollider性能上會不會好一些?不知道大家有沒有這方面的優化經驗?

A:按之前的優化經驗來看,物理的contacts數(有接觸的物體對)對於物理的開銷影響會比較大。而計算MeshCollider與其他物體是否有接觸的時候,是用的AABB包圍盒,所以對於彎曲的、狹長的MeshCollider還是建議做一下拆分,避免其包圍盒過大,導致過多的contacts產生。但對於方方正正的地形塊來說,是否需要拆分、拆分到什麼粒度就不太好判斷了,這方面的文檔或者經驗分享確實不多。

該回答由UWA提供,歡迎大家轉至社區交流:
https://answer.uwa4d.com/question/5ec4d442979400061e54534a


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問答社區提供了回答,歡迎大家轉至社區交流:
https://answer.uwa4d.com/question/5ed7c18e96525d41c9512b2e


Audio

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

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

感謝題主徐蓮一蒙@UWA問答社區提供了回答,歡迎大家轉至社區交流:
https://answer.uwa4d.com/question/5ed7730096525d41c9512b1f

封面圖來源於網絡


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

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章