備忘録

備忘録

C++/DirectX/Metal等のネタを書きます。
基本的に、ググって即出るような情報は書きません(検索結果を汚すだけなので)。
スマホ表示だとコード部分がCSS無効になるのでPC版でお願いします。
プログラミング以外のネタを書くこともありますが消す可能性あります。

 大昔から言われてたことで、今更そう「信じ込んでる」人もなかなか居ないとは思うけど、以前の記事でvtbl(仮想関数テーブル)について触れたので解説してみる。

 「(基底)クラスのデストラクタに必ずvirtualを付けろ」というのは、ポリモーフィックな(多態性を利用する)クラスのポインタをdeleteしたときにデストラクタが正しく実行されない場合があるということだけど、これは場合による。
 また、クラスの用途によっては「virtualをつけてはならない」こともある(後述)。

class A {
public:
virtual void Func1();
virtual int Func2();
virtual short Func3();
void Func4();

~
A(); // 非virtualなデストラクタ
};

class B : public A {
public:
virtual short Func3() override;
~
B() override;
};
 このような継承関係にある場合、例えば

A *p = new B();
// 色々した後に
delete p;
 とした場合にBのデストラクタが実行されない(正確には未定義)。が、もちろん

B *p = new B();
// 色々した後に
delete p;
 なら実行される。また、

{
B b();
// 色々した後に
} // スコープを抜けることでbのデストラクタが実行される
 これでもBのデストラクタが正しく実行される。

 つまり基底クラス(A)のポインタでdeleteする場合にのみ、そのクラスかそれより基底のクラスにvirtual指定が必要(基底のデストラクタがvirtualなら派生は自動でvirtualになる。可読性のためには書いた方がいいけど)なだけであって、そうでなければvirtualは必要ない。
 なんなら、そもそも行うべき解放処理がBに無い場合も、Aのデストラクタだけ呼ばれれば良いので必要ない。はず(deleteは確保時に記録されたサイズを読むので、BとAのサイズ差によるメモリリークは起きない)。

 virtualが必須になる状況はこれだけ限定的であるにも関わらず、「クラスのデストラクタには必ずvirtualをつけろ」と当たり前のようにあちこちで言われていたのは、それだけ昔C++でも杓子定規なOOPが流行っていたせいだろうと思う。
 「流行っている」=「正しい」というような安易な考え方は、今のC++界隈の「何でもテンプレートで解決できる」「今どき◯◯など古い(◯◯にはOOPも入る)」という風潮も完全に同類だけど。

 そもそもdelete演算子で動的に確保されたクラスのデストラクタを呼ぶとき問題になるのは、「そのポインタが指す実体はどの派生クラスのインスタンスなのか」がコンパイラから見て分からないから。つまりポリモーフィズム(多態性)を使って基底クラスのポインタで管理する場合にのみ、問題になる。
 (newするときは生成したいインスタンスの型でnewするので、実体の型がコンパイラから見て明らかであるため問題にならない。)


 で、そのような「どの派生クラスのインスタンスかが分からない」状況でそれを判別するために使えるのがvtbl(仮想関数テーブル)だということです。この辺の仕組みの経緯はD&E(C++の設計と進化)で詳しく解説されてます。


 先ほどの基底クラスAでデストラクタをvirtualにし、
class A {
public:
virtual void Func1();
virtual int Func2();
virtual short Func3();
void Func4();

virtual ~A(); // virtualなデストラクタ
};

 それを継承したBのメモリイメージは
+-------------------------+
| vfptr (8bytes)   | <-- 仮想関数テーブル(vtbl)へのポインタ。必ず先頭にある。
+-------------------------+
| (Aのデータメンバ) |
+-------------------------+
| (Bのデータメンバ) |
+-------------------------+
(この場合データメンバは無いけど。)

 で、vtblはこうなります。
+-----------------------+
| ptr to A::Func1  | <-- エントリ0: Func1のアドレス
+-----------------------+
| ptr to A::Func2  | <-- エントリ1: Func2のアドレス
+-----------------------+
| ptr to B::Func3  | <-- エントリ2: Func3のアドレス
+-----------------------+
| ptr to B::~B    | <-- エントリ3: デストラクタのアドレス
+-----------------------+
| (終端: NULL など) | <-- コンパイラ依存。仮想関数テーブル終了を示す
+-----------------------+
(Func4は非仮想なので入らない)

 この仕組みのおかげで、実際のインスタンスの型のデストラクタが呼べるわけです。B::~Bを呼べさえすれば、Bから見て基底がAであることは分かりきっているためA::~A()も呼んでくれる。そのためにAのデストラクタを仮想にする必要があるわけです。

 逆に言えば、先に述べた例のようにそれが不要であれば、virtualなデストラクタも必要ありません。


 (補足)std::shared_ptr や unique_ptrは、コンストラクタや代入演算子で受け取る際に実際の型がわかるので、そのときの型でdeleteするデリータを保持してくれるため、デストラクタがvirtualでなくてもBのデストラクタを呼んでくれるようです。さすがに100% shared_ptr/unique_ptrで扱わなければならないクラス設計をするのは、事故を招くとは思うけど。





 で、先ほどの図で示した通り、1つでも仮想関数があるとオブジェクトの先頭に64bit環境であれば8bytes、32bit環境であれば4bytesのvfptrが強制的に入ります(先頭なのは規格で決まってるわけではないけど事実上ほとんどの環境で)。

 「クラスのデストラクタには必ずvirtualをつけろ」というのは、「vfptrに先頭8bytesを占領されることを常に受容しろ」と言っているのに等しいわけで。
 それを受容するなら、以下のようなクラスは必然的に書けない。

