【Blender】BlenderとPythonでデータをビジュアル化する方法

Blenderは内部にPythonを備えており、それを使用することで、データの可視化に応用することができます。
この記事ではデータの取り込みの方法、そしてSTYLYへのアップロードなどの応用について解説しています。

Pythonとは

Pythonは様々な用途に使用されるプログラミング言語で、様々な企業や団体等で使用されています。
また、その言語仕様の特性から、データサイエンスなど数値計算を扱う場面でも人気な言語です。

PythonはBlenderの中に組み込まれており、Blenderの多くの処理は実はPythonがその動きを管理している他、アドオンなどもほとんどがPythonで書かれています。

そのため、BlenderはPythonの実行環境を内包しており、ほぼ完全な形でPythonを実行することができるようになっています。
例えば、これを利用することでパーティクルライブなどを作成することも可能です。

データを可視化する

今回、この記事で紹介するのはPythonを使用してデータを可視化する方法です。
データの可視化を簡単に言うと、データとして存在する数値情報をより見やすい状態に置き換えることです。

データ可視化の一例を挙げると、表計算ソフトのグラフ描画もそのうちのひとつです。
グラフ描画は数値情報として存在しているものを、視覚的に見やすい情報に変換するプロセスです。

BlenderではPythonを使用して、数値データを視覚しやすい情報に変換することができます。
これは以下のような特徴があります。

  • 数値データを視覚的にリッチな形で表現することができる。
  • アニメーションを使用し、数値の変化によって見える情報を動きとして表示することができる。

これを利用することで以下のような応用が可能です。

  • 数値データをアニメーション化し、数値の動きを多角的に見せることができる。
  • インフォグラフィックなどの作成。

地震計データの可視化

データの取得

日本では地震が頻発する国であり、気象庁はその観測を絶えず行っていて、特に強い地震に関しては、強震観測データとして一般公開を行っています。

STYLYでは、防災に役立つアセットなどを公開しており、これを使うことで防災計画などにも利用できるようになってきています。

Pythonを使うことで地震の揺れを可視化をすることができ、防災に役に立つツールをとなり得ます。

このデータを使用したアニメーションを使うことにより次のようなことができるようになります。

  • 地震を視覚的に見ることによりどのような揺れが起こりうるのかを事前に見ておき、準備することができる。
  • VRを使用した視覚的な地震の体験。

まずは使用するデータを取得してみましょう。
まずは強震観測データのサイトから、地震を選択します。

強震データ選択

強震データ選択

執筆時点では「2021年2月13日23時07分 福島県沖の地震」が最新のものとなっていますので、こちらを使用します。

続いて、場所が表示されますので、使用したいデータを選択します。

地震データのリスト

地震データのリスト

ここの1の「波形プロット」下の2の「波形」をクリックすると波形をグラフ化したものが表示され、「データ取得」の「ダウンロード」をクリックすると、CSVファイルでデータをダウンロードすることができます。

このCSVファイルには100分の1秒ごとの北・南の揺れ、東と西の揺れ、そして上下の揺れのデータが含まれています。

CSVデータの内容

CSVデータの内容

今回はこのデータをアニメーションデータとして取り込み、3次元データとして取り込んでみたいと思います。

Pythonコードの解説

今回使用するコードは次のようなものとなります。

import bpy, csv

data = "FILEPATH" # (1)
current_scene = bpy.context.scene
target_object = current_scene.objects["Cube"] # (2)

scale = 100 # (3)
interval = 1 # (4)

current_frame = 1

with open( data, encoding='shift_jis' ) as csvfile: # (5)
reader = csv.reader( csvfile )
for i, row in enumerate( reader ):
if i < 8: continue # (6)
x, y, z = row[0:3]
x = float(x) / scale
y = float(y) / scale
z = float(z) / scale
target_object.location = (x, y, z)
target_object.keyframe_insert(data_path="location", frame=current_frame*interval)
current_frame += 1

上記のコードに(1)~(5)をコメントとして注記していますが、それぞれの事項について説明します。

  1. ここにCSVファイルの場所を指定
  2. 動きを付けるオブジェクトで、この例ではCube(デフォルトキューブ)が指定されている
  3. 揺れ幅を抑える。数字が大きいとブレが小さくなる
  4. 間に入れるフレーム(大きいと再生が実時間より長くなる)
  5. 強震観測データはShift-JISなのでencodingを指定
  6. 最初の8行は取り出さないヘッダーデータなので無視

