2018年5月4日金曜日

Blender上でMIDIファイルを読み込み3Dモデルの鍵盤を動かすpythonスクリプトに挑戦したこと



昔取り組んだことについての忘備録

作成日

2016/8/7

目的

  • MIDIファイルの仕様の理解
  • BlenderとPythonの学習

内容

MIDIファイルのバイナリを読み込んで解析し、ノートオン、ノートオフ情報に従って、対応する音階の鍵盤オブジェクトのトランスフォームにキーを打ち込みます。

感想

4/4拍子でテンポ120、分解能が480だった場合、1秒が960分割されます。鍵盤を連打する場合、鍵盤のオンオフが960分の1秒で起こる可能性があり、24fpsや30fpsでは同フレームで鍵盤のオンとオフが上書きされ、鍵盤が押しっぱなしになる、もしくは音が鳴ってるのに鍵盤が動かないという状況がよく起こりました。
キーを打つ前に鍵盤の状況を判定し、必要であれば直前のフレームに戻ってキーを打つ処理が必要になります。




2017年3月26日日曜日

【Unity5】キャラモーションをリミテッドアニメにする  ~ 再生フレーム指定編 ~

前回のボーントレース編に続き、今回はアニメーションクリップの再生位置を指定する方法でリミテッドアニメ化してみます。

使う素材は前回と同じく、プロ生ちゃんの【PronamaChan_Ver3.unitypackage】 と、スタンダードアセット【Characters】 に入っているアニメーションクリップ【HumanoidRun】 です。インポート方法は前回記事を参照してください。
※Unity 5.5.2f1 (64-bit)を使用しています。




キャラクターを準備


【PronamaChan】 > 【Prefabs】 > 【Normal】 > 【Standard】
にある、【PronamaChan_dynamic】を【Hierarchy】に配置。

【Standard Assets】 > 【Characters】 > 【ThirdPersonCharacter】 > 【HumanoidRun】にある
【HumanoidRun】を【Hierarchy】の【Pronamachan_Dynamic】にドラッグ&ドロップ。

プロ生ちゃんが走り去ってしまわないように
【PronamaChan_dynamic】の【Inspector】 > 【Animator】の【Apply Root Motion】のチェックを外しましょう。

今回のスクリプト【LimitedAnimationByPlayClipFrame.cs】


【project】に【C# Script】を新規追加し、「LimitedAnimationByPlayClipFrame 」という名前に変更、ダブルクリックしてファイルを開き、下記の内容に書き換えて保存。

【LimitedAnimationByPlayClipFrame.cs】
using UnityEngine;
using System.Collections;
public class LimitedAnimationByPlayClipFrame : MonoBehaviour
{
       //各要素1フレームとして、-1は更新しないフレーム、それ以外の数字は描画するフレーム位置を指定
       public int[] timesheet = new int[] { 0, -1, -1, -1, -1, 5, -1, -1, -1, -1, 10, -1, -1, -1, -1, 15, -1, -1 };
       private Animator m_animator;
       private AnimationClip clip;
       private int animationHash;
       void Awake()
       {
              //アニメーションクリップの情報をゲット
              m_animator = GetComponent<Animator>();
              clip = m_animator.GetCurrentAnimatorClipInfo(0)[0].clip;
              animationHash = m_animator.GetCurrentAnimatorStateInfo(0).shortNameHash;
              m_animator.speed = 0;
       }

