【東方ゲームジャム2022】アリスのドキドキ人形ラブトレイン

東方ゲームジャム2022に参加しました。 東方好きな人は遊んでみてください。 東方好きじゃない人はなんもおもんないので遊んじゃだめ。

アリスのドキドキ人形ラブトレイン - 東方ゲームジャム 2022

ゲーム内イラストは @milsizk さんに描いてもらいました。ありがとうございます。 公開は9/25までだそうです。

去年の話

モリヤリズムRAINBOW

東方ゲームジャム2021には「モリヤリズムRAINBOW」ってゲームで参加してました。 今はBoothに置いてます。

モリヤリズム RAINBOW - FriendNavy - BOOTH

内容は下記のブログが詳しいです。これもう説明書だろ。ありがとうございます。

www.capriem-touhou.com

かなり面白いものが出来たと思ってるし、べた褒めしてくれる人もいました。 ただし、「真面目すぎたなー」というのが1つ反省点です。 全然ゲームジャムっぽくないんですよこのゲームは。

「天弓千亦服飾店」が賢い

東方ゲームジャム2021では「天弓の継ぎ接ぎに色を当てて他の東方キャラの配色を再現するゲーム」を作った方がいました。

fumakura.hatenablog.com

あの意味分かんない衣装が意味を持ってゲーム性とマッチしてるし、 東方の二次創作であることに意味があるし、 ゲームジャムらしさも有って配信にも映える。 あと楽しい。完璧ですね。

これに感心して「東方じゃないと作れないゲーム」いいなーとなんとなく思ってた。

今年つくったゲーム

今年は冒頭の動画のバカみたいなゲームを作って…今までで一番遊んでもらいました。 他の力入れてるゲームも見てくれよ。

今回はゲームジャム期間の3日目に突然思いつきました。それまでは参加しないでいいかなーと思ってた。 今年は夏休みも明けてたので実作業は3日くらいでした。

データの収集

下記のpixiv百科事典の記事を頑張ってパースしてます。

dic.pixiv.net

C#人間なのでdotnet scriptとAngleSharpでゴリ押ししました。 人間が書く記事なので表記ゆれがあることに注意。気づいたのが締切前日。

↓あほくさ

string NormalizeName(string name){
    return name
        .Replace("・", "・")
        .Replace("二ツ岩", "二ッ岩");
}

これで取れたカップリングタグの検索結果から件数を取得してます。

データの傾向

データが取れたとこでざっと見てゲームが成立しそうか確認しました。 全部で124人いるので組み合わせは7688通り、対して有効なタグは735種類。 「東方ってなんでもカップリングあるから無限に繋がりそう」と思ったんですが意外と少ない。

東方知らなかったら「1割以下の選択を何十回も通せ」という無理ゲーですが、東方知ってると遊べるゲームになる。 すごいね。

うわさ

お相手の数上位はこれだ!

おなまえ お相手の数
博麗霊夢 62
チルノ 49
アリス・マーガトロイド 43
霧雨魔理沙 42
  • 相手が1人だけの「君しかいない!」は9人いるらしいぞ。
  • 実は相手が0人の「誰もいない」が1人いるらしいぞ。

ゲームシステム

最初は「いくつかのランダムな選択肢から一番多い相手を選ぶ」という形で考えてましたが、結果的には全キャラから選ぶ形に落ち着きました。 pixivの検索数という未知の要素に加えてランダムも加わるとかなり運ゲーになっちゃいます。 全部好きに選べる上で使えるカードが減っていく形だと自然と難易度上昇カーブが出来上がってよかった。

ゲームルール自体は単純で、実のところグラフの最長経路問題です。 これを解いて楽しくなれるのは一部の人間だけなので、ただ連結数が増えるだけただ繋がるだけをなんとなく楽しくしたい。 ということで「過剰かな?」くらいの演出を入れてみました。

デケデケデケデケ...デン!!!!!

つなげるたびにプレイヤーを3秒待たせるのはどうなの…?とも思いましたがやってよかったんじゃないかと思います。

出来なかったこと

やりたいけど時間的に間に合わなかったものもあります。

リアルタイム更新

集計データは提出直前の23日夜のもので固定です。 出来ればリアルタイムに件数をとりたかった。

