Refactoring Houdini Node Network – メンテナンス性の高いノードネットワーク構築のために

■はじめに

 この記事は、「Houdini Advent Calendar 2018 – 8日目」の記事です。

 既存のノードネットワークを変更する際、変更する対象が巨大であるためにどこを変更すべきかわかりにくくなってしまっていたり、ある箇所への変更が他の箇所に影響してしまい、メンテナンスしづらい状況を経験したことは誰にでもあると思います。

 この記事では、そのような状況を改善・予防するため「リファクタリング」と呼ばれる手法に焦点を当て、筆者の主観をもとに基本的な手法を紹介したいと思います。

■対象読者

・Houdini初級~中級者
・メンテナンスしにくいノードネットワークに日々苦しんでいる方
・メンテナンスしやすい設計でノードネットワークを構築したい方
・プログラミング初心者で、読みやすいコードを書くための作法を知りたい方


■リファクタリングとはなにか?

 リファクタリング (refactoring) とは、コンピュータプログラミングにおいて、プログラムの外部から見た動作を変えずソースコードの内部構造を整理することである。また、いくつかのリファクタリング手法の総称としても使われる。ただし、十分に確立された技術とはいえず、また「リファクタリング」という言葉に厳密な定義があるわけではない。(Wikipediaより抜粋)

※ここでいう「プログラムの外部から見た動作を変えず」というのは、リファクタリング前後で、リファクタリングする対象が行う処理の結果を変えないという意味です。


■Houdiniでのリファクタリング

 Houdiniでの作業はプログラミング色が強く、ノードネットワークを組み立てることはプログラミングすることそのものと言えます。
 ノードネットワークは、ある種ソースコードのようなものです。
 更に、HoudiniではVEX/Wrangle/Pythonなど、プログラミングそのものを行う要素も含んでいます。

 そのため「リファクタリング」手法のいくつかをHoudiniでも比較的素直に取り入れることができます。


■リファクタリングのメリット

 リファクタリングにより、ノードネットワークの構造を整理することができ、結果として以下のようなメリットが得られます。

・ノードネットワークを局所的/全体的に理解しやすくなる
・ノードネットワークの修正(保守)が簡単になる
・ノードネットワークの拡張が簡単になる
・理解しやすく整理された形で新たなノードネットワークを作れるようになる


■手法ごとの具体的な方法

□名前の変更

 ノード名、パラメータ名、アトリビュート名、Wrangleの変数名など、各種「名前付きの要素」を、誰が見てもわかりやすい形にリネームします。

 これにより、その要素の役割が判断しやすくなり、時間が経ってから見直したときや、他人へデータを渡したときに処理の内容を理解する助けになります。

・名前のプリフィクス(接頭辞)について

set_, del_ などの部分だけでノードごとの基本的な動作が伝わります

 その要素が何を行うものであるか判断できるよう、名前の先頭に目的に応じたプリフィクスを追加します。
 ルールに則ったプリフィクスを利用すると、ひと目でその要素が大雑把にどのような動作をするものか判断しやすくなり、メンテナンス性が向上します。

 例えばノード名はそのノードの動作に適した動詞をプリフィクスにします。
 変数名の場合も同様に、変数の役割がわかるようなプリフィクスをつけます。

 このようにしておけば、ノードリストなどでノードを検索する際のヒントにもなります。

目的の例プリフィクスの例
何かを追加するadd_
何かを削除するdel_
何かを計算するcalc_
何かを移動するmove_
何かをセットするset_
何かのテストにつかうtest_

・意味のある名前について

aaaaaaaaaaaは最終的に必要?目的は?
1年後に思い出せる気がしません・・・

 プログラミング学び初めの頃によくやってしまいがちなことの一つに、実験用の変数のような「瞬間的にほしい要素」に対し、一見して意味のない名前をつけるということがあります。

 これは、実験中はいいのですが、実験終了後にこの要素が不要となったにもかかわらず、要素を消し忘れたまま時間が経ってしまった時に問題を引き起こします。

 このような要素は本来不要であるにもかかわらず、なんとなくまだ必要そうな気がしてしまい、出来上がった仕組みを壊してしまうことに対する恐れも手伝い、消せないまま放置してしまったことがある方は多いのではないでしょうか。

 また、実験用に作った要素が最終的に採用され、利用されることになるケースもあります。
 このような場合も、はじめから意味のある名前をつけておけば、名前を修正する手間が省けて一石二鳥です。

