読者です 読者をやめる 読者になる 読者になる

Onoty3D

Unityに関するメモとか

高崎柚乃ちゃんのBlendShaperをGUIで操作する

Unity 高崎柚乃

高崎柚乃ちゃんには、表情の変更用にBlendShapeが設定してあるのですが、SkinnedMeshRendererが細かく分割してあるため、インスペクタ上でそれぞれの値を変更するのがけっこう大変です。

というわけでGUIで変更できるようにするスクリプトを作りました。

f:id:onoty3d:20170227010123g:plain

プロ生ちゃんで使っているやつをいじった感じです。
高崎柚乃ちゃんのモデルにセットすれば、各パラメータは空のままでも実行時に自動でSkinnedMeshRendererを探しに行きますが、うまくいかない場合は手動で各パラメータに該当するSkinnedMeshRendererをセットしてみてください。

f:id:onoty3d:20170227005803p:plain

BlendShapeValueChangerYuno

© Gugenka from CS-REPOERTERS.INC/YUNO

クリエイティブ・コモンズ・ライセンス
この作品は クリエイティブ・コモンズ 表示 4.0 国際 ライセンスの下に提供されています。

高崎柚乃ちゃんを触ってみる

Unity 高崎柚乃

先日Gugenkaさんから高崎柚乃(Takasaki Yuno)ちゃんというフリー(商用利用無料)のかわいい3Dモデルが公開されました。

https://gugenka.jp/original/yuno-3d.php

f:id:onoty3d:20170226115056j:plain

日本で企業から公開される3DモデルというとMMDが先行するイメージが強いんですが、このモデルのフォーマットはMA形式とFBX形式で、しかもおすすめシェーダがユニティちゃんシェーダと、Unityでの使用をまずメインにしたような感じで公開されています。

目もMMDで定番の「コッチミンナ」モーフを前提とした凹んだ白目ではなく球体!いいね!

というわけでさっそくUnityに取り込んでみることにしました。

取り込み

MA形式とFBX形式はどちらもそのままUnityに取り込み可能ですが、前者はMayaがインストールされている必要があるようです。
自分は持ってないのでFBXのみをインポート。

インポートすると1モデルに付きエラーと警告が1つずつでます。

f:id:onoty3d:20170226115324p:plain

エラーはアニメーションのタイムレンジが上限超えてるよ、的な。
警告はScale Compensationが云々。とりあえず無視。
これらが出ても、モデル自体は取り込めているようでした。

見た目

とりあえずぐるりと見てみたんですが、ごっそりはみ出てる!!!

f:id:onoty3d:20170226115841p:plain

f:id:onoty3d:20170226115856p:plain
下着がショートパンツやブラウスを突き破ってます。

これは
・上着状態にしたいときは下着を非表示
・下着状態にしたいときは上着を非表示
にすればとりあえず気にならなくなります。

しかし、公式サイトには「ショートパンツからはみ出る下着や脇のラインを堪能しろ」とありますし、公式立ち絵ではブラウスからブラの紐をチラチラさせているので、やはり本来同時表示させるべきものらしく、バージョンアップで改善されるとのことです。
ちなみに上着も下着も非表示…も可能。

<2017/02/28追記>
上記突き抜け問題は、特に改善の必要はないようです。
上着状態にしたい場合は、下着すべてを非表示にするのではなく、bra_hiでグルーピングされている側のみを非表示にすれば良いとのこと。
これで上着を突き抜ける部分のみが非表示になり、裾からチラリと見える部分はのこされるので、公式サイトに書かれているこだわりポイントは維持できます。

 

f:id:onoty3d:20170228001946p:plain

f:id:onoty3d:20170228002112p:plain

Rigの変更

取り込んだ状態のまま、RigをGenericからHumanoidに変更しようとすると、Unityが落ちます(5.5.1f1)。
いきなりフッと落ちるのでどうしたものかと思いましたが、取り込み時にアニメーションがエラーを出していたのを思い出し、AnimationsのパネルからImport Animationのチェックを外した後、改めてRigをHumanoidに変更するとうまく出来ました。