R18作品の集計

今回R18の作品は集計外になってます。 ログイントークンが無いと見れないし検索件数にも反映されない。 そのトークンの生成が面倒。自動化も難しそうだったので見送りました。

本当はえっち率ボーナスとか作りたかった。

理論値を知りたい

ほんとか…? 知りたくて全探索書いたら組み合わせ爆発おねえさんになってしまった。 連結数についてはただの最長経路問題なので適当なソルバーで解けそう。 得点については10連結毎にボーナスが入るのでちょっと複雑。解法あるの…?

おしまい

なんか楽しいものができました。 今までで一番遊んでもらってるし東方ゲームジャムじゃないと作れないゲームが出来たし公式の配信も盛り上がってたし大変満足している。

もっとかっこいいゲームも作りたい。

ゲンソウフロードフロント

そういうわけでゲームができました.
その所感です.

パズルアクションとは

パズルアクションを作りたかったんですが,
1ギミックに1ステージずつ作ってネタ切れになってしまいました.

さらに,慣れるとショトカできる場所があることに気づいてしまい,
途中からショートカット前提のステージを組むようになりました.

f:id:FriendSea:20200105054107g:plain
移動速度やジャンプ力や泡の挙動がベストマッチして偶然三段跳び

そんな感じで最初思ってたのと違うものができてます.
はじめはタイムアタックを実装するつもりもなかった.

タイムアタック

今作のタイムアタックはルート取りを探すゲームです.
ショートカットを見つけたらあとは走るだけです.
なのでタイムをガチガチに詰めるような精度は求めていません.
ちょっとくらい被弾しても間に合います.

しかし猶予をもたせた結果ほかのルートでもギリギリ間に合う場合が出てしまいました.他ルートでノルマに近づけてしまうと更に速いルートの存在に気づきにくくなります.

f:id:FriendSea:20200105063216p:plain
大回りしてもギリ間に合う(あとから気づいた)

あまり苦行じみたプレイをしてほしいわけじゃないので,できるだけ最短ルートに気づいてほしいです.これは最短ルートとその他でもっと絶望的なタイムの差がでるようなステージにすれば解決する気がします.

それと壁抜けがタイムアタックをぶっ壊してます.

壁抜け

開発の途中で気づきましたが壁の接合部分で非常に簡単にコリジョン抜けが起こります.抜け方が悪いとプレイヤーが奥行方向にズレて落下死します.

f:id:FriendSea:20200105072301g:plain
奥方向にズレて死(これは直せた)

これは上下を見て壁があれば止まるようにして対応しましたが,
直しきれないものが何箇所か残っていました.

その壁抜けをプレイヤーが見つけ,その配信を開発者が見て,その頭を抱えるという流れです.

残った壁抜けの原因は単純に水中での移動速度が速いからだと思います.
速いと横の壁にめり込みます.めり込むと壁の有無の判定が効かなくなります.
その結果,上方向の移動が止まらずに抜けます.

f:id:FriendSea:20200105080026p:plain
壁の中にいる

今,横方向の判定も行うようにしてみたら普通に直りました.
公開版は直しませんが.

2Dと3D

このゲームはサクッと完成させるのが目標だったのででできるだけ手間を掛けずに絵を作ろうとしています.

基本的にあまり動かないものは2Dで描いてしまえば良いですが,動きの多いものは3Dモデルを作っています.人によると思いますが,私の場合はモーションが多いプレイヤーキャラなどは明らかに3Dモデルを用意したほうが楽です.

f:id:FriendSea:20200105085221g:plain:w400
ドット絵も少し作ってみたけど手間だからやめた

2Dのタイルマップの上に3Dモデルを置いていますが,そのままだとモデルにパースがかかって変です.パースがかからないように平行投影にすれば解決しますが,今回は奥行きのあるステージで遠くのものは小さく表示されて欲しいのでカメラのパースは必要です.

f:id:FriendSea:20200105090414p:plain
ペーパーマリサ

そこでキャラモデルを全員ぺっちゃんこに潰して対応しました.
ぺっちゃんこのデメリットとして法線方向がぶっ壊れる事が挙げられます.
仕方ないのでリムライトはオミットしてしまいました.残念.

