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
220
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
300
心理的安全性を学び直し、 「いい組織とは何か?」を考えてみる
infiniteloop_inc
0
380
ゼロからつくる 2D物理シミュレーション ~物理現象をコードに落とし込む方法~
infiniteloop_inc
0
490
詫び石の裏側
infiniteloop_inc
0
400
[新卒向け研修資料] テスト文字列に「うんこ」と入れるな(2024年版)
infiniteloop_inc
6
25k
リファクタリングで実装が○○分短縮した話
infiniteloop_inc
0
150
ADRという考えを取り入れてみて
infiniteloop_inc
0
140
500万行のPHPプロジェクトにおけるログ出力の歩み
infiniteloop_inc
0
110
I ❤ Virtual Machines 仮想環境をより便利に使うツールたち
infiniteloop_inc
0
93
Other Decks in Programming
See All in Programming
CSC305 Lecture 26
javiergs
PRO
0
140
Stackless и stackful? Корутины и асинхронность в Go
lamodatech
0
750
talk-with-local-llm-with-web-streams-api
kbaba1001
0
180
Effective Signals in Angular 19+: Rules and Helpers @ngbe2024
manfredsteyer
PRO
0
140
Semantic Kernelのネイティブプラグインで知識拡張をしてみる
tomokusaba
0
180
暇に任せてProxmoxコンソール 作ってみました
karugamo
2
720
バグを見つけた?それAppleに直してもらおう!
uetyo
0
180
テストケースの名前はどうつけるべきか?
orgachem
PRO
0
130
20年もののレガシープロダクトに 0からPHPStanを入れるまで / phpcon2024
hirobe1999
0
470
競技プログラミングへのお誘い@阪大BOOSTセミナー
kotamanegi
0
360
testcontainers のススメ
sgash708
1
120
nekko cloudにおけるProxmox VE利用事例
irumaru
3
430
Featured
See All Featured
Designing on Purpose - Digital PM Summit 2013
jponch
116
7k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
247
1.3M
Build The Right Thing And Hit Your Dates
maggiecrowley
33
2.4k
GitHub's CSS Performance
jonrohan
1030
460k
For a Future-Friendly Web
brad_frost
175
9.4k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
28
900
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
28
2.1k
It's Worth the Effort
3n
183
28k
VelocityConf: Rendering Performance Case Studies
addyosmani
326
24k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
159
15k
Writing Fast Ruby
sferik
628
61k
Product Roadmaps are Hard
iamctodd
PRO
49
11k
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