Pythonコードの取り込み

さっそくこれをBlenderで使用してみましょう。
BlenderでPythonを扱うのには内蔵の「テキストエディタ」を使用します。

Blenderのテキストエディタ

Blenderのテキストエディタ

テキストエディタに切り替えると、このように何もない画面が表示されますが、上部の「新規(New)」を押します。

新規テキストの作成

新規テキストの作成

そうすると、次のような空のテキストエディタになります。

空のテキストエディタ

空のテキストエディタ

ここに上記のコードを貼り付けてみてください。
尚、この記事から貼りつけるとインデントが失われてしまい、エラーになってしまう可能性があります。
インデントはPythonでは重要なので、貼り付けに失敗する場合はGistのコードより貼り付けてみてください。

貼りつけた後

貼りつけた後

このコードで、(1)のFILEPATHになっている部分を実際のファイル名に変更します。
ファイル名は絶対パスで指定してください。
Windows環境ではバックスラッシュ(「\」やもしくは円マーク)の部分はフォワードスラッシュ(「/」)に置き換えてください。
つまり、「C:\Data\data.csv」の場合は「C:/Data/data.csv」になります。

取り込み処理の実行

これを設定したあと、早速処理してみましょう。

実行するには右上にある再生ボタンをクリックします。
尚、こちらが表示されていない場合、表示エリアが小さすぎる可能性がありますので、広げてみてください。

Pythonの実行

Pythonの実行

エラーが出ている場合は、コンソール画面を見ることで、その内容を見ることができます。
出ていない場合は、「システムコンソール切替え(Toggle System Console)」で表示してみてください。

コンソールの表示

コンソールの表示

多くの場合はファイル名が間違えているなどのエラーになると思いますので、修正し、再度実行してみてください。

実行が成功すると処理が始まります。強震観測データは大きなデータなので、処理にしばらく時間がかかるので、終わるまでそのままにしておいてください。

取り込んだデータの確認

処理が完了するとこのようにタイムラインにキーフレームが打たれます。

処理後のタイムライン

処理後のタイムライン

「グラフエディタ」でアニメーションカーブを見てみましょう。

グラフエディタに切り替え

グラフエディタに切り替え

切り替えた後に、今回はCubeオブジェクトにアニメーションを割り当てたので、3Dビュー上に表示されているCubeオブジェクトを選択します。

追加されたアニメーション

追加されたアニメーション

ここで左上の1の部分にX、Y、Zの位置情報、そしてグラフが追加されています。

グラフはそのままでは見えにくいのでマウスホイールや中ボタンなどで動かしてみてください。

グラフの表示移動・拡大

グラフの表示移動・拡大

なお、この地震データのアニメーションは18007フレームありますので、このまま再生しようとすると全部が再生されないので最終フレームを変更する必要があります。

終了フレーム

終了フレーム

この数字を18007に変更します。

次に「出力プロパティ(Output Property)」の「フレームレート(Frame Rate)」が24fpsにデフォルトになっていますが、こちらを100に変更します。
100の選択肢はありませんので、Customを選択します。

カスタムを選択

カスタムを選択

次に「FPS」のボックスが出てきますので、100を指定します。

FPSを設定

FPSを設定

再生の前に再生設定を変更します。
必要な設定は「再生(Playback)」→「シンク(Sync)」の設定を「コマ落とし(Frame Dropping)」に変更します。

再生設定

再生設定

この変更がなぜ必要かというと、デフォルトの設定「毎フレーム再生(Play Every Frame)」を使用するとBlenderは全てのアニメーションフレームを再生して、以下のような問題が発生します。

  1. 処理が追い付かない場合に通常より時間をかけて再生されるようになる。
  2. 画面のリフレッシュレートが低い場合(この場合、例えば100のフレームレートに対して60Hzの画面を使っている場合)に遅く再生される。

そのため、この設定で表示できない場合はフレームの再生そのものをスキップし、時間の正確さを優先する設定となります。
地震計データのようにリアルタイム性が重視されるデータに関してはこの変更は重要となります。