BGM

soundcloud.com

タイトル,ステージ,ボスステージ,ボス戦の4曲です.
でもタイトルとステージはひと繋がりなので3曲だけです.

タイトルとステージの曲は主旋律とドラムパートだけ異なっていて,
ほかは同じ伴奏になっています.
タイトル画面とステージの間の移動に伴ってアレンジが切り替わる感じで遷移します.プレイヤーが水中にいる場合も水中バージョンのアレンジに変化します.

水中での変化は気づいてくれる人が多かったですが,
タイトルとステージ曲がつながっているのはあまり気づいてもらえなかったようです.そもそも同じ曲だと分かりづらかったんだと思います.残念.

f:id:FriendSea:20200105110519p:plain
6chオーディオにして1曲にまとめている

タイトル/ステージ曲のイントロはゴール時のジングルになっています.
ジングルを鳴らしたあとBPMを上げていってタイトル曲につなげてます.
実はゲーム起動直後のタイトル曲はループの終わり際から再生開始している.

ボス戦のBGMにはアウトロがついてます.
ボス撃破と同時に曲が終わるやつです.
4小節毎に遷移可能なポイントがあります.
遷移するタイミングに合わせて6種類アウトロを作りましたがプレイヤーが聞くのは1つだけ.

f:id:FriendSea:20200105111550p:plain
青い線のタイミングを待ってアウトロに遷移

おしまい

つまりうまくできてない点も多かったんですが完成はしました.
僕はこのゲームの続きがほしいです.
初見でやりたいです.無理ですが.

みんなゲーム作ってください.

【Unity】弾幕を張る

見て.弾幕です.

弾幕のgif

これもゲーム制作の副産物を整理したものです.

github.com

弾幕を張りたい

これは人の基本的な欲です.
しかしUnityなどのゲームエンジンでオブジェクトを大量に出すと重いです.
弾にRigidbodyが付いてる場合は特にヤバいです.*1
ドローコールすうも単純に増えるのでヤバいです.*2
そこで大量の弾の当たり判定と描画をまとめて行っています.

つかいかた

シーンにマネージャを置いて弾のデータを作って弾源に参照させる.

マネージャを置く

全ての弾幕を1つのMonoBehaviourから動かしてます.
BulletManagerをシーンに1つだけ配置します.

f:id:FriendSea:20191208163750p:plain

ここでは弾幕が衝突するレイヤーとかを選べる.
Vanish Effectは弾が消えたときに出る弾です.

弾源の設定

GameObjectにBulletSourceコンポーネントを付けてDataに弾のデータを参照すると弾幕ができます. 色は配列になっていて上から順に射出する弾の色が変わります.
OnFireイベントは射出音とかに使える.

f:id:FriendSea:20191208164007p:plain

弾のデータはメニューの
Assets/Create/Bullets/
の中から選んで用意しておきます.

弾のMaterialのシェーダには
Bullets/OpaqueBullets/Transparentを使います.

被弾するもの

IBulletColliderを継承したコンポーネントを付けるとOnBulletCollisionが呼ばる.

using UnityEngine;
using InstancedBullets;

public class BulletCollisionTarget : MonoBehaviour, IBulletCollider
{
    public void OnBulletCollision(BulletBase.Bullet bulletElement, BulletBase bulletData)
    {
        //被弾した!
    }
}

Colliderも要ります,Rigidbodyは要らない.
冒頭のgifではプレイヤーの被弾の他に,弾消しでアイテムが出るのもこれで書いてます.

いろんな弾幕

いろんな弾

なんか加速する弾や曲がる弾があります.
もっと複雑な動きをさせる場合はBulletBaseを継承したスクリプトを用意すれば
UpdateBulletに弾の挙動を書けます.

using UnityEngine;
using InstancedBullets;

[CreateAssetMenu(menuName = "Bullets/CustomBullet")]
public class CustomBullet : BulletBase
{
    protected override void UpdateBullet(Bullet bullet)
    {
        //弾1つに対するUpdate処理
    }
}

弾源を書く

インスペクタなどでBulletBaseを参照してAddBulletを呼ぶと弾を出せます.

using UnityEngine;
using InstancedBullets;

