ニッチなblender手記

世の中には自分に似た人が3人いるとされています。その人達へと情報共有するために主にblenderの記事を書いていきます。

waving OBJ in blender

概要

Animation Nodes を利用して、複数のオブジェクトが波のように動くアニメーションを作成する。

参考

下の参考先を見て理解できれば以降を読む必要はない。


[05 Object Instancer] Introduction to Animation Nodes Tutorial Series for Beginners


#3 - Animation Nodes in Blender 2.8 - Tutorial Series

大量のオブジェクトが波打つような動きをする方法


#6 - More Fun with Audio - Animation Nodes Blender 2.8 Tutorial Series


Create a Looping Animation using Instancing in Blender 2.9

手順

  1. ウォーミングアップ
    1. 大量のオブジェクトを用意する
    2. 個々のオブジェクトへそれぞれ異なる位置となるように移動させる
    3. フレーム単位で位置が変わる(=移動)ようにする
  2. 本番
    1. 大量のオブジェクトを用意する
    2. オブジェクトを移動させて、一定の範囲をオブジェクトで敷き詰める
    3. 個々のオブジェクトを操作できるようにする
    4. 波形の移動をするようにする
  3. 別解
    1. Blender の Instance 機能を利用して、オブジェクトを大量配置する
    2. Wave モディファイアを利用して波形の移動をするようにする
  4. 応用
    1. Animation Nodes を使って、一枚の板ポリを波打たせる

ウォーミングアップ

一気に波形に動きをつける前に、下図のように複数のオブジェクトが時間と共に上下へ移動するようなものを作る。

f:id:r9aArrowhead:20210114185843g:plain

大量のオブジェクトを用意する

f:id:r9aArrowhead:20210114184813j:plain f:id:r9aArrowhead:20210114184820j:plain

個々のオブジェクトへそれぞれ異なる位置となるように移動させる

f:id:r9aArrowhead:20210114184827j:plain f:id:r9aArrowhead:20210114184835j:plain

フレーム単位で位置が変わる(=移動)ようにする

f:id:r9aArrowhead:20210114184843j:plain

本番

大量のオブジェクトを動かす方法が分かったところで、本番に移る。
ここでは下図のようにより波のような動きをするような調整をしていく。

f:id:r9aArrowhead:20210114185125g:plain

大量のオブジェクトを用意する

f:id:r9aArrowhead:20210114184900j:plain f:id:r9aArrowhead:20210114184907j:plain

オブジェクトを移動させて、一定の範囲をオブジェクトで敷き詰める

f:id:r9aArrowhead:20210114184921j:plain f:id:r9aArrowhead:20210114184913j:plain

個々のオブジェクトを操作できるようにする

f:id:r9aArrowhead:20210114184928j:plain f:id:r9aArrowhead:20210114184935j:plain f:id:r9aArrowhead:20210114184943j:plain f:id:r9aArrowhead:20210114184950j:plain

波形の移動をするようにする

ここで本格的に三角関数を用いて波形のアニメーションを実装するが、オブジェクトのY軸の位置を0より上にしたことがここで関わってくる。
三角関数は基本的に -1 から 1 の間を遷移するので、初期位置は0の方が上下移動が分かりやすくなる。

f:id:r9aArrowhead:20210114184956j:plain f:id:r9aArrowhead:20210114185004j:plain f:id:r9aArrowhead:20210114185010j:plain f:id:r9aArrowhead:20210114185018j:plain f:id:r9aArrowhead:20210114185027g:plain

f:id:r9aArrowhead:20210114185117j:plain

以上で完成となるが、更に処理をプロシージャルに。
最初はシリンダーオブジェクトを手で作成したが、この部分も Animation Nodes を利用して生成しておく。折角だからよりパラメトリックでプロシージャルにしておきたい。

f:id:r9aArrowhead:20210114185206j:plain f:id:r9aArrowhead:20210114185213j:plain

別解

今回 Animation Nodes で作成した方法は、バニラの blender でも実現できる。

