ゲーム「ゆかりん症候群」用にVoxelキャラの表情を変更したい!
普通の3Dモデルと同じだろうけど・・・まずモーフかテクスチャかの方法だけど、
Voxelキャラにモーフは無理、口とかないしするとテクスチャしかないですね!
調べてみると、下記のような資料が見つかりました。
■第17回_プレゼン資料(Unityはじめるよ~フェイスアニメーション~)
表情をテクスチャで実装する資料 ※リンク
■「だいしブログ」
VoxelキャラのUV展開等を説明いただいた方がいらっしゃったので
大変参考になりました!
「だいしブログ」
http://github.dev7.jp/b/2016/07/16/mgopt/
こちらの資料以外にも参考にした資料がありますが、
主に参考となって資料は上記になります。
また、Voxelモデルで表情作成までの流れを記載しますが、
他のモデルでも実装できるかと思います。
※今回紹介の方法がベストとは限りませんし、問題があるかもしれませんが・・・
さて今回、テクスチャで表情変更する方法ですが
「第17回_プレゼン資料(Unityはじめるよ~フェイスアニメーション~)」でも記載のある「1枚の画像に複数の表情を配置するUVアニメーション」で実装していきます。
まずは表情を適用する顔部分だけのメッシュ作成の為、MagicaVoxelで顔のみをPLY出力します。
ここから「だいしブログ」様からの情報をなぞらえる箇所が多くなります。
PLY出力したデータをBlenderでインポートします、必要に応じてサイズ等を変更します。
表情を適応するメッシュのみにするため、編集モードで余分な頂点を削除します。
ついでに、ツール→重複頂点を削除 も行います。
次にUVを展開するため、画面左メニューの「シェーディングUV」から
「UVマッピング」→「展開」→「スマートUV投影」を行います。
展開する際にはメッシュを全選択しておいてください。
画面上の「ScreenLayout」を「UV Editing」に切り替えます。
画面左下の「新規」から新規テクスチャを作成します。
サイズは「1024*1024」となっており、大きいので縮小します。
正直どれくらいが正しいかは不明なので、「128*128」で作ってみます。
このサイズが表情ひとつ分のサイズになります。
サイズが小さいとUnityで表示させた際に、ぼやけたりするのかな・・・?
作成したら「画像」ボタンから「画像を別名保存」します。
次に画面上の「ScreenLayout」を「Defaoult」に切り替えます。
画面右側のメニューから「カメラアイコン」を選択、メニュー最下部の「ベイク」から
ベイクモードを「頂点色」に変更して、「ベイク」ボタンを押します。
再度「ScreenLayout」を「UV Editing」に切り替えて、
テクスチャに焼きこまれていたら上書き保存してください。
また、不要な頂点色を削除するため、
メッシュ上で、スペースキーを押して、「頂点色を削除」を検索して実行します。
次に「ScreenLayout」を「Defaoult」に戻して
画面右側のメニューから「マテリアルアイコン」を選択、
「新規」ボタンを押してマテリアル作成します。
「テクスチャアイコン」を選択して、先ほどのテクスチャを、アタッチします。
アタッチには「新規」ボタンの横の「テクスチャアイコン」を押して、
先ほど作成したテクスチャを選択します。
が、出てきませんでした・・・
そこで新規ボタンを押して、タイプに「画像または動画」を選択
メニュー下から「画像」項目の「開く」から、先ほど作成したテクスチャを開きます。
この状態で、「FBX形式」でエクスポートしておきます。
また、先ほどの色を焼き付けたテクスチャが、表情1つ分ということで
そのテクスチャを編集、サイズを大きくして、他の表情をタイリングします。
今回テスト用に適当な画像を用意します。
タイリングは左上からの順として、顔の向きはそのままとします。
出来れば回転させたいですが、メッシュの向き?と合わなくなって変になります。
現状では我慢!
次はUnity側の対応になります。
Unityを起動して、出力したFBXと表情テクスチャを読み込みます。
Scene上に該当のFBX 顔メッシュを配置し
適用されているマテリアルには、上記の表情テクスチャを適用させます。
表情を変更する為に、スクリプトを適用します。
「FaceChanger」とでも名前を付けて、顔メッシュにアタッチしてください。
親のオブジェクトではなく、「MeshRenderer」を持つ子のオブジェクトです。
スクリプトの内容は下記となりますが、
こちらは資料「第17回_プレゼン資料(Unityはじめるよ~フェイスアニメーション~)」を自分用にいろいろ変えております。
また正直これがベストな方法かはわかりません・・・素人なもので・・・
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
public class FaceChanger : MonoBehaviour { private struct TextureInfo { public float TextureWidth; // テクスチャの幅 public float TextureHeight; // テクスチャの高さ public float TileWidth;//タイル1つ分の幅 public float TileHeight;//タイル1つ分の高さ public float TileNumX; //タイルシートの数(x 列数) intにすると以降の計算で少数が消えるのでNG public float TileNumY; //タイルシートの数(y 行数) } private struct AnimationInfo { public Material Mat; // マテリアル public Vector2 OffsetUV; // 参照するUV座標 public Vector2 OffsetUVSize; // UV座標から切り出すサイズ } public Renderer Rend;//レンダラー public Vector2 TextureTileSize;// テクスチャ内の一つのタイルサイズ private TextureInfo _TextureInfo;// 画像情報 private AnimationInfo _FaceInfo;// アニメーション情報 public int FaceNo; void Awake() { //マテリアルを取得 _FaceInfo.Mat = Rend.material;//マテリアル格納 //テクスチャ情報の格納 Texture texture = _FaceInfo.Mat.mainTexture;//マテリアル中のテクスチャ格納 _TextureInfo.TextureWidth = texture.width;//テクスチャサイズ幅 _TextureInfo.TextureHeight = texture.height;//テクスチャサイズ高さ _TextureInfo.TileWidth = TextureTileSize.x;//テクスチャ上のタイルサイズ幅 _TextureInfo.TileHeight = TextureTileSize.y;//テクスチャ上のタイルサイズ高さ _TextureInfo.TileNumX = (int)(_TextureInfo.TextureWidth / _TextureInfo.TileWidth);//タイル数計算 _TextureInfo.TileNumY = (int)(_TextureInfo.TextureHeight / _TextureInfo.TileHeight); //UV情報の格納 _FaceInfo.OffsetUV = new Vector2( 1.0f, 0.0f);//初期値 //タイル一つ分のUVサイズ 切り出しに使用 _FaceInfo.OffsetUVSize = new Vector2( 1.0f / _TextureInfo.TileNumX, 1.0f / _TextureInfo.TileNumY); //表情変更 //ChangeEyeType(FaceType.f_2); } void Update() { ChangeEyeType();//ChangeEyeType(FaceType.f_1); } public void ChangeEyeType()//FaceType type { // テクスチャ上のタイル座標を求める _FaceInfo.OffsetUV.x = (int)(FaceNo % _TextureInfo.TileNumX);//タイル番号X _FaceInfo.OffsetUV.y = (int)(FaceNo / _TextureInfo.TileNumX);//タイル番号Y _FaceInfo.OffsetUV.x *= _TextureInfo.TileWidth;//タイルX座標 _FaceInfo.OffsetUV.y *= _TextureInfo.TileHeight;//タイルY座標 // UV座標計算と更新 _FaceInfo.OffsetUV.x = _FaceInfo.OffsetUV.x / _TextureInfo.TextureWidth; _FaceInfo.OffsetUV.y = 1.0f - (_FaceInfo.OffsetUV.y / _TextureInfo.TextureHeight); _FaceInfo.OffsetUV.y -= _FaceInfo.OffsetUVSize.y; //テクスチャ反映 _FaceInfo.Mat.SetTextureOffset("_MainTex", _FaceInfo.OffsetUV); _FaceInfo.Mat.SetTextureScale("_MainTex", _FaceInfo.OffsetUVSize); } } |
内容は単純に「FaceNo」をテクスチャ上の参照するタイル番号として
タイル番号からテクスチャ上の位置XYを割り出し、
XY座標をUV座標の 0.0f ~ 1.0f に計算し直して、マテリアルに反映しております。
実際に動作を見てみますと・・・
分かりにくいと思われますが、「FaceNo」を変えることで変化しております。
これを「Update」などで、切り替え続けることでアニメーションもできそうですね。
ちなみにクエリちゃんも表情はテクスチャであるとのことで、
同様のスクリプトで切り替えることもできました!
・クエリちゃん公式サイト
http://www.query-chan.com/
さて表情となる顔部分は出来ましたが、本体モデルとどう合体させるかですが
資料「第17回_プレゼン資料(Unityはじめるよ~フェイスアニメーション~)」では
モデルの手前に置くことで対処しておりますが、クエリちゃんモデルを見ると
顔部分がくり抜かれた状態であることがわかります。
ので、自分も顔部分を取り除いたモデルで対応したいと思います。
顔の部分はBlender上で、面を選択して、面削除などを行います。
あとはUnity上でモデルを読み込んで、位置を合わせて子要素にして完成です!
長くなりましたが、これで表情つきのキャラが作れますね!
※その他参考資料
http://blog.livedoor.jp/akinow/archives/52169431.html
http://blenderfaq.blender.jp/oldfaq/tips/hyoujou-no-animeshon-wo-tekusucha-no-kirikae-de-hyougen-suru
http://yukuto.net/blog/201512blender_material_and_texture_for_unity/
http://krlab.info.kochi-tech.ac.jp/kurihara/lecture/cg/BlenderWeb_Hayashi/html/materialAndTexture.html