Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
VRChatでお酒が注げる飲み物アセットの紹介
Search
Infiniteloop
October 18, 2023
Programming
0
240
VRChatでお酒が注げる飲み物アセットの紹介
【タガヤス その27】わくわくUnity! ~CPUとGPUを酷使しよう~【仙台発信の定期勉強会】
https://tagayas.connpass.com/event/255830/
Infiniteloop
October 18, 2023
Tweet
Share
More Decks by Infiniteloop
See All by Infiniteloop
俺の PHP プロファイラの話 PHP スクリプトで PHP 処理系のメモリをのぞき込む
infiniteloop_inc
0
330
心理的安全性を学び直し、 「いい組織とは何か?」を考えてみる
infiniteloop_inc
0
420
ゼロからつくる 2D物理シミュレーション ~物理現象をコードに落とし込む方法~
infiniteloop_inc
0
540
詫び石の裏側
infiniteloop_inc
0
420
[新卒向け研修資料] テスト文字列に「うんこ」と入れるな(2024年版)
infiniteloop_inc
6
26k
リファクタリングで実装が○○分短縮した話
infiniteloop_inc
0
160
ADRという考えを取り入れてみて
infiniteloop_inc
0
150
500万行のPHPプロジェクトにおけるログ出力の歩み
infiniteloop_inc
0
120
I ❤ Virtual Machines 仮想環境をより便利に使うツールたち
infiniteloop_inc
0
100
Other Decks in Programming
See All in Programming
Lookerは可視化だけじゃない。UIコンポーネントもあるんだ!
ymd65536
1
130
AWSのLambdaで PHPを動かす選択肢
rinchoku
2
390
毎日13時間もかかるバッチ処理をたった3日で60%短縮するためにやったこと
sho_ssk_
1
530
Findy Team+ Awardを受賞したかった!ベストプラクティス応募内容をふりかえり、開発生産性向上もふりかえる / Findy Team Plus Award BestPractice and DPE Retrospective 2024
honyanya
0
140
traP の部内 ISUCON とそれを支えるポータル / PISCON Portal
ikura_hamu
0
180
rails newと同時に型を書く
aki19035vc
5
700
ESLintプラグインを使用してCDKのセオリーを適用する
yamanashi_ren01
2
200
Stackless и stackful? Корутины и асинхронность в Go
lamodatech
0
1.3k
PHPで学ぶプログラミングの教訓 / Lessons in Programming Learned through PHP
nrslib
4
1.1k
KubeCon NA 2024の全DB関連セッションを紹介
nnaka2992
0
120
Alba: Why, How and What's So Interesting
okuramasafumi
0
190
shadcn/uiを使ってReactでの開発を加速させよう!
lef237
0
290
Featured
See All Featured
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
8
1.2k
Build The Right Thing And Hit Your Dates
maggiecrowley
33
2.5k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
28
4.5k
It's Worth the Effort
3n
183
28k
Rebuilding a faster, lazier Slack
samanthasiow
79
8.8k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
47
5.1k
Designing Experiences People Love
moore
139
23k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
49k
Why Our Code Smells
bkeepers
PRO
335
57k
GitHub's CSS Performance
jonrohan
1030
460k
Producing Creativity
orderedlist
PRO
343
39k
GraphQLの誤解/rethinking-graphql
sonatard
68
10k
Transcript
VRChatでお酒が注げる 飲み物アセットの紹介 myxy
自己紹介 • myxy • @3405691582 • 愛知県出身 大学から仙台在住 • 30歳
• 入社3年目 • 業務は主にUnityでクライアントサイドの開発 • 最近はVRChatを遊んでいる
VRChat • VRHMD対応メタバース • アバター等3Dモデルをアップロードして遊べる • 制作の自由度が高い ◦ スクリプトが使える(ほぼC#で書ける) ◦
シェーダが使える(ビルトインレンダーパイプライン)
発表内容:製作物の紹介 VRChat上で動作するグラスとボトルのアセット https://youtu.be/H6QDChcddqY
アセットに用いられている各種技術を • GPU編 ◦ グラスや液体の描画 • CPU編 ◦ 揺れや体積の物理演算 の2つに分けて解説
GPU編
グラスの描画にはSDF (Signed Distance Field)を用いる 空間位置から物体表面からの距離を出す関数 物体外側が正、物体内側が負となる 円の距離場 正方形の距離場
複数のSDFを組み合わせることで 様々な形状を作ることができる min(円,正方形) max(円,正方形)
3次元のSDFはレイマーチングという レイトレーシングの手法を用いて描画することができる float sphere(vec3 p, float r) { return length(p)
- r; } float cube(vec3 p, vec3 b) { vec3 q = abs(p) - b; return length(max(q,0.)) + min(max(q.x,max(q.y,q.z)),0.); } float map(vec3 p) { return min(cube(p-.25, vec3(.5)),sphere(p+.25,.5)); }
アセットではグラス本体と内部の液体をSDFで表現し、 レイマーチングを用いてCubeのメッシュに描画している
Q: なんでそんな面倒なことするの?モデリングすれば? A: • 動作に合わせて傾いたり波が立ったりする 液体の複雑な形状はモデリングでは再現できない 計算したほうが都合が良い • パラメータを変更するだけで様々な形状、色のボトルを 生成することができる
描画の流れ 視点からボトル表面にレイを飛ばす →ボトル表面の情報が取れる 内部の水面情報や ボトル裏側の情報も必要 複数回に分けてレイを飛ばすことで 各部の情報を取得
1. 視点からボトルに向けてレイを当てる 視点 描画の流れ 2. レイ方向に十分離れた地点から 視点方向にレイを当てる 2つのレイ衝突地点の中間点が ボトルのガラス部分にあるかどうかで 描画ピクセルにおいて
ガラスが重なっているかどうか判定できる
液体部分に対しても同様にレイを飛ばすことで • 水面を上から見ている • 水面を下から見ている • 水面を見ていない 等の状態を判定することができる 視点
• ボトルの表面を見ているか • 水を見ているか • 水面を表面/裏面から見ているか • 見えている水面は ガラスに遮蔽されるか 等の場合分けを行い、
物理的に整合性が取れるような ピクセルの描画内容を決定する
透明度 水部分の視点側と視点の逆側にレイを当てているので 液体の厚みの情報が得られる 液体の厚みに対して 指数関数的に透明度が下がる様子を 表現できる
表面張力の表現
グラス壁面 グラス壁面からの距離d 0 a*exp(-b*d) グラスのSDF=壁面からの距離を適当な関数に入れると 壁面付近で盛り上がる形状を表現できる a
泡 水中に玉を描画 玉を複製 → → 確率で玉を消去 動きも実装する 炭酸飲料のような泡の表現
水流はレイマーチングではなく円柱状メッシュを変形している 体積、速度に応じて水流の太さが変化する 瓶の口付近では水面高さに合わせて形状が変化する 水流
水流 格子状に展開されたUV座標を用いて各頂点を識別している スクリプトから渡される水流の位置情報から頂点位置を計算
CPU編
グラス形状データ グラスは基本的に回転体 半径の配列(長さ32)をテクスチャに記録している スクリプトで処理した上でシェーダに渡す
ボトル側面形状の計算 半径の配列(長さ32)をCatmull-Rom splineで補間している 半径配列から毎フレーム計算するのではなく 3次の多項式の係数をスクリプトで計算し、 Vector4の配列としてシェーダに渡している ax^3+bx^2+cx+d
水面揺れの計算 水面全体の傾き (CPUで計算) 細かい波 (GPUで計算) 最終的な水面形状 + ⇒
水面に接続されたばね - 質点系を計算 質点の逆方向が水面の向きとなる 振り子の計算
振り子が激しく動くほど 水面の細かい波が大きくなる 具体的には振り子の躍度(加速度の 時間微分)に波の大きさが比例する 振り子の計算
グラスは液体の体積を保持している 体積一定であっても水面の傾きによって水面高さは異なる 体積と水面の傾きから水面高さを算出する必要がある 水面高さの計算
目標体積より大きい 水面高さと水面の傾きから液体体積を計算する関数を作り、 目標の体積になるような水面高さを二分探索で求める 目標体積より小さい ・・・
目標体積より大きい 二分探索各ステップ毎の体積計算が重い処理なので 8bit=256段階の水面高さの二分探索を8フレームに分けている 目標体積より小さい ・・・ 1フレーム目 2フレーム目 8フレーム目 ・・・
x π/2+asin(x) +t√(1-t^2) 液体部分の体積は弓形の底面の柱の積み重ねとして 近似的に積分する 弓形面積の式に重い関数があるのでテーブル化している
体積断片を積み重ねていく過程で • 液体部分の体積の最小値 • 空気部分の体積の最小値 がそれぞれ増加していく • 液体体積最小値が目標液体体積を上回る • 空気体積最小値が目標空気体積を上回る
ときに目標体積との大小関係が決定し、 計算を打ち切ることで処理を軽くしている 液体 空気 未計算
水流の計算 • 水流チューブは水流方向に 64個のセグメントに分割されている • 各セグメント毎に ◦ 初期速度 ◦ 現在速度
◦ 体積 ◦ 水流の側面方向 の情報を持つ • 水流半径は 開口半径√(初期速度/現在速度) となる
注ぐ処理 • 水流セグメント毎に レイキャストを行い、 レイが衝突したグラスに セグメントの体積を追加する • 注ぐ先の液体の色や泡の量を 変化させる
現状の課題 • GPU・CPU共に重い処理をやっている ◦ 特にレイマーチングはループ回数が200回くらい 距離関数等の見直しが必要 • ライティング設定によっては見栄えが悪い ◦ VRChatで動くシェーダはありとあらゆる
ライティング設定で機能する必要がある ◦ シェーダ書くのがむずかしい
Boothで販売中 https://usamimi-zakka.booth.pm/items/3636706