f:id:onoty3d:20170226115816p:plain

 

とりあえずまずはここまで。

これからアニメーション適用させてみたり、表情モーフなんかを見ていきたいと思います。

f:id:onoty3d:20170226115732g:plain

© Gugenka from CS-REPOERTERS.INC/YUNO

クリエイティブ・コモンズ・ライセンス
この作品は クリエイティブ・コモンズ 表示 4.0 国際 ライセンスの下に提供されています。

 

パラパラ漫画風プロ生ちゃん

Unity Asset Image Effect プロ生ちゃん

プロ生ちゃん Advent Calendar 2016と関係なく書く気でしたが、7日目が空いていたので7日目の記事とします

qiita.com

さて、さっそく本題に入ります。
UnityにCamera Filter Packというイメージエフェクトが300超も詰まったアセットがあります。

色味の調整等基本的なものから、ドット絵化、古いビデオのような表現、雨だれの表現、血しぶき表現、複数カメラの融合等々、思いつく限りのエフェクトが詰まったようなアセットです。

紹介動画

www.youtube.com

ドキュメントはWEBで公開されているので、実際にどんなエフェクトがあるか見てみてください。
Introduction - Camera Filter Pack 3.x for Unity 5.x - Documentation (c) Vetasoft 2016

その中に紙に描いたようにモデルを描画するPaperというエフェクトがあるのですが、特にPaper2というエフェクトが、ノートに書いた絵のように見せるエフェクトで面白いです。

f:id:onoty3d:20161207141306p:plain


また、様々なエフェクトをGitHubで公開されている高橋 啓治郎さんの作品のひとつに、パラパラ漫画風に見せるFlipBookというエフェクトがあります。

github.com

デスノートの映像に使われたのだとか。

 このふたつを組み合わせれば、ノートに書いたパラパラ漫画風に見えるかな、ということで、やってみました。

下準備

GitHub - keijiro/FlipBook: Flip book effect example for Unity
から、FlipBookのエフェクトをZipでダウンロードし、展開します。

展開できたらUnityを起動し、Openボタンで展開したFlipBook-masterフォルダを選択し開きます。
Unity5.5で開く場合、警告ダイアログが出るかと思いますが、そのままContinueで問題ありません。

f:id:onoty3d:20161207142142p:plain

エディタが起動したら、プロ生ちゃんの3DデータCamera Filter Packもインポートします。
以上で準備完了です。

準備が終わったら、まずはSceneを選択します。
SceneはAssets>Test配下にTestという名前であります。
そのまま実行してみると、GitHubで公開されているような画を見ることができます。

キャラクタの置き換え

もともとのキャラクタはMazeLowManという名前で、Sceneオブジェクトの下に居ます。
なので同じ位置にプロ生ちゃんのPrefabを配置します。

f:id:onoty3d:20161207142227p:plain

プロ生ちゃんはお好みのPrefabで構いませんが、シェーダーはToonのやつを使うと、アウトラインが出やすいです。
適当に位置をずらして、ついでにMazeLowManが利用していたKarateのAnimationも拝借して適用しましょう。

f:id:onoty3d:20161207142410p:plain

MozeLowManと周りを飛び交っていたパーティクルは利用しないため、Removeするか非表示にします。

カメラの設定

シーンにはカメラが2つあります。最終的な結果を描画するカメラと、キャラクタを映すカメラ。
ここでは後者を編集します。
後者のカメラはやや深い部分にあります。

f:id:onoty3d:20161207142453p:plain

MazeLowManをコミック風に見せていたエフェクトのContour、Obscurance、Binaryは今回利用しないので、Removeするか、チェックを外します。
新たにCamera Filter PackのPaper2エフェクトを適用します。

f:id:onoty3d:20161207142549p:plain

プロ生ちゃんの線がはっきり出るように、Paper2のパラメータを調整します。
Paper2のパラメータ以外に、プロ生ちゃんの各MaterialのMain Colorの色を明るめにしたほうが線が出やすいかも。

