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
93
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
詫び石の裏側
infiniteloop_inc
0
130
[新卒向け研修資料] テスト文字列に「うんこ」と入れるな(2024年版)
infiniteloop_inc
5
19k
リファクタリングで実装が○○分短縮した話
infiniteloop_inc
0
65
ADRという考えを取り入れてみて
infiniteloop_inc
0
57
500万行のPHPプロジェクトにおけるログ出力の歩み
infiniteloop_inc
0
74
I ❤ Virtual Machines 仮想環境をより便利に使うツールたち
infiniteloop_inc
0
40
アニメーションとスキニングをBurstで独自実装する
infiniteloop_inc
0
110
3Dプリンタって いいね
infiniteloop_inc
0
32
社内ソフトスキルを考える
infiniteloop_inc
0
60
Other Decks in Programming
See All in Programming
戦略的DDDは重いのか? / Is strategic DDD heavy?
pictiny
3
2.1k
Documentation testsの恩恵 / Documentation testing benefits
ssssota
1
550
Fragment Composition of GraphQL
quramy
14
1.7k
TCAとKMPを用いた新規動画配信アプリ 「ABEMA Live」の設計
tomu28
2
140
Escolhendo (ou não) o melhor ORM para o seu projeto
andreiacsilva
1
160
TypeScriptの型とパフォーマンス (TSKaigi 2024)
ypresto
14
4.4k
ソースコードを美しくたもつために ~コードレビューの認知限界を突破し、年間400リリースを達成する~
kotauchisunsun
1
640
Go製Webアプリケーションのエラーとの向き合い方大全、あるいはやっぱりスタックトレース欲しいやん / Kyoto.go #50
utgwkk
6
2k
Sheets API使ってみた
toshi0383
2
180
ServerAction で Progressive Enhancement はどこまで頑張れるか? / progressive-enhancement-with-server-action
takefumiyoshii
6
510
Runtime Objects in Rust
mitsuhiko
0
220
一文字エイリアスのすすめ
fujimura
0
190
Featured
See All Featured
Atom: Resistance is Futile
akmur
260
25k
The Invisible Side of Design
smashingmag
294
49k
Navigating Team Friction
lara
179
13k
Six Lessons from altMBA
skipperchong
22
3k
StorybookのUI Testing Handbookを読んだ
zakiyama
13
4.7k
A better future with KSS
kneath
231
16k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
21
1.6k
How GitHub (no longer) Works
holman
305
140k
Rebuilding a faster, lazier Slack
samanthasiow
74
8.3k
Side Projects
sachag
451
41k
Thoughts on Productivity
jonyablonski
60
3.9k
ParisWeb 2013: Learning to Love: Crash Course in Emotional UX Design
dotmariusz
104
6.7k
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