public class CustomBulletSource : MonoBehaviour
{
    [SerializeField]
    BulletBase data;

    private void FixedUpdate()
    {
        //画面奥に赤い玉を撃つ
        data.AddColorBullet(transform.position, Quaternion.identity, Vector3.forward, Color.red, transform, 1f);
        //色は指定しなかったら白, 親は指定しなかったらnull,スケールは指定しなかったら1.0
        data.AddBullet(transform.position, Quaternion.identity, Vector3.forward);
    }
}

やってること

当たり判定

弾の数だけClliderを用意するとしんどいのでPhysics.OverlapSphereNonAllocで行っています.
物に当たった弾は無条件で消えるようにしているので現状はグレイズなどは取れません.

描画

Graphics.DrawMeshInstancedを使って多数の弾をまとめて描画しています.
MaterialPropertyBlockを使って弾ごとに色を変えられるようにしています.

おしまい

今の所これで困ってないですがもうちょっと分かりやすくしたいです.
ParticleSystemみたいにコンポーネントのインスペクタで設定が完結するようにしたい.

*1:必要ない場合が多いですが地形に当たった弾が消えてほしい場合などは必要

*2:これはマテリアルをGPU Instanciongに対応させれば勝手にまとめてくれる

【Unity】なんでもReorderableList

Unity Editorではシリアライズされた配列のインターフェイスとしてReorderableListが使われている部分があります.
これが便利なので全部ReorderbleListで編集できるEditor拡張を書きました.

f:id:FriendSea:20190727184006p:plain

面倒なのでAttribute等も用意せず無条件で置き換えます.

ソースコード

これをEditorフォルダに入れれば動きます.
思ったよりシンプルになってくれました.

配列ぜんぶReorderableListにする

やってること

MonoBehaviourやScriptableObjectを含むUnity.ObjectのEditorを書き換えてます.

[CustomEditor(typeof(UnityEngine.Object), true)]

第2引数にtrueを渡すと派生クラスにも適用されるので全てのインスペクタ表示が変わる.

あとはシリアライズされているプロパティを1つずつ拾っていき,配列ならReorderbleListで, そうでなければデフォルトのPropertyFieldで描画しています.

ReorderbleListを利用した拡張の書き方についてはこちらのページが参考になります.

anchan828.github.io

ReorderableListは同じインスタンスを利用し続けないと要素の選択ができないので,
OnEnableのタイミングでインスタンスの生成とコールバックの登録を行っています.
あと,ReorderbleListに渡したSerializedPropertyにNextVisibleなどを呼ぶとバグります.
Copyしてから渡しましょう.

配列の入れ子

今回の拡張では一番外側の配列のみReorderableListになります.
内側はデフォルトのまま.

f:id:FriendSea:20190727190314p:plain

一応これは

[CustomPropertyDrawer(typeof(System.Object), true)]

なPropertyDrawerで同様の実装をすればReorderableListになってくれるはずです.[要検証]
今のところ必要になっていないので書いてません.

Shaderで顔を動かそう

久々の更新ですが今回はいつも以上に利用機会が少なそうな話です.

f:id:FriendSea:20190615030833g:plain

製作中のゲームでようやくキャラクタの表情を動かせるようになりました.
ざっくり紹介します.
つまりこれの続き

friendsea.hateblo.jp

Blend Shapeでの表現がちょっと難しかったので代わりにシェーダを使っています.

Blend Shapeによる表情

3Dのキャラモデルの顔を動かす方法としてBlend Shapeが利用されることが多いですね.
私が使っているBlenderでもシェイプキーを作ってUnityにインポートすることができます.

ただ当然ですがBlend Shapeを使うとメッシュの頂点数が変わる編集ができなくなります.
やろうと思うとシェイプキーをすべて作り直すことになる.
また,ミラーモディファイアも利用できなくなるのでモディファイアなしで左右対称な編集を行う必要があります.

この殆ど取り返しがつかない感じがとても嫌だ.

目を動かす

目をシェーダ内で合成

今回は顔のパーツを描いたテクスチャを用意して合成します.
昔から使われている手法のようです.

スクウェア・エニックス モバイルオープンカンファレンス | SQUARE ENIX (1つ目の資料)

