年始からお手軽ベクトル検索を作る

あけましておめでとうございます。

今年は、もうちょっとblogを書こうかなということで、三が日のうちに1つ出してみようと思います。

さて、2023年はLLMの利用と同時にベクトル検索が急に利用されるようになった年でした。 Retrieval-Augmented Generation(RAG)をみんな使い出したのと、OpenAI の embedding APIの性能が思った以上に良かったことが主な理由だと思います。

ベクトル検索は faiss でもchromaでも、qdrant でも何を使ってもよいと思いますが、numpy を使えば数行で実装できるし性能も悪くないことがわかったので書き残しておきます。

import numpy as np
class SimpleVecSearch():
    def add(self, ndarray):
        self._ndarray = ndarray

    def search(self, vec, topk=10):
        scores = np.matmul(self._ndarray, vec)
        idx = np.argsort(scores)[-1:-(topk+1):-1]
        return [scores[i].item() for i in idx], list(idx)

if __name__ == '__main__':
    def gen_vecs(n, dtype='float32'):
        tmp = np.random.rand(n, 1536).astype(dtype)
        return tmp / np.array([[i] for i in np.linalg.norm(tmp, axis=1)])

    raw_index = gen_vecs(10**5)
    simple_index = SimpleVecSearch()
    simple_index.add(raw_index)

    vec = np.random.rand(1536)
    d, i = mlx_index.search(vec, 1)

if 文以下はテスト用コードなので、実装自体は8行です。faiss に同じ入力をして結果が一致することも確認しています。インターフェースも faiss にそろえています。

性能比較

faiss vs numpy
クエリに一番近いベクトルを見つけるのに必要だった時間を、データ量毎に計測しました。100回の検索を行った平均値で単位は秒です。 総当り探索なので検索対象のデータ量(横軸のデータ数)が増えると線形に計算時間が増えます。n=1000までは numpy の方が速く、その後 faiss に抜かれますが実用の範囲だと思います。どのみち、query 用のベクトルを取得するのに OpenAI の API を呼び出すのに数10msecから数100msecかかるはずなので。 まあそれに誤差もデカいのであまり差が無いという以上のことが言える差では無さそうです。

テストコードの全体はこちらにあります。

背景

OpenAI の embedding API は、文章を 1536次元のベクトルに変換して返してくれます。 大雑把に言うと、このベクトルを比較して文章が似ているかどうかを判定し一番似ている文章を返すというのがベクトル検索のキモです。

似ている度合いの計算方法は色々ありますが、OpenAI は コサイン類似度の利用を推奨しています。 コサイン類似度の定義は以下のとおりです。

 \cos \theta =  \frac{\langle x,y\rangle}{||x|| ~||y||}

x, y はベクトルで、 \langle x,y\rangle は xとy の内積 ||x|| はベクトル x の大きさです。 そして、Open AI の embedding API はベクトルを大きさ1に正規化して返すので、コサイン類似度の分母は常に1になります。 ということは、ベクトルの内積を計算するだけで類似度が計算できます。

コサイン類似度はベクトルとベクトルの内積によって計算されますが、ベクトル検索で行いたいのは多数のベクトル(本稿ではindexと呼ぶ)から、あるベクトル(本稿ではqueryと呼ぶ)に一番近いベクトルを見つけることです。なので、index の方を行列として保持しておいて、行列とベクトルの掛け算で一気に類似度を計算してしまおうというのが最初のコードの内容です。

高速化

上記の通りindex にある全てのベクトルとqueyrのベクトル比較する総当りアルゴリズムなので、正確ですが速くはないはずです。 が、faiss の IndexFlatIP インデックスも同じ手法なので速度的にはあまり変わりません。

nが大きいとfaiss のほうがちょっと速いんだし、faiss でええやんという話ではあるので高速化を試みます。 ちょうど昨年末に appleMLX という apple silicon 向けの numpy 互換ライブラリを出しました。apple silicon の GPU を使って線形代数計算を高速に計算するものですので、これを使ってみます。 numpy を mlx.core に書き換えるだけなので、コードはほぼ変わりません。

