Unity - 使用Pixels來判斷物件在畫面中所佔的比例

  判斷一個物件在畫面當中所佔的比例,如果是正方形、圓形等等固定形狀就很容易計算面積,同時如果是2D平面的物件又會比3D物件來的好算,在不考慮紀錄每個三角點座標計算每個三角形的體積,同時還要判斷是否重疊的情況下,這邊使用的是一個簡單的方法,雖然在效能上可以說很糟,畢竟是每個Pixel都跑一次判斷,但是可以簡單判斷各種形狀物件佔畫面的比例,不過還是要避免每個Frame或太常做這個判斷。
  簡單來說就是擷取兩張攝影機畫面,一張全畫面一張只有背景,然後比對每個Pixel,以此來計算比例。

 


  調整方塊大小後再檢查一次確實有發現比例改變了。


  開始前先決定要排除物件的Layer,假設在Water,接著場景中的Main Camera的CullingMask除了Water Layer之外都照,這個是背景Camera。

  接著再建立一個新的Camera作為前景Camera,這個Camera設定只接收一個Culling Mask,也就是Water Layer,同時Clear Flags設定Depth only。

  記得把產生物件的Layer設定到Water,接著只要分別擷取前後的畫面然後每個Pixel去判斷就可以取得比例了。

Code
public class Percent : MonoBehaviour {
 public Camera myCamera; //掛著前景Camera

 void Update () {
  if(Input.GetKeyDown(KeyCode.Space)) {
   StartCoroutine("GetPercent");
  }
 }

 public IEnumerator GetPercent() {
  //先擷取所有物件的畫面
  yield return new WaitForEndOfFrame ();
  Texture2D texF = new Texture2D (Screen.width, Screen.height, TextureFormat.ARGB32, false);
  texF.ReadPixels (new Rect (0, 0, texF.width, texF.height), 0, 0, false);
  texF.Apply ();


  //接著先Culling掉目標Camera,然後擷取畫面取得背景圖片
  int PrevMask = myCamera.cullingMask;
  myCamera.cullingMask = 0;
  yield return new WaitForEndOfFrame ();

  Texture2D texB = new Texture2D (Screen.width, Screen.height, TextureFormat.ARGB32, false);
  texB.ReadPixels (new Rect (0, 0, texB.width, texB.height), 0, 0, false);
  texB.Apply ();

  myCamera.cullingMask = PrevMask;
  myCamera.Render (); //強制Render一次避免產生閃爍


  //取得並判斷Pixel是否相同
  Color32[] colB = texB.GetPixels32 ();
  Color32[] colF = texF.GetPixels32 ();
  Destroy(texB);
  Destroy(texF);
  int count = 0;
  for(int i = 0; i < colF.Length; i++) {
   if(!Color32.Equals(colB[i],colF[i]))
    count++;
  }

  //計算百分比
  float percent = (float)count * 100 / (float)(Screen.width * Screen.height);
  Debug.Log ("COLOR:" + percent);
 }
}



  基本使用上沒什麼大問題,但是在編輯器當中有時候你可能會發現即使你填滿畫面也沒有到100%,不過這個問題如果是在Build出來的遊戲中卻又沒有,主要問題還是在於ReadPixels在編輯器下會多擷取的問題超過實際Game視窗的大小,就如同這張在編輯器擷取後存的圖,會發現多了一條黑邊。不過在Build出來的軟體卻沒問題,只能暫時提報Bug看看了,畢竟對遊戲沒有影響。


No comments:

Post a Comment