上の資料の例では目を作るために瞼,眉,瞳,ハイライトなどを別々に描いていますが,
今回はテクスチャ内でも形が見えるようにしたかったので瞳以外は重ねて描いてます.

f:id:FriendSea:20190615113719p:plain

チャンネル毎にパーツの形の領域を指定しています.

領域
R-1
G-1 上まぶた
B-1

値がひっくり返っているのは白目部分を白く描きたかったからです.

UV座標について

瞼や眉のテクスチャと瞳のテクスチャで,それぞれ別のUV座標を使ってサンプリングしています.
瞼はキャラクタ毎のテクスチャの一部として描いているのに対して,瞳は共通で1つのテクスチャを利用しています.
瞳のUV座標はUV2として書き出してもいいのですが,今回は頂点カラーのRGチャンネルを使ってます.
左右のどちらの目かをメッシュデータに持たせる必要があるので,そこでBチャンネルを使うためです.

ハイライト

瞳のハイライトはテクスチャには描かずに,Shader内で生成しています. 光源方向に応じた位置にハイライトを乗せることが可能になります.
また,半目状態でもハイライトが隠れてしまわないように移動させたりなんかもできます.

f:id:FriendSea:20190615134522g:plain

テクスチャの変形

表情を作るためにテクスチャを変形します.
チャンネル毎にサンプリングする際にUV座標をオフセットすることでテクスチャをズラします.
alphaは基本的に乗算ですが上瞼の領域は必ず描画されるようにしています.

f:id:FriendSea:20190615140548p:plain

瞳の位置,つまり視線もこの方法で動かしています.

また,瞳用のUVを利用して適当な関数を利用すればもう少し複雑な変形も可能です.
例えば,瞬きでは円弧の関数をv座標に足すことで上に凸の瞼を下に凸に変えています.

f:id:FriendSea:20190615142142p:plain

口を動かす

口の開閉

口を動かす場合,口角の上下などは目と同様に変形させれば良いですが,
口の開閉はあまりうまく表現できなさそうです.
そこでアルファクリップの閾値の変化によって動かすことにしました.

f:id:FriendSea:20190615143533p:plain

口の閉じた形と開いた形を決め,その間をグラデーションでつなぎます.
このテクスチャをブレンドを行わずにアルファクリップで描画し,
しきい値を[0, 1]で動かすことで口が開閉します.

f:id:FriendSea:20190615144643g:plain

口が横から見えるようにしたい

アニメとかでよくある表現です.よく見ると怖いですね.
単純に口のポリゴンを視線方向に少し回して表現しました.

f:id:FriendSea:20190615145555p:plain

割と強引なことをしているので角度によっては稀に変な見え方になっちゃいます.
もともと立体として破綻しているものを表現しようとしているので
仕方ないかもしれないけどそのうちなんとかしたい.

パラメータの制御

Shaderで顔が動かせるようになりました.マテリアルのパラメータを動かすことで顔が動きます.

f:id:FriendSea:20190615150755p:plain

でもコレをランタイム中に動かすわけには行きません.
動かすと異なるパラメータを持った新たなマテリアルとして別インスタンスができてしまいます.
そのため,Material Property Blockを利用してRenderer毎にパラメータを指定しています.

UnityEngine.MaterialPropertyBlock - Unity スクリプトリファレンス

パラメータは個別に動かすとしんどそうなのでScriptableAssetとして表情のセットを作っています.
これを呼び出す処理をStateMachineBehaviourやアニメーションイベントから呼び出すことでモーションに応じた表情に遷移可能です.

f:id:FriendSea:20190615151729p:plain

おしまい

というわけで顔が動くようになりました.
シェイプキーを作りたくないという理由でこのような方法をとっていますが,
正直あんまり変わったことをすると思わぬところでトラブりそうな不安もあります.

組んだコードはかなり汎用性が低くなったので公開などできませんが,
ブレンドシェイプに親を殺された方やアレルギーのある方は同じようなことをしてもいいかもしれません.

uGUIの上で本をめくる

ゲーム内のUIで本をめくりたくないですか?
僕はめくりたかったんです.

f:id:FriendSea:20181228202146g:plain

github.com

本みたいなUI