ただし、利用するモディファイアの仕様変更が影響するため、 blender 2.91以降 が条件となる。

Blender の Instance 機能を利用して、オブジェクトを大量配置する

f:id:r9aArrowhead:20210114185221j:plain f:id:r9aArrowhead:20210114185229j:plain f:id:r9aArrowhead:20210114185235j:plain f:id:r9aArrowhead:20210114185242j:plain f:id:r9aArrowhead:20210114185249j:plain

Wave モディファイアを利用して波形の移動をするようにする

f:id:r9aArrowhead:20210114185259j:plain f:id:r9aArrowhead:20210114185314g:plain f:id:r9aArrowhead:20210114185436j:plain f:id:r9aArrowhead:20210114185444g:plain f:id:r9aArrowhead:20210114185526j:plain f:id:r9aArrowhead:20210114185535g:plain f:id:r9aArrowhead:20210114185740j:plain f:id:r9aArrowhead:20210114185748g:plain

欠点

オブジェクトを一つ一つ生成しなくてもいいので作業的には楽になるが、同時に以下のような問題が発生する。

  • 大量のオブジェクトを生成するため、メモリ消費量が上がる
  • オブジェクトの数に比例してループ処理によるCPUへの負荷が上がる
  • サイン波などを利用した独自の波形を作成しようと思った場合、感覚ではなく数学的知識が要求される

また、 今回の範囲では Animation Nodes と バニラで結果はあまり変わらなかった。
しかし、より複雑な動きを追求していく場合はそれぞれ得手不得手が分かれるのでどちらで実行するかを選ぶ必要がある。

loose generate polys about Animation Nodes

概要

Vector ノードを利用すればポリゴンの生成ができることが分かったことと、複数のポリゴンを結合することができた。
しかし、手入力で座標を指定しているため、頂点数の増加はそのまま作業量の増加へとつながってしまっている。 ここでは手入力で設定していた頂点座標をジェネレータへ置き換え、毎回座標を手で入力しなくてもいいようにする。

いわゆる ジェネラティブアート、パラメトリックモデリング などの手法の基礎の基礎にあたる部分となる。

f:id:r9aArrowhead:20201223155249p:plain

制限

ここでの主目的はあくまで座標入力の自動化であるため、以下のようなことは気にしない。

  • 乱数生成
    • シード値とかそういうやつは今回触れない
  • トポロジの精密さ
    • ポリゴンの流れやエッジの流れについては、今回は気にしない方向でいく
  • メッシュの形

手順

  1. 複数のランダムな頂点座標を生成
  2. 頂点データの整理
  3. ポリゴンの生成、マージ
  4. メッシュの表示

複数のランダムな頂点座標を生成

ここでの手順をまとめると、以下の通り。

  1. ノードの追加
    • Random Vector ノード
    • Math ノード
    • Integer Input ノード
  2. Math ノードを Multiple へ変更する
  3. Integer Input ノードを Math -> A ソケットへ接続する
    • 作りたい三角ポリゴンの数を指定できるようにする
  4. Math -> B ソケットの数値を 3 にする
    • 生成する頂点の数が必ず3の倍数となるようにする

手入力しないといっても、頂点座標は必ず必要となる。
今回はトポロジには頓着しないため、ここでは既存のオブジェクトやテキストデータを利用せずにランダムに生成した頂点座標を利用する。

幸い、 Animation Nodes はランダムにベクトルを生成する Random Vector ノードというノードが用意されている。このノードを利用すればあっさりと必要な数だけのベクトルをランダム生成してくれる。

しかし、ポリゴンを生成する場合は 頂点の数が必ず3の倍数になること という条件を追加する必要がある。
この問題を解決するために、生成するベクトルの数は必ず3の倍数となるように調整する。
そのために利用するのが、 Integer Input ノードと Math ノードとなる。