意味のない名前の例
a b c
aaa bbb ccc
gngingaio miewaaaaaa

※ループカウンターで使われる[i,j,k]や、座標を表現する際に使われる[x,y,z][u,v,w]などは、それ単体では意味のないアルファベットですが、一般的な名前として広く認知されているので、意味を持っています。
そのため、使用しても何ら問題ありません。

・名前の記法について

各種記法で記述したノード名のサンプル

 プログラミングで使われる名前の記法には いくつか種類があります。
 よく目にする主な記法はだいたい以下の3通りだと思います。

スネーク記法
全部小文字
単語の区切りをアンダーバーで区切る
プログラミングでは主に変数名で使用
calc_cut_distance
point_num
prim_area
add_two_point
ローワーキャメル記法
名前の先頭は必ず小文字
単語の区切りごとに頭文字を大文字にする
主に変数名で使用
calcCutDistance
pointNum
primArea
addTwoPoints
アッパーキャメル記法
すべての単語の区切りごとに頭文字を大文字にする
プログラミングでは主にクラス名で使用
CalcCutDistance
PointNum
PrimArea
AddTwoPoints

 筆者は最近、Pythonのコード規約であるPEP8にならうことが多いです。
 具体的に言うと以下のようなルールに従っています。

・ノード名やプログラムの変数名はローワーキャメルケースで記述
・Pythonコード中のクラス名はアッパーキャメルケースで記述

・略称について

略しすぎると、そのノードの役割が全くわからなくなります

 名前付き要素に略称を使うことは可読性を損なう一因となります。
 メンテナンス性を高めるためには、極力名前のパーツに略称を使わないことが望ましいといえます。

 例えば、あるノードを「calc_center_position」という具体的な名前にする場合を考えます。
 このとき、「position」という言葉が長すぎると感じるかもしれません。
 そのような場合、略称を使いたくなります。

 しかし、ここで「position」を「p」と極端に略した場合、その「p」がどのような意味合いで選択された名前なのか第三者には瞬時に理解できません。(もちろん前後の文脈から想像はできますが、瞬時に理解するのは難しいでしょう)
 もしかしたら、数日後の自分ですらその「p」が何なのか即答できないかもしれません。

 そこで、この「position」という文字列を、一般的によく使われる「pos」という略称に置き換えるのは悪くない考えです。
 ただし、前後の文脈によっては「pos」から「positive」など、別の言葉を連想する可能性もあり得るので、意味をはっきり伝えるという意味では少し確実性に欠けます。

 とはいえ名前が長くなりすぎるのも困りものです。
 実際のところ、若干の読みやすさを犠牲にして、明らかに一般的な共通認識として定着している略称のみを必要最小限の範囲で使用するのが良い落とし所となるでしょう。

元の名前の例略称名略称名(悪い例)
positionposps, p
pointptp
attributeattra, at,
numbernumm, nm,

・長すぎる名前について

長過ぎる名前は、詳細はわかりますが不便です
適度に略称を取り入れながら、ほどほどの長さに収めましょう

 名前の文字数は長くても20文字~30文字までといった意見をよく見かけます。
 確かに長い名前はコードが複雑化すると全体が見づらくなる原因になります。
 ちょっとした文章のような長さの名前はおすすめできません。

 ですが、省略しすぎて意味が全くわからない名前よりは遥かに良いです。
 短すぎる名前を使うくらいなら、意味のわかる長い名前を使いましょう。


 VEXやPythonの場合、Visual Studio CodeやSublimeなどに、対応する言語のプラグインをインストールして外部エディタとして利用すると、インテリセンス(コード補完機能)が使えるようになります。
 Houdini内ではノードパスなどでインテリセンスが利用できます。

 そのため、多少長い名前を使用していても間違いなく簡単に入力できるうえに、いざ名前が長すぎたと感じる場合でも、エディタの機能で特定の対象だけ簡単にリネームできるので、さほど問題になりません。

・名前付けの具体例

 上記を踏まえた上で、具体的な名付けの例を挙げてみます。