f:id:onoty3d:20161207142600p:plain

いざ実行

こんな感じになりました。

f:id:onoty3d:20161207143131g:plain

Main CameraのMotionスクリプトのMultiple Frame Blendingの設定をいじると、よりパラパラ漫画っぽく見えるかもしれません。

コーディング不要なので、是非是非試してみてください。

 

幼生(おさなま)ちゃん -プロ生ちゃん幼女化-

Unity スクリプト プロ生ちゃん

プロ生ちゃん Advent Calendar 2016、4日目の記事となります。

qiita.com

やること

以前、むにむに教授の動画でユニティちゃんを幼くする、というものを見ました。

www.youtube.com

この動画を見た時点では、自力での実装は無理だなと思っていたのですが、
最近になってメッシュの頂点を直接移動させる技も覚えてきたので、プロ生ちゃんを対象に挑戦してみることにしました。

題して「幼生(おさなま)ちゃん」。
では早速やっていきたいと思います。


顔の実装

動画では、変化後のメッシュの頂点位置が片対数グラフみたいになっていました。

f:id:onoty3d:20161204105122p:plain
(ユニティちゃんの顔がやばい)

変化させたい座標軸の始点の座標を0、終点の座標を1として、途中の点の座標を全体の長さの割合として見立てた場合に、以下の数式で変化させたら上手く行くかな、と思ってまずはそれで実装してみました。
b=a^n
もともとの座標(割合)をa、変更後の座標(割合)をbとする
nは可変パラメータf:id:onoty3d:20161204111106p:plain
nが大きくなるほど、座標は始点側に近づいていく。

この実装でnを変化させてみた場合、このような動きになりました。
・キューブの座標に適用してみた場合
f:id:onoty3d:20161204105640g:plain

・メッシュに適用してみた場合f:id:onoty3d:20161204105800g:plain

これが幼女化の第一歩です。

で、顔のメッシュに適用させてみた場合。f:id:onoty3d:20161204111219g:plain
なるほど幼くなりました!

体の実装

これができれば、あとは体を小さくさせていくだけ。
体型変化についてはネットでググるといろいろとデータが出てくるので、今回はここのデータを参考にさせていただきました。

子供の年齢別・平均体重と平均身長・座高データ(年度別平均表):スクスクのっぽくん | :スクスクのっぽくんスクスクのっぽくん

サイトのデータを参考に、座高を上半身、身長-座高を下半身の変化と見立てて、変化させていきます。
顔と同じようにメッシュの頂点操作をまずは考えたのですが、腕の角度やら何やらを考えるのが大変だったので、ボーンのスケール変更でやってみることにしました。

親ボーンのスケールを変更すると、子ボーンも同様にスケールが変化しますが、この時親ボーンに対して子ボーンに角度がついてると偏った変形になります(Y方向を半分のスケールにしたいのに、子は親に対して垂直についているため、X方向が半分になってしまう、みたいな)。
なので、親ボーンのスケール変更→子ボーンのスケールを一旦戻す→子ボーンのスケール変更…みたいな感じで実装しました。
これに関しては、テラシュールブログさんを参考に、lossyScaleを利用して対応しています。

tsubakit1.hateblo.jp

で、出来上がったのがこれ。

f:id:onoty3d:20161204111733g:plain

体の発育データを参考にしているため、変化は一様ではなく、15歳くらいからゆるやかになります。

f:id:onoty3d:20161204113101p:plain
(体の発育をデータ打ち込みしてるとき、なんか妙に変態な感じがしたんですが気のせいだろう。)

単純に全体のスケールを一様に小さくした場合との比較。f:id:onoty3d:20161204113206g:plain
ただ小さくなっているだけの左とは違い、ちゃんと幼くなっている感じがします。

問題点

一連の実装法の場合、ポーズの変更をしなければとりあえず破綻しません。
ただ、ポーズを変えると妙な具合になります…。

f:id:onoty3d:20161204112126p:plain(頭が歪んでいる…)