製作中のゲーム(ゲンソウファインダー)では手帳をイメージしたUIが出てきます.
なので設定画面などの遷移ではページを捲りたかったのですが,面倒だったので今までは現在の画面が退出して別の手帳がスライドインしてくるという謎仕様でした. それがやっと本来やりたかった見た目になったんです.

f:id:FriendSea:20181229031627p:plain

(いつまで2018秋のつもりなんだ?)

使い方

BookUI

まず見開きサイズとなるRectTransformを配置して,その子オブジェクトとして必要な見開きの数だけUIを横につなげて配置します.
親の方にBookUIアサインして実行すればUIがよしなに変形されて本の形に整うはずです.開いてるページはBookUI.CurrentPageで操作できる.

f:id:FriendSea:20181229034015p:plain

UI要素を横方向に並べるときはHorizontalLayoutGroupが便利.

PageSelector

BookUIと同じオブジェクトにアサインすれば動きます.本の中のUI要素が選択されたとき,その要素のあるページを開くようにBookUI.CurrentPageを更新するやつです.

BeseMeshEffectと頂点シェーダ

見ての通り本の形への整形では頂点を動かす必要があります.uGUIの場合BaseMeshEffectを利用することで描画時にメッシュを編集することができます.
ただ,当然ですが渡されるメッシュはローカルな座標空間でのものです.しかし今回は本を基準とした本座標系(今名前つけた)で変形をを行いたい.これをBaseMeshEffectで行おうと思うとUI要素毎にそれぞれローカル座標系と本座標系の変換行列を用意する必要があります.
一方で頂点シェーダに渡される頂点はCanvas内での位置であり,どのオブジェクトでも共通した座標系となっています.これは多分バッチ処理で複数のメッシュをまとめて描画するために全体で共通した座標系を使っているのでしょう.今回もこれが好都合で,ローカル座標系(Canvas座標系にまとまる)と本座標系の変換行列が全体で共通の1つで済みます.

f:id:FriendSea:20181229044058p:plain

というわけで結局シェーダを使って変形してます.

テッセレーション

メッシュは頂点単位で折り曲げられています.だから折り目近くに頂点がない場合グシャってなっちゃう.
というか変なとこで貫通して来たりします.

  f:id:FriendSea:20181229052247p:plain

だったらテッセレーションみたいなことをして頂点を増やせばいいよね.これはローカル座標系で処理でる上に,全体に適用する必要もないのでBaseMeshEffectを使って実装しました.
ページの背景みたいに大きな要素や折り目部分にまたがっている要素にアサインしてます.

問題点

張り切って作ったんですが結構扱いづらい点が多いです.

マウス/タッチで操作できない

UIのポインター系のイベントはraycastで対象のオブジェクトを取ってます.頂点シェーダで変形してしまうと,Raycast targetには影響がないので正しく選択できません.
固定されたUIでページを捲って本の中では絵を見せるだけなら平気ですが,本の中のUIを操作したければキーボードやコントローラでカーソルを移動することになります.

Maskを使えない

uGUIのMaskの下に本を置くと何故かカスタムシェーダのいくつかのパラメータが初期値に固定されます.なんで?(不服)
具体的には変換行列がIdentityに固定されてしまうのでまともに動いてくれません.
シリアライズされないパラメータが初期化されちゃうのかな?」と考えてMatrix4x4が2つの代わりにVectorを8つ与えると正しく変換できました.アホくさ.
でも今度は現在のページを指定するパラメータが固定された.なんで?
結局Maskは諦めて普通に行列与えてます.

負のスケールを使えない

UI要素のXかYのスケールを負にすることで画像などを反転させて利用できます.でも今回のシェーダはCullBackしてるので無理です.
負のスケールにすると裏側のページに現れちゃいます.

おしまい

本ができたよ.ドンドン使っていきたいね.
正直Maskが使えないのはかなり痛いですが運用でカバーしような.

ゴリ押しキャラモデル

これみて.かわいいよね?

f:id:FriendSea:20181213205553p:plain

東方projectの二次創作ゲームを作ってます.その主人公のモデルです.
モデリングはあまり得意ではないので色々妥協してこんな見た目になってます.

デフォルメ