要素の目的や動作名前の例
ポイントを追加するwrangle名add_point
primにsizeアトリビュートを追加するwrangle名add_size_attr_to_prim
三角ポリゴンを削除するwrangle名del_triangle_prims
ループ数を格納する変数名loop_num
ポイント数を格納する変数名point_num
ベクトルAとBの内積を格納する変数名
dot_A_B

□アルゴリズムの更新とテスト

compare_geometryでunittestを行いながら処理を分解

 リファクタリングの重要なポイントに、処理の内容を変えずに構造を整理するということを挙げました。
 そのためには、リファクタリングの前後で結果に差がないことを確認しながら作業をすることが重要です。

 通常のプログラミングでのリファクタリングは以下のように進めます。

1リファクタリング対象を複製し、もとのロジックをとっておきます。
2リファクタリング後の処理がどうなっていれば正解なのか判断できるデータを作ります。
このデータを、リファクタリング後の処理結果と常時比較しながら、結果が異なる場合に即座に検知するために使います。
この比較は、一般的にユニットテストと呼ばれます。
3リファクタリング語の処理結果が、リファクタリング前と同じであることを確認しながら構造の修正を行います。
4リファクタリングが完了し、もとの処理が必要なくなったら削除

 Houdiniの場合もこれによく似ていて、以下のように進めます

1リファクタリング対象のノードや一連のノードチェーンを複製、分流。
2Switch SOPを作成し、分流したノードの出力を接続します。
このSwitch SOPでリファクタリング前後の結果を簡単にスイッチして確認しやすくします。
ジオメトリのアトリビュートを比較するユニットテスト用HDAを作成してもいいでしょう。
3リファクタリング前後で結果が同じであることを確認しながら構造の修正を行います。
4リファクタリングが完了し、もとの処理が必要なくなったら削除

□関心の分離

1つのWrangleに3種類の処理が含まれていたので分解した例

 1つのノードでは、1度に1種類の処理のみを行うようにします。
 例えば、色を設定するWrangle SOPでは色を設定することのみを行うようにします。
 このWrangle SOPでは、色を設定すると同時に法線を設定するように複数種類の処理をさせることはしません。
 色の設定と別に法線を設定する必要がある場合、2つの処理を切り分けて別々のノードを作成し、それぞれで処理を行います。

 処理を切り分けることでその処理が影響する範囲が小さくなります。
 これにより、この処理に対する何らかの変更が必要な場合に気を配る必要にある範囲が小さくなります。
 これが「関心を分離する」ということです。

 関心を分離した結果、それぞれの処理に変更を加えたい場合や、ある処理の前後に新たな処理を追加する場合に、変更すべき箇所がわかりやすくなります。

 また、ノードを切り分ける場合は、処理のステップが複数のノードに分かれるので、各ノードのVisibilityフラグを切り替えながら、各処理ごとの結果が確認しやすくなります。

 Wrangleの場合、コード中の特定の行で処理を止めて途中経過を確認するようなデバッグ機能がないので、Wrangleコードとそのコードで使われるパラメータを機能単位のWrangleに切り分けて関心を分離することになります。


□処理の集約

整理された5つの処理を、1つのsubnetに集約した

 Houdiniに限らず一般的なプログラミングでは、複数の小さな処理を積み重ねて大きな処理を組み立てていきます。

 Houdiniでは、複数のノードをSubnetノードにパックしてまとめることができます。
 複数の小さな処理で成り立つ大きな処理をパックすることで、処理のくくりが明確になり、ノードネットワークの見通しが良くなります。

 これは一見すると、上で挙げた「関心の分離」に反するように見えます。
 たしかに、何も考えずにSubnetに複数のノードをまとめてしまうと、むしろノードネットワークが俯瞰しづらくなり、混乱の原因になります。

 そのため、処理を集約する際は、必ず集約する処理に対し関心の分離を適用します。
 複数の処理を一つのSubnetにまとめるタイミングは、関心の分離を適用する前でも後でも問題ありません。
 関心の分離を適用するとノードが増えます。
 すでにノードネットワーク全体が膨大なノード数で構成されていて、これ以上ノードを増やすと視覚的に全体を俯瞰しづらくなる場合などは、先に関心の分離を適用する処理の範囲をSubnetにまとめておき、そのSubnet内で適用することで、その他の箇所に気を取られずに作業できるようになります。

 これもまた、ノードネットワーク全体を巨大な処理と見立てた関心の分離とも呼べます。


