汚れをブラシで掃除するようなやつが作りたい
※初めに
このブログはUnity駆け出しの人間が完全独学であれこれ模索した様子を備忘録的に残しているだけなので、十中八九非効率なあんなことや、間違ってるこんなことを書いてしまってると思うので、あくまで参考程度に見てください。
初投稿となる今回の課題はタイトルにもある通り
汚れ的なテクスチャをちょっとずつ消してくやつ
です。
↓こんなの
とはいえUnity駆け出しの人間の頭に入ってる情報だけでは、どうすればこういったのが作れるのかビジョンが思い浮かばず、ひとしきり悩んだのち、
あ、お絵描きアプリを調べればいいのでは?
と思いついた。
一番頭を悩ませていたのが、
・どうやってオブジェクトを少しずつ削るように徐々に透明にしていくか
だったので、お絵描きアプリ的なものを作り、それを参考に改編していけば何とかなるのではないか、ぶっちゃけそこ出来ればあとは何とでもなるのではないか。
そう思いつき検索開始。
情報は多くなかったもののわかりやすいサイトを見つけることができた。
↓参考にさせて頂いたサイト
nn-hokuson.hatenablog.com
まずこのサイトをほぼ丸パクリして参考にして平面にお絵描きを出来るように、そしてそこから目的の形に変えていった。
ひとまず透明化
現状色を塗るだけなので、何とか弄ってテクスチャはそのままに、アルファ値だけ変更して透明にする形に持っていく。
その為にまずシェーダーの設定をいじる。ぶっちゃけまだよくわかっていないが、どうやらRendering Mode を Transparentにしないと透明にならないらしい。
ということでシェーダーをスタンダードに、モードをTransparentに変更。
そして参考にさせて頂いたソースコード(長いので元データと呼ばせて頂く)を一部改変、
public float AlphaPercentage; //一回の読み込みでどれくらい透明にするか テスト時数値「0.1f」 public void Draw(Vector2 p) { Color original; //なんか間違ってる気がするが現在地ピクセルの格納容器 for(int x = 0;x < mainTex.width; x++) { for(int y = 0;y < mainTex.height; y++) { if ((p - new Vector2(x,y)).magnitude < 5) { original = (Color)buffer.GetValue(x + mainTex.width * y); //現在のピクセルのカラーを抽出 original.a -= AlphaPercentage; //抽出したカラーの現在のアルファ値から一定値をマイナス buffer.SetValue(original, x + mainTex.width * y); } } } }
テクスチャのピクセルを一個ずつ移動しながら処理をしていく形だったので、現在地のカラーを取得→アルファ値だけを改変→反映。という形に変更。
そしてテストプレイ...
うまく動いた!
この時点で峠を越えた感があったので結構うれしかったです。
クリア判定
さてあとはここから消えた面積を測定してクリア判定を作るだけです。
まず最初に思ったのが純粋に平面の面積を出すことができれば楽に判定できるのでは?というもの。
というのも先ほどのテストプレイシーンをよく見てみると、シーンビューにある平面の判定が透明化により消えていってるのが見えると思います。あれ消えた部分はシーンビュー上でクリックしても反応が無いんです。
なので面積を出すコードなりなんなりがあればそのサイズで条件分岐できるのではと踏んで検索検索.........
結論から言うと
ありませんでしたもとい見つけられませんでした
一応似たところでリジッドボディをくっつけてオブジェクトの体積を求めるという記述が見えたので一応やってみたのですが変化なし...
シーンビューでのクリックの判定が消えていくだけであってオブジェクト自体削れてる判定ではないのかもしれません。
そこで別の手を思いつきました。
テクスチャ全体をスキャンするように1ピクセルずつ動いていくならその時ついでにアルファ値調べて判定すればいいのでは?と
いうことでまたコードを改変...
public float ClearParcentage; //エリアの何割を消せばクリア判定に移るか int Check; //指定アルファ値を下回った合計ピクセル数 int mainpix; //メインテクスチャの全ピクセル数 public void Draw(Vector2 p) { Color original; Check = 0; //Drawメソッドが呼ばれる度Checkをリセット for(int x = 0;x < mainTex.width; x++) { for(int y = 0;y < mainTex.height; y++) { original = (Color)buffer.GetValue(x + mainTex.width * y); //Check加算用のif関数がoriginalを使えるように外へ if (original.a < 0.1) //現在地から取得したカラーのアルファ値が0.1を下回ったらCheckを加算 { Check++; } if ((p - new Vector2(x,y)).magnitude < 5) { original.a -= AlphaPercentage; buffer.SetValue(original, x + mainTex.width * y); } } } if (Check > mainpix * ClearParcentage) //チェックにかかった数が全ピクセル数×任意の倍率を上回ったらクリア判定に移行 { ClearCheck(); } } public void ClearCheck() { Debug.Log("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); //クリア判定代わりの発狂 }
色変更の仕組みがテクスチャの全ピクセルスキャンなのをいいことに、そのスキャン中に透明度をチェックする記述を割り込ませてやろうという中々のゴリ押し法。
嫌な予感がするが私の知識では現状どうすることもできないのでひとまず棚上げ。
全体の1%のアルファ値を0.1以下にしたらクリアに設定してテストプレイ...
動いたぁ!^^
思った以上に想定通りの挙動をしてくれたので結構うれしかったが、お察しの通りテクスチャの画素を上げてくと馬鹿みたいに重くなった。
今後改良、というかそもそもの作り方から変えなきゃいけない気がするが、何度も言う通り駆け出しの人間にはこれでも精いっぱいなのでやはり棚上げ。
いい感じの方法が思いついたらまた記事にしようかなと思います。