import mlx.core as mx
class MLXVecSearch():
    def __init__(self, stream=mx.gpu):
        self._stream = stream

    def add(self, ndarray):
        self._ndarray = mx.array(ndarray)

    def search(self, _vec, topk=10):
        vec = mx.array(_vec)
        scores = mx.matmul(self._ndarray, vec, stream=self._stream)
        idx = mx.argsort(scores, stream=self._stream)[-1:-(topk+1):-1]
        return [scores[i].item() for i in idx], [i.item() for i in idx]

コンストラクタで stream を指定できるようにしていて、mx.gpu と mx.cpu を切り替えると GPU計算 CPU 計算を切り替えられます。 で、肝心の性能はこんな感じ

faiss vs numpy vs mlx

n=105 以上ではfaissを抜いて最速です。(ただし精度的な問題があるので後述します。) では、n=107 以上では?と思うところですが、メモリ不足のため私の環境では実験出来ませんでした。 これは faiss でも同じで、そこそこ巨大な行列をメモリ上に展開するので、メモリが確保できなくて落ちます。 OpenAI の返すベクトルの次元を大雑把に 2*103 次元と考えると、1つの次元を表すのに、float32 = 32bit = 4 Byte が必要ですから、ベクトル全体では 4 Byte * 2 * 103 で 8 kB です。 そのベクトルが 107 個有ると 8kB * 10 ^7 = 80 GB となるので、24GB しか積んでない私の MacBook Air M2 では確保できないのは道理ですね。

107 を超えるような文書数があるならば、もっと高尚なアルゴリズムを使うべきで、この資料の案内が頼りになります。

speakerdeck.com

実用的にはRAG に入れたい文書数が1000万文書もあるというのは相当稀なことで、あって数千というところなのではと想像するところです。 その程度であれば最初に掲載した numpy 実装でも十分なはずで、使う機会も有るかなと思います。

MLX の謎挙動

手軽に numpy を高速化してくれるので、MLX いいね!と言いたいところなのですが、微妙に計算結果が numpy と異なることがあります。 これは stream を GPU にした時だけに起こるもので、CPU を指定したときには起きません。追いかけると楽しいかもですが、現時点ではよく分からず。 精度の違いも疑ったのですが、numpy も MLX も float32 を利用しており精度の問題では無さそう。アーキテクチャが違う計算機なんだからこのぐらい誤差も有るでしょという話かもしれません。 RAG で使う分には問題にはならない気もしますが、numpy や faiss と一致しないことは覚えて置いたほうが良いでしょう。

計算が一致しない例の再現コード

matrix = [[0.58551717, 0.13656957],
                 [0.12464499, 0.09199308]]

np_matrix = np.array(matrix, dtype='float32')
mx_matrix = mx.array(matrix, dtype=mx.float32)

a = np.matmul(np_matrix[0],np_matrix[1]).item()
b = mx.matmul(mx_matrix[0], mx_matrix[1],stream=mx.gpu).item()
print(a) #  => 0.08554524183273315
print(b) #  => 0.08554523438215256

本稿の詰めが甘い部分

numpy が利用している BLAS ライブラリがもっと高速なら、numpy でも fiass に勝てるのでは? とか、ARM64 の SIMD 命令を直接呼べばもっと高速なのでは? など追いかけると面白そうなところは色々あるのですが、今回はお手軽に実装してみるのがテーマなので深掘りはやめておきます。

まとめ

  • 数行のコードで実用的なベクトル検索が実装出来ることを示しました
  • MLX は速いけど謎挙動があります。まだ0.0.6だしね。
  • ことしはもうちょい blog 書くぞ

GPT-4 は高度情報処理技術者試験(午前I)に合格する

GPT-4は医師国家試験に合格するという研究結果が発表されて話題だったので、我々も馴染み深い IPA の試験にGPT-4は合格できるのか試してみた。 高度情報処理技術者試験の 午前I に限って言えば合格しているので、レポートをこちらに置いておく。

github.com

まとめ

  • 高度情報処理技術者試験の共通科目である午前I に 合格できる解答(正答率6割を超える)をGPT-4は生成する
  • GPT-3.5 では合格できない。GPT-4 の賢さが際立つ
  • ちなみに図表読み取り問題は入力できないので、すべて不正解扱いした

