アップロードされた画像が残ることは、一切ありません
Soft Touch

技術・約8分で読めます

WebGLで肌の触感を再現する — 実装のポイント

「写真の肌に触れる」という体験を、ブラウザだけで、しかもスマホで滑らかに動く速度で実現するために考えたことをまとめます。ライブラリは使わず、素のWebGLとGLSLだけで書いています。

変形だけでは肌に見えない

画像を局所的に縮めれば「押した」風には見えます。ただ、それは肌ではなくゴムシートに見えます。足りないのは陰影です。

押し込みを高さ場として定義し、その勾配から法線を作り、光を当て直す。この一手間で見え方が変わります。重要なのは「元の写真に写っている光」との差分だけを足すことです。絶対値で照明すると写真本来の陰影が壊れます。

へこみの形は「輪郭を持たない」ものにする

最初は、指の腹を平らな皿、その縁を壁、外側を土手として形を定義しました。理屈は正しいのですが、実際に描くと輪郭のはっきりした円が浮かび上がり、非常に不自然でした。

最終的にはなだらかな釣鐘型に落ち着きました。境目を持たず、外側にごく薄い盛り上がりを付けるだけ。さらに、押すたびに少しずつ違う不規則な形になるよう、角度に応じた揺らぎを加えています。真円は自然界にほとんど存在しないためです。

スマホで滑らかに動かすための工夫

当初は、画面の各ピクセルについて高さ場を5回(本体と勾配用に4回)計算していました。それぞれが全接触点をループするので、高精細なスマホ画面では1フレームあたり1000万回規模の計算になり、目に見えて重くなります。

解決策は、高さ場を画面の3分の1の解像度で別パスとして一度だけ描き、テクスチャに保存することでした。本描画ではそれを読むだけです。これで高さ関連の計算量はおよそ40分の1以下になりました。あわせて描画ピクセル数に上限を設け、端末の画面密度に応じて自動調整しています。

顔メッシュの変形で表情を作る

表情を付ける際、最初は目や口の周りをガウス状にずらしていました。これは失敗で、パーツが動くのではなく画像がにじむように歪み、強い違和感を生みます。人の顔に対する違和感の検出力は非常に高いです。

正解は、顔認識で得た478点を頂点とする三角形メッシュを変形させることでした。目を閉じる動きは「上まぶたの頂点が下まぶたの位置へ移動する」という解剖学どおりの実装にします。動かす量はFACS(顔面動作符号化システム)の動作単位に沿って決めました。

メッシュが破れないようにする

変形を強くすると、三角形が裏返って面が破れます。三段構えで防ぎました。各頂点の移動量に上限を設ける(飽和関数で頭打ちにする)、隣接頂点と変位を混ぜてなだらかにする、それでも裏返った三角形を検出して該当頂点の動きを弱める、の3つです。

ただし、まぶたと唇は意図的に反対方向へ動くため、なだらか化の対象から外す必要がありました。ここを一律に処理すると、目が閉じなくなります。

MediaPipeの顔メッシュには穴がある

MediaPipeが提供する三角形分割には、目の穴と口の穴(上下のまぶたの間、上下の唇の間)が含まれていません。そのため口を開けると、その部分だけ変形が効かず、割れたように見えました。

認識した468点と外周の補助点をまとめてドロネー分割し直すことで解決しました。穴のない完全な三角形分割にすれば、口の中や目の中まで一枚の面として動きます。

実際に触ってみてください

登録なしで、トップページのサンプル画像をそのまま触れます。

ほかの記事