Random Vector -> Count の入力ソケットに、 Math ノードを接続する。そして Math ノードを Multiple に設定する。
Math -> Multiple ノードは A, B という2つの入力ソケットが存在する。つまり、 A * B ということ。
A へは Integer Input の出力ソケットを接続する。この Integer Node作りたい三角ポリゴンの数 ということになる。 Multiple は入力した数値による掛け算を行うので、 B の入力ソケットへ 3 を設定すればこのノードを通過した数値は必ず3の倍数となる。

これらでネットワークを形成したのが、下図のものとなる。
これで任意の数の頂点データを生成する準備ができた。

f:id:r9aArrowhead:20201223155256p:plain

頂点データの整理

ここでの手順をまとめると、以下の通り。

  1. Separate Vector ノードを追加
  2. Random Vector ノードと Separate Vector ノードを接続する
    • 生成した頂点データのXYZ成分を分離した
  3. Sort Numbers ノードを追加
  4. Separate Vector -> X 出力ソケットを、Sort Numbers ノードへ接続する
    • 頂点データから抽出したX成分で昇順ソート
  5. Get List Element ノードを追加
  6. Get List Element ノードの入力ソケットへ接続する
    • Random Vector -> VectorsGet List Element -> List 入力ソケットへ接続
    • Sort Numbers -> IndicesGet List Element -> Indices 入力ソケットへ接続
    • 昇順ソートの結果、X軸に沿った並べ替えたインデックスの順番通りにデータを取得しなおす

生成した頂点データは座標にばらつきがあるため、これを整理する。
なんで整理するのかというと、ポリゴンやエッジは頂点インデックスの組み合わせで形が変わるためである。
ランダム生成のままでも利用はできるが、整理しておいた方が見た目が多少良くなるためなので、完全にここは気分の問題となる。

精緻なパラメトリックモデリングやジェネラティブアートをしたい場合はもっと高度な整列をする必要があるので、簡単なものから順次慣れておきたいという思いも少なからずあった。

今回は極めてシンプルな整列方法として、下図のように X軸に沿ったソート を行った。 言い換えれば、 頂点データのX成分で頂点をソートする

f:id:r9aArrowhead:20201223155311p:plain

生成した頂点データのX成分を抽出するには、 Animation NodesSeparate Vector ノードを利用する。
Random Vector ノードからランダム生成した値を Separate Vector へ接続すれば、出力ソケットからXYZの各成分に分離したデータを取得できるようになる。

頂点データのX成分を抽出できるようになったので、このデータを使ったソート(並べ替え)処理を実行する。今回は何も考えずに昇順ソートを実施する。
Animation NodesSort Numbers ノードという数値のソート処理も用意してくれているので、これを利用する。
このノードを使うと、入力ソケットで渡した頂点データのX成分のリストを昇順ソートして結果を出力してくれる。

生成した頂点データをどう昇順すれば良いかが分かったが、このままでは頂点データの整理は終わっていない。
今回の昇順ソートはあくまでX成分だけのソートをした。
頂点データはXYZ成分の3つがワンセットなので、X成分だけを入れ替えると生成した頂点データとは異なるデータが生成されてしまう。

頂点データをXYZ成分まとめてX軸に沿って並べ変えるには、 Sort Numbers ノードのもう一つの出力ソケットの indices 出力を利用する。
これは、並べ替えた順番がそれぞれ元のリストの何番目のデータを使ったかのインデックスを出力してくれる。
この昇順ソート結果を反映したインデックスのリストと インデックスを指定してリストの中からデータを取ってきてくれる Get List Element ノードを使うことで頂点データの並べ替えが実現できる。

これらの処理をネットワークを形成したのが、下図のものとなる。
これで頂点データの整理ができた。

f:id:r9aArrowhead:20201223155305p:plain f:id:r9aArrowhead:20201223155316p:plain

ポリゴンの生成、マージ

使いたい頂点データを整理したので、いよいよこの頂点データ達を使ってポリゴンを生成、マージする。
ベクトルデータ群からポリゴンを生成する方法や不要データのマージ方法は既に記載したので、ここでは割愛。

minorblender.hatenablog.com

minorblender.hatenablog.com

メッシュの表示