[Space]キーを押すと再生が開始されます。

再生するとしばらくは静止していますが、だんだんと揺れが激しくなってくるのが表示されます。

再生した地震計データ(実際はもっと滑らかに表示されます)

再生した地震計データ(実際はもっと滑らかに表示されます)

FBXとして出力し、STYLYにアップロードするとそのまま再生することもできます。

時系列データ

次の例では時系列データを取り込んでみたいと思います。
この例では二系列のデータを扱い、使用するのは日本の人口推移データです。
このデータは男女別のデータとして人口が記録されています。

Pythonコードの解説

この例で使用するのは次のコードです。

import bpy, csv

data = "FILEPATH" # (1)
current_scene = bpy.context.scene
target_object_male = current_scene.objects["Male"]
target_object_female = current_scene.objects["Female"]

scale = 20000000 # (2)
interval = 10 # (3)

current_frame = 1

with open( data, encoding='shift_jis' ) as csvfile:
reader = csv.reader( csvfile )
for i, row in enumerate( reader ):
if i < 6: continue # (4)
if i > 126: continue # (5)
_,_,male,female = row[0:4]
male_scale = float(male) / scale
female_scale = float(female) / scale
target_object_male.scale = (1,1,male_scale) # (6)
target_object_female.scale = (1,1,female_scale) # (7)
target_object_male.keyframe_insert(data_path="scale", frame=current_frame*interval) # (8)
target_object_female.keyframe_insert(data_path="scale", frame=current_frame*interval) # (9)
current_frame += 1

こちらもGistにコードを用意しました。

上記のポイントとなる点としては以下の通りです。

  1. 前項の例にならい、こちらにファイル名を指定してください。
  2. 今回は数字が大きいため、2000万分の1の縮尺で表示します。
  3. ここが10に指定しているため、10フレームごとにキーフレームを打つ、という指定になります。
  4. ダウンロードしたデータは最初の5行がデータではないので除外します。
  5. 127行目以降はデータでないので同様に除外します。
  6. 男性の値をスケール値として指定します。
  7. 女性の値をスケール値として指定します。
  8. 男性のオブジェクトに対してキーフレームを打ちます。
  9. 女性のオブジェクトに対してキーフレームを打ちます。

表示用オブジェクトの準備

前項の例ではデフォルトキューブを対象オブジェクトとして使用しましたが、今回は二つの系列データを採用するのでオブジェクトを用意します。
今回はそれぞれ「Male」、「Female」としました。
また、それぞれ、色を指定しました。

用意したオブジェクト

用意したオブジェクト

次に原点をオブジェクトの下部に指定します。
以下の手順で限定を指定します。

  1. 対象のオブジェクトの編集モードに入り対象としたい部分(この例の場合は最下部)を指定する。
  2. [Shift]-[S]で「スナップ(Snap)」メニューを出し、「(Cursor to Selected)」(もしくは[2]キー)を押す。
  3. オブジェクトモードに戻り、対象となるオブジェクトを選択。
  4. 原点の設定メニューから原点を3Dカーソルへ移動(Origin to 3D Cursor)を選択。
基点をオブジェクト下部に設定

原点をオブジェクト下部に設定

この設定をする理由は、今回はZ軸のスケール値を数値の可視化として使用するためです。

原点を下部に指定した場合の拡大縮小の挙動

原点を下部に指定した場合の拡大縮小の挙動

このように、Z軸のスケール値を指定すると原点はそのままで大きさが変わっているのが分かります。

データの取り込み処理

前項と同じように取り込みを行うと、同様にキーフレームが打たれます。
今回の場合はインターバルとして10を指定しているので、10フレームごとにキーフレームが指定されています。

10フレームごとに打たれたキーフレーム

10フレームごとに打たれたキーフレーム

最終フレームを1212に指定し、このアニメーションを再生すると以下のようになります。

再生した人口データ(実際はもっと滑らかに表示されます)

再生した人口データ(実際はもっと滑らかに表示されます)

複数のオブジェクトのアニメーションを個別に出力する方法