□処理の再利用

 一心不乱にノードネットワークを作成していると、途中で行ったコピー&ペーストの影響なども手伝い、全く同じ処理を随所で繰り返している事態に陥ることがあります。

 全く同じ処理が複数箇所にあり、それぞれの処理に同じ変更を加えたい場合、それぞれに対し個別に同じ変更を加えるのは現実的とは言えません。

 このような場合、処理を切り出して再利用できるようにします。
 その後、切り出した再利用可能な処理で各所の重複部分を置き換えることで、その後の処理変更が1箇所で行えるようになります。

・HDA

 Subnetにまとめた仕組みは、デジタルアセットに変換することで再利用が簡単になります。(この方法については、多くの方が言及されているので、ここでは解説しません)

・Compiled Block/Invoke Compiled Block

同じ処理の一つCompiled Blockにまとめ
Invoke Compiled Blockによって呼び出しながら再利用

 Compiled Blockに対応しているノードだけで処理を構成する必要がありますが、Compiled Blockを使って一連の処理をひとくくりにし、Invoke Compiled Blockを通して、一連の処理を再利用できます。


 他にも多くのリファクタリングテクニックがあるのですが、ここでは基本的なものに絞って紹介させていただきました。
 タイムリミットも迫り記事も長くなってしまったので、より実践的なリファクタリングの実例紹介は別の機会に・・・

 この記事について、なにかご質問や間違いがありましたら遠慮なくツッコミをいただけると助かります。


 最後に、個人的にリファクタリング関連で参考になったと感じる書籍をいくつか紹介します。

 Houdiniはそもそもプログラミングツールではないため、これらの書籍で紹介されるすべてのテクニックが適用できるわけではありませんが、多くの点で役立ちます。(今回ご紹介したリファクタリングや、Wrangle、Pythonでコーディングする際など)

 特に「レガシーコード改善ガイド」の方は、古いコードのメンテナンスに際し起こりうる様々な問題ごとに適用できる、リファクタリングとテストを使うコード改善テクニックが紹介されています。
 今回紹介したユニットテストを使う安全な開発方法(テスト駆動開発)も、こちらの書籍から着想を得ています。

 興味のある方はぜひ読んでみてください。


 

KINGSGLAIVEセミナーおさらい プロテス – サンプルhiplcファイルあり

先週と同様、Indyzone主催のHoudiniセミナー「KINGSGLAIVE FINAL FANTASY XV メイキングストーリー」のおさらいをしていました。

というわけで、今日はプロテスのエフェクトです。

今回もサンプルファイルを付けてみました。
興味のある方はぜひ覗いてみてください。

■ダウンロード(One Drive)
MYAM_imitation_FF_KINGSGLAIVE_Protes.zip

zipファイル解凍後に出てくるHoudiniProjectフォルダにSetProjectしてからシーンを開いてください。


■シーンファイルに関して

うろ覚えではあるのですが、セミナーの説明では、@Cdアトリビュートを利用してプロテスエフェクトの「生成、再生、破壊」の振る舞いを決める部分で、ベースになるプロテス障壁の形状を分流してそれぞれを個別のグループに入れながらPaintSOPなどで@Cdの設定を行い、最後にMergeSOPで各データフローを統合してから、最終的に使用しないグループに含まれる成分を削除するという解説だったように思います。

今回は、この部分を極力簡略化し、カラーを独自アトリビュートに変換したあとでAttributeTransferSOPでレンダーモデルに転送する方法を試してみました。
空間転写は処理負荷が高いので、もう少し上手に軽い方法を使えばよかったと思っていたりします。


何か間違いなどあればご遠慮無くツッコミください。
とても喜びます。

KINGSGLAIVEセミナーおさらい ワープエフェクト – サンプルhiplcファイルあり



三連休でやっと時間が取れたこともあり、少し前に行われたIndyzone主催のHoudiniセミナー「KINGSGLAIVE FINAL FANTASY XV メイキングストーリー」のおさらいをしています。