最後はちゃんとポリゴンを表示すれば完了

f:id:r9aArrowhead:20201223155322p:plain f:id:r9aArrowhead:20201223155329p:plain

ここまでできれば、後は Integer Input ノードで生成したいポリゴンの数を指定するだけでポリゴンを生成してくれるようになる。 Integer Input ノードの代わりに Viewport Input ノードを利用すれば、下図のようにビューポート上から数値を入力して生成できるようになる。ちょっとアドオンっぽい。

f:id:r9aArrowhead:20201223155337g:plain

問題点

自動で頂点を生成できるようになったとはいえ、問題点を残している。その問題点とは、単純にポリゴンの形が汚い。
今回はあくまでX軸の沿ったソートしかしていないため、YZ成分のソートを対象にはしていない。
また別の機会でこの問題を解決したい。

loose create quad poly about Animation Nodes

概要

単一のポリゴンを作成することができたので、次は複数のポリゴンを生成する。

今回はシンプルに隣接する2つの三角ポリゴンを生成して、 Quad に見えるようにした。

f:id:r9aArrowhead:20201222165548p:plain

手順

  1. 三角ポリゴンを2つ作る
  2. 2つの三角ポリゴンを一つにまとめる
  3. 不要なポリゴンを削除する
    1. メッシュデータを BMesh 型へ変換する
    2. 重複しているデータを削除する
    3. BMesh 型のデータを Mesh 型へ変換する
  4. 表示する

三角ポリゴンを2つ作る

まずは独立した三角ポリゴンを2つ用意する。 三角ポリゴンを作る手順は以前作成したので割愛。

f:id:r9aArrowhead:20201222165555p:plain

2つの三角ポリゴンを一つにまとめる

下図のように、Animation Nodes は複数のメッシュを個別にビューポートへ出力することができない。
そのため、ノード上に独立したメッシュが複数存在する場合はこれを一つにまとめる必要がある。

f:id:r9aArrowhead:20201222165601p:plain

Animation Nodes には生成したメッシュを一つにまとめる機能があるので、それを利用する。
特に難しい操作は必要なく、下図のように Create Mesh List で複数のメッシュを含んだリスト型データを用意して、 join Mesh List でまとめれば完了する。

f:id:r9aArrowhead:20201222165607p:plain

不要なポリゴンを削除する

ポリゴンを表示するだけならば、前操作までで完了しているのでビューポート上に個別に作成した三角ポリゴンがそれぞれ表示されているのが分かる。
しかし、下図のようにオブジェクトの情報を見てみるとピンとくると思うが、見た目と頂点数が一致していない。

f:id:r9aArrowhead:20201222165613p:plain

それぞれ個別に頂点を作成したので、頂点の座標が重複している状態になっている。
用途によっては三角ポリゴン同士に分かれている方がいい場合もあるが、今回は頂点をマージして重複した頂点は削除したい。

マージするためには、 Animation Nodes が用意している BMesh APIのラッパーノードを利用する必要がある。

BMesh についてはここでは割愛。

メッシュデータを BMesh 型へ変換する

作成したメッシュデータを BMesh データへ変換するためには、 Create BMesh ノードを利用するだけでいい。

f:id:r9aArrowhead:20201222165654p:plain

重複しているデータを削除する

BMesh へデータ変換できたなら、以後も Animation Nodes が提供している機能を利用することとなる。
Remove Double ノードで重複を削除する。

Remove Double ノードは blender APIremove_doubles のラッパー

f:id:r9aArrowhead:20201222165701p:plain

BMesh 型のデータを Mesh 型へ変換する

マージが終わったデータは、そのままでは表示できない。
BMeshMesh はデータ型が異なるため、 Animation Nodes が提供している Mesh Object Output へ入力できないようになっている。
ビューポートへ表示するためには、一度 BMesh 型へ変換したデータを改めて Mesh データ型へ再変換する必要がある。

f:id:r9aArrowhead:20201222165708p:plain