やりかた

  • IPA の Webサイトから、2022年度秋試験の午前I問題のPDFを取得 (PDF)
  • Google DocsOCR 機能でテキスト取得
  • 手でコピペして整形
  • 整形したファイルは こちら にある
  • OpenAI の API に問い合わせて解答を取得。スクリプトこちら
  • 追試験に必要なものは、ぜんぶリポジトリに有るつもりなので、興味のある人は試してほしい。

感想

ためしに、ChatGPT(GPT-3.5) の Web UI で問題を2つ3つ出してみたところ、どれも正解したので、これはもしやと思ってちゃんと実験環境を整えてみた。GPT-3.5 は不得意な問題が結構あって結果としては正解率50%で惨敗(レポートはこちら)。 GPT-4 はお値段高いし、遅いし、動作も不安定だが驚異の正答率96%を誇った。もちろんこの数字は、入力が可能な問題に限った話で図表問題は含んでいない。とは言え図表も入力方法が無いわけではないので、時間をかけて入力フォーマットを整えれば正解してしまうかもしれない。

GPT-3.5 は一見正しそうな解説から間違った答えを導いていて読んでいて微笑ましい。解説をせよという指示を省いて、解答だけを求めると正答率があがるという挙動もあり、解説を作りながら間違った方向へ文章を並べているような印象がある。この挙動の確認のコードはリポジトリには含めていないので興味のある人はコードを改造して試して欲しい。GPT-4 では、解答可能な問題の中で唯一間違った問題(問8)でさえ解説は正しい文章になっており、なぜ最後にその解答を選んだ...という面白さがある。

基本的に GPT シリーズは算数が苦手なのだが、GPT-4 ではそこもかなり改善されているようだ。

午前I の問題 30問は、応用情報の午前問題 80問 からの抜粋なので、応用情報の問題を全部整形して、GPT-4 は応用情報に合格できるぞ! などと言ってみたかったのだが、午後問題の入力の面倒くささの前に挫折してしまった。チャレンジする人を待ちたい。

和服で出社するようになって半年

この記事は クラスター Advent Calendar 2022 (2枚目) 4日目の記事です。昨日は kyokomi さんのとある中距離通勤の基本リモート月1物理出社でした。月1出社あるあるが楽しい記事でしたね!

さて、クラスター株式会社で Engineering Manager をしている kurain です。弊社では年に2倍の速さで社員が増えているので、これは外見的な特徴がないとなかなか自分を覚えてもらえないので和服を着て出社することにしたという話です。

和服の始め方

これは本当にぜんぜんわからん。ということで和服に詳しい友人の nanto_vi さんに連絡して1時間ほどビデオチャットで色々教えてもらいました。要点としては以下

  • (6月頃だったので) 浴衣から始めると楽
  • 洗える布地にしておいたほうがよい
  • おすすめの本がある(同じ著者なのでどちらかで大丈夫)

教えてもらった本は、そうかしこまらずに気軽に和服を始めようという本で、だいぶ背中を押してもらった気がします。コーディネートを眺めるにはこの本も楽しかった。

nanto_vi さんのこの記事

nanto.hatenadiary.jp

も参考にしています。

和服出社初回

7月の出勤日から浴衣で出勤してみました。浴衣は大阪のこちらのお店に行って買ってきました。相談にも乗ってもらえて助かりました。やる気が高まりすぎて、クラスター柄の帯を作ったりしていました。

自分で作った帯

作り方はこちらのblogが参考になります。布は大阪にある布印刷の会社であるREALFABRICさんで印刷してもらいました。納期は約1.5週間で、印刷代と布代,送料合わせて2500円くらいです。

こういう布が届きます
リバーシブルに作りましたが大きいロゴの方は不評だったので、小さいロゴの方を使っていました。その後会社のロゴが変更になったので、こちらの角帯はお蔵入りです。

今見ると締め方に不満が残る...

夏の間

浴衣で2回くらい出社したのですが、毎回同じ服なのもなー。ということで、次はヤフオクにチャレンジ。特に男性の場合、自分に合うサイズの和服が新品で売っているということは稀です。なので早く欲しい場合は、古着を買ってくる必要があります。着丈と裄丈が合えばそれなりに着れます。ただ、自分の場合、裄丈がちょっと長めなのでちょうどよいサイズが見つからないことが多いです。ヤフオクアプリに、”裄XX‘ という検索ワードを登録してひたすら新着を眺めたりしていました。

