2016年9月4日日曜日

【MayaLT2017】HumanIKのポーズを反転するMEL

MayaLT2017で歩行など左右で同じポーズを使うモーションを作成する際、反転コピー機能が欲しくなったのでMELの勉強がてら作ってみました。(探せばありそうですが)
標準で入っている HumanIK のリグを前提としています。

●使い方
 ・シェルフ等にスクリプトを登録して反転コピーしたいリグを選択し、実行。

●仕様
 ・片側選択して実行すると片側のみの反転コピーになります。
 ・両側選択して実行で左右入れ替え状態となります。

●注意
 ・全身を反転させるときは IKリグ(関節部分の赤や青のボックス)と FKリグ(オレンジのボックスやライン) の両方を選択してください。範囲選択ではIKのみしか選択されないようです。
  (HumanIKのUIのなにもない所をクリックするとIKもFKも 全選択/解除 できます。)
 ・部分的に実行するときはIKブレンド率にも注意
 

●MEL



global proc MirrorPose()
{
    print( "\n------------ Start MirrorPose() ------------\n" );
    
    string  $allObjects[];
    string  $obj;

    $allObjects = `ls -sl`;               // 選択中のオブジェクトリスト
    int $nAllObjects = size($allObjects); // 要素数
    
    // 退避テーブル
    float $rotX[];
    float $transX[];
    float $rotY[];
    float $transY[];
    float $rotZ[];
    float $transZ[];
    
    // 選択対照の情報を退避
    if( $nAllObjects == 1 )        // 一つ
    {
        $transX[0] = `getAttr $allObjects.translateX`;
        $transY[0] = `getAttr $allObjects.translateY`;
        $transZ[0] = `getAttr $allObjects.translateZ`;
        
        $rotX[0] = `getAttr $allObjects.rotateX`;
        $rotY[0] = `getAttr $allObjects.rotateY`;
        $rotZ[0] = `getAttr $allObjects.rotateZ`;
    }
    else if( $nAllObjects > 1 )   // 複数
    {
        $transX = `getAttr $allObjects.translateX`;
        $transY = `getAttr $allObjects.translateY`;
        $transZ = `getAttr $allObjects.translateZ`;
        
        $rotX = `getAttr $allObjects.rotateX`;
        $rotY = `getAttr $allObjects.rotateY`;
        $rotZ = `getAttr $allObjects.rotateZ`;
    }
    
    // ポーズ反転処理
    for ( $cnt = 0; $cnt < $nAllObjects; $cnt++ ) 
    {
        $obj = $allObjects[$nAllObjects - $cnt - 1]; // 逆順で入ってるみたい?
        $isLR = false;
        print ($obj + " -> ");
        
        // 選択対象の名称置き換え
        if( `gmatch $obj "*Left*"` )
        {
            $obj  = substituteAllString( $obj, "Left", "Right" );
            $isLR = true;
        }
        else if( `gmatch $obj "*Right*"` )
        {
            $obj  = substituteAllString( $obj, "Right", "Left" );
            $isLR = true;
        }
        else if( `gmatch $obj "*_L"` )
        {
            $obj  = substituteAllString( $obj, "_L", "_R" );
            $isLR = true;
        }
        else if( `gmatch $obj "*_R"` )
        {
            $obj  = substituteAllString( $obj, "_R", "_L" );
            $isLR = true;
        }
        else if( `gmatch $obj "*_l"` )
        {
            $obj  = substituteAllString( $obj, "_l", "_r" );
            $isLR = true;
        }
        else if( `gmatch $obj "*_r"` )
        {
            $obj  = substituteAllString( $obj, "_r", "_l" );
            $isLR = true;
        }
        print ($obj + "\n");
         
        
        // 選択反転
        select -r $obj ;
        
        // 座標
        move ($transX[$cnt] * -1) $transY[$cnt] $transZ[$cnt];
        
        // 回転
        if( `gmatch $obj "*Effector"` ) // IK?
        {
            // IK
            rotate ($rotX[$cnt] * -1) ($rotY[$cnt] * -1) $rotZ[$cnt];
        }
        else
        {
            // FK
            
            if( $isLR ) // 対照リグ?
            {
                if( `gmatch $obj "*Arm"` )
                {
                    // 腕
                    rotate $rotX[$cnt] $rotY[$cnt] $rotZ[$cnt];
                }
                else if( `gmatch $obj "*Shoulder"` )
                {
                    // 肩
                    rotate $rotX[$cnt] ($rotY[$cnt] * -1) ($rotZ[$cnt] * -1);
                }
                else
                {
                    // その他
                    rotate ($rotX[$cnt] * -1) ($rotY[$cnt] * -1) $rotZ[$cnt];
                }
            }
            else
            {
                // その他(胴体など)
                rotate ($rotX[$cnt] * -1) ($rotY[$cnt] * -1) $rotZ[$cnt];
            }
        }
    };
    
    print( "------------ End MirrorPose() ------------\n" );
};