先述の、親ボーン・子ボーンの関係と三軸のバラバラスケーリングのせいです。
これに関しては、スケール(年齢)を変更する前にポーズを決定し、そのポーズでスケールを変更すればきれいになります。

f:id:onoty3d:20161204112256p:plain
なので、とりあえず今回は観賞用の幼女といった実装になりますでしょうか…。

この辺を上手くクリアして、揺れものの設定とかもサイズに即したものに変化するようにすれば、ゲームとかでも使えるかもしれません。
実際はこうやってモデル側にボーンモーフ・頂点モーフ的に組み込むのが楽そうな気がします。

以上、プロ生ちゃん幼女化でございました。
最後に年齢変化のシーンと今回作ったスクリプトを公開しておきます。
シーンはUnityPackage、スクリプトは単体で同梱しています。

UnityPackageおよびスクリプト


プロ生ちゃんの3Dモデルは含んでおりませんので、プロ生ちゃんの3Dモデルを含むプロジェクトに本UnityPackageをインポートすると、動くはずです。
最新のUnity5.5でエクスポートしたので、Unity5.4以前にうまくインポートできるかは不明です。

クエリちゃんのご当地フォトコンテストに参加してました

クエリちゃん

先々月から先月にかけて、クエリちゃんのサイトでご当地フォトコンテストというコンテストが開催されていました。
日頃からクエリちゃんにはハチャメチャさせてもらっているの(※)で、是非とも参加せねば!という思い出参加させていただきました。

ところで以前にも、ご当地SDクエリちゃんコスプレ案コンテスト
2015年ご当地SDクエリちゃんコスプレ案コンテスト | クエリちゃん公式サイト
というコンテストがあったのですが、この時自分は大分のクエリちゃんをデザインし、見事ご当地大将という賞を頂くことが出来ました。多謝多謝…。(ちなみに自分は福岡在住ですが、生まれ育った土地は大分なのです。)

 さて、今回のコンテストは、ご当地の写真を撮りそこにクエリちゃんを絡めて応募する、というもの。

あまり遠出しない自分は、持ち合わせの写真も福岡のものがほとんどだったので、今回は福岡をテーマに応募することにしました。なかでも、いちばん写真を多く撮っている太宰府をテーマに…。

そしていざ、いい写真を選定しようとして困りました。
応募用紙に貼り付ける写真は横長のサイズ指定だったのですが、自分は最近スマホメインで写真をとっているため、縦長写真ばかりなんです。

もちろんそこから横長にトリミングすることも可能でしたが、それでは被写体の一部しか見せることが出来ません。今から改めて写真を撮りに行くにも、太宰府の見どころの梅が咲く季節はとうに過ぎている…。

そして編み出した奇策が、縦長写真を3枚組み合わせるというもの。
奇策でしたが、3枚1セットにすることで1枚では表現しきれいない魅力を詰め込められたと思います。

そうして作られた1枚、そこに普段使っているUnityを使って、大好きな福岡クエリちゃんを普通にその場にいるかのように混ぜ合わせました。
この混ぜ合わせ作業は非常に楽しかったです。うまく影を載せて、枝に隠れる用にして…。

 コスプレ案コンテストの時は、締め切りギリギリになってしまったので、フォトコンテストは早めに応募しました。
早めに応募すると奇策も早々にバレてしまうので、結果は高望みできないだろうと思っていたのですが、結果は…

2016コンテスト 入賞作品一覧 | クエリちゃん公式サイト

なんと大賞を頂いてしまいました!

本当にびっくりしました。
結果を受けた日は、一日にやにやしていました。
3枚1セットにしたことや、クエリちゃんを混ぜ合わせたこともコメントで言及していただき、嬉しい限りでした。

あらためて、大賞に選んでいただき、ありがとうございました!
これからもクエリちゃんで変なこといろいろ遊ばせていただきたいと思います。

uGUIのテキストエフェクトを作ってみたりした

Unity スライド

Unity Fukuoka 12に参加して、前回に引き続き登壇しました。

atnd.org

前回はShaderネタでしたが、今回はuGUIのテキストエフェクトネタ。
とりあえずやってみて覚えたことを発表してみました。