       void LateUpdate()
       {
              if (IsDrawFrame(Time.frameCount))
              {
                     DrawAnimationFrame(timesheet[Time.frameCount % timesheet.Length]);
              }
       }
       //アニメーションクリップの指定時間のフレームを静止再生
       void DrawAnimationFrame(int drawFrame)
       {
              //アニメーションクリップの長さを1とした時のフレームの位置
              float normalizedtime = ((float)drawFrame / clip.frameRate / clip.length);
              m_animator.Play(animationHash, 0, normalizedtime);
       }
       //ポーズを更新するフレームかどうかチェック
       bool IsDrawFrame(int checkFrame)
       {
              if (timesheet[checkFrame % timesheet.Length] >= 0)
              {
                     return true;
              }
              return false;
       }

実際、アニメーションクリップは複数あったりするものですが、今回は実験なのでアニメーションクリップは一つだけの想定のスクリプトになってます。
結果、あまり汎用性がないのでご注意ください。

このスクリプトを【Hierarchy】の【Pronamachan_Dynamic】にアタッチし、
【Inspectr】の【Timesheet】に使用するフレームの情報を入力します。
【Size】はループするフレーム数と思ってください。以下【Element】が各フレームで、値がアニメーションクリップのフレームナンバーです。

【-1】はポーズの更新なし、つまり前の絵のままのフレームです。
【0】以上の値はフレームナンバーで、元のクリップのフレーム数より大きい値も入ります。
10フレームしかないアニメーションクリップで15と入れたら、5フレーム目が使われます。
ちなみに今回使ったアニメーションクリップ【HumanoidRun】は【clip.framerate】が「30」で長さ【clip.length】は「0.593」なので、フレーム数換算で19程度です。

もちろん数字を順番に入れる必要はないので、唐突に違うフレームを差し込んだりできます。

これで再生してみると、スカートなどの揺れ物以外はコマ落ちして再生できます。
この方法とボーントレースを組み合わせて、両者の欠点を補えれば・・・。

2017年3月25日土曜日

【Unity5】キャラモーションをリミテッドアニメにする ~ボーントレース編~

Unityのキャラクターの動きのコマを抜いて、リミテッドアニメにしてみます。

  • 【方法1】 アニメーションクリップの再生フレームを指定する
  • 【方法2】 任意のフレームで、フルアニメーションするキャラのボーントランスフォームを複製する

【方法1】は、アニメーションクリップの再生時間を指定して一時停止、数フレーム待って再び再生位置を指定して一時停止、というイメージです。これは使いたいポーズのフレームを直接指定できますが、物理で動く揺れ物のコマは落とせません。

【方法2】は仕込みに少々手間がかかりますが、揺れ物のボーンまでトレースするのでコマ落としできます。

今回はボーンをトレースしてリミテッドアニメを実現する、【方法2】について書きます。使用したUnityは【5.5.2f1 (64-bit)】です。

※【方法1】については次回記事、再生フレーム指定編へ。


素材のインポート


テストに使うキャラクターモデルはこちらの「プロ生ちゃん」Unityパッケージ。

ダウンロードしたファイルの中から【PronamaChan_Ver3.unitypackage】をプロジェクトにインポートします。

次に、テスト用のアニメーションを用意します。
スタンダードアセットの【Characters】をインポートし、そこに含まれるアニメーションを使います。

Hierarchyに配置


複製元となるプロ生ちゃんを配置します。

【PronamaChan】 > 【Prefabs】 > 【Normal】 > 【Standard】
にある、【PronamaChan_dynamic】を【Hierarchy】に配置します。

このプロ生ちゃんにアニメーションをさせます。
【Standard Assets】 > 【Characters】 > 【ThirdPersonCharacter】 > 【HumanoidRun】にある
【HumanoidRun】を【Hierarchy】の【Pronamachan_Dynamic】にドラッグ&ドロップします。

これでプロ生ちゃんが走るようになりましたが、このままだと画面の外まで走って行ってしまいます。
【PronamaChan_dynamic】の【Inspector】 > 【Animator】の【Apply Root Motion】のチェックを外しましょう。

これでプロ生ちゃんはその場で走るようになります。

リミテッドアニメーション用のキャラクタを配置します。
スクリプトで同名ボーンのトランスフォームを複製するようにしますので、複製元と同じ【PronamaChan_dynamic】を【Hierarchy】に追加し、名前は【PronamaChan_dynamic_clone】とします。

プロ生ちゃんの髪の毛やスカート、リボンは【Spring Manager】と【Spring Bone】というスクリプトで動いていますが、クローン側には必要ないのでオフにします。
【Spring Manager】だけオフにすれば十分ですので、【PronamaChan_Arm】の【lower_body】【Upper_body2】【head】についている【Spring Manager】のチェックを外します。


ライトやカメラの位置も調整します。右が複製元、左がクローンです。

ボーントレースのスクリプト


次にスクリプトを用意します。
下記のサイトを参考にさせていただきました。


【project】に【C# Script】を新規追加し、「LimitedAnimation」という名前に変更、ダブルクリックしてファイルを開き、下記の内容に書き換えて保存。

LimitedAnimation.cs
using UnityEngine;
using System.Collections;
using System.Collections.Generic;//list使用のために必要
public class LimitedAnimation : MonoBehaviour
{
       public int flameInterval = 3;//抜くフレーム数
       public GameObject masterObject; //ボーンの複製元になるオブジェクト
       private GameObject cloneObject;
       public bool rotationOnly = false;
       private Dictionary<string, Transform> masterAllChildren = new Dictionary<string, Transform>();
       private Dictionary<string, Transform> cloneAllChildren = new Dictionary<string, Transform>();
       void Awake()
       {
              //スクリプトがアタッチされているオブジェクトを取得
              cloneObject = gameObject;
              //すべての子オブジェクトのトランスフォームを取得
              GetChildren(masterObject, ref masterAllChildren, true);
              GetChildren(cloneObject, ref cloneAllChildren, false);
       }