というわけで、とりあえず手始めに今日はワープエフェクトに関してです。

今回もサンプルファイルを付けてみました。
完全な再現とまでは行かなくとも、ボリュームと移流の扱い方に関しては、だいたい再現できていると思います。
興味のある方はぜひ覗いてみてください。

■ダウンロード(One Drive)
MYAM_imitation_FF_KINGSGLAIVE_WarpFX

※ノード名がセミナー中の説明と合ってなかったので、修正しました

zipファイル解凍後に出てくるHoudiniProjectフォルダにSetProjectしてからシーンを開いてください。


概要

ワープエフェクトは、5つの単純な要素を組み合わせて作ります。

  • Spark:火花
    荒いボリュームからパーティクルへ力を渡し、移流して動かします
    その後、TrailSOPなどを使用して火花っぽい見た目を作ります。
  • Ash:灰
    Spark同様に移流してパーティクルを動かします。
    その後、灰オブジェクトをパーティクル上にコピーします。
  • Fire:小さな火の玉
    Spark同様に移流してパーティクルを動かします。
    その後、あらかじめ作成しておいた火の玉シミュレーションのキャッシュをパーティクル上にコピーします。
    その際、キャッシュのスタート時間をランダム化して見た目にばらつきをもたせます。
  • Steam:体から立ち上る蒸気
    Sparkなどで使用する荒いボリュームを複製後に編集し、高解像度化したボリュームを蒸気として使用しました。
  • Crystal:体から飛び散るクリスタル片
    初速と重力によって動く単純なパーティクルにクリスタル片オブジェクトをコピーして作ります。

一見複雑なワープエフェクトは、実は単純な要素を組み合わせて作られています。


シーンファイルについて

スケール調整の手間を省いたので、現実スケールに対しシーンスケールが大きめになっているため、ダイナミクスオブジェクトの動きが若干遅く感じられると思います。


何か間違いなどあればご遠慮無くツッコミください。
とても喜びます。

Houdini – 基本的なデータの取り回し方(サンプルファイルあり)

Houdiniを触り始めた頃、アトリビュートや変数のデータの取り回し方がわかりにくいと感じていました。
中でも特にローカル変数の挙動がよく理解できずに、正しく値を操作できても何だか狐につままれたような気持ちになっていました。

最近はそのようなこともなくなり、意図したとおりに値を操作できるようになってきたので、実践している値の取り回し方を備忘録的な意味で書いてみます。

今回もまたちょっとしたサンプルファイルをつけてみます。

■ダウンロード(One Drive)
MYAM_attributeAccess_exsample


Houdiniで扱うデータのスコープ

Houdiniの中で主にユーザーが直接扱うデータには、以下のようにいくつかの種類とスコープがあります。

  • グローバル変数
  • ローカル変数
  • パラメータ
  • アトリビュート

Houdiniに触り始めた頃、わかりにくいと感じていた部分が、ローカル変数とパラメータとアトリビュートの相互の関係性です。

※グローバル変数は、環境に依存しすぎる気がするので、最近でも極力手を付けないようにしています。(パス文字列の簡略化などに使えばとても便利ですが)
よって、今回の記事では扱いません。


なにがわかりにくかったのか?

さまざまなチュートリアルを見ると、Attribute Create SOPを使い、アトリビュートを作成すると同時にローカル変数も定義して、下流のパラメータエクスプレッションの中でローカル変数を参照して処理をするやり方が散見されます。

これは勝手な印象ですが、特に古いバージョンのチュートリアルで顕著だったように思います。

チュートリアルの後、自分なりに実践してみてうまく値を扱えない時に感じたのが

  • データフローの上流で作ったはずのローカル変数が下流で参照できない・・・
  • と思ったらなぜか使える場合があったりする・・・
  • オペレータの性質から想像するに、マニュアルを引くまでもなく明らかに使えそうに思えるローカル変数が使えない・・・
  • オペレータのリファレンスマニュアルに記載されてるローカル変数が使えない・・・
  • アトリビュートを直接操作したい・・・ローカル変数を参照できない理由がわからない・・・まるで異次元に迷い込んだようだ・・・地獄だ・・・

といったあたりです。
平たく言うと

「ローカル変数が値の操作を混乱させる諸悪の根源」

のように感じていたわけです。


