ARプログラミング入門 ⑤ アニメーションで命を吹き込もう!
Voxelamming(ボクセラミング)で作った作品に、動きをプラスできたら…と想像してみてください。キャラクターが歩き回り、オブジェクトが変化する、そんなゲームや映画のような表現を、Voxelammingでも実現できるのです。
この記事では、Pythonを使ってVoxelamming作品にアニメーションを吹き込む方法を、基礎から丁寧に解説していきます。あなたの作品がAR空間で躍動する感動を、ぜひ体験してください!
今回は、Voxelammingでアニメーションを作成する方法を学び、AR空間に躍動感あふれる世界を創造してみましょう!あなたの作った作品が動き出す感動を、ぜひ体験してください!
前回の復習と今回の目標
前回は、Pythonの random パッケージを使って、ランダムな線を描く方法を学びました。
予測できないランダムな要素を取り入れることで、Voxelammingで表現できる世界がさらに広がることを実感できたのではないでしょうか。
今回は、Voxelammingでアニメーションを作成する方法を学びます。
Voxelammingのアニメーションには、大きく分けて2つの種類があります。
ノードアニメーション: 1つのボクセルアート全体を動かすアニメーション
グローバルアニメーション: 複数のボクセルアートを含む、ステージ全体を動かすアニメーション
これらのアニメーションを使い分けることで、Voxelammingで表現できる動きの幅が大きく広がります。
今回の目標は、それぞれのアニメーションの特徴を理解し、Voxelammingで躍動感あふれる作品を作ることです。
さあ、あなたの作った作品に命を吹き込み、ARの世界をさらに豊かにしていきましょう!
今回使うPythonの知識
リスト:複数のデータをまとめて管理する
リストは、複数のデータを順番に並べて管理するためのデータ構造です。
例えば、果物の名前をリストで管理したい場合は、以下のように記述します。
fruits = ["りんご", "バナナ", "みかん"]
リストの要素には、数値、文字列、真偽値(True/False)など、様々な種類のデータを格納することができます。
リストの要素へのアクセス
リストの要素にアクセスするには、インデックスを使います。
インデックスは、リストの先頭を0として、順番に1ずつ増加する番号です。
fruits = ["りんご", "バナナ", "みかん"]
print(fruits[0]) # "りんご" が表示される
print(fruits[1]) # "バナナ" が表示される
print(fruits[2]) # "みかん" が表示される
多重リスト:リストの中にリストを格納する
リストの中に、さらにリストを格納することもできます。
このようなリストを多重リストと呼びます。
例えば、以下は、Voxelammingでボクセルを配置する位置を、多重リストで管理する例です。
positions = [
[0, 0, 0],
[1, 2, 3],
[4, 5, 6]
]
print(positions[0][0]) # 0 が表示される
print(positions[1][2]) # 3 が表示される
多重リストを使うことで、複数の位置情報など、複雑なデータ構造を表現することができます。
timeパッケージ:時間を操る
time パッケージは、時間を扱うための標準パッケージです。プログラムの実行を一時停止したり、経過時間を計測したりする際に使用します。
timeパッケージの関数
今回は、time パッケージの sleep 関数を使います。sleep 関数は、指定した秒数だけプログラムの実行を一時停止します。
sleep(seconds): プログラムの実行を指定した秒数だけ一時停止します。
Voxelammingでは、ボクセルデータ送信を連続で行うと、受信側のサーバーが処理しきれず、データが正しく受信されないことがあります。
そこで、今回のサンプルコードでは、sleep 関数を使って、データ送信の間に適切な間隔(インターバル)を挿入することで、データの受信を確実にするようにします。
まとめ
今回は、Pythonのリストと time パッケージについて解説しました。
リストは、複数のデータをまとめて管理するのに便利なデータ構造です。
多重リストを使うことで、より複雑なデータ構造を表現することができます。
time パッケージの sleep 関数は、プログラムの実行を一時停止させることができます。
これらの知識を踏まえて、次の章でサンプルコードを見ていきましょう!
サンプルコード解説
この記事には2つのサンプルコードを含みます。サンプルコードを理解するための前提知識として、初めにノードについて説明します。
ノードとは
Voxelammingでは、ボクセルアートをノードと呼ばれる階層構造で管理しています。
図2は、Voxelammingがボクセルを管理するノード構造を示しています。ノード構造は「ツリー構造」とも呼ばれ、逆さまにした木のような形をしています。木の節に当たる部分をノード(node)と呼びます。
一番上のノードをルートノードと呼び、その下に複数のノードを含みます。
それぞれのノードは、複数のボクセルを含んでおり、1つのボクセルアートを形作っています。
Voxelammingのアニメーションには、大きく分けて2つの種類があります。
ノードアニメーション: 個々のノードを動かすアニメーション
グローバルアニメーション: ルートノードを動かすアニメーション
ノードアニメーションでは、ボクセルアートの一部を動かしたり、複数のボクセルアートをそれぞれ独立に動かすことができます。
一方、グローバルアニメーションでは、ステージ全体を動かすような、ダイナミックな表現が可能です。
これらのアニメーションを使い分けることで、Voxelammingで表現できる動きの幅が大きく広がります。
サンプルコード1: ノードアニメーションでボクセルアートを動かす
まずは、ノードアニメーションを使って、1つのボクセルアート全体を動かす方法を学びます。VS Codeで「node_animation.py」という名前のPythonファイルを作成して、次のコードを記述してください。
from time import sleep
# voxelammingパッケージからVoxelammingクラスをインポートします
from voxelamming import Voxelamming
# Voxelammingアプリに表示されている部屋名を指定してください
room_name = "1000"
# Voxelammingクラスのインスタンスを生成します
vox = Voxelamming(room_name)
# ボクセルの設定を行います
vox.set_box_size(0.5)
vox.set_build_interval(0.01)
for i in range(10):
vox.create_box(-1, i, 0, r=0, g=1, b=1)
vox.create_box(0, i, 0, r=1, g=0, b=0)
vox.create_box(1, i, 0, r=1, g=1, b=0)
vox.create_box(2, i, 0, r=0, g=1, b=1)
for i in range(5):
vox.remove_box(0, i * 2 + 1, 0)
vox.remove_box(1, i * 2, 0)
# ボクセルデータをアプリに送信します。(1回目)
vox.send_data()
# 1秒待機します
sleep(1)
vox.animate(10, 0, 0, pitch=0, yaw=30, roll=0, scale=2, interval=10)
# ボクセルデータをアプリに送信します。(2回目)
vox.send_data()
コード解説
このコードでは、まず、これまでと同様にボクセルを使ってオブジェクトを作成し、 vox.send_data() でVoxelammingアプリに送信します。
その後、sleep(1) で1秒間プログラムの実行を停止し、vox.animate() を実行してアニメーションの設定を行い、再度 vox.send_data() でデータを送信しています。連続でデータを送信すると、データが混線して実行されないことがあるため、適切なインターバル(この場合は1秒)を挟んでいます。
vox.animate(10, 0, 0, pitch=0, yaw=30, roll=0, scale=2, interval=10) : このコードは、オブジェクトに対して、以下のアニメーションを設定します。
10, 0, 0: x軸方向に10cm移動
pitch=0, yaw=30, roll=0: y軸を中心に30度回転
scale=2: 2倍の大きさに拡大
interval=10: 10秒かけてアニメーションを実行
ポイント
ノードアニメーションでは、 vox.send_data() を2回実行する 必要があります。
1回目の vox.send_data() は、オブジェクトの初期状態をアプリに送信するためです。
2回目の vox.send_data() は、アニメーションの設定を送信するためです。
それでは、いよいよサンプルコードを実行して、AR空間にボクセルアートを出現させてみましょう!
コードの実行1. ルーム名を確認
まず、Voxelammingアプリを起動し、画面中央に表示されているルーム名を確認してください。
コードの実行2. ルーム名をコードに反映
サンプルコードの room_name 変数の値を、アプリに表示されているルーム名に書き換えます。書き換え後、保存するのを忘れないようにしてください。
room_name = "XXXX" # XXXXをアプリのルーム名に書き換える
コードの実行3. ターミナルでコードを実行
VS Codeでターミナルを開き、次のコマンドを実行します。
ターミナルからコマンドを実行する
python node_animation.py
プログラムが正常に実行されると、Voxelammingアプリ上に、2つのノード(ハシゴのボクセルアート)が表示されます。一つ目のノードは動きませんが、2つ目のノードは、「右に動く」「回転する」「スケールアップ(大きくなる)」の3つのアニメーションを同時に実行します。
以上で、ノードアニメーションの説明を終わります、次は、グローバルアニメーションを見ていきましょう。
サンプルコード2: グローバルアニメーションでステージ全体を動かす
次に、グローバルアニメーションを使って、複数のボクセルアートを含むステージ全体を動かす方法を学びます。VS Codeで「global_animation.py」という名前のPythonファイルを作成して、次のコードを記述してください。
from time import sleep
# voxelammingパッケージからVoxelammingクラスをインポートします
from voxelamming import Voxelamming
# Voxelammingアプリに表示されている部屋名を指定してください
room_name = "1000"
# Voxelammingクラスのインスタンスを生成します
vox = Voxelamming(room_name)
# ボクセルの設定を行います
vox.set_box_size(0.3)
vox.set_build_interval(0.01)
# ボクセルを配置するため、位置と色を設定します
for i in range(10):
vox.create_box(-1, i, 0, r=0, g=1, b=1, alpha=1)
vox.create_box(0, i, 0, r=1, g=0, b=0, alpha=1)
vox.create_box(1, i, 0, r=1, g=1, b=0, alpha=1)
vox.create_box(2, i, 0, r=0, g=1, b=1, alpha=1)
for i in range(5):
vox.remove_box(0, i * 2 + 1, 0)
vox.remove_box(1, i * 2, 0)
# ボクセルを配置する位置を設定します
node_positions = [
[0, 0, 0],
[-10, 0, 0],
[10, 0, 0],
[0, -20, 0],
[0, 20, 0],
[0, 0, -10],
[0, 0, 10],
]
for x, y, z in node_positions:
# ボクセルを配置するため、位置を設定します
vox.transform(x, y, z, pitch=0, yaw=0, roll=0)
# ボクセルデータをアプリに送信します。(位置を変えて、複数回送信)
vox.send_data()
# 1秒待機します
sleep(1)
vox.animate_global(0, 0, 0, pitch=0, yaw=180, roll=0, scale=1, interval=100)
# ボクセルデータをアプリに送信します。(グローバルアニメーション)
vox.send_data()
コード解説
このコードでは、まず、同じボクセルアートを、node_positions リストで定義された複数の位置に配置しています。
node_positions: 各ボクセルアートを配置する位置のリスト。多重リストで、各要素は [x, y, z] の形式で座標を表しています。
for x, y, z in node_positions: のループ内で、vox.transform(x, y, z) を実行することで、ボクセルアートの配置位置を移動し、それぞれの位置で vox.send_data() を実行して、ボクセルアートをアプリに送信しています。
その後、vox.animate_global() を実行してグローバルアニメーションの設定を行い、vox.send_data() でデータを送信しています。
vox.animate_global(0, 0, 0, pitch=0, yaw=180, roll=0, scale=1, interval=100) : このコードは、ステージ全体に対して、以下のアニメーションを設定します。
0, 0, 0: 移動はなし
pitch=0, yaw=180, roll=0: y軸を中心に180度回転
scale=1: 大きさの変更はなし
interval=100: 100フレームかけてアニメーションを実行
ポイント
グローバルアニメーションでは、vox.send_data() を最後に1回実行する 必要があります。
これは、グローバルアニメーションの設定は、ステージ全体に適用されるため、最後にまとめて送信すればよいからです。
コードの実行
先ほどと同じ手順で、ターミナルで次のコマンドを実行します。
python global_animation.py
プログラムが正常に実行されると、Voxelammingアプリ上に、7つのノード(ハシゴのボクセルアート)が表示されます。グローバルアニメーションの設定により、ステージごと全てのノードが同じ方向に回転します。黒と白のベースアンカーも同じように動くことから、全ての要素が回転していることがわかります。
この章では、ノードアニメーションとグローバルアニメーションのサンプルコードを解説しました。
次の章では、アニメーションを使った次の章では、応用として、今回作成したアニメーションを改造して、オリジナル作品作りに挑戦してみましょう!
応用:オリジナル作品作りに挑戦!
問題1: 爆発のスローモーションを表現しよう!
ノードアニメーションを使って、爆発の瞬間をスローモーションで表現してみましょう。100個のボクセルの破片が、それぞれランダムな方向にゆっくりと飛び散っていく様子をARで表現します。
挑戦する前に
自分で考えてコードを書いてみると、プログラミングの理解がより深まります。時間がない方は、回答例を参考にしてください。
回答例
VS Codeで「explosion.py」という名前のファイルを作成し、以下のコードを記述してください。
from time import sleep
from random import random, uniform
from math import sin, cos, pi
from voxelamming import Voxelamming
# Voxelammingアプリに表示されている部屋名を指定してください
room_name = "1000"
# Voxelammingクラスのインスタンスを生成します
vox = Voxelamming(room_name)
# ボクセルの設定を行います
vox.set_box_size(1)
vox.set_build_interval(0) # インターバルを0にする
# 爆発の中心座標
center_x = 0
center_y = 0
center_z = 0
# 破片の数
fragment_num = 100
# 破片を配置
vox.create_box(0, 0, 0, 1, 0, 0)
# 各破片のノードを作成
for i in range(fragment_num):
# ランダムな方向と速度を設定
angle_h = uniform(0, 2 * pi) # 水平方向の角度
angle_v = uniform(0, pi / 2) # 垂直方向の角度
speed = uniform(50, 100)
# 移動距離を計算
x = speed * cos(angle_h) * sin(angle_v)
y = speed * cos(angle_v)
z = speed * sin(angle_h) * sin(angle_v)
# ランダムな色を設定
r = random()
g = random()
b = random()
# アニメーションを設定
vox.animate(x, y, z, interval=100) # 100フレームかけて移動
# ボクセルデータをアプリに送信します。
vox.send_data()
sleep(0.5) # 0.5秒待機
解説
このコードでは、まず赤いボクセルを一つ作成し、その後、そのボクセルが爆発して、fragment_num 個の破片が飛び散る様子をノードアニメーションで表現しています。
各破片は、ランダムな方向と速度で移動するように設定されています。
angle_h: 水平方向の角度 (0 ~ 360度)
angle_v: 垂直方向の角度 (0 ~ 90度)
speed: 速度
animate メソッドの interval 引数を 100 に設定することで、100フレーム (約10秒) かけて破片が移動するようにしています。
sleep(0.5) を入れることで、各破片のアニメーションデータ送信間隔を0.5秒に設定しています。
ポイント
vox.set_build_interval(0) : ボクセルの設置間隔を0秒に設定することで、破片はすぐに配置されます。その後、アニメーションで指示した方向に動き始めます。
animate メソッド: ノードアニメーションでは、animate メソッドで設定したアニメーションが、send_data を実行するたびに、前回の最終状態から開始されます。
そのため、破片が連続的に移動していくように見えるのです。1つのボクセルをアニメーション: このコードでは、1つのボクセルに対してアニメーションを設定し、それを連続して送信することで、爆発を表現しています。
これは、Voxelammingのアニメーション機能のユニークな使い方と言えるでしょう。
このプログラムを実行すると、赤い破片がランダムな方向に飛び去っていく爆発のスローモーションを再現できます。
挑戦してみよう!
破片の色や大きさを変えてみよう
爆発の速度や破片の数を調整してみよう
重力を表現するために、y軸方向の移動距離を調整してみよう
問題2: メリーゴーランドを作ろう!
回転するメリーゴーランドを、グルーバルアニメーションを使って作ってみましょう。
回答例
VS Codeで「merry_go_round.py」という名前のファイルを作成し、以下のコードを記述してください。
from time import sleep
from voxelamming import Voxelamming
# Voxelammingアプリに表示されている部屋名を指定してください
room_name = "1000"
# Voxelammingクラスのインスタンスを生成します
vox = Voxelamming(room_name)
# ボクセルの設定を行います
vox.set_box_size(0.4)
vox.set_build_interval(0) # インターバルを0にする
# 土台
for i in range(-16, 17):
for j in range(-16, 17):
if i ** 2 + j ** 2 < 16 ** 2:
vox.create_box(i, 0, j, r=0.8, g=0.5, b=0.2)
# 支柱
for i in range(10):
vox.create_box(0, i + 1, 0, r=0.6, g=0.3, b=0.1)
# 回転軸
vox.create_box(0, 11, 0, r=0.9, g=0.9, b=0.9)
# 馬を作成する関数
def create_horse(x, y, z, r, g, b):
vox.create_box(x, y + 3, z, r=r, g=g, b=b) # 頭
vox.create_box(x, y + 2, z, r=r, g=g, b=b) # 体
vox.create_box(x + 1, y + 1, z, r=r, g=g, b=b) # 足
vox.create_box(x - 1, y + 1, z, r=r, g=g, b=b) # 足
# 馬の初期位置
horse_positions_and_colors = [
[8, 1, 8, 1, 0, 0],
[-8, 1, 8, 0, 1, 0],
[8, 1, -8, 0, 0, 1],
[-8, 1, -8, 1, 1, 0]
]
# 馬のノードを作成
for positions_and_colors in horse_positions_and_colors:
create_horse(*positions_and_colors)
vox.send_data("merry_go_round")
sleep(1)
# メリーゴーランドを回転させる
for i in range(10):
# メリーゴーランドを回転させる(グローバルアニメーション)
# 回転できる角度は180度までです。
vox.animate_global(0, 0, 0, pitch=0, yaw=180, roll=0, scale=1, interval=1)
# ボクセルデータをアプリに送信します。(グローバルアニメーション)
vox.send_data()
sleep(1.1)
解説
このコードでは、円形の土台、支柱、回転軸を作成し、create_horse 関数で馬を作成しています。
馬は horse_positions_and_colors リストで定義された4つの位置と色で配置されます。
その後、グローバルアニメーションを使って、メリーゴーランド全体を回転させています。
ポイント
horse_positions_and_colors : 各馬のx座標、y座標、z座標に加え、色情報(r, g, b)もリストに含めています。
create_horse(*positions_and_colors): *を使って、リストの要素を関数の引数として展開しています。
これにより、create_horse関数を呼び出す際に、リストの各要素を個別の引数として渡すことができます。vox.animate_global(): グローバルアニメーションは、ステージ全体に適用されるアニメーションなので、vox.send_data()は最後に1回だけ実行すればよいです。
回転角度: animate_global() の yaw 引数は、180度までしか設定できません。180度を超える角度(270度)を指定すると、逆方向-90度)に回転してしまいます。これは、Voxelammingが内部で利用している3Dグラフィックスフレームワーク(RealityKit)の仕様による制限です。
このプログラムを実行すると、メリーゴーランドが180度回転します。しかし動きをよく見ると、2回目以降は、元の角度(0度)に戻ってから、180度まで回転する動作を繰り返しています。
つまり、スムーズに360度回転させることは現時点では難しいことがわかります。今後のVoxelammingアプリの開発進展に期待しましょう。
この章では、2つの例を示して、アニメーションの理解を深めることができました。アニメーションをマスターすれば、Voxelammingで表現できる世界はさらに広がります!
ぜひ、今回のサンプルコードを参考に、色々な動きを試して、あなただけのオリジナル作品作りに挑戦してみてください!
まとめ
今回は、アニメーションという、Voxelammingの世界に動きを与える強力なツールを手に入れました。
ノードアニメーションでは、個々のボクセルアートに動きを与えることができます。
グローバルアニメーションでは、ステージ全体を動かすような、ダイナミックな表現が可能です。
time パッケージの sleep 関数を使うことで、データ送信のタイミングを制御したりすることもできるようになりました。
アニメーションをマスターすれば、Voxelammingで表現できる世界はさらに広がります。
ぜひ、今回のサンプルコードを参考に、想像力を膨らませて、あなただけのオリジナル作品作りに挑戦してみてください!
次回は、タートルグラフィックスに挑戦します。
タートルグラフィックスとは、タートル(亀)を動かしながら、その軌跡に線を描くことで、様々な模様や図形を作成するプログラミング方法です。Pythonのタートルグラフィックスは2次元ですが、Voxelammingのタートルグラフィックスは、3次元空間を自由に移動できます。
前進、後進、右折、左折など、まるで自動車を運転するようにタートルを制御できるので、幼稚園児を含めた子供でも直感的に理解することができます。
Voxelammingの世界で、タートルグラフィックスを使って、どんなアート作品を生み出せるか、ご期待ください! 🐢
AR プログラミング入門シリーズ
ARプログラミング入門シリーズの一覧です。全8回で完結します。
次回、中級編は構想中です。ご期待ください!
第1回 Voxelammingについて
第2回 ボクセルアートの色と形を変えてみよう!
第3回 球体を作る
第4回 ランダムな線でアートを描こう!
第5回 アニメーションで命を吹き込もう!
第6回 タートルグラフィックスで図形を描こう!
第7回 文字でAR空間にメッセージを描こう!
第8回 再帰関数でフラクタルに挑戦!
サンプルコードを公開
GitHubレポジトリでサンプルコードを公開しています。記事を読むときに参照してください。