地震計のアニメーションのように、こちらもSTYLYに取り込むことができますが、この例のように複数のオブジェクトで別のアニメーションを含むものを出力する場合、工夫が必要になる場合があります。
流れとしては、それぞれのオブジェクトを個別のFBXとして出力する手法となります。

まず、「ノンリニアアニメーション(Nonlinear Animation)」に切り替えます。

ノンリニアアニメーション

ノンリニアアニメーション

次に両方のアニメーションの「アクションをストリップ化(Push Down Animation)」ボタンを押します。

アクションをストリップ化

アクションをストリップ化

表示が次のように変わります。

ストリップ化の状態

ストリップ化の状態

この後、単一のオブジェクト(この例の場合、MaleもしくはFemale)を選択しFBXを出力します。この時、以下のように「選択したオブジェクト(Selected Objects)」が選択され、「全アクション(All Actions)」の選択が外れていることを確認してください。

FBX設定

FBX設定

これをそれぞれのオブジェクトに対して行うと、二種類のファイルが出力されます。
これらのファイルをアップロードするのには二種類の方法があります。

  1. それぞれのファイルを別オブジェクトとしてSTYLYにアップロードする。
  2. Unityに取り込み、二つのFBXファイルを取り込み、単一のプレハブとしてアップロードする。

Unityでのアニメーションの扱いに関しては次の記事も参考にしてください。

以下は上記2の方法を使い、ブルームなどのポストエフェクトを追加した例です。

このように、数値データを見せることも可能なので、他のアニメーションを追加したりする工夫で、印象に残る形で数値を映像化できます。
そのため、プレゼンテーションなどでの、各種ビジネスグラフィックとしての用途も考えられます。

取り込んだデータの応用

STYLYで地震データを利用してみましょう。

今回は簡単な地震シミュレーターを作ってみます。
以前、アセットブラウザの解説で使用した部屋のモデルを使用し、周りに地面としてのオブジェクトを配置する構成にします。

揺れを再現するわけですが、揺れを体感的するのは画面やVRでも困難です。
ということで今回は、部屋としての足場を固定し、周りの景色を揺らすことで疑似的に地震を体験できるようにします。

地震シミュレーターのモデル

地震シミュレーターのモデル

地面に箱をいくつか設置することにより、地面の動きがより分かるようにしました。

地面と箱は同じ動きになるので、地面、及び箱を選択し[Ctrl]+[J]キーで結合します。

次に地震データをこの地面に割り当てます。

今回使用したものは以下のコードになります。

import bpy, csv

data = "FILEPATH"
current_scene = bpy.context.scene
target_object = current_scene.objects["Env"]

scale = 100
interval = 1

current_frame = 1

with open( data, encoding='shift_jis' ) as csvfile:
reader = csv.reader( csvfile )
for i, row in enumerate( reader ):
if i < 8: continue # (6)
x, y, z = row[0:3]
x = float(x) / scale * -1
y = float(y) / scale * -1
z = float(z) / scale * -1
target_object.location = (x, y, z)
target_object.keyframe_insert(data_path="location", frame=current_frame*interval)
current_frame += 1

コードを使用する場合は、Gistより取得してください。

以前と似たコードですが、太字の部分が変わっています。
これは-1とすることで反転させました。

今回立っている部屋が静止していてその周りの景色を動かすので、反転させることで錯覚後の見かけが実際の揺れになる、という具合です。
実行するとキーフレームが打たれるので、これをFBXで出力し、Unity経由でアップロードしました。

STYLYでは以下のようになります。

 

VRで体験すると揺れの激しさが体感できます。
敏感な方は実際に強い揺れを体感しているような感覚を得る方もおられるかとおもいますので、安全に留意し、周りの物に衝突しないように気を付けてください。

STYLYにアップロードする方法

3DモデルをSTYLYにアップロードしてみましょう。

STYLYアカウントを作成する

アカウント作成方法

STYLYにアップロードする方法

UnityからSTYLYにアップロードする方法

STYLYに関する質問、バグ報告、改善してほしい要望はSTYLY FORUMまで
https://jp.forum.styly.cc/support/discussions

このようにPythonを使用して外部データを取り込むようにいろいろな種類のデータを視覚化し、訴求力のある表現をすることができるようになります。
是非、他のいろいろな種類のデータを取り込んでみて実験してみてください。

newbview popup