Three.jsでテクスチャペイントをしよう!
テクスチャペイントを実装できれば何かのスペシャルサイトを作ったときに 手書きでイラストを描いて投稿できたり、メッセージを投稿できたり、オリジナルデザインの車を作れたり・・・いろいろな可能性が膨らみます。■Version1 簡易版 UVテクスチャーペイント
![terrain.jpg](https://qiita-image-store.s3.amazonaws.com/0/59095/d32198d5-2764-8e1b-7334-528c51ec6974.jpeg) (上記のURLはこの簡易版の実装方法でテクスチャペイントを実装し、地形生成を行ったデモです。色が明るいほど地面が盛り上がります。)これはもう単純なものです。
①canvasをテクスチャとして反映したマテリアルを用意
②一時的にuvをそのままピクセルシェーダーに表示させuv値を読み取る
③読み取ったuv値をcanvas内の座標に変換してペイントする
④ペイントされたcanvasをマテリアルに再度割り当てる。
▼!簡易版の問題点
uvの位置にペイントするという性質上、以下の画像のようにuvの島をまたぐ場合ペイントが途切れてしまう。 ![pic1.jpg](https://qiita-image-store.s3.amazonaws.com/0/59095/743e7d48-1f92-ab8c-4e1e-99baec0d8e6c.jpeg)■Version2 改良版 プロジェクションテクスチャーペイント
![pic2.jpg](https://qiita-image-store.s3.amazonaws.com/0/59095/0b915ec3-3089-98b0-ccd5-6d05a7e2d224.jpeg)(左ドラッグでペイント、Alt+左ドラッグでカメラ回転。真ん中に柱状のものがあるのでそこにペイントします)
これは東大・五十嵐健夫教授の製作したchameleonを参考に実装したものです。
(http://www-ui.is.s.u-tokyo.ac.jp/~takeo/chameleon/chameleon-j.htm )
ただこちらの方法をそのまま行うと、
たとえば、以下の画像のように同一メッシュ内でカメラの方向を向いていて なおかつ重なった部分があるとおかしな結果になってしまいます。
おかしな結果というのは本来他のfaceにさえぎられていてペイントされるはずのない部分にペイントされてしまうことです。
以下の方法はそういったおかしな結果にならないように
頂点カラーなどを使用して実装したものです。
▽Step1
①カメラとメッシュの内積を計算してカメラ側を向いているfaceを取得し、それらのfaceをペイント対象とする
② ①で取得したfaceにペイントしたいが カメラ側を向いているもののface同士が重なって本来はカメラからは見えないfaceもある。隠れている部分にはペイントしたくない。それを回避するための仕込みをする。faceそれぞれに違う色の頂点カラーを持たせる。
③頂点カラーを表示した状態で画面をキャプチャしてそれを一時的に保存する。この画像を画像Aとする。
▽Step2
①画面をマウスムーブ・タッチムーブした座標を取得。その座標をそのままcanvasにペイントする座標として使用する。canvasにペイントする。
②Step1の①で取得したfaceのuv座標を、カメラから見たfaceの頂点座標と同じ位置に調整する。
③ ②のfaceの頂点の座標それぞれをuvの座標に移動させる。
④ ③の状態で画面キャプチャーして保存する。
⑤ ③で移動させたfaceの状態で頂点カラーを表示させ画面キャプチャする。この画像を画像Bとする。
⑥Step1の③で保存した画像Aと⑤で保存した画像Bを比べて 色が一致しているピクセルはカメラ側を向いていてなおかつカメラから隠れていることなく見えているピクセルということになる。
⑦ ⑥のピクセルのみに①でペイントしたものを有効化する。