デジタルアセットとローカル変数の罠

また、このローカル変数というやつは、デジタルアセット上で使用できないという、恐るべき制約も手伝って、更に話をややこしくしています。
※ColorSOPのマニュアルに記載あり。
もしかしたら、全デジタルアセットの性質ということではなく、ColorSOPに限った話かもしれません

例えば、Color SOPはデジタルアセットで、Colorパラメータ内ではローカル変数を使用できません。上流で独自アトリビュートを作成し独自のローカル変数を作っても参照できません。

紛らわしいことに、そもそもColorSOP自体、上流で@Cdアトリビュート操作があることを想定していません。あくまでも@Cd操作の開始点として使用する前提です。

このような場合、Color SOPではなくPoint SOPを使用し、その中でローカル変数を参照することで問題なく@Cdアトリビュートを直接操作できます。

このような紛らわしさもまた、一つの地雷と言えそうです。


ローカル変数よ、さようなら

ではどうすればいいのか。

結論を言うと、Attribute Wrangle SOPを介してアトリビュートを直接管理や操作をするのがベストだと考えています。

最近のバージョンでは、VEX周りがかなり進化しています。
Attribute Wrangle SOP内だけでなく、各オペレータのパラメータエクスプレッションでも、VEXのように@記法で直接アトリビュートを参照したり、それができない場合でもpoint関数などを使ってアトリビュートを直接参照する事ができます。

値の管理と操作を、一貫したVEXの世界で行えるのは、この上なくシンプルで理想的です。
今のところこの方法で困ったことは一度もありません。

よって、もう、ローカル変数の出番は無いとすら思います。


まとめ

というわけで、今考えているわかりやすくデータを取り回すための方策は以下の通りです

  • アトリビュートの作成にはAttribute Wrangle SOPを使う
  • アトリビュートの操作にはAttribute Wrangle SOPやAttribute VOP SOPを使う
  • アトリビュートの参照は@記法を使って直接参照する
    またはpoint関数などのアトリビュート値を直接取得する関数を使う
  • ローカル変数は使わない
    $CEXなど便利なローカル変数はあるが、同様のVEX関数もあるのでそちらを使うようにする。

これが同じ悩みを持つ方の一助となれば幸いです。

何か間違いなどあれば遠慮なくツッコミをください。

“NATURE OF CODE” in Houdini – 002 – 力

長い間、仕事ではパイプライン系ツールを書くことが多くなり、幾何学や物理などの数学とはだいぶ疎遠になってしまいました。

最近になって、やっとHoudiniを業務で使用させてもらえる環境が与えられたこともあり、これも良い機会ということで、これからしばらくの間、数学の勉強や復習とリハビリを兼ね、Processingの名著 [NATURE OF CODE] の内容を、Houdiniを使って追いかけていきたいと思います。




 

■動画内容の御品書

  1. シンプルな力
    単純な力を与えて動かす。
  2. 力と質量
    質量を考慮しながらシンプルな力(重力+風)を与えて動かす。
    小さいものほど風の影響を受けやすく水平方向によく動く。
  3. 力と摩擦
    摩擦による減速。
  4. 力と流体抵抗
    Y=0の位置から流体があると仮定し、ポイントが抵抗を受ける。
    この流体の範囲に入った時、ポイントは赤くなります。
  5. 引力(固定アトラクタ)
    原点の位置に引力を発生するポイントを配置し固定。
    その他のポイントは原点のポイントと引き合う。
  6. 引力(ポイントの相互作用)
    各ポイントはそれぞれ相互に引き合う力を持っている。
    質量や引力の設定にもよるが、小さな塊ができ、それぞれの塊が引き合い徐々に大きな塊になっていく。(ポイント半径に合わせたコリジョンは設定していないので、実際には、塊は大きくなりません。)

2.0 Houdiniの単位系

Houdiniは標準的なSI単位を採用している。
https://www.sidefx.com/docs/houdini15.0/dyno/about
http://www.cranenet.or.jp/tisiki/si.html

2.1 力とニュートンの運動の法則

力とは、質量を持った物体に加速度を生じさせるベクトル。

・ニュートンの運動の第1法則(慣性)