秋の間

だんだん和服で出社するのがそれほど困難で無いことが分かってきたので、ちゃんとサイズがあっている新品の和服が欲しいな。と思い始めました。ということで、こちらのお店で仕立てました。

ichiri-mall.jp

女性向けのブランドですが、電話をしたら男性向けの仕立てもやってくれるということでした。生地をネットで選ぶと実店舗で見せてもらえるので大変便利です。木綿だと反物代+1.5万円くらいで仕立ててもらえます。スーツと比べると安い気もします。新型コロナウィルスの影響もあり仕上がりまで2ヶ月くらいかかります。

仕立てた和服は、長襦袢と合わせてちゃんと着たり、スタンドカラーシャツに合わせて書生風に着てみたりなどしました。

冬に向けて

前回の11月頭の出社日は暖かったので羽織は不要でした。長着も前述の木綿の単衣で十分だったのですが、次の出社は12月下旬なのでそれなりに寒そうです。ということで、実家のタンスに眠っていたウールの長着と羽織をもらってきました。父のものですが、私は父が和服を着てるのを見たことが無いんですよね...とはいえ継承できるのはありがたい話です。羽織紐は無かったので、あまり房がうるさくない羽織紐がほしいなあとECサイトを眺める今日このごろです。

和服のよいところ

目論見通り、同僚から声をかけてもらえる機会が増えました! 初めて会う人との話題にとりあえず困らないのも良いところです。

和服のこまったところ

とにかく始めるに敷居が高い...呉服屋さんにも行ってみたけれど、"とりあえず仕立てましょう。"と言われる店もあって最初からそれは難しい。とはいえ、良さそうなお店を探したり、オンラインで買えるところを検討するのはなかなか楽しいので、趣味としてほそぼそと続けて行けたらと思っています。

あしたのクラスター Advent Calendar 2022 (2枚目)は Swanman さんが担当します!

Slackで本を紹介しやすくするサービスを作った

まとめ

解決したかった課題

slack で本を紹介するのに、Amazon の URL を貼ったはる人は多いハズ。しかし、商品によって、書影が展開されたりされなかったりします。Link preview が表示されたりされなかったりするわけです。これはイライラする。ということで、必ず本の書影とタイトルが展開出来る Webサービスを作りました。

動作イメージ

使い方1

  • https://yomu.jp/ の後に ISBN をつなげて URLを作成してください
  • たとえば https://yomu.jp/4274065979 というような URL です
  • この URL を slack で共有すると Link preview で書影とタイトルが現れます。
  • ISBN は本に固有の番号で、本の裏表紙に書いてあることが多いです。通常は13桁ですが古い本は10桁です。yomu.jp では 10桁に集約しています

使い方2

  • https://yomu.jp/ の後に ISBNを含む URL をつなげてURL を作成してください。
  • たとえば https://yomu.jp/ + amazon の書籍のURL という形です
  • yomu.jp では後ろにつなげた URL から ISBN を抜き出して、使い方1の URL へ自動で転送(redirect)します

そのうち改善したいこと

  • 時々書影が slack 上で展開されないことがあり、原因を探っているがよくわからない。画像は存在するので slack 側に理由がありそうな気もする。
  • Amazon 以外の購入リンクを作る
  • barcode で 本のISBN を読み取って Link を作れるようにする
  • kindle のリンクも変換出来るようにする。沢山使ってもらえれば可能になるかもしれない。

感想

  • 久々に個人サービスをリリースしたけど楽しいものですね。

新しい仕事と大阪東京通勤と子育ての話

この記事は クラスター Advent Calendar 2021 7日目の記事です。

この記事では今年2021年1月にクラスター株式会社に入社した kurain が、大阪から東京の会社に出勤する日々の様子をお送りします。

さて2021年は1月6日水曜日がクラスター社の仕事初めでした。乗り物全般大好きな私は、航空機出社をきめて友人に自慢しています。残念ながら、航空機は予約変更が大変なのと最終便がそこそこ早いので、以後全て新幹線での通勤になってしまいました。