スライド内にAnimation GIFを盛り込んだため、SlideShare上で再生してもそこは動きません。
ちゃんと内容を見るにはダウンロードしたほうがいいかも…。

www.slideshare.net

 

本スライドで紹介したTypeface Animatorはとっても便利なアセットで、コードもとてもお勉強になるので、是非興味がある方は購入してみてください。

 

 

Particleの動きを制御して、Trailで文字を書く

スクリプト Unity Particle

Unity5.5から追加されたParticleのTrailsモジュールで遊んでいた時、
Particleの動きを制御すればTrailで文字が書けたりするかな?と思ったのでやってみました。
f:id:onoty3d:20161115195659g:plain

Particleの動きの制御はVelocityOverLifetimeモジュールで行えますが、事前にキーを打ってCurveを作るのは大変です。
そこで、まずマウスで手書きで文字を書き、その時のカーソルのXY座標の変化をVelocityOverLifetimeにセットして文字を書くことにしました。

VelocityOverLifetimeの制御の仕方は以下QAが参考になりました。
answers.unity3d.com

VelocityOverLifetimeでのX,Y各軸の速度変化はMinMaxCurveというクラスのインスタンスをセットすればいいみたいですが、
インスタンス生成時にAnimationCurveを渡してやれば、それがそのままCurveになります。

AnimationCurveのキー追加方などは以下Qiitaの記事が参考になりました。
qiita.com

とりあえず動かせるサンプルを作ってUnityPackageにしてみました。
UnityPackage

Unity5.5b11で作成しています。
新規にシーンを作ってPrefabを投げ込んで実行すれば確認できると思います(背景は暗くしたほうがいいかも)。
実用するにはカメラの位置、角度なんかも考慮する必要がありそうですが、今回は簡易な実装になっています。

ただ文字を書くだけならLineRendererなんかで十分ですが、Particleにすれば設定によっては複数発生させたり、
変形操作もできたりして楽しい気がします。
f:id:onoty3d:20161115200251g:plain

以下ソース

using System.Collections.Generic;
using UnityEngine;

namespace Onoty3D
{
    public class HandWriteCurve : MonoBehaviour
    {
        //操作するパーティクル
        public ParticleSystem TargetParticle;

        //座標を取得するFrame間隔
        public int CaptureRate = 6;

        //セットするMinMaxCurveのMultiPlier値
        public float CurveMultiPlier = 1.0f;

        //座標のリスト
        private List<Vector3> _posList = new List<Vector3>();

        // Use this for initialization
        private void Start()
        {
        }

        // Update is called once per frame
        private void Update()
        {
            if (Input.GetMouseButtonDown(0))
            {
                this._posList.Clear();
                this._posList.Add(Input.mousePosition);
            }
            else if (Input.GetMouseButton(0))
            {
                if (Time.frameCount % this.CaptureRate == 0)
                {
                    this._posList.Add(Input.mousePosition);
                }
            }
            else if (Input.GetMouseButtonUp(0))
            {
                this._posList.Add(Input.mousePosition);

                this.SetCurve();
                this.TargetParticle.Play();
            }
        }

        private void SetCurve()
        {
            var interval = 1.0f / (this._posList.Count - 1);

            var curveX = new AnimationCurve();
            var curveY = new AnimationCurve();
            curveX.AddKey(new Keyframe(0, 0));
            curveY.AddKey(new Keyframe(0, 0));

            Vector3 delta;
            for (int i = 1; i < this._posList.Count; i++)
            {
                delta = this._posList[i] - this._posList[i - 1];

                curveX.AddKey(new Keyframe(interval * i, delta.x));
                curveY.AddKey(new Keyframe(interval * i, delta.y));
            }

            var module = this.TargetParticle.velocityOverLifetime;
            module.enabled = true;
            module.x = new ParticleSystem.MinMaxCurve(this.CurveMultiPlier, curveX);
            module.y = new ParticleSystem.MinMaxCurve(this.CurveMultiPlier, curveY);
        }
    }
}