Mesh 型への変換には、 Create BMesh ノードのようなワンタッチでできるノードは用意されていない。 幸い BMesh 型からは 頂点データからメッシュを作成した時のように、頂点データ・エッジインデックス・ポリゴンインデックスを出力できる BMesh Mesh ノードが用意されている。
BMesh Mesh ノードを利用すれば Combine Mesh ノードで改めてメッシュを生成することができる。

f:id:r9aArrowhead:20201222165716p:plain

表示する

マージしたメッシュを表示すれば、重複していた頂点が削除されていることが確認できる。

f:id:r9aArrowhead:20201222165723p:plain

参考

Animation Nodes - Doc - Create BMesh

Blender python API - BMesh Module (bmesh)

Blender python API - BMesh Operators - Remove Double

loose create polygons about Animation Nodes

概要

Animation Nodes だけを用いて下図のようなシンプルな形でポリゴンを生成する。
当たり前といえば当たり前すぎる操作だが、いざやってみると色々手順が面倒なので覚えておく必要がある。

f:id:r9aArrowhead:20201222143424p:plain

手順

  1. 頂点を作成する
  2. ポリゴン用のインデックスを生成する
  3. エッジ用のインデックスを生成する
  4. 表示する

頂点を作成する

ポリゴンを生成するにあたっては、なにはともあれポリゴン位置を決定するための頂点が最低でも 3 点すなわち三角ポリゴンが必要となる。
頂点座標は [x, y, z, (w)] のベクトル形式となっているので、まずはそこからのスタートとなる。

頂点座標となる数値を作成する方法はいくつかあるが、一番手っ取り早いのは下図のように頂点となるベクトル型データのリストを Vector List で作成する方法になる。

モデルデータの情報量が増えれば頂点数は増大するだけではなく、頂点座標の構造も複雑になるためこの方法は使えなくなる点には注意。

f:id:r9aArrowhead:20201222143431p:plain

ポリゴン用のインデックスを作成する

blender はポリゴンを作成するために前述で作成した頂点座標データとは別に、頂点インデックスと参照データを必要とする。

幸い Animation Nodes は頂点データを渡せば頂点インデックスを作成してくれる Cleate Polygon Indices ノードがあるためそれを利用する。
下図の A では、作成した頂点データそれぞれに Cleate Polygon Indices ノードが頂点インデックスを作成している。

f:id:r9aArrowhead:20201222143436p:plain

ただし、 Cleate Polygon Indices ノードが作成しいてくれるのは頂点インデックスだけである。これだけではポリゴンは作成できない。
ポリゴンを作成するために、どの頂点インデックスを利用するかを指定するための参照データも必要となる。
ポリゴンは三角ポリゴンを無数に組み合わせて一つのメッシュを構築するため、どういった組み合わせで頂点インデックスをつなげるのかという指示が必要となる。

上図の B にある Create Polygon Indicies List ノードがが参照する頂点の組み合わせを作成している。
ノードに繋げているビューワでは [(0, 1, 2)] と表示されているのが分かる。
これによって 頂点インデックスの 0, 1, 2 を使って三角ポリゴンを生成する という流れになる。

エッジ用のインデックスを作成する

ポリゴンを作成するために専用のインデックスを作成する必要があるのと同じで、エッジを生成するためのインデックスも必要となる。
幸いこの機能も Animation Nodes が標準搭載しているので、それを利用する。

f:id:r9aArrowhead:20201222143445p:plain

上図では先ほど作成したポリゴン用のインデックスを使い、 Edges of Polygons ノードでエッジ用のインデックスを生成している。
エッジは 2 点間で生成するものなので、 [(1, 2), (0, 2), (0,1)] という3つの組み合わせが生成された。

表示する

頂点、頂点インデックス、エッジ用のインデックス、ポリゴン用のインデックスの生成が終わったのでようやくポリゴンを表示できるようになった。

下図の Combine Mesh ノードを使えば、これまでに作成したデータでポリゴンを生成してくる。
ただしこのノードはビューポート上への表示機能を有していないので、 Mesh Output Object ノードでメッシュをビューポート上で表示することを忘れずに。