template <size_t N>
struct vector_member;

template <>
struct vector_member<4> {
union {
struct {
float x, y, z, w;
};
float f[4];
};
};

template <size_t N>
class vector : vector_member<N> {
vector<N> operator +(const vector<N> &rhs) const noexcept;
// その他ベクトル演算や代入とかメンバ関数色々
};


vector<4> coordinates[8] = {...};
 基底であるvector_memberに仮想デストラクタを入れると(必要な解放処理が無いのに)、先頭に8bytesのvfptrが作成され、vector<4>のサイズは4bytes * 4 = 16bytes ではなく8bytes + 4bytes * 4で24bytesになります。
 余分なものが入るので、D3DやMetalなどの頂点バッファにこの自作ベクトルクラスの配列を放り込むことも出来なくなります。


 さらに、例えば
struct allocation_policy_from_heap {
void *allocate();
void deallocate();
};

template <class AllocationPolicyT>
class hoge : AllocationPolicyT {
hoge()
{
void *p = AllocationPolicyT::allocate();
}
};
 このような、いわゆるポリシークラスを用いる際も、継承してるけどvfptrは不要です。

 他にも色々例はあると思うけど、場合によるのです。


 ”なぜそうなっているか””なぜ必要なのか”というのを理解していれば、通説にとらわれず柔軟な設計ができるはず。

(゚∀゚)キt



||||||||||||||||||orz


 IKの伸縮を毎フレーム強制オフにしたら足の形だけは治ったけど、そんなんじゃなくてもっと根本的に何か足りてない気がする・・・
 spine-cppの4.0〜4.1あたりはIK周りにバグがあったらしいけど、4.0/4.1の最新のコミットでそれが直されてるのかどうかも不明。
 どうしよ・・・・・・・


バイパーは治った。
 方法は昔から知られていて、自分は昔ここ↓を読んで学んだ。

Lesson 3.DLL側のクラスを呼び出す - The deep inside of Windows / BM98's ROOM つう(やねうらお)

 要は、異なるコンパイラ・異なるバージョン間でもポータビリティを保つためには、

・仮想関数のみを持つ基底クラス(ライブラリ利用側、作成側で共通のヘッダ)を作ってインターフェースだけ定義し、実装はライブラリ側で隠蔽した派生クラスで書く
・生成と破棄は共に、必ずライブラリ側で行う(COMでいうところのCreate◯◯系関数と、純粋仮想のRelease()。)
・(↑には書いてないけど)C++の名前マングリングを避けるため、生成関数はextern "C"で宣言する


 ちなみにRelease()内の{delete this;}は、デストラクタが仮想なので別に末端のクラスで行う必要は無く、ライブラリ側のdeleteが呼ばれるのであればどこでも良い(インターフェースを書いた基底クラスに書くとアプリ側のdeleteになるので基底には書けない)。

 これらを守れば、基本的に異なるコンパイラ間でも利用できるはず。

 ちなみに基底クラスにデータメンバを書いてはならないのは、異なるコンパイラ間で構造体のパディングやアラインメントが異なる可能性があるため。アプリ側(ライブラリ利用側)で操作すると、ずれたアドレスで操作してしまう可能性がある。

 (生成関数だけでなくメンバ関数呼び出しも安全なのは、vtableへのポインタがクラスの先頭にあるのは大抵のコンパイラで共通しているので「シンボル名を探さずとも関数アドレスがわかる」からで、また thiscall呼び出し規約が少なくとも「Windows向けコンパイラ間では共通している」から。他OSでは不明)





 で、以下はXcodeでのSpineランタイムのバージョン差異の吸収の話。

 異なるコンパイラも何もXcode clangで共通の上、スタティックライブラリでやろうとしてるので神経質になる必要は無いんだけど色々と苦労した。

 まず、既定でシンボルが全て公開なので、Spineのバージョン違いのソースをコンパイルすると、4.0と4.1で中身が違ってもシンボルは同じなので、2つリンクするとシンボルの重複で大量にエラーが出る。

 「Symbol hiding in static libraries built with Xcode - Stack Overflow」や