2016年7月4日月曜日

「第3回UE4札幌Meetup!!!」 のスライドを公開しました。

前回に引き続き、2016/07/02 札幌で行われた 「第3回UE4札幌Meetup!!! (https://nfglabo.doorkeeper.jp/events/46882)」 で登壇しました。
今回はセルシェーダについてお話させていただきました。


Grayちゃん


【第3回UE4札幌Meetup!!!】 UE4で実装するセル表現 from Tomohiro Ogiwara


スライド内にも埋め込んでありますが、今回の発表のために30秒ほどの短い動画を制作しました。
シーケンサはほぼ初めてですがとても使いやすく、楽しかったです。



まだUE4のセルシェーダは詰められると感じているので、今後も研究していこうと思っています。

今回は関西からわざわざ alwei さんが来て登壇していただいたり、VR体験が出来たりとなかなか良いイベントになったのではないかと思います。



2015年12月27日日曜日

近況とC89告知

まずは近況報告から。
前の記事で書いたように、アンリアルフェスでぷちコン作品が展示され、
ぷちコンの最優秀賞をもらいました!プレイして下さった方はありがとうございます!

それにちなんで、11/28に行われたUE4札幌Meetupで登壇とかしたりしてました。


さて、いよいよ年末が近づいてきましたが年末といえばコミケですね。
ぷちコン用に作成した 「跳霊の剣」 ですが、その後も継続して制作を続けてました。
まだ完成には程遠いのですが、今回の冬コミでは体験版 (v0.2.0.0) を頒布することにしました。
完成した暁にはDL販売などができたらな~と思っています。

C89 告知用動画



以下詳細です。

頒布日時: 3日目 12月31日(木)
頒布場所: 東ヤ-35b
サークル名: OGMF工房
作品名: 跳霊の剣
頒布予定価格: 100円


興味がある方は是非!よろしくお願いします~

2015年10月14日水曜日

【UE4】第4回UE4ぷちコン応募作品「跳霊の剣」がアンリアルフェスで展示されることになりました!

株式会社ヒストリア様主催の「第4回ぷちコン」に応募しました。

開催概要

応募作品動画:「跳霊の剣」



審査の結果、ありがたいことに全57作品の中から選ばれ、予選を通過8作品の中にノミネートされました!
これにより、10/18日に開催される 「UNREAL FEST 2015 YOKOHAMA」 の会場にて展示していただくことになりました!

ノミネート作品は会場にてユーザ投票が行われるらしいので、会場に行く方はよろしければ投票をお願いします~!僕も北海道から行きます!


会場に展示して貰う予定のインストカードです


作品について


今回のテーマ「反射」の発表された後、比較的早めにゲームの方向は決まりました。
前回はぎりぎりまで内容に悩んでしまって実作業に割ける時間が殆ど無くなってしまったため、今回は一度決めたら後からアレコレとあまり考えないようにしました。

システム


敵の射撃を反射するという被りそうなシステムでしたが案外ガッツリ被ってるという感じはなかったですね。
 反射することに気持ちよさを感じてもらいたかったのでヒットストップを入れ、いつでもステップで行動をキャンセル出来るようにすることでスピード感も出したつもりです。
 また、プレイヤキャラに射撃を持たせないことで反射する価値を上げました。

キャラ


アセットはキャラをはじめ大体は自作となっています。
キャラは前回同様にセル調で、このブログでも記事にしたやり方をベースに作っています。

ちょっと古いスクリーンショットなのでデザインがかわってますが…

背景


背景については前回、審査員の方に言われた反省を活かし、キャラのセル調に馴染むような画面作りをしたつもりです。

 工夫した点は背景に使用するモデルは手塗り感があるようなアセットを配置し、
ポストプロセスではUE4備え付けの色調の調整、被写界深度、フォグをかけています。
その他の自作ポストプロセスとして、別途色調補正、エッジ、フレア、ディフュージョン的なものをかけています。もしかしたら処理的には結構重いかもしれません。
 
 また、ディレクショナルライトを複数配置し、キャラのセルマテリアル専用のライトとステージのライティング用のライトを設置しています。

ポストプロセスなし

ポストプロセス入

エフェクト


斬撃のエフェクトは「ゲームグラフィックス2015」に掲載されていた、某爆乳ハイパーバトルのやり方を参考にさせてもらいました。
 実際に使用した画像はグレースケール化してあり、UE4内のマテリアル設定で色を変更できるようにしました。
ボスとプレイヤの斬撃エフェクトに使っています
斬撃

 敵出現時の壁のエフェクトはノイズテクスチャのスクロールと閾値を使用して作りました。
このエフェクトは壁の他、HP/SPゲージのUIにも使いまわしています。
敵出現時の壁

UI

 敵の出現、殲滅時の煙は3Dの球体で作っていて、これにセルマテリアルを適用したものをパーティクルエフェクトにして使用しています。
敵の出現エフェクト

カメラ


 カメラはプレイヤが不快にならないように処理を組みました。
基本的に注視点を進行方向が見やすいように少し進行方向にずらし、橋の上ではカメラの位置を若干上の方から見下ろすようにしました。
意識しないとあまり気づかない気がしたのであえて書かせてもらいました。

右向き

左向き

橋の上


今後


 今後はさらなるブラッシュアップとシステムの作り込み、ステージの追加を行っていくつもりです。
もし受かっていれば年末のコミケで頒布できればいいな~と思っています。

ひとまず、アンリアルフェスではヨロシクお願いします!m(_ _)m


2015年8月29日土曜日

【UE4】ポストプロセスボリュームの自分用設定メモ

UE4は最初の状態でもポストプロセスがかかっているため、何も考えずにオブジェクトを配置するだけでもそれなりの見た目にはなるようになっているのですが、最初から出したい色や見た目がある場合には想定したのと違ってしまったりします。

僕の場合、テクスチャの色は出来るだけそのまま出したかったり、AOはいらなかったりするので、デフォルト設定に比べてポストプロセスの効果を少なくする方向で調整しています。

各プロパティの詳しいことはよく理解してなかったりするのですが、プロジェクトを作りなおすたびに設定を忘れるので備忘録として書くことにしました。
(項目の詳しい説明は公式を見ると良いと思います)

PostProcessSettings

Film
     Crush Hilights:1.0 
          彩度や輝度が抑えられてしまう?

Scene Color
     Vignette Intensity:0.0
          画面まわりが黒っぽくなる

Bloom
     Intensity:1.0~2.0
          明るい部分の光の拡散

Auto Exposure 自動露光(MinとMaxを同じにすることで固定)
     Min Brightness:1.0
     Max Brightness:1.0

Lens Flares
     Intensity:0.0 
          明るい光が出た時にレンズ的な演出が入る

Ambient Occlusion
     Intensity:0.0 
          セル調の場合などに不要な陰が入ってしまう

Motion Blur
     Amount:0.0 
          軽くかけるくらいならいいと思います

Misc
     Blendables 
          自作ポストプロセス


上記以外はデフォルト(チェックを外した状態)で使用しています。

2015年5月14日木曜日

【UE4】第3回UE4ぷちコンに応募しました

ヒストリア様主催の「第3回UE4ぷちコン」に応募しました。


【開催概要】
http://historia.co.jp/ue4petitcon03

【提出作品:「RejectionHammer」
https://www.youtube.com/watch?v=6qVMYu9K3ts
【応募作一覧】
http://historia.co.jp/archives/2575


 発表当初から参加することは決めていたのですが、ゲームの内容考えていたら結局作業に入れたのは締め切り5日前というありさま。最終日までは3Dも2Dも素材を全く作っていないという状況でしたw

動画を見ればわかると思いますがまだ完成しているわけではないので今後も続けて制作し、なにかしらの形で発表できれば、と思っています。

はじいてはじける!


せっかくなので簡単に技術的な部分の解説を。

●ルック

ディフュージョン:背景の建物に空の色が滲んでいる
法線の平均化:キャラの髪の陰が凹凸に影響されていない
 今回、ルックは敵とプレイヤをセルルック、背景はラインのみ描画しています。
セルルックについては以前の記事で説明しているのとほぼ同じものを使っています。

 今回はじめて実装した部分としては、UE4側でのキャラ法線の平均化、画面全体へのデュフュージョン、画面上部への青みがかったフレアを追加してます。
長くなりそうなので実装方法は割愛します。

●敵の管理


ゲーム中のWave

Mapエディタ上での敵管理用のBPアクタ
 ウェーブ形式で敵が出てくるのでマップにそのまま配置するのは効率が悪いので敵を管理するブループリントをステージ内に配置しました。
 敵管理BPのConstructionScript内で敵のポップ座標に番号を振り、エディタ側で座標番号と敵の種類を指定します。
一番下のチェック用関数を実行すると、敵の出現位置の番号がピンク色に変化する

ひとつ前の画像のStagePopDataを展開したところ。
Waveごとのテーブルに座標番号と敵クラスを指定する
 あらかじめ敵管理クラスを作っていたので提出2時間前までほぼ敵を配置してない状態でも何とかなりました……



●まとめ

こういうコンテストに参加したのははじめてで、心残りがないわけではないですが楽しく製作出来ました。またこういうのがあれば参加してみたいですね。

5月下旬ごろに結果が発表されるらしいので、なにかしらの賞に入れればいいな~


2015年4月3日金曜日

【UE4】セルっぽいルックを頑張ってみる その4(エッジ)


エッジについてです
【最終ルック】

 上の画像は左のキャラとそれ以外の部分で、2通りのエッジの付け方を使っています。

 キャラの方は、モデリングの段階でポリゴンを法線方向に拡大し、面を反転してエッジとしています(バックフェース法というらしいです)。
この方法の特徴としては、

  • モデリング時にリアルタイムで調整ができる
  • ポストプロセスが不要なのでモバイル/HTML5環境でも使える
  • 実装が簡単
  • 輪郭の表現はできるが、凹凸部分の表現ができない
  • カメラとの距離によって画面上の線の太さが変わる
  • メッシュの交差時に表示が不自然になる場合がある
  • 頂点数が2倍近くになってしまう


 それ以外の部分はポストプロセスを使い、オブジェクトの深度を表すデプス値と面の向きを表すノーマル(法線)の値を参考にエッジの検出を行っています。
特徴は

  • 輪郭以外の凹凸に対しても線の描画が可能
  • ポリゴンが平面でもノーマルマップがあればエッジをつけることができる
  • カメラの位置にかかわらず画面上の線の太さが一定
  • 機械的に検出するため、意図しない位置に線がでる場合がある
  • ポストプロセスがない環境(モバイルなど)では使用できない

といったところでしょうか。

 既存のタイトルを見ると、ハイエンド向けだからポストプロセスとかというわけではなく、それぞれの特徴を考えて選択しているみたいで、両方を同時に使っているタイトルもあるようです。

 バックフェース法は単にモデリングして表示するだけなので、ここではポストプロセスでの実装方法を中心に説明したいと思います。

●ポストプロセスによる実装


【エッジ検出BP】
エッジを検出するBPの全体像です。

 デプスと法線からラインとなる場所を検出し、距離により表示の有無を判断したあと最後にカスタムデプス以外の部分を表示するようにマスク処理を行っています。
 パラメータで線の太さ、密度、色、表示距離の調整ができるようになっています。


●デプスでの輪郭検出


それぞれの処理を個別に見ていきます。

【デプスの値を色として描画】
 デプスは3D空間上でのカメラからの距離がピクセルごとに数値として入ってるので隣接するピクセルの差が大きいと、空間として前後に離れていることになるので輪郭となります。

【デプスによる輪郭検出】
左キャラはカスタムデプスで対象外にしているので表示されません

【ラプラシアンフィルタっぽいもの(デプス)】
 デプスでの輪郭検出には上下左右のピクセルの平均をとって、中央のピクセルとの差分を算出しています。本来は3x3の周囲8ピクセルでやるみたいですが上下左右の4ピクセルでもさほど問題なさそうだったので4ピクセルのみでの処理にしています。
 ここで算出した値に閾値を設定してラインの検出をすることになります。

上のBPで使用している指定ピクセルのデプス値を取得する関数は以下のようにしました。

【ピクセルデプス取得関数】
InvSizeには1/Sizeの値が入ってくるのでそこから1ピクセルあたりのUV値が求まります。



●ノーマルでの凹凸検出


デプスの値だけではオブジェクトの輪郭しか検出できないのでディティールが足りません。
なのでディティールを加えるためにノーマルを利用して凹凸の検出を行います。

【ノーマルベクトルを色として描画】
RGBがそれぞれXYZに対応しています
ノーマルは面の向きを表しているので、周囲のピクセルのノーマル値つかって尖っている部分や凹んでる部分を判断します。

【ノーマルによる検出】

【ラプラシアンフィルタっぽいもの(ノーマル)】
 基本的にはデプスでやっていることと同じです。ただ、ノーマルはXYZの3つの値が入っているので一度色情報に対応させてから輝度に変換することで1つの値にして差分を計算しています。
 

【ピクセルノーマル取得関数】
使用している指定ピクセルの取得関数もデプスからノーマルに変わっただけです。


【輝度の算出】
輝度の算出です。定数はPhotoshopなどで使われている、人間の感覚に近づけるための値……らしいです。


●エッジ消失距離


 上記2つの処理でエッジの検出と描画は可能となったのですが、このままだと天球に同心円状のラインが入ったり、カメラを引いた時に線の密度が高くなって潰れてしまいます。
 その対策として、デプス、ノーマル、それぞれ個別に線が消える距離を設定できるようにしました。

【エッジ消失距離】
ピクセルデプスの値を元に、設定された距離以上の値は0となるように計算しています。
この計算結果をそれぞれのエッジ検出処理の結果に乗算することでマスクしています。

【カメラを引いた時の比較(拡大画像)】
左:全部の線を描画すると線同士が詰まりすぎてしまっている
右:ノーマルでのラインを消し、デプスによる輪郭だけ描画することでスッキリさせた

●画像への合成


 最後にシーンの画像と乗算合成し、カスタムデプスによるマスクをかけます。

【シーン画像との合成】
線の色は一律で加算し、Clamp関数を使ってつけています。

【カスタムデプスによるマスク関数】
カスタムデプスマスク関数はカスタムデプス内の色とカスタムデプス外の色を指定して対応した色を返します。
 今回はカスタムデプス外にのみ、エッジラインを足した色が出るようにしています。



以上です。



 ここまででセルルックに必要なことはひと通り説明したつもりなので、セルルックに関しては今回までにするつもりです。またなにかネタができたら追記していきます。
 実際のアニメっぽくするにはもっと画面にフィルタをかけたりしてなじませる必要があると思いますが、ココらへんはちょっと勉強不足なもので……。

【とりあえずディフュージョンっぽく……?】