【UV_Painter.cs】オブジェクトの表面のUVの値をとるまずはオブジェクトのUV値をとる方法です。オブジェクトのUV値はtectureCoordで取得できます。レイを飛ばして、ヒットした位置のtextureCoordをとることで、オブジェクトのUV値を取得します。}}このようにUV値を取得できます。レイがヒットした位置のオブジェクトのUV値を取得オブジェクトの表面に色をつける🐼準備をする🐼UV値をとって、その場所に色をつけていきます。Planeを用意し、テクスチャを貼り付けます。次に、ペイントをする対象のオブジェクトにMeshColliderをつけます。MeshColliderじゃないとtextureCoordが値を取得できないみたいです。ConvexやIsTriggerにはチェックを入れないでください。これにチェックを入れると値を取得してくれませんでした。※他のブログでは、テクスチャの設定でRead/Writeにチェックを入れると書いているものや、他にもいくつか設定をしているものもありましたが、Read/Writeにチェックを入れるとRead用・Write用のテクスチャが確保されるため容量が倍になるので重たくなるみたいです。この記事ではテクスチャの設定を変えずにできる方法で書いています。新しくスクリプトを作り、Brushという名前にして以下のスクリプトを貼り付けます。}}次に、UV_Painterという名前のスクリプトを作り、以下を貼り付けます。}}空のゲームオブジェクトを2つ作り、それぞれにそれぞれのスクリプトを貼り付けます。インスペクターを見るとBrushの方はブラシのサイズと色を決めれるようになっています。Brushのサイズと色を決めれるUV_Painterの方は、インスペクタからBrushと色をつける対象のものをドラッグアンドドロップでセットしておきます。Brushとペイント対象のオブジェクトをセットこれで実行すると、こんな感じで絵がかけるおお、いい感じですね。ペンを細くしたらいい感じにペイントアプリっぽいですね。ペン細くしたらこんな感じ可愛いですね。【Brush.cs】ブラシを作るクラスです。Colorの配列の数をブラシの面積分の数にして、そこにインスペクタから設定したcolorを入れています。_paintObj.GetComponent<Renderer>().material.mainTexture.height);スタートでペイントをする対象のオブジェクトにセットしてあるテクスチャと同じサイズのテクスチャ2Dを作ります。0);そのあと、Graphics.CopyTexture()で元のテクスチャをコピーして先ほど作成したテクスチャ2Dに入れています。Graphics.CopyTextureの引数はGraphics.CopyTexture(コピー元のテクスチャ、コピー元テクスチャの要素、コピー元テクスチャのミップマップレベル、コピー先テクスチャ、コピー元テクスチャの要素、コピー先テクスチャのミップマップレベル)です。公式リファレンスはこちらdocs.unity3d.comコピー元テクスチャの要素とコピー先テクスチャの要素は何かよくわかりません。「複数枚のテクスチャを含むテクスチャオブジェクト」を渡してもコピーできるようになってるとかそういうやつっぽいです。ミップマップは簡単に言うと「節約のための機能」です。3Dの場合「遠くのオブジェクト」はサイズが小さくなってあまりわからないものになるので、それをレンダリングするときに真面目にテクスチャを使うのは勿体無いですよね、3Dではテクスチャはリソース的にとても重いので、できるだけ軽く節約したいです。mapレベルを下げて小さいテクスチャを使用し、負荷を軽減するのがミップマップの仕組みです。mapをひとつ下げるとテクスチャは1/4になります。(縦半分、横半分で、1/4)。map2は1のさらに1/4、って小さくなっていきます。ここでは一旦0にしておきます。ここで元のテクスチャをコピーするかというと、お絵かきの流れとしてここで作ったテクスチャ2Dに色をつけたものをテクスチャとして最終的にオブジェクトにセットするので、テクスチャ2Dを作っただけだと元の絵柄は反映されず真っ白な状態になってしまいます。真っ白になる元の絵柄の上に絵を書くために、元の絵柄をコピーして新しく作ったテクスチャ2Dに貼り付けておく、ということです。_tex.height;ここでは、hit.textureCoordでヒットした所のUV座標を取っています。hit.textureCoordでは値が0から1で帰ってくるので、それをテクスチャのサイズ分だけ乗算してピクセルの座標の値に変換しています。_tex;SetPixels()でピクセルを塗り替えます。塗りたいピクセルの範囲y、Color配列);です。pixel.UVから_brush.brushWidth/2を引いているのは、ブラシの中心をタップの位置に合わせるためです。指定した位置から縦と横にピクセルの範囲を塗るので、pixelUV(タップ位置)をそのまま渡してしまうとタップ位置から横と縦にピクセルの色を塗ることになります。タップした位置を真ん中にして色をつけて欲しいので、指定位置を縦と横にそれぞれの長さ半分ずつずらすことで、タップいちを真ん中にして色をつけてくれます。指定する位置をずらしてタップした位置を中心に色が出るようにする最後に_tex.Applyで適用し、ペイント対象オブジェクトのメインテクスチャにセットしています。_tex;ブラシの形を丸くする🐼四角の中に丸を書くブラシの形が四角だと、なんだかペンっぽくないしカクカクして微妙な感じです。これを丸くしましょう。Brush.csの中に少し書き加えます。}}これで実行してみると、黒い四角の中に丸が現れます。黒い四角の中に青いまる丸が作れました。あとはこの黒い部分を透明にすればいけそうです!その前にここまでのコードを解説しておきます。centerの中に入れています。for文の中で、今処理をしようとしているピクセルが、ブラシの真ん中からどのくらいの距離に位置しているのかを求めます。求めるのですが、そのままだとブラシの中のピクセルはただの配列になっていて、真ん中からの距離を求めにくいです。現在処理しようとしているのピクセルの位置をXとYという座標に変換し、真ん中からの距離を求めます。以下の図をご覧ください。4X4のブラシだったとします。描画する順番で0、1、2とピクセルに配列番号が与えられています。1あまり3になります。同じように9番のピクセルを計算してみます。割った答え部分がY軸の位置の値、あまりの数がX軸の位置の値になっています。これをコードにして、以下のようになっています。Mathf.Floor()は少数点を切り捨てて整数部分だけを求める関数です。これで現在処理しようとしているピクセルのXとYの値が求まったのでそれをVector2に格納しています。ポジションB)で求め、距離がbrushWidth/2より小さければ青、大きければ黒にすることで、半径がブラシサイズの半分の円ができます。colorOutSide;}🐼黒い部分を透過するオブジェクトの透過について続いて、黒い部分を透過させていきます。ClolorにColor.clearがあるのでそれでいいんじゃないの?と思うかもしれませんが、それにするとそのまま下の色も透過してしまい、下のUnityデフォルトの地面が見えてしまいます。下の地面が見えてしまいます。いうと、SetPixelsは「その色」に完全に上書きするので、透過しても「その下の色は完全に無視して」上書きします。下の黄色を無視して透過してしまってるため地面が見えてる状態になってるんですね。3DCGでの透過の仕組みは、ディスプレイという平面に出力するときに、アルファ値の値を元に「重なる色を合成して」「新しい色を作って」います。下のテクスチャ(塗る前の色)の上に透過を再現する場合は「前のテクスチャの色」と「塗りたい色」を混ぜる必要があります。Brush.csとUV_Painter.csを以下のように書き加えます。_tex;これで実行してみましょう。//引数を付け足す塗る前の色をColor配列で受け取ります。previousCol[i];丸の外側の色(重ねる側の色)と塗る前の色(重ねられる側の色)を加算することで合成を行なっています。1.0になるので、赤色になりますね。重ねる側の色は黒色にしてあります。_brush.brushHeight);_brush.UpdateBrushColor(col);SetPixels()の前に付け足した部分です。「塗る前の色」を入れるためのカラー配列を作り、そこにGetPixels()でブラシと同じ範囲のピクセルの色を取得しています。配列のサイズはブラシのColor配列と同じ数です。塗りたいピクセル範囲y);です。null)の引数に渡して上げることで、塗る前の色とブラシの色を合成することができます。この一連の流れの後にSetPixels()を実行すると合成された後の丸いブラシが塗られるわけです。オブジェクトが通ったところに色をつけるあとは今クリックしたところに色をつけるようになっているので、オブジェクトが通ったところに色をつけるように変更します。やり方としては、現在タップしたところからレイを出しているのを、オブジェクトから下向きにレイが出るようにします。UV_Painter.csを少し書き換えます。0));これで絵を描く側になるオブジェクトをインスペクタから設定すれば完了です。今回の例ではジョイスティックでキャラクターを動かす仕様にしています。ジョイスティックの実装には以下の記事をご覧ください。www.wwwmaplesyrup-cs6.workこれで無事おまるが通った跡をペイントすることができました。おまるが通った跡をペイントUVの値をとってるので、平面じゃなくてもオッケーです。凸凹した面にもいける!まとめなど実装に関しては以上です。GetPixels()やSetPixels()は重たい処理なのでShaderでやるのが一番良さそうですというのがまとめです(ここまで解説しておいて、おい)。この実装なんですが、端っこの方まで行ってブラシサイズがテクスチャからはみ出すとエラーが出ます。ブラシサイズよりはみ出すとエラーが出るまた、形がややこしいオブジェクトにペイントしようとすると、多分UV展開図の問題でペイントの丸が切れてしまったりとかもします。うまくできないところとかあるこの辺含めてShaderでやる方がうまくいきそうな気がする...誰かいい方法わかる方いたら教えてください!Shaderで試した際にはまた記事にしようと思います。Foundationでマーカーを使用する方法。最近GLSLにハマっているのですが、今回はレイマーチン...2019-06-12【Unity】トレイルレンダラーでオブジェクトの軌跡を描くUnityでオブジェクトに軌跡をつけたい時はトレイルレンダラー!2019-05-27【Unity】Texture2Dの画像から一部を切り抜くTexture2Dの画像から一部を切り抜く方法です。はてなブログProアイドルになりたいと思いながら死んだ顔で仕事をするプログラマー。めーぷるしろっぷをちょんちょんしています。LSDJについての記事を書きます。(1)リンクはてなブログブログをはじめる週刊はてなブログはてなブログProスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。