RenderTexture 存png顏色變暗問題

最近在處理ARFoundation掃描後將圖像資訊存檔並取出到另外一個專案使用,發現一個問題,發現存檔的圖顏色會變暗。

基本上ColorMap是讀取ARFoundation傳來的ARCameraFrameEventArgs,經過shader合併TextureY和TextureCbCr,以及依照Portrait或Landscape旋轉貼圖再Blit給RenderTexture。

本來我的做法是直接把RenderTexture丟到Compute Shader處理,所以不需經過Texture2D轉換,但這次必須存成圖檔或是轉成Texture2D給其他人寫好的程式使用,所以發現了轉成Texture2D會變暗,查了一下,是RenderTexture轉成Texture2D後,會有sRGB轉換的問題。

[這篇文章]有講述基本sRGB的問題,最簡單的方法是把RenderTexture設定中sRGB設為為enable,就可以解決。

但因為我的RenderTexture是透過程式宣告的,但上面的方法sRGB在Script中是Read Only,所以我必須使用其他方法。

查到[這篇文章]中提供了幾個解決方法,目前我先是直接將讀取出的Color重新linear轉換。

C# partial class 的用法

在看Keijiro最新的Unity ML的範例時,發現他用了一個特別的class語法partial,研究了一下,這個語法可以方便將一個超長的程式碼切割在不同的檔案中。

partial  class  A   就是說明這是類A  只是一部分。我可以在建立一個類B.cs。在程式碼裡也寫partial  class  A。那麼程式在編譯後。兩個 A中的屬性和方法會合並在一起統一叫做類A的成員。

partial關鍵字 C#2.0提供的新關鍵字,用來將一個class、struct或interface的定義拆分,寫在不同的原始檔中。每個原始檔包含類定義的一部分,編譯應用程式時將把所有部分組合起來。在以下幾種情況下需要拆分類定義:

  1. 處理大型專案時,使一個類分佈於多個獨立檔案中可以讓多位程式設計師同時對該類進行處理。
  2. 使用自動生成的源時,無需重新建立原始檔便可將程式碼新增到類中。Visual Studio 在建立 Windows 窗體、Web 服務包裝程式碼等時都使用此方法。

ex. 使用方法:

A_Setting.cs

namespace TestA {
   public partial class A {
      public void Setting(){
         // setting action
      }
   }
}

A_Process.cs

namespace TestA {
   public partial class A {
      public void Process(){
         // process action
      }
   }
}

這樣的就可以把語法分開,但要小心一點,partial適合把程式切割成不同區塊,但換言之,也就造成在維護與閱讀時比較零散

Unity Advaced Mesh API – 胡亂摸經驗 part I (animation curve for job)

這幾天開始摸索Unity Advanced Mesh API來處理Mesh Derform的功能,因為原本使用的asset是利用純CPU來處理mesh,asset的效果不錯,只是在iOS上時,大約同時處理8~10個點雲物件的變形FPS開始就不行了。

所以開始摸索Advanced Mesh API,基本上摸到一個程度,發現有些細節官方文件也沒有說的很清楚,有點經驗後,回頭看Keijiro大神的範例(https://github.com/keijiro/DanmakuBenchmark),發現好到一個不行,自己目前寫出來的code根本還沒有很完整地用到最新的mesh 直接由這邊學習比較清楚,之後有空再來寫一篇。

在自己摸索的過程中,因為要把原來純CPU版本simple mesh api的版本轉換成job來運算Vertices的位置,需要用到animation curve來自定變形的動畫參數,但因為job並不支援animation curve當作輸入參數類型,所以得先將animation curve切割為native array,再傳入job來EvaluateLerp

我參考這邊的code來用(https://github.com/5argon/E7Unity/blob/master/SampledAnimationCurve/SampledAnimationCurve.cs)

iOS 上使用timeline

在嘗試製作AR MV時,使用Timeline來控制歌詞的出現

但發現輸出到手機後,按播放都沒有反應,檢查了按鈕的設定跟一堆東西後,發現是timeline並沒有被觸發,查詢之下,發現是Unity Timeline目前的bug之一。

解決辦法是在Unity Assets資料夾下新增一個link.xml檔案,並在裡面寫下:

<linker>    
<assembly fullname="UnityEngine.Timeline" preserve="all"/>    <assembly fullname="Unity.Timeline" preserve="all"/>    
<assembly fullname="UnityEngine">      
<namespace fullname="UnityEngine.Playables" preserve="all"/>    </assembly>
</linker>

這樣在輸出的時候,會將其註冊成AssetBundle,而不會被Unity濾掉,Timeline就可以正常運作。

Reference:
https://www.yui-tech-blog.com/entry/2019/12/09/【Unity】Unityを2019にアップグレードしたらTimelineが上手く再

ComputerShader處理後由CPU後續處理的方法

在最近的專案中,必須透過ComputerShader(CS)處理大量的點雲判斷,並回傳處理後的點來後續處理。

通常的狀態下,是使用GetData來將CS處理完的buffer資料塞回陣列再處理

_kernelIndex = Shader.FindKernel("CS_PointCloudMove");
_buffer = new ComputeBuffer(Count, sizeof(float));
Shader.SetBuffer(_kernelIndex, "floatBuffer", _buffer);
int groupX = (Count / _num);         
Shader.Dispatch(_kernelIndex, groupX, 1, 1);

var data = new float[Count]; 
_buffer.GetData(data);

但GPU到CPU的處理時間相當耗時,會使得FPS大幅地降低,我研究了一下後發現Unity有新的語法AsyncGPUReadback.Request(COMPUTE_BUFFER, METHOD),可以非同步地處理回傳的資料,能大大提升GPU<->CPU的運算效能

using System.Runtime.InteropServices;

...
AsyncGPUReadback.Request(_buffer, OnParticleCallback);
...

void OnParticleCallback() 
{
   if (request.hasError)
      return;
   // CPU particle data process
   _tmpParticles = request.GetData().ToArray();
   int pCount = 0;
   for (int i = 0; i < _tmpParticles.Length; i++)
   {
      if (_tmpParticles[i].hit > 0f)
      {
         _interactiveCount++;
         hitPoints.Add(_tmpParticles[i].position);
         pCount++;
      }
      if (pCount > touchCheckMaxNums)
         break;
      }
}