f:id:r9aArrowhead:20201222143452p:plain

loose introduction about Animation Nodes (Viewport input)

概要

Viewport Input ノードに関する説明。

f:id:r9aArrowhead:20201221152512p:plain

名前だけ見るとビューポートから情報を引っ張りこむようなノードに見えるが、一言で言えば ビューポートに入力用のパネルを用意するノード

Animation Nodes はデータの入力用ノードとして IntegerObject といったノードが用意されているが、これらは全て Animation Nodes エディタ画面内部でしか機能しない。
Viewport Input はそうしたエディタの枠を超えて、ビューポートから値を設定できるようしてくれるノードとなっている。

f:id:r9aArrowhead:20201221152519p:plain

もちろんこのノードを使ってビューポートから入力した値は Animation Nodes エディタ上で利用できる。

f:id:r9aArrowhead:20201221152526p:plain

参照

Animation Nodes - Doc - Viewport input

loose introduction about Animation Nodes (Expression)

概要

Expression ノードに関する説明。

f:id:r9aArrowhead:20201221143817p:plain

一言でいうと、シングルライナー版の Script ノード
a + b など、短い処理をすることに特化しているため、 Script ほど複雑な処理はできないが Animation Nodes が提供していない簡単な処理を記載することができる。

f:id:r9aArrowhead:20201221143824p:plain f:id:r9aArrowhead:20201221143830p:plain

注意点

Expression は一見すると 数式のようなイメージを持つかもしれないが、中身は数式以外も記載できる。
下図は python の条件式を Expression へ記載した例。数式を記載できるノードではなく、プログラムを記載できるノード であることに注意。

f:id:r9aArrowhead:20201221143837p:plain

参考

Animation Nodes - Doc - Expression

loose introduction about Animation Nodes (Script)

概要

script ノードの説明。 このノードは他のノードと異なり python や 数学知識 を必要とするコードベースのノードとなるので、利用に注意。

f:id:r9aArrowhead:20201221112027p:plain

Animation Nodes 上で python スクリプトを実行することができるノード。
その特性上、ノードによるビジュアルプログラミングというよりはバニラの blender が提供しているコードベースのプログラミングになる。

f:id:r9aArrowhead:20201221112039p:plain

また、script はコードベースという性質のために他のノードにはない特徴がある。

  • 追加した入力ソケットに別のノードを接続した場合、 script ノード内では接続したノードから受け取った値で変数が初期化される。
  • 同様に出力ソケットにノードを接続した場合、 script ノードから接続したノードへ値を渡すことができる。
  • python として動くので、コードの中身の基本ルールは python ベース。
  • python にはモジュールインポート機能が存在するが、 * を用いたモジュールインポートは制限されている。 from random import * というよくある書き方はできなくなっている。
  • script ノードは 以下の python モジュールをデフォルトでインポートしている
    • bpy
    • sys
    • itertools
    • animation_nodesAN として短縮系でインポート
    • AN.algorithmsalgorithms として短縮形でインポート
    • MathutilsVector, Matrix, Quaternion, Euler.
    • AN.data_structures に含まれている全モジュール : Vector3DList, Matrix4x4List, MeshData などなど

f:id:r9aArrowhead:20201221112049p:plain

注意点

ノード内に書いたコードは基本的に Animation Nodes が処理を実行する度に処理される。
そのため、細かく制御したい場合は条件分岐やトリガーなどで制御すること。

下図は特に何も制御せず実行した例。 Animation Nodes が処理を実行する度に結果が変わっている。

f:id:r9aArrowhead:20201221112113g:plain

欠点

コードベース故にこのノードは他のノードと異なる欠点も存在する。

  • 処理内容を記述しなければならないので、 Animation Nodes だけではなく python や数学的知識が必要となる。

まとめ

このノードは特別説明するような内容はない。
ノードでは実現できない処理や機能をスクリプトとして Animation Nodes へ追加するためのノード

参照

Animation Nodes - Doc - Script