f:id:r_kurain:20211207222707p:plain
出勤の様子

入社時点でクラスター社は水曜日のみの出社になっており、ここから週1回の大阪-東京通勤が始まるはずでした。しかし初出社翌々日の1月8日から新型コロナウィルス蔓延防止のための緊急事態宣言が発令。クラスター社も出社がなくなり、入社早々フルリモート状態になります。

うまくチームに馴染めるか心配もありましたが、メンターに毎日1on1してもらったり、いい感じのタスクを用意してもらったりと手厚い支援をうけまして、久しぶりのWeb Frontend 開発が順調にスタートします。この第2回の緊急事態宣言は3/24で終わりますが、その後も緊急事態は断続的に続いたので、結局今年の出社できた日はこんな感じでした。(赤が緊急事態宣言下or祝日)

f:id:r_kurain:20211207222813p:plain
緊急事態宣言の様子

このまま年末まで無事に出社できたとして最大21回しか出社することはなく、当初予定の半分以下しか東京に遊びに行く出社することはできないようです。

そして来年からはクラスター社の方針としてソフトウェアエンジニアは月1出社になります! ますます飛行機や新幹線に乗れなくなってしまいますが、私と同じように遠方からでもクラスター社に joinする人が増えるのではないかと期待しています!(交通費等細かい条件についてはお問い合わせください。)

ちなみに出社がある日は12:30が集合時間なので、普段と起きる時間は変わりません。

f:id:r_kurain:20211207225037p:plain
理想状態の一日

私の家は共働きなので子どもたちと過ごす時間がとれないと家庭が崩壊してしまいます。幸いこのような生活時間で運用しているので、朝夕の食事や就寝準備の時間は十分確保することができています。(むしろflexではかったらどうやって働けるのだろうか...と思わずにはいられませんが...) 一方で週1回とはいえ、妻に夜の育児を全てお願いし夜まで帰れない日があるので妻と子どもたちには、とても感謝しています。

在宅勤務・flex勤務と子育ての相性の良さはいろいろとあります。例えば長女が帰ってくる時間に私が家に居るようになったので、娘は家で友人と遊ぶようになりました。オンラインミーティング中に騒がしい声が入ってしまう事があるのは悩みのタネではありますが、会社の理解に助けられています。他にも子供の病院だとか、幼稚園の父母会だとか、小学校の個人面談だとか、諸々の用事をスキマ時間で済ます事ができています。

肝心の業務のほうは入社から半年は Web Frontend の開発と、社内のデータ分析の仕事を担当しました。7月から始まったcluster社の下期では、所属するプラットフォーム事業部の中でも、エンタープライズ事業部の支援を行う event 班のリードを担当。エンタープライズ事業部はclusterの中で行われる、企業主催のeventの制作進行を行う部署で、CG制作やイベント制作進行のプロフェッショナルが揃っています。一方私の所属するプラットフォーム事業部は3D空間の制御からWebやモバイルアプリのようなユーザーの接点となる部分まで一般のユーザーさんが使う機能全般を開発します。UGCプラットフォームとしての機能と、toB向けイベントプラットフォームとしての機能がお互いに影響しあい、新しいプラットフォームを作り出しているところは clsuter の非常に面白い特徴です。こうした部署をまたいだ仕事をしたいというのは、入社前から伝えていたことで希望がかないとても満足しています。

そして先月11月からエンジニアのチームが2つに再編成されました。Engine Team と Growth Team という名前で、そのうち Growth Team のリードを務めています。Growth Team は Web やモバイルアプリなどユーザーさんとの最初の接点になる開発を主に担当し、ユーザー体験やユーザー数を Growth させていくためのチームです。前述のevent班はGrowth Teamの担う機能の一つになっています。こちらのチームの成果もそう遠くないうちに公開されますので、ユーザーの皆さんに楽しんでもらえたらと思っています。

このように地方在住であっても、東京のメンバーと特に差のない仕事ができると思えることはとても幸いなことです。少なくとも出勤日に差はありません。月イチ出勤が開始されるとリモートとオフラインのメンバーが混ざる会議が増えることが考えられえ、その対策も進められています。地方在住メンバーは私だけでなく愛知在住の先輩社員、そして取締役が京都におり、この勤務形態が続くことには疑念の余地がありません。