極端にデフォルメしたキャラクターを使っています.私の好みも理由の1つですが,色々な面でごまかしが効きやすいというのも嬉しい点です. 頭の比率が大きいのであまり胴や四肢に拘らないで済むだろうという考えです.2.5頭身だと初めから人の形をしていないので多少おかしな造りをしていても違和感を感じにくいですね.
例えば腕は完全に六角柱です.

f:id:FriendSea:20181213212830p:plain

でも髪と手のモデリングは難しかった.
頂点数は少なめで作っています.これは別に描画負荷的な話ではなく,頂点が多いと収拾がつかなくなって僕の手に負えなくなるからです.なめらかな曲面が欲しかったらBlenderの細分化に任せてる.

シェーディング・テクスチャ

テクスチャ

テクスチャが描けない!
でもトゥーンシェーディングならそういうのもありだよね.ほとんど部位ごとに単色で塗っただけのテクスチャを使ってます.

f:id:FriendSea:20181213220858p:plain:w400

UV展開も簡単.

シェーディング

シェーダは基本的にアウトラインとリムライトと1段階の陰だけです.髪に使うマテリアルだけはMatcap的なマッピングのマスクを使ってハイライトを足してます.

f:id:FriendSea:20181213221301p:plain

ちょっと情報量少ない気もしますが背景の情報量も少なめで揃えれば気にならないかな?

陰マップ

東方のキャラはフリル多いよね.でも作りたくない.
そこでテクスチャのアルファチャンネルに,その部分を陰にする基準の閾値を書き込んでいます.つまり,どのくらい陰になりやすいかを表したマップです.これをシマシマにしてフリルってことにしてる.

f:id:FriendSea:20181213222047p:plain

顔の描画

顔のモデリング難しい.これには色々理由があるけど,1つは顔の部品の配置と輪郭の編集を同時に行う必要があるためだと思っています.どっちもきれいに見える状態でメッシュを繋げないといけない.見栄えのいい顔を作ろうと思うと顔が平たくなりがち.でも横スクロールのゲームだから横顔も見えて欲しいな~.

f:id:FriendSea:20181213230019p:plain

輪郭と顔は完全に別々に作ってます.ただ,顔が見えるように輪郭の表面に乗せてしまうと角度によっては顔が浮いてるのが見えてしまいます.
実際には顔の殆どを頭の中に埋めてしまってシェーダで少し手前に移動させて描画しています.

f:id:FriendSea:20181213230741p:plain

目や口が手前に出てくれるので,ついでに目や眉が前髪を貫通してたり横顔で口が見えたりみたいなアニメ的な表現もできます.

ウェイトペイント

難しすぎ.特に肩.
よほどうまくウェイトを塗らないとすぐにおかしなことになる.(むしろ人間の肩の可動範囲がおかしい)
背面ポリゴンでアウトラインを出しているのでメッシュがクシャってなるとかなり見た目が悪くなります.
胴と腕と手は完全に分離しました.ブレンドしません.スーパーマリオ64で見た.

f:id:FriendSea:20181213232246p:plain

テクスチャがないのでメッシュが連続していなくてもそんなに気にならないと思います.
膝や肘はウェイトをブレンドしてますが2-Bonesのみで,ループを1つ入れるだけにしています.

f:id:FriendSea:20181213232834p:plain

綺麗に変形させようとすると本当に手に負えなくなる.

揺れもの

髪とスカートが揺れます.胸はありません.
モーションを手付けするにしても物理演算の設定を組むにしてもボーンが多いと難しくなるので,できるだけ少なくしています.
具体的には髪に1つ,スカートで4つです.

f:id:FriendSea:20181213233847p:plain

今のところすべてのキャラで同じような構造になってます.髪やスカートが長いキャラも居ますが,なにか不思議な力でフワフワさせておきました.

f:id:FriendSea:20181213234129g:plain

この動きは頂点シェーダで作ってます.

おしまい

ツイッターとか見ているとここ1年でモデリングをする人が増えた気がします.彼らが完成度の高いモデルを作っているのを見るとヒエ~ってなる.特にもともと絵が上手い人は何の誤魔化しもない良いモデルをいきなり出してくる.神絵師は何をやっても神.