ハロウィン用に、3Dテキストとクロスの物理演算を使ったエフェクトを作成しました
Blenderでモデルを作成し、Three.jsで動的に表示する仕組みを実装しています
3Dテキストの作成
テキストの追加
- 3Dビューポートで「Shift + A」→「テキスト」を追加
*r x 90で回転すると正面に - 編集モードで文字列を入力
- ちなみに日本語は
テキストの「オブジェクトデータプロパティ」の「フォント」で日本語に対応しているフォントを選択する必要があります
*Macのシステムフォントのパス: /System/Library/Fonts/
また、日本語は直接入力ができないのでコピーしたテキストを貼り付けます
テキストのオブジェクトデータプロパティ
- テキストの揃え方を調整:「オブジェクトデータプロパティ」の「段落」の「配置」
- 文字の間隔を調整:「オブジェクトデータプロパティ」の「段落」の「間隔」
- 文字の押し出し:「オブジェクトデータプロパティ」の「ジオメトリ」の「押し出し」
- 丸みをつける:「オブジェクトデータプロパティ」の「ジオメトリ」の「ベベル」の「深度」
3Dオブジェクトにするために「メッシュ」に変換する
「Alt + C」キーで「メッシュ」に変換
*または「オブジェクト」→「適用」→「表示の形状をメッシュ化」
Blenderでモデリングした際に、曲線は頂点が密集、直線は頂点が少なくなります
今回の3Dテキストはモデルから頂点データを取得して作成したBufferGeometryの頂点を
THREE.Points を使って頂点ごとに点を描画するために利用したいので
頂点を均等に配置します
「リメッシュモディファイア」や「サブディビジョンモディファイア」を使ってモデルの頂点を均等に分布させることができます
リメッシュモディファイア
「モディファイアプロパティ」から「モディファイアを追加」ボタンを押し「リメッシュモディファイア」を追加
サイズを調整して適切な頂点数を維持しつつ形状を確保
リメッシュモディファイアを適用する
作成した3Dテキストのモデルを使ったパーティクルのモーフィングアニメーションの実装について
https://koro-koro.com/threejs-shader-3d/#chapter-9
クロスの物理演算
物理演算は、コンピューター上で重力や衝突、風などの力をシミュレートして物体の動きや変形を再現できます
「クロス」の物理演算を使うと、風や重力の影響を受けた「布」の揺れや、他の物体との接触による変形を表現できます
今回は、UV球の上に平面をかぶせることでお化けの形状を作り、その布が上下に動く際の揺れを表現するために利用
お化けの形状を作成
平面をUV球にかぶせることでお化けの形状にする
*UV球はお化けの「体」の形状を再現するために使用
1:3DビューポートのUV球と平面を配置
2:布の動きや揺れをリアルに表現するために、平面には十分な頂点数が必要なので「サブディビジョンモディファイア」で頂点数を増やす
平面を選択し、「モディファイアプロパティ」から「モディファイアを追加」ボタンを押し「サブディビジョンサーフェイス」を追加
サブディビジョンモディファイアを適用する
- 「カトマルクラーク」と「シンプル」
カトマルクラークは、オブジェクトのメッシュを細分化し、かつ表面を滑らかに
シンプルは、メッシュは細分化しますがオブジェクトの見た目に変化ない - ビューポートのレベルは「0」~「6」で数値が大きいほど滑らかになる
3:平面にクロスの物理演算設定
平面を選択し、右側の「物理プロパティ」タブから「クロス」を追加
「クロス」の「コリジョン」から「セルフコリジョン」にチェックをつける
*これは布が他の部分をすり抜けて不自然な動きにならないように、自身と衝突する動きを考慮するため
余談:ちなみに「コリジョン」とは、3Dグラフィックスや物理シミュレーションの分野で、物体同士が衝突することや、その衝突を検出する技術
オブジェクトにコリジョンを設定することで、そのオブジェクトが他のオブジェクトに影響を与えます
4:UV球にコリジョンの物理演算設定
UV球を選択し、「物理プロパティ」タブから「コリジョン」を追加
5:タイムライン上でシミュレーションを再生、形状を固定したいフレームを選んで、平面を選択してその時点でのクロスモディファイアを適用する
UV球は不要になったため削除
お化けの形状に対してスムースシェードを適用
余談:その他の工程について
- 帽子のモデリングとUV展開
*UV展開はベイクしたテクスチャ画像作成時に必要
ちなみに平面から作成したお化け(布)は、デフォルトでBlenderが自動的にUV展開してくれるため、手動でのUV展開は不要
UV展開について
https://koro-koro.com/blender-no3/#chapter-6 - 帽子とお化け(布)にマテリアルを追加
*お化け(布)にはテクスチャペイントを使用し、手書きで目と口を描く
テクスチャペイントについて
https://koro-koro.com/blender-no3/#chapter-7 - カメラとライトを設定して影をベイクしたテクスチャ画像を作成
*これはThree.jsではライトを使わずにリアルな陰影を再現するため
ベイクしたテクスチャ画像について
https://koro-koro.com/blender-no4/#chapter-6
上下に動く際の揺れを表現
上下に動く際の揺れのシミュレーションを物理演算で作成
1:お化け(布)の上下動アニメーションの設定
タイムライン上でお化けにキーフレームを設定します
タイムラインとキーフレームについて
https://koro-koro.com/blender-no5/#chapter-2
余談
実際には、帽子と布を一緒に動かすために、十字型のエンプティを追加して、このエンプティを親として、帽子と布を子オブジェクトに設定して親子関係を作成しました
これでエンプティを動かすことで、帽子と布が一緒に動きます
2:お化け(布)にウェイトペイントする
*クロスの物理演算を適用すると、布は重力従って全体が下に落ちてしまうので、ウェイトペイントを使って頭部は固定して影響度を調整(グラデーション)します
ウェイトペイントについて
https://koro-koro.com/blender-no5/#chapter-9
3:お化け(布)に物理演算設定
お化け(布)選択し、右側の「物理プロパティ」から「クロス」を追加
クロスの設定内にある「シェイプ」セクションで、「固定グループ」を選択
既にウェイトペイントで作成された「グループ」があるので、そのグループを選択し、布の特定部分を固定します
*剛性を0.01程度の小さい値にするとより布が柔らかく流動的に動くようになります
タイムライン上でシミュレーションを再生
クロスの設定内にある「キャッシュ」で「ベイク」しておきます
備考:「ベイク」について
「ベイク」は物理演算やアニメーションの計算結果を事前にキャッシュとして保存することで、再生するたびにリアルタイムで物理演算を計算する必要がなくなる
- ベイク:全フレームにわたってシミュレーションを計算し、キャッシュに保存
- このフレームまで計算:現在のフレームまでの物理演算をベイク
- 現在のキャッシュをベイク:現在キャッシュに保存されているシミュレーションデータをベイク
- 全物理演算をベイク:すべての物理演算(クロス、流体、パーティクルなど)を一括でベイク
- 全ベイクを削除:現在のシミュレーションキャッシュを削除し、再計算を行える状態に戻す
- このフレームまで全て更新:現在のフレームまでの物理演算のキャッシュを再度更新し保存
複数のフレームで変形した頂点の状態をシェイプキーとして保存
*Three.jsで上下に動く際の揺れを表現したい場合
現在の状態では、お化け(布)の頂点自体は変形していません
編集モードにするとこんな感じです
もしThree.jsで上下に動く際の揺れをリアルに表現したい場合、複数のフレームで変形した頂点の状態を作成し、それをシェイプキーとして保存します
シェイプキーについて
https://koro-koro.com/blender-no5/#chapter-5
1:お化け(布)を選択した状態で、オブジェクトデータプロパティのシェイプキーで「+」ボタンを押してベースを作成
このまま、フレームを移動してシェイプキーを追加しても頂点は変形していないので意味がありません
ポイント
モディファイアを適用すると、頂点は変形しますが、シミュレーションができなくなります
さらに、オブジェクトデータプロパティが切り替わってしまうため、シェイプキーのベースも消えてしまいます
この問題を解決するために
Pythonスクリプトを使ってモディファイア適用後の頂点位置をシェイプキーを追加します
2:Pythonスクリプトを使ってモディファイア適用後の頂点位置をシェイプキーを追加
画面のレイアウトを少し変更して「テキストエディタ」を追加
「テキストエディタ」で「新規」ボタンを押して、新しいテキストファイルを作成
以下のスクリプトをそのままテキストエディタにコピー&ペースト
タイムラインでフレーム(例: 25フレーム、75フレーム、65フレームなど)に移動して
「テキストエディタ」で「実行」ボタン(またはAlt + Pキー)を押してスクリプトを実行します
import bpy
# アクティブオブジェクトを取得
obj = bpy.context.active_object
# 現在のフレーム番号を取得
current_frame = bpy.context.scene.frame_current
# ディペンデンシーグラフからモディファイア後のメッシュデータを取得
dg = bpy.context.evaluated_depsgraph_get()
eval_obj = obj.evaluated_get(dg)
# シェイプキーがあるかどうか確認
if obj.data.shape_keys is None:
# ベースシェイプキーを作成
bpy.ops.object.shape_key_add(from_mix=False)
# 新しいシェイプキーを追加
bpy.ops.object.shape_key_add(from_mix=False)
new_shape_key = obj.data.shape_keys.key_blocks[-1]
new_shape_key.name = f"Sim_Frame_{current_frame}"
# モディファイア後の頂点位置をシェイプキーに保存
for i, v in enumerate(eval_obj.data.vertices):
new_shape_key.data[i].co = v.co
# シェイプキーの保存完了メッセージ
print(f"Frame {current_frame} vertex positions saved to shape key: {new_shape_key.name}")
例として作成したシェイプキー
アニメーションを整える
*物理演算ではなくシェイプキーを設定してアニメーションさせる
1:「物理プロパティ」から「クロス」の「✖️」を押して物理演算を解除します
2:タイムラインを確認しながらでオブジェクトデータプロパティで、作成したそれそれのシェイプキーごとに、値0・値1・値0のキーフレームを設定します
例えば、以下のようにタイムライン上にキーフレームを設定
- Sim_Frame_25
フレーム0: 値 = 0
フレーム25: 値 = 1
フレーム50:値 = 0 - Sim_Frame_75
フレーム25:値 = 0
フレーム75:値 = 1
フレーム100:値 = 0 - Sim_Frame_65
フレーム0:値 = 0
フレーム65:値 = 1
フレーム100:値 = 0
シミュレーション結果と完全に一致するわけではないものの、シェイプキーを使ったキーフレームによるアプローチで、ある程度の自然な動きや変形が再現できるのでは😅
これで、アニメーションを含めたgltfファイルをエクスポートし、それをThree.jsでアニメーションさせることが可能です