ということで、東京以外の地域からもクラスター社への参加をおまちしてます!

recruit.cluster.mu

文字起こし再生に Mac の QuickTime Player を使うときのTips

3行まとめ

  • Automator を使うと QuickTime で文字起こし再生するのも簡単。任意のエディタが使えて便利。
  • 任意のショートカットキーで再生と停止を行うことができる
  • 再生再開時に、すこし巻き戻したり、再生速度を早くしたり遅くしたりもできる

たまには技術の小ネタを一つ。所要で文字起こしをすることになり、音声ファイルを再生しては止め、文字を打ちこむというアレをすることになりました。なるべくキーボードから手を動かしたくないので、ショートカットキーで再生と停止を出来るようにします。

Automator でクイックアクションを作る

Automator の 新規作成から、クイックアクションの作成を選ぶ。 f:id:r_kurain:20210602230528p:plain

下の画面になるように、左ペインのライブラリ > ユーティリティーから "Apple Script を実行" を選ぶ。 f:id:r_kurain:20210602230550p:plain

スクリプトを入力する

on run {input, parameters}
    tell application "QuickTime Player"
        tell front document
            set s to playing
            if s then
                pause
            else
                step backward by 20 # 20 step 巻き戻す。1 step 何秒かは不明
                play
                set rate to 1.2 # 1.2 倍速再生
            end if
        end tell
    end tell
    return input
end run
  • QuickTime で対象のファイルを開いた状態Automator の右上の再生ボタンを押して、正しく動くことを確認する。
  • 名前を付けて保存

作ったクイックアクションをショートカットキーに登録する

f:id:r_kurain:20210602230855p:plain 一番したのやつ。Automatorで保存した名前が、一般の下にあるはず。

はい。これで、どの画面にいても、登録したショートカットキーで、QuickTime の再生停止が出来ます。再開時にちょっと巻き戻してくれるので、入力の確認もできます。便利ですね。ぜひご利用ください。

Apple Script かなり便利なのに、文法が慣れないのがつらい。

VR空間にインスタレーションを再現する試み

7月から足掛け4か月ほどかけて、とあるインスタレーション作品をVR空間に再現するという制作を行っていたのだが、先ごろやっと公開することができた。どうにかなるだろうとは思っていたけれど、なかなか大変で、そして楽しかったのでその記録を残す。

f:id:r_kurain:20201018092057p:plain
cluster 上の記憶のミライ

なにを作ったのか

札幌のミニシアターの代表であり、映像作家、美術家である、中島洋さんの作品 "記憶のミライ" のVR版を cluster というサービス上に構築した。

cluster.mu

こちらから鑑賞できるので、よかったら見てもらえると嬉しい。PC, Mac, スマートフォンで見ることができるし、Steam VR が使える環境なら VRゴーグルでも見られる。

"記憶のミライ"の詳しい説明は、こちらにあるのだけれど古い8ミリフィルムから作成された映像作品を、4面のスクリーンに囲まれながら鑑賞する。というインスタレーションである。札幌のイベントスペースで開催されていた展示で、COVID-19流行の中では家族で見に行くことはかなわず、僕一人で見にいったのが7月のことだ。その場でVR作品にさせてもらえないかという交渉をしたのが制作のきっかけだった。 cluster の方は、PC, スマートフォン, VR ゴーグルで 3D空間の中をアバターで動き回って、ほかのユーザーとインタラクションもとれるというサービスである。

f:id:r_kurain:20201018094256p:plain
現実の"記憶のミライ"

なぜ cluster で作ったのか

そもそも、VR 空間でインスタレーションの再現を申し出たのは、自分の家族のようにCOVID-19の為にインスタレーションを見に行けない人にも、会場のように4面に囲まれたスクリーンで映像を鑑賞するという体験をさせて見たかったというのが大きい。VR空間を作成して共有するというツールは、

  • Amazon Sumerian
  • VRChat
  • cluster

などがあるのだけれど、