静止している物体は静止状態を続け、運動している物体は不平衡力の影響を受けないかぎり、一定の速さで一定の方向へ運動を続ける。

・ニュートンの運動の第3法則(作用・反作用)

力は常に反作用が対になって生じ、その強さは等しく、向きは正反対である。

-F[N]

 押し合う物体の質量が違う場合や、接地面の摩擦力が違う場合、同じ力が加わってもそれぞれの物体が静止し続けるとは限らない。

2.2 力とProcessing

・ニュートンの運動の第2法則(運動方程式)

質量(m)に加速度(A)を掛けあわせると力(F)になる。

・重量と質量

  • 質量(m):物体内の物質の量[kg]
  • 重量(W):物体にかかる重力[N]
  • 密度(Density):単位体積(m^3)あたりの質量(kg)

2.3 力の積算

書籍では質量を1として計算し、F=Aとして簡単化する。

通常、物体にはいくつかの外力が同時に作用する。
そのような場合、全外力の合計値を使用する。
物体に働く力は、特殊な状況を除いて常に変化し、積算されないので、毎フレームで新たな値を計算して使用する。

windForceやgravityForceなどを追加してみる。

2.4 質量

先に計算された外力を質量で割ることで、各ポイントごとに設定された質量を考慮したシミュレーションが行われる。

2.5 力の作成

・力の作り方

  • 直接指定
    自由に直接指定する
  • シミュレーション
    物理公式などを利用し、計算する。

2.6 地球と重力と力のシミュレーション

この時点では、質量が小さいものほど重力の影響を強く受けるようになっている。
物体の落下速度は、その質量にかかわらず一定。
重力加速度の式から正しい加速度を求めて適用するため、重力に質量を掛けあわせてる。

2.7 摩擦

摩擦は散逸力(非保存力)。

※散逸は、抵抗力によって運動エネルギーを熱エネルギーに変換する現象。
散逸力とは、摩擦力などのエネルギーを減少し、別の力に変換させる力。
車のブレーキなどは運動エネルギーを熱エネルギーに変換。

・摩擦の種類

  • 静止摩擦
    接触面に対し静止している物体が受けている摩擦
  • 動摩擦
    動いている物体が接触面から受ける摩擦

摩擦の方向は速度方向の逆。

・摩擦の公式

・公式を使用する際のポイント

  • 右辺を計算し、左辺に代入する。
  • 変数がベクトルかスカラーかを見極める。
  • 記号が隣り合っている場合は乗算を表す。

■各項の意味

  • F friction:摩擦により働く力

  • μ:摩擦係数

    特定の表面上に生じる摩擦力の強さ。

  • N:垂直抗力
    物体が接触面から受ける反作用で接触面に対して垂直方向に物体を押し返す力。
    物体が接触面から受ける垂直抗力の大きさは物体の質量に比例する。
  • v:正規化済みの速度ベクトル
    式中の-1と掛けわせることで摩擦による力の発生する方向を取得する。
    この場合、速度ベクトルの真逆方向に摩擦力による力が発生する。

2.8 空気抵抗と流体抵抗

物体が空気や液体(流体)の中を通り抜けるとき、抵抗力が働く。
これは、粘性力(Viscous Force)や抗力(Drag Force)、流体抵抗(Fluid Resistance)などと呼ばれる。

・流体抵抗の公式

■各項の意味

  • F drag:流体を物体が通り抜ける際に働く抗力
  • 1/2:定数
  • ρ(rho):流体の密度
  • v^2:速度ベクトルの長さの2乗
  • A:進行方を向いている面の表面積
  • Cd:抗力係数、自由に決定する
  • v:正規化された速度ベクトル

2.9 重力

■重力の公式

■各項の意味

  • F gravity:重力
  • G:万有引力定数、独自の値を使っても面白い。
  • m1とm2:相互に作用する2つの物体が持つそれぞれの質量。
  • r:物体間の距離ベクトルを正規化したベクトル。物体同士が引き合う方向。
  • r^2:物体間の距離の2乗。
    物体同士が引き合う力は距離が長いほど弱くなり、近いほど強くなる。

2.10 相互引力と反発

2.9の計算を、各ポイント間で計算し、毎フレーム全ポイントの影響を合計して適用する。


何か間違いがあればツッコミをいただけると助かります。