静的ライブラリで内部シンボルを隠蔽する方法(macOS)
 を参考にして、Symbols hidden by defaultとPerform Single-Object PrelinkをYESに、かつother linker flagsに-ObjCを指定し、生成関数だけ__attribute__((visibility("default"))修飾したらいけた。(-ObjCはObjectiveCのメソッドを消さないようにするフラグらしいけど、なんでC++の関数が消されたのか不明・・・)

 (ていうかSpineのソースからのヘッダのインクルードが"hogehoge.h"(ダブルクオート)ならライブラリ化する必要無かったんだけど、全部山括弧になってるのが痛い。これさえ無ければ・・・・)
 トヨタ新型「ミッドシップ“スポーツカー”」登場へ!? 600馬力の「2.0リッター“直4”」搭載? 価格はGRヤリス超え? 新たなGR MR2どんなクルマになるのか

 昔、白のSW20(Ⅲ型NA)に乗ってたけど、どんな車になるのかめっちゃ気になる。クラッチペダルありのHパターンが好きだけど、さすがに今どきそうはならないかなぁ。

 学生のとき友人や先輩とお金出し合って小さいサーキット借りて練習してたけど、SW20はフロント荷重が足りないせいか、すぐアンダーが出た。けど少しブレーキ入れて荷重かけた途端に、ノーマルシートだと吹っ飛ばされるような横Gが😱
 そしてミッドシップのお約束で、いざオーバーが出たときは振り出しが速い。なので「扱いづらい」と敬遠される。けど自分は好きだったな。まるで自分の手足で走ってるかのような一体感は、唯一無二だった。

 バケットシートやLSD入れる前に手放したけど、もし次買うとしたら絶対ミッドシップだと決めてる。手頃で楽しい良い車だといいな。



 AI戦で敵後衛(黄色)が味方に貢がれて即帝イーグルしてきてボッコボコにされたので最初からやり直して、怒りのイノパク2匹。
(何度も失敗するのでイノシシの場所で保存してからやってます。)

 イノ食いまくって早め即で多めに得た肉を使って騎兵+騎士でTC建設邪魔しまくって、こっちも早めに帝王入ってトルコの帝王編成でボコったヾ(゚ω゚)ノ゛


 ワンミスで斥候死ぬので難しいけど、仮に出来そうなチャンスがあったとしても人間相手にやって万が一成功すると
©岡田モフリシャス
このレベルでガチギレされると思うので絶対出来ない。
 年末だしちょっと部屋の片付けとかで気分転換しつつ、Spine4.0に対応完了。意外と変更点が少なくて楽だった。


 (一瞬なんか変なメッシュが出るけど。)

 NI◯KEのモデルでしかテストしてないけど、軽く見た限り、↑のバイパーとジャッカル以外は正しく表示され、4.1のときのようなアニメーションの問題は無かった。ちな遊んでた頃はシンデレラとバイパーがお気に入りヾ(゚ω゚)ノ゛(バイパー活躍する場面少ないけど・・・)

 4.0/4.1共に一部のatlasで表示が変になるのは、マイナーチェンジの影響なのかLevel Infiniteがカスタマイズしたコード使ってたのか謎だけど・・・Spineで読み込めば修正出来る可能性が高いと思うので、とりあえずこのまま複数バージョンへの対応のためのラップ&ライブラリ化とかインターフェースとか作っていこうかなと。
 Googleで検索するとAIが要約出してくれた。

_view.window.level = NSMainMenuWindowLevel + 2;
 これだけでいいっぽい(+1だと挙動が安定しないとのこと)。


 ただ、ループ描画してるためか自分の場合メニューバーより下に戻されたので、その場合は描画時に毎回やる必要があった。
 CAMetalLayer使っても、viewのサイズ変更中のdrawableのテクスチャサイズは、報告されたものと一致しないことがあった。

 ウインドウがデスクトップ内に収まってる場合は大丈夫なんだけど、範囲外に出した途端に、サイズ変更中に時々そういう症状が出る。で、renderPassDescriptorにバックバッファ指定するときにマルチサンプルテクスチャのサイズと一致しなくてエラー吐かれる(これはMTKViewをsampleCount > 1 にしてマルチサンプルテクスチャを作ってもらっても起きる)。

 サイズが一致しない場合はレンダリングを飛ばすことも考えたけど、それでも引っかかることがあった上、自作APIではrenderPassDescriptor作成のタイミングはもうレンダリングを中断出来ない段階のため、サイズ一致しない場合は内部で非マルチサンプルに切り替えるようにした(PSOと深度ステンシルテクスチャに、非マルチサンプル版を用意しておく・・・・本当はやりたくないんだけど)。


 けどAppleのサンプルのような単純なコードだと起きない症状なのが謎・・・(drawableのサイズが実際のウインドウのサイズと一致しなくて歪むのはどれでも起きるが)。



 ・・・・・・こういうのが一番メンタル削られる。
 iOSのキーボードもここ数年おかしな挙動してるしテキストエディットのコンテンツで変な挙動あるらしいし、AppleのAPIどうなってんの・・・?
 NI◯KEのアセットでテストしてるけど、一部のatlasで表示が狂う。

 アニメーション適用せず基本ポーズだと大丈夫なんだけど、アニメーション再生させた途端にこうなる。単純にボーンを外から動かしてみても伸びるだけで形は治らないので、ウエイトの問題のようにも見えるけど・・・。
 Nikke-DBから拝借したデータだからかもしれないけど、Spineのプロ版をまだ買ってないので、Spineで正常なデータなのかどうかも調べられない。


 NI◯KE専用じゃないので、万が一データの異常だった場合(=カスタマイズしたコードを使ってる前提だった場合)にどうすべきか・・・・自分のコードにミスがあるのならいいんだけど、今のところ原因が掴めてない(バグり方を見るに、コードのミスっぽくはないんだよなぁ・・・)。

 Spineで開けない以上、調べるのに時間かかりそうだしとりあえず他の部分進めるかなぁ・・・・
 2000年代、自分が読んで強い感銘を受けたエッセイ。

 「ものつくりのセンス ---Taste for Makers--- / Paul Graham」。

(「ハッカーと画家 コンピュータ時代の創造者たち (Amazon)」というエッセイ集にも含まれている)


 「良いデザインには、分野を問わず共通項がある」というテーマで、数々の良いデザインの条件や、「良いもの」を作るための哲学のようなものが、少し難しいけれど小気味よい文章(&良訳)で書き連ねられている。

 志ある若い人達にぜひ読んで欲しい内容(なのだけど、感想や解説など書くのも野暮だと思ったり、出し惜しみwもあって、一度も紹介しなかった)。







 完全に蛇足になるんだけど、以下は自分の感想。



 まず序文。

 ―――現代では、センスについて語ろうとすると、多くの人がこう言うだろう。 「センスなんて主観的なものさ」。 実際彼らにとってはそう感じられるから、そう信じているんだ。 何かを好ましいと思っても、何故そうなのか彼らにはわからない。 それが美しいからなのかもしれないし、母親も同じ物をもっていたからなのかもしれないし、 雑誌で映画スターと一緒に写ってたのを見たからかもしれないし、 あるいは単に高価なものだと知っているからかもしれない。 色々な思い付きが絡み合っていて、人々はそれをよく考えてみようとはしない。

 「母親も同じ物をもっていたからなのかもしれないし(以下略)」の部分は、少し皮肉めいたものを感じる。
 (「流行っているから」「他の人も持っているから」というのは、「なぜそれが良いものなのか」を考えること、そして「主体的に評価すること」を放棄する言い訳、または「ある種の権威主義」だと言いたいのかもしれない。消費者側はそれでいいかもしれないが、我々作り手側がそうであってはならない、と。)


 余談だけど、

 ―――弟が塗り絵で人を緑に塗っているのをばかにしていると(略)

 これはあまり知られてないけど色覚異常によるものである可能性が高いので、この場合は弟を眼科でみてもらった方がいいかもしれない(一部の緑色が肌色に見えるパターン)。





 良いデザインは単純である。 数学から絵画に至るまでこの文句を聞いたことがあるだろう。 数学では、これは短い証明ほど良いものである傾向があるということだ。 特に公理に関しては少ない方が良い。 プログラミングにおいても同じことが言える。
(中略)
 単純さをわざわざ強調しなければならないというのは不思議なことだ。 何もしなければ単純になるだろうと思うかもしれない。 装飾をつけるのはもっと大変な仕事じゃないかと。 だが、人々が創造的であろうとする時、何か不思議な力がやってくる。 駆け出しの小説家は普段話している言葉とかけ離れたおおげさな言い回しを使いたがる。 デザイナーは芸術的であろうとして、 画家は表現主義者になる。 これらはみな言い逃れだ。 長ったらしい単語や「表現主義的な」絵のタッチの下には、 実は大した中身がない。それって恐いことじゃないか。


 これはよく分かる。プログラマとしてだけでなく、それ以外でも。

 プログラミングにおいて実際、よけいな機能やよけいなコードを書きたくなる時はある。が、その流れで作ってみたものは大抵役に立たない。役に立たないどころか、無理に使うとその後の設計の足を引っ張ることすらある。

 ひどい例だとC++ユーザーの中には、コンストラクタやら代入演算子やらごてごてと書いたわりに「実質なにもしないクラス」をドヤ顔で晒してる人もいる(コピー・ムーブコンストラクタ / 代入演算子は、値として振る舞うクラスでない限り、不要であることが多い)。
 何かを解決するために書いているのではない(カッコつけ?ドヤ顔したいだけ?)のだから、何の役にも立たないコードになるのは当然の帰結と言える。

 仕事・作業に没頭するor成果を出す自分をカッコいい、イケてると感じるのは悪いことではないし、むしろ良いことだ。けれど一つ一つの下す決断は、最終的に全てユーザーのためでなければならない、と個人的には思う(ユーザーとは、消費者だけでなくツールを使うデザイナー、ライブラリを使うプログラマや未来の自分を含む)。
 「ものつくりのセンス」にも似たようなことが書かれているが、作り手にとって基本的に”エゴ”は邪魔なものだ。






 良いデザインは正しい問題を解決する。 よくある台所のレンジは4つの火口が四角に並んでいて、 それぞれを調節するつまみがついている。 このつまみをどうやって配置したらいいだろう。 一番簡潔な答えはそれを横一列に並べることだ。 だがそれは、間違った問いに対する簡潔な答えなのだ。 つまみは人が使うものだ。つまみが横一列に並んでいたら、 不幸なユーザーは毎回どのつまみがどの火口に対応しているかを考えなければならないだろう。 火口と同じようにつまみを四角に配置した方が良い。

悪いデザインの多くは、勤勉であるが勘違いした仕事の結果だ。


 日本人は哲学が苦手だと思う。「何が正しい問題か」がわからない。

 スマホアプリでもインフラでも、やたら使いにくいインターフェースに出会うことは多い。「誰が使うのか」「何のためのソフトウェアなのか」の根本を忘れ、クライアントの思慮不足や、様々なしがらみから来る「とにかくこれだけは守れ」という雑な要求、きつすぎる納期や無能な上司、安月給などに振り回されて、結果誰も使いたがらないクソみたいなインターフェースが出来上がるのだろう。
 誰もが「何のためのソフトウェアか」を考えていない。

 そしてこれは、個人のプログラマにも言える。

 「自分が使いたいと思うかどうか」というのも一つの大きな指針だけど、これを守るのはソフトやライブラリの基本設計ですら簡単ではない。でも、その段階から手を抜けば、いずれ何倍〜何十倍もの時間を無駄にすることになる。

 ソフトウェアでは、追跡不可能な問題を、等値でしかも解くのが容易な問題へと 置き換えることが出来る場合が多い。

 これも何となくわかる気がする。コードでも設計レベルでも、よくよく考えているうちに「もっと単純なやり方で済む」ことに気付くことはある。その結果、設計も単純になり、不必要な依存関係から解放される。





 良いデザインは想像力を喚起する。 ジェーン・オーステンの小説には叙述がほとんどない。 いろんなものがどんなふうに見えるかを説明するかわりに、 彼女は物語を実にうまく語るので、あなたは情景を目に浮かべることができるのだ。 同様に、色々想像できる絵画の方が全部描いてあるものよりも見ていて飽きない。 誰もがモナ・リサに関して自分だけの物語を作り上げる。

この原則は建築とデザインにおいては、建物や品物は人々が使いたいように使えるべきである ということになる。例えば良いビルディングは、そこに住む人々が自分の生きたいように 生活を送る背景となるべきであり、建築家の書いたプログラムを実行しているように生きる ためであってはならない。


 これはもう、ゲームで例えると「新イベント!」「新ガチャ!」と、プレイヤーに飽きが来ないように(とっくに皆飽きてるのだが)必死に実装し続けるガチャゲーと、マインクラフトとかを比べればわかりやすい(ひどい?)。
 プレイヤーのアイデア次第で色々出来るシンプルな土台となるようなゲームの方が(オンラインでもオフラインでも)シンプルでも息が長いのは、こういう理由だろう。それで十分に成功出来るゲームというのは相当なものだとは思うけれど・・・。


 ソフトウェアにおいては、ユーザーが自分の思う通りにまるでレゴのように 組み合わせることができる少数の基本要素を提供すべきだ。

 これは言わずもがな。





 良いデザインはしばしばちょっと滑稽だ。 これはいつでも正しいというわけではないかもしれない。
(中略)
 私が思うに、これはユーモアが力と関連しているからだ。 ユーモアのセンスがあることは、力強くあることである。 ユーモアのセンスを持ち続けるということは、不幸な出来事も肩をすくめてやり過ごせるということだし、 ユーモアを失うということは、そういう出来事で傷ついてしまうということだ。 そして、力強さのしるし、あるいは特長は、自分のことを深刻に考えすぎないということだ。 この自信は、しばしば過程の全てをちょっとばかり茶化すようなところがある。 ヒッチコックが彼の映画でやったように。あるいはブリューゲルが彼の絵画でやったように。 この点に関してはシェークスピアも同様だ。

良いデザインが常におもしろおかしくなければならないというわけじゃない。 でも、良いデザインでかつユーモアを感じないものを想像するのはとても難しい。


 自分はお笑いが割と好きなので、M-1グランプリの決勝に出ていた数々のコンビを思い出した。

 かつて、何年も出てるのに段々とファイナルに残れなくなったり順位を落としたコンビは、やはりユーモアというか余裕を失って、視野が狭くなり始めていたんだなと思う(ものすごくシビアな舞台だとは思うのだけど)。
 逆にあの舞台で名を残したりその後テレビで活躍するような人達は、↑の文章にまさに当てはまる気がする。

 というか自分自身も長年プログラミングを楽しめてないし、ユーモアを失っていると身につまされた。





 良いデザインをするのは難しい。 素晴らしい仕事をした人々を見ると、 彼らに共通することは非常に頑張ったということだ。 実際、頑張っていないのなら、それは時間の無駄というものだ。

困難な問題は多大な努力を要求する。 数学では難しい証明には技巧的な解法が必要で、それはまた興味深いものにもなる。 工学でも同様だ。

山を登る時は、不必要なものは荷物から捨ててゆくだろう。 同じように、建築家は難しい建築物や限られた予算を前にすれば、 エレガントなデザインを強いられることを悟るだろう。 流行や華美な装飾は、そもそも問題を解くという困難な仕事の中に入って来る余地が無いのだ。
(中略)
 バウハウスのデザイナーがサリヴァンの「形態は機能にしたがう」という方針を 採用した時、彼らが意図したのは「形態は機能にしたがうべきである」ということだった。 そして機能が難しいものであるなら、形態もそれに従わざるを得ない。 誤りを犯す余地は無いからだ。野性の動物が美しいのは、彼らが困難な生を生きているからだ。


 この部分は、「良いデザインは単純である」の項も絡んできている。「困難な問題を解こうとすれば、必然的に余計なものは削ぎ落とされる」と。

 特に「野性の動物が美しいのは・・・」の部分にはハッとさせられる。
 確かに、人間のアスリートの筋肉などを見ても、ボディビルダーの筋肉とはまた違う、「洗練された機能美」のようなものを感じる。

 我々が、動物や人の動き・体つきを見たときに「美しい」と感じるのは、きっと我々の遺伝子がそれを「理にかなった」動きや体つきであると本能的に知っているのだと思う。

 同様に、映画などでも仲間を助けるシーンや愛する人との再開、巨悪に立ち向かうシーンなどドラマチックな&感動するシーンや演出はたくさんあるが、それをドラマチックと感じるのも感動するのもきっと「そういった行為の繰り返しで、我々人類が繁栄してきた」ということを、我々の遺伝子が知っているのだろう。





 良いデザインは自然に似る。 自然に似ているからとにかく良い、というのではなく、 自然は問題を解くのに非常に長い時間をかけてきたから、参考にする価値がある。 あなたの解が自然の解に似ていたら、それは良いしるしだ。
(中略)
十分な計算力を手にした現在、我々は自然の結果だけでなくその手法までも模倣することができる。 遺伝的アルゴリズムは通常の手法では複雑すぎる設計をも行うことができるだろう。


 この文章で遺伝的アルゴリズム(GA)について知ったのが懐かしい。今やニューラルネットワークの方が死ぬほど有名になったけど、GAは組み合わせ問題においては非常に有用だった(解を計算で自動評価出来ることが大前提にはなるけど)。

 ニューラルネットワークもそもそも動物の脳の仕組みを真似たもので、これからも脳の仕組みが解明されるたびにニューラルネットワークに応用されていくのだと思う。一定の量を超える電流が入ってきたら自分自身も発火(電流を出力)するという仕組みはまさに、何億年という進化の歴史が生み出した天然のトランジスタと言える。





 良いデザインは再デザインだ。 最初からうまくできるということは滅多にない。 熟練者は初期の仕事は捨てるつもりでやる。計画が変更されることを予定してかかるのだ。

仕事を捨てるのには自信が必要だ。 「ここまで出来たのなら、もっと出来るはずだ。」こう考えることができなくちゃならない。 例えば絵を描き始めたばかりの人は、うまく描けなかった部分をやり直したがらない。 ここまで出来たのはラッキーだった、これ以上何かやったら悪くしてしまうかもしれない、 そう思ってしまうのだ。 やり直す代わりに、そんなに悪くないじゃないか、多分こう描くのが良かったんだと、 人は自分を納得させてしまう。

危険な領域だ。むしろ、不満足な点を突き詰めなければ。
(中略)
間違うのは自然なことだ。間違いを大失敗のように考えるのではなく、 簡単に見付けて簡単に直せるようにしておくことだ。 ダ・ヴィンチは絵画においてより多くの可能性を試すことができるように スケッチを発明したと言っても、当たらずとも遠からずであろう。


 これは良くわかる、というか身につまされる。

 若い頃は友人と共にイラストとかにも挑戦したが、手を加えることがひどく怖かった。そもそも才能も無いし、描いていてそんなに楽しくないのだから当然だったかもしれない。

 というか今やプログラミングですら、「これ以上何かやったら悪くしてしまうかもしれない」という思考に陥りかけることがある(好奇心や冒険心がおとろえたせいだと思うけど)。
 ”自分を信じる”というのはとても大事なことだと思う。実際、大胆に変えてしまった方がより良いコードになることが多い上、勉強にもなるのだから(ただし、時間が許すなら・・・。企業で働いてたらほぼ無理だけど)。





 良いデザインは模倣する。 模倣に対する態度はしばしば一巡する。初心者は知らず知らずのうちに模倣する。 そのうち、彼は意識的に独自性を出そうとする。 最後に、独自性よりも正しくあることがより重要だと気づく。

気づかずに模倣することは、ほぼ間違い無く悪いデザインをもたらす。 どこから自分のアイディアが来たのか知らない場合、 たぶんあなたは模倣者の模倣をしている。 ラファエルは19世紀中ごろの美術界を席巻したため、 その時代に画家を志した者のほとんどは彼を模倣していた。 ラファエル前派が反発したのは ラファエル自身の作品よりも、そういった風潮であった。

志有る人は単なる模倣では満足しない。 センスの成長の次の段階では意識的に独自性を出そうとする。

最も偉大な作り手達は、ある種の滅私状態に達するのではないかと私は思う。 彼らは正しい答えを知りたいだけなのだ。そしてもし、 答えの一部が誰かによって発見されていたのなら、それを利用しない手はない。 誰かの仕事を借りても自分のビジョンは曇らないという十分な自信があるのだ。


 「模倣者の模倣」というのは、例えば映像作品などで、「エヴァンゲリオン」「マトリックス」といった、社会現象を起こしたほどの作品から演出を真似るのが流行った結果、巡り巡って「そうと知らずに」似たような演出が使われていることなどが当てはまるのだと思う。ただ演出をパクっただけの作品も(演出が合ってるか合ってないかを問わず)多かったが、その起源がどこであるかすら知らずに真似た作品も多分あっただろう。

 「そういう演出がなぜその作品に必要なのか」というのは大事なポイントだと思う(マトリックスシリーズのCGや多数のカメラを使ったスローモーション、主人公・ネオの敵を見ない&未来まで予知しているかのような淡々とした戦闘シーンなどは、「サイバー空間である」「武器の使い方や武術はロードするだけで学習できる」などの大前提があるからこそ活きる。必要性を説明出来ないのなら、それは先の項にあった「表面的な装飾」「流行や華美な装飾」になりかねない)

 昔、多くの若手お笑い芸人が、ダウンタウンに憧れて彼らのスタイルを真似しまくっていたらしいが、最終的にそのスタイルのまま売れた若手はほぼゼロだった(一度も売れなかった我々の知らないコンビを含めれば、もっともっと大勢いるはず)。
 けれど、自分のビジョンをハッキリ持った作り手が、優れた作品の細かいアイデアを借りるのであれば、良い作品を生み出しうるということだろうと思う。


 当然、これはプログラミングでも言える。論理と技術の世界で「流行ってるから」「カッコいいから」みたいな理由で、どこかで聞きかじった知識やコーディングスタイルを安易に真似るべきではない。単に「それがこのソフトに/会社に/実装に適しているから」「必要だから」こそ、堂々と真似るべきだ。
 (極端な例だけど、どこぞのサンプルコードをコピペしただけで実装&理解できた気になっていたり他人の猿真似ばかりしてる人は多い。が、それでまともな実力が身についたプログラマというのを(プロアマ問わず)自分は一人も見たことが無い。知恵を”借りる”のと”パクる”のでは全く違う。前者は自分の頭を使うし経験値になるが、後者はならない。「自分の知識/成果物」と「他人の知識/成果物」の境界線が曖昧になるからだ。)





 良いデザインはしばしば奇妙だ。 もっとも優れた仕事のいくつかは、妖しい性質を帯びている。 オイラーの公式、 ブリューゲルの雪中の狩人、 SR-71、 Lisp。 これらは単に美しいだけでなく、奇妙な美しさを持っている。

何故だか私にはわからない。単に私が鈍いだけなのかもしれない。 缶切りは犬にとって神秘的に見えるだろう。 私がもっと賢かったら、ei*pi = -1 であるような世界が 一番自然に思えるのかもしれない。結局のところ、それが真理なのだから。
(中略)
アインシュタインは相対性理論をわざわざ奇妙にしようとしたわけではなかった。 ただ正しくしようとして、その結果奇妙な真実が現れたのだ。

私がアートスクールで学んでいた時、学生は何を置いても自分のスタイルを確立したがっていた。 だが、ただ良いものを作ろうとすれば、必然的にそれを他とは違ったやり方でするようになるのだ。 ちょうど歩き方が人それぞれであるのと同じように。 ミケランジェロは、ミケランジェロのように描こうとしたわけではなかった。 ただうまく描こうとして、その結果どうしてもミケランジェロのように描いてしまったのである。


 この部分は、個人的には日本人(特に映像・広告業界人、たまにゲームクリエイター志望の素人)がよく言う「オリジナリティ」の嘘っぽさについて看破しているようにも見える(例:映画業界の人に「なぜ実写化で改変するのか」と聞いたら「例えば桃太郎なら誰も見たことがないものを作りたいでしょ」と言われたお話「メシマズの理論だ!」)。
 (↑そういえば2年近く前、ドラマの原作となった作品を描いた漫画家が自殺したよね・・・・ドラマ化を何度も断ったにも関わらず半ば強引に許諾させられて、脚本家にインスタで陰口叩かれて。あの時「ひるおび」を除く全ての番組が、発端が脚本家のインスタであることを報じなかったことに、薄ら寒さを感じた)

 「オリジナリティがあれば売れる」などというのはゲーム業界志望の素人が昔よく言ってたが、「よそと違っているだけで売れる」のならば、UnityやUnrealEngineの普及、さらにはSteamというプラットフォームの普及によってスマホ・PCゲームではほとんどの個人開発者が大儲けしてなければおかしい
 ↑の節を読めば、「オリジナリティ」などというのは、鑑賞者が勝手にそう呼んでいるだけに過ぎないというのがわかる。


 先ほどお笑いコンビのダウンタウンの話を出したけど、かつてダウンタウンがデビュー間もない頃に横山やすしに本番中にこき下ろされたという事件があった。
 それに対してダウンタウンの松ちゃんは「オリジナリティがあって何が悪いねん」と本の中で反論してたと思うが、「ものつくりのセンス」のこの項を基準にして考えれば、ダウンタウンの漫才は別に「オリジナリティ」があるから面白いのではない。

 「やすしきよし」も、当時の漫才ブームを支えた他の芸人達も、当時は非常にテンポの速い漫才ばかりだった(悪く言えば、「勢いでごまかしていた」)。それに対してダウンタウンの漫才は非常にゆっくり。
 ゆっくりでないと、松ちゃんのボケ方は伝わりにくかったのだ。
 ボケのレベルが高すぎて(聞き手に想像力を要求するため)、急いで喋ると逆に伝わらなくなってしまう(「松本のボケを引き立てる間(ま)とツッコミにした」というのは浜ちゃんがたまに語っている)。

 ダウンタウンの2人は、小学生の頃からコンビを組んで、クラスで漫才を披露していたらしい。つまり、

 ―――私がアートスクールで学んでいた時、学生は何を置いても自分のスタイルを確立したがっていた。 だが、ただ良いものを作ろうとすれば、必然的にそれを他とは違ったやり方でするようになるのだ。

 NSC(吉本のお笑い専門学校)に入学した時にはすでに↑のレベル、つまり「自分たちにとっての、良いもの=面白い漫才 のスタイルはすでにわかっている(わかる程度の経験は積んでいる)」レベルだったのだろう(島田紳助が、NSCでの面接でダウンタウンの漫才を見たあと、「お前ら、テンポはどうすんねん」と純粋に興味から聞いたところ、「いや、自分らはこのままで行きます」と彼らは答えた。島田紳助からすれば、彼らのスローテンポはあまりに異様に見えたらしい)

 上の方で若手芸人がダウンタウンの真似をしても売れなかったと書いたけれど、それはそのコンビにとって正しいスタイルじゃなかったからだと思う。皆「自分達にとっての正しいスタイル」を見つけてから売れている(アンタッチャブルを見よ、千鳥を見よ。彼らは最初ダウンタウンに憧れて真似したというが、漫才が洗練され、売れた頃には似ても似つかないものになっている)
 仮にもし、松ちゃんの相方が別の人、浜ちゃんの相方が別の人であったとしても、それぞれ「ダウンタウン」とは全く違ったスタイルになっていたはずだ。


 ―――唯一持つべきスタイルは、どうしてもそうなってしまう、というようなものだ。 特に奇妙さにおいてはそうだ。そこに至る近道はない。 マンネリスト、ロマン派、そして2世代にわたるアメリカの高校生達が探した 北西航路は存在しないようだ。 そこに至る唯一の方法は、良いものをひたすら求めて、 気が付くと反対側に出ていた、というようなものでしかあり得ない。

 (訳注にもあるけど、北西航路というのは北極の氷に阻まれ、20世紀になるまで通れなかったという。砕氷船なしで通れるようになったのは21世紀に入ってからだとか。)

 結局のところ、「より良いもの」を作ろうと考え抜き、努力し続ける(=経験を積み、実力やセンスを磨く)以外の近道など無い、ということだと思う。「今どきはこう書くのがカッコいいらしい」「このやり方をパクれば良いものが出来る」「オリジナリティを持ってアピールしたい」などという”都合の良い近道”を求めることこそが、”最大の遠回り”なのだと。





 良いデザインは集団で生起する。
(中略)
関連した問題を解こうとしている才能ある人々のコミュニティほどパワフルなものはない。 それに比較すれば遺伝子の影響なんて小さなものだ。 遺伝子的にレオナルドであるだけでは、フィレンツェではなくミラノに生まれてしまった 不利を打ち消すことはできない。 現代では人々の移動は激しいが、良い仕事は依然としてごく少数の「ホットスポット」から 集中して出てくる。
(中略)
どんな時代にも、少数のホットなトピックがあり、それに向けて多くの仕事をなす少数の集団がいる。 それらの中心から遠く離れてしまっていては、良い仕事をするのはほとんど不可能だ。 このような流れを押しよせたり引き寄せたりすることはある程度できるが、 完全に逃れることは出来ない。 (いや、あなたなら出来るかもしれないけどね。でもミラノのレオナルドには出来なかった)。


 これは本当にそうだと思う。

 よく知られているところでは、VOCALOIDとMMD(MikuMikuDance)を起点としたニコニコ動画での動画投稿コミュニティは、関連して音楽や3Dモデリング等のクリエイターの活動を大きく推し進めた(米津玄師やYOASOBIのコンポーザー・Ayaseもそこがスタートだったというのは有名な話)。
 (脱線するけど、MMDの作者は”マジモンの天才”だと思う。思い立って実際に完成させるまでのスピードと集中力、スキンメッシュや3DCGのレンダリングなどそこそこ難しい理屈への正確な理解(Blenderを長年使ってたにしても。ゲームプログラマ(=専門職)志望者やプロですら、その理解と実装で挫折した人は数知れない)、そしてそれを適切に破綻無く実装するセンス。このレベルの天才は何人か知ってても、実際にお目にかかる機会は無かった。)

 自分はある時期から人間関係を断ってしまった(というかもともと人間関係が嫌い)ので、コミュニティどころか人脈もゼロになった結果、モチベーションも刺激も失われた。やはり、環境というのは大事だと思う。





実際問題としては、美を想像するよりは醜に目をやる方が簡単だと思う。 美しいものを作った人々の多くは、彼らが醜いと思ったところを直していったのだと思える。 誰かが何かを見てこう考える:「俺ならもっとうまくできる」。 これが偉大な仕事の発端なのだろう。 ジョットは人々が何世紀にもわたって満足してきた方式で描かれたビザンチンのマドンナ像を見て、 無表情で不自然だと感じた。 コペルニクスは、同時代の他の学者が許容してきたツギハギにどうしても我慢できず、 もっと良い方法があるに違いないと感じたのだ。

醜いものを許せないだけでは十分ではない。 どこを直せば良いのか知る嗅覚を得るためには、その分野を十分に理解していなければならない。 しっかり勉強しなくちゃならないんだ。だがその分野で熟練者となれば、 内なる声が囁き出すだろう。「なんてハックだ!もっと良い方法があるはずだ」。 この声を無視してはいけない。それを追求するんだ。 厳しい味覚と、それを満足させる能力。それが偉大な仕事のためのレシピだ。


 (注:日本人にはあまり知られてないけど、「ハック(hack)」には「やっつけ仕事」のようなニュアンスがある。「過程を問わず、結果を出す」ことだととらえればいいと思う。「ハッキング」も元々そういう意味で、コンピュータへの不法侵入などを直接意味するわけではない。)

 誰か有名なクリエイターが言っていたけど、「『嫌いなこと』をモチベーションにするのが、一番効果的」だとか。大きな目標をモチベーションにするのは、なかなか息が続かない。

 昔、PCの世界では「無ければ作ろう」という動機でプログラミングに手を出す人が多かった。「無い」ことが不便で気に入らないのだ(実際、自分が最初にC++とグラフィックスの勉強のために作ったフリーソフトは「あったら使ってみたいけど、世の中に無い」ものだった。あれこれ手を出しすぎてバグだらけになったけど・・・)。今でもゲームのMOD文化などではそういう雰囲気が残っているが、ソフトウェアの世界では・・・。
 でも、今は「何もかもが出揃ってしまった時代」に見える一方、細かなところでは「不便」がたくさん隠れていたりもする。そういうところで「無いなら作ってしまえ」と思える人は、きっと成長するタイプの一つだと思う。