というようなツールはなかなか無くて、cluster を選択することはかなり最初に決めていた。友人が働いている会社というのも大きい。結果的にこれは大正解で、Unity で作った3D空間が特別な設定なしに、3つの環境で簡単に動くのはかなり良い体験だった。とくにVRゴーグルで体験するのは最高で、VR空間を自作するつもりでゴーグルを買ったのに結局いくつかゲームをして機材が眠っているという人にこそ試してもらいたいツールだと思う。

制作記録

この先は、cluster のVR空間、cluster ではワールドと呼ばれる物をつくるのに、どんな回り道をしつつ進めて行ったかを書きたい。

まず作り始める方法は、かなりよく解説されているので、cluster 社のブログ

creator.cluster.mu creator.cluster.mu

を読んで、書いてある手順通りに進めれば、とりあえず動くワールドが作れる。この時点で、スマートフォンや、ゴーグルなどで起動してみると、自分が作った3D空間が実機で動くワクワクが味わえると思う。

空間の制作

さて、チュートリアルができたら、自分の思い描く空間を作らねばならない。今回の目標はイベントスペースで開催されたインスタレーションの再現である。当初はイベントスペースの図面をとってきて、完全な再現を試みたのだが、わりとすぐに破綻することが分かった。一つには現実にあるものの再現は、とても労力がかかるという事実による。株式会社積木製作さんによる Unity Japan 社屋のVR空間再現がものすごく気合が入っていて作品として、また制作録としてとても面白い。

aec.unity3d.jp

tsumikiseisaku.com

しかし個人でこれをやるのは時間的、技術的に無理と悟って別の方法を考えることにした。もう一つの理由として、VR空間にはVR空間に向いた文字の大きさ、会場のサイズというのがあるという事が制作を進めるにつれてわかって来て、当初より大幅に大きな空間を作成することになった。という事もある。現実世界には、イベントスペースの広さという制限があるが、仮想世界に物理的制限はないのだ。

f:id:r_kurain:20201018092813p:plain
真面目に現実を模倣していたころのblender

空間制作には、blender を使って、blender から Unity へのインポートを行う形で行った。ここで気を付けるべきことは2つ

スケールをちゃんとしておく

ポリゴンの裏表が意図した方向になっているか確かめてからエクスポートする

  • blender はポリゴンをどちらの面から見ても描画してくれるシェーダーが標準なのだが、Unityは表面から見ないとポリゴンが描画されない。(3Dは専門外なので変な言葉を使っているかもしれない。指摘してくれると嬉しい。) なので、ポリゴンの表裏を意図している方向に揃えておかないと、Unityに移動したときに、天井や床が消える惨事が起きる。

dskjal.com

blender でのポリゴンの表裏についてはこちらのサイトの解説が良かった

blenderに標準でついている archmesh は壁を作っていくと、床も天井も作ってくれたり、窓やドアを壁と接触させるとちゃんと穴をあけてくれたりして、建築物をつくるにはとても良いツールだった。しかし、今回の案件ではそもそも現実の空間を模倣する必要がないと途中で気づいたので、はなから Unity 付属の ProBuilder とかのほうが良かったかもしれない。

動画を流す

大まかに空間ができたところで、今回の制作のメインである、動画の表示を確認した。最初にも書いたけれど、この作品は8mmフィルムから編集された動画が4面の布スクリーンに投影されている。これを Unity内の空間で再現する必要がある。幸い Unity には Video Player というめっちゃ便利なコンポーネントがあり、これを Quad オブジェクトにくっつけるだけで、平面上で動画を再生することができる。

docs.unity3d.com

注意点

Video Playerによる動画は自分で発光しているわけではない。つまり外からの光が当たらないと動画は見えない。現実の作品では、プロジェクターによる投影だったので、Unity上でもスポットライトをスクリーンに投影することでスクリーンに光を当てている。全くの3D制作初心者だったので、地面に垂直なポリゴンに、光が全くあたらず真っ黒になって焦るみたいなことがあったのだ...

blender のところにも書いたが、Unity上では、ポリゴンの表側しか描画がされない。板ポリゴンである quad オブジェクトに動画を流すと、表側でしか動画が見られず反対側から見ると何もない空間になってしまう。なので、今回は両面を描画するシェーダーを使って描画している。

tutorials.shade3d.jp