       void LateUpdate()
       {
              if (IsDrawFrame(Time.frameCount))
              {
                     foreach (KeyValuePair<string, Transform> child in cloneAllChildren)
                     {
                           child.Value.transform.rotation = masterAllChildren[child.Key].transform.rotation;
                           if (!rotationOnly)
                           {
                                  child.Value.transform.position = masterAllChildren[child.Key].transform.position;
                           }
                     }
              }
       }
       //すべての子オブジェクトのトランスフォームを取得
       void GetChildren(GameObject obj, ref Dictionary<string, Transform> allChildren, bool springBoneEnabled)//listは参照渡し
       {
              Transform children = obj.GetComponentInChildren<Transform>();
              //子要素がいなければ終了
              if (children.childCount == 0)
              {
                     return;
              }
              foreach (Transform ob in children)
              {
                     allChildren[ob.name] = ob.gameObject.GetComponent<Transform>();
                     GetChildren(ob.gameObject, ref allChildren, springBoneEnabled);
              }
       }
       //ボーンコピーするフレームかどうか判断
       bool IsDrawFrame(float nowframe)
       {
              if (nowframe % flameInterval == 0)
              {
                     return true;
              }
              return false;
       }
}

このスクリプトをクローン側の【PronamaChan_dynamic_clone】にアタッチします。
【Master Object】には複製元を登録します。【Hierarchy】の【Pronamachan_dynamic】をドラッグ&ドロップしてください。
【Flame Interval】に、抜くフレーム数を入力します。ここでは3フレームごとに動くようにします。
今回はわかりやすく複製元と並べて再生したいので、【Rotation Only】にチェックを入れます。
※【Rotation Only】のチェックを外すと複製元と位置が重なるので、レイヤーを分けるなどして複製元がカメラに映らないようにする必要があります。

これでプレビューしてみると、【Rotation Only】にチェックが入っているので上下運動は拾えていないですが、クローン側がコマ落ちアニメーションしていることがわかると思います。

連番画像の出力


連番画像で出力してみます。

こちらのサイトで紹介されているスクリプト【SaveToPng.cs】をカメラにアタッチします。


再生直後は少し挙動が荒れるのでキャプチャ開始する【StartFrame】は「30」にしました。

再生すると【StartFrame】から【EndFrame】の間だけキャプチャされ、画像がプロジェクトフォルダ直下の【ScreenShot】フォルダに保存されます。

左側のプロ生ちゃんのポーズが3フレームごとに更新されているのがお分かりいただけるでしょうか。


今回のスクリプトでは一定の時間間隔でボーントレースしました。
落とすコマ数に変化をつけようとするなら、タイムーシートのような形で配列データを用意したうえでアニメーションクリップの再生フレームも監視する必要がありそうです。

2015年7月16日木曜日

レイヤーをコピーして移動、コピーして移動、コピーして移動…の手間を減らすシンプルなフォトショップスクリプト





選択中のレイヤーを複製して、レイヤーサイズぶん移動させるだけの、簡単なフォトショップスクリプト(JSX)です。
ダウンロード  SK_IncreaseLayer.zip


右に増やすスクリプト
var layLoc= activeDocument.activeLayer.bounds;        //レイヤーのバウンディングボックスの座標を得る
var w = Math.abs(layLoc[2]-layLoc[0]);                //バウンディングボックスの幅を得る
var dupObj = activeDocument.activeLayer.duplicate();  //レイヤーを複製
dupObj.translate(w,0);                                //バウンディングボックスのサイズ分、移動
activeDocument.activeLayer = dupObj;

下に増やすスクリプト
var layLoc= activeDocument.activeLayer.bounds;
var h = Math.abs(layLoc[3]-layLoc[1]);
var dupObj = activeDocument.activeLayer.duplicate();
dupObj.translate(0,h);
activeDocument.activeLayer = dupObj;



レイヤーもしくはレイヤーフォルダを一つだけ選択して、スクリプトを実行してください。レイヤーの複数選択には対応していません。
(制作環境:Photoshop CS5)

2015年5月10日日曜日

【blender】アニメ背景屋のための、無料3Dツール「blender」活用法 その2:円筒形の変形ツールとして使う


「難しいモデリングはやりたくないけど、何とかうまく3Dをつかえないかな」と思っているアニメ背景屋さんのために、無料の3DCGツール「Blender」の活用例を紹介します。

今回は、「blenderを使って画像を円筒形に変形させる簡単な方法」です。

電信柱の広告とか、模様のついた柱などに使えるのではないでしょうか。





円筒形に変形したい画像を用意します。

円柱オブジェクトを追加。

マテリアルを追加(名称を「test」に変更しました)。シェーディング項目の「陰影なし」にチェック。
テクスチャに画像を指定。マッピング項目の「座標」を「生成」、「投影」を「チューブ」。

レンダーのシェーディング項目のアルファを「透過」にすると背景が透明色になります。
これでとりあえず画像を円筒形にできました。

このままでも下地用の素材として使うことはできると思いますが、無駄な上面を削除してみます。
すると裏面が見えてしまいました。

ノードエディターを表示して「ノードを使用」にチェック、「追加」「入力」「ジオメトリ」でジオメトリノードを追加。

ジオメトリノードの「前後」を出力ノードの「アルファ」に接続。
マテリアルノードのマテリアルリストから先ほど設定したマテリアル名を選択。

レンダリングすると、裏面が表示されなくなりました。

円柱オブジェクトを上下に拡大縮小することで、比率の調整ができます。
画像が伸びないよう正確に円筒形にするには、円柱オブジェクトの円周と高さが画像の幅と高さの比率と同じになるように計算して調整する必要があります。

下絵に合わせて円筒を配置するには、こちらの記事の「シーンの準備」を参考にしてください。

2015年3月28日土曜日

【Photoshop】レイヤースタイル「ベベルとエンボス」で作った立体感をノーマルマップにする





1:レイヤースタイル「ベベルとエンボス」をかけたレイヤーを用意します。


2:そのレイヤーをコピーし、「ベベルとエンボス」の「陰影」の部分だけ変更します。
包括光源のチェックを外し、角度0、高度30、光沢輪郭「線形」、
ハイライトのモード「スクリーン」、色「R:255 G:0?B:0」、不透明度100%、
シャドウのモード「乗算」、色「R:0 G:0?B:0」、不透明度100%。
その他の「ベベルとエンボス」の設定値は変えないでください。
更にレイヤースタイル「カラーオーバーレイ」にチェックを入れ、描画モード「通常」、色「R:128?G:0?B:0」、不透明度100%。
新規にレイヤーフォルダを作り、名前を「red」として、そのフォルダの中にレイヤーを移動させ、色「R:128?G:0?B:0」で塗りつぶしたレイヤーをその下に作ります。
レイヤーフォルダ「red」の描画モードは「スクリーン」にします。


3:再び元のレイヤーをコピーし、「べヘルとエンボス」の「陰影」の値を変更します。 
包括光源のチェックを外し、角度90、高度30、光沢輪郭「線形」、
ハイライトのモード「スクリーン」、色「R:0 G:255 B:0」、不透明度100%、
シャドウのモード「乗算」、色「R:0 G:0?B:0」、不透明度100%。
「カラーオーバーレイ」にチェックを入れ、描画モード「通常」、色「R:0 G:128 B:0」、不透明度100%。
レイヤーフォルダ「green」を作り、そのフォルダの中にレイヤーを移動させ、色「R:0 G:128 B:0」で塗りつぶしたレイヤーをその下に作ります。
レイヤーフォルダ「green」の描画モードを「スクリーン」。


4:またまた元のレイヤーをコピーし、「べヘルとエンボス」の「陰影」の値を変更します。 
包括光源のチェックを外し、角度0、高度90、光沢輪郭「線形」、
ハイライトのモード「乗算」、色「R:0 G:0 B:128」、不透明度100%、
シャドウのモード「乗算」、色「R:0 G:0?B:128」、不透明度100%。
「カラーオーバーレイ」にチェックを入れ、描画モード「通常」、色「R:0 G:0 B:255」、不透明度100%。
レイヤーフォルダ「blue」を作り、そのフォルダの中にレイヤーを移動させ、色「R:0 G:0 B:255」で塗りつぶしたレイヤーをその下に作ります。
レイヤーフォルダ「blue」の描画モードは「通過」。


5:レイヤーフォルダ「blue」を「red」「green」の下に配置して終了。


以上の作業を自動で行うスクリプトを用意しました。
「べヘルとエンボス」をつけたレイヤーを選択して、スクリプトを実行すると、自動でノーマルマップ化したレイヤーが作られます。


「べヘルとエンボス」>「輪郭」の「輪郭」にプリセットのカーブを選んでいる場合、エラーが出ることがあります。
そのときは、一度プリセットからカーブを選択した後、プリセットのプルダウンメニューから「カスタム」に変更してからスクリプトを実行してみてください。
blenderでこのノーマルマップをテストした結果。

2015年2月28日土曜日

オリジナルのツールパネルを作る方法【Photoshop】


Adobe Configuratorをつかうと、Photoshopのオリジナルツールパネルが作れます。

私が使用しているphotoshopはCS5ですが、最新のAdobe Configurator 4 ではSC5に対応していないので、古いバージョンのAdobe Configurator 3を使います。





Adobe Configuratorを使うには最新のAdobe AIRが必要らしいので、インストール。
CS5に対応しているAdobe Configurator 3を、下記リンクのページからダウンロード。

ダウンロードしたzipファイルを展開し、Set-up.exeファイルをダブルクリックすると、次の画面が表示されるので、[インストール]をクリック。


インストール終了後、Adobe Configurator 3を起動すると次のような画面が表示されるので、[ファイル]>[新規パネル]をクリックするか、下の[パネルを作成]ボタンをクリック。


作成するパネルの名前と製品を選択。ここではPhotoshop CS5/CS5.1を選び、[OK]ボタン。

左側のウィンドウから、配置したいツールアイコンを中央のグレーの四角の中にドラッグして並べます。右側のウィンドウの[作成者]項目の入力が必須のようなので、入力。


作成したパネルをPhotoshopで使用するには[ファイル]>[パネルを書き出し]をクリック。


[フォルダーの参照]ウィンドウが開いて「Photoshop CS5/CS5.1プラグインパネルフォルダーを指定」とでるので、フォトショップのインストールフォルダの中にあるPlug-ins/Panelsフォルダを指定します。
C:\Program Files\Adobe\Adobe Photoshop CS5 (64 Bit)\Plug-ins\Panels
私の環境では「フォルダに書き出せませんでした」と出て書き出せなかったので、別のフォルダを指定して、書きだされたフォルダごと移動しました。


Photoshopを起動し、「ウィンドウ」>「エクステンション」の中に、先ほど書きだしたパネル名が追加されています。


パネル名をクリックすると作成したパネルが表示されます。



こちらのサイトを参考にさせていただきました。

Blender上でMIDIファイルを読み込み3Dモデルの鍵盤を動かすpythonスクリプトに挑戦したこと

昔取り組んだことについての忘備録 作成日 2016/8/7 目的 MIDIファイルの仕様の理解 BlenderとPythonの学習 内容 MIDIファイルのバイナリを読み込んで解析し、ノートオン、ノートオフ情報に従って、対応する音階の...