うまい具合に動画が両面で再生されており、かつ裏と表では鏡像になるという、布スクリーンを再現したような状態が作れている。

ライティング

3D空間の肝はライティングにある。ということが今回の制作でよくわかった気がする。ショボショボだった空間もライティングに凝っていくことで、それなりに見られるものになっていく。3D空間上のスクリーンにスポットライトを当てるというのも、そのような工夫がある。スクリーン以外の範囲に光が当たらないように、不可視オブジェクトを使って光の当たる範囲を制限したりと、実際のプロジェクターの構造を再現している。

f:id:r_kurain:20201018102057p:plain
スクリーンに投影してる感じを目指して頑張った

注意点

cluster の Creator Kit では、ライティングの自動ベイクが最初から切られている。これはよくお勧めされる設定なのだが、初心者は、どうやってライティングをベイクするのかわからずハマるかもしれない。なんども手動でベイクすればよい。というのが正解で、GPU利用の計算手法でベイクしよう。解説はこちら。 パネルライトはベイクしないと結果がわからないし、ほかのライトもベイクしないダイナミックライトは空間内に2つまでしか置けないのでベイクについて理解しないと、空間の制作はおぼつかない。

Unity のライティングについてはこちらなどが参考になる

qiita.com

装飾と導線

動画しか流れない空間というのも、ありかもしれないが作品の解説も必要だし、現実のイベントの写真などにも興味を持ってほしかったので、そういった文章や写真の展示も行った。cluster の解像度を考えると、現実に比べてそうとう大きな文字サイズ、写真サイズにする必要がある。実際の大きさは作品で見てもらうとうれしい。写真については、横3メートル縦2メートルの想定でオブジェクトを作成していて、これ現実にプリントしたらいくらなんだろうという気分が味わえた。写真や文章の掲示は、ちゃんと厚みのあるパネルを作ったほうがよい。というのも発見だった。べつに板ポリゴン置いておくだけでも見えるが、3cm くらいの厚みのある板に乗せると周囲に影が落ちてそれらしくなる。(この影の落ち方があまりきれいではなくて、どうにかしたいのだが僕の Unity 力が足りていないようだ。)

f:id:r_kurain:20201018093913p:plain
パネルには厚みがある方がよい

文章や写真を置いておくだけでは、おそらく読んでもらえないので、美術展のレイアウトを記憶から掘り起こし配置を考える。結局直線的な廊下に置いているだけではあるので、もっと工夫する余地はあると思う。ある種のハックとして廊下の幅を狭くすることで、3人称視点の時のカメラが文章のパネルに近づくようにしている。カメラが近づくと、文字が大きくなってすこし読みやすくなる。なぜ廊下の幅がこれに関係するかというと、カメラが壁にめり込まないように動くため、アバターと壁が近づくほどカメラがアバターに寄っていくのだ。

レビューとフィードバック

制作を始めた段階から、もとの映像作品の編集を担当した中野均さんに、レビューをお願いしていた。結果としてディレクションのような立場で制作に付き合ってもらうことができとても助かった。映像作品の意図などは製作者にしかわからないし、どういう空間にしたいのかというのも含めたインスタレーションであると思っていたので、自分ひとりではどうにもならなかったと思う。また、作ってはアドバイスをもらって、というイテレーションを回せたのもとても良かった。仕事ではない個人製作だとこれができなくて、進捗が停滞しがちなのだ。誰かと一緒にやるというのは私にとってはとても必要なことだと痛感した次第。

おわりに

勢いに任せて随分書いてしまったけれど、作品を見てもらえたら、とにかくうれしい。3Dの空間表現などは枝葉の話で、やはり本編である映像を見てもらいたい。30年以上前の札幌に住んでいた人たちが、いったいフィルムで何を撮影していたのか。見るときっと発見があると思う。

3D空間の構築作業はとても楽しく、無限に時間の奪われる困った趣味だということも分かった。良いアセットがUnity ストアだけでなく、Booth などにもあって、見ているだけでも大量の時間が消えていく。それでもなお楽しいのと、やってみたいことがあるので、細々と続けていきたいと思う。もし、こういったインスタレーションとか写真展とかを3D空間で表現したいというような人があれば相談に乗るので連絡してほしい。