このコラムはLiveViewでVRMファイルを読み込んで口パクするプログラムを作ります
下記のコラムの延長になります
環境構築
$ git clone https://github.com/ymn-t-yamanashi/live_vrm.git
$ cd assets
$ npm i
$ cd ../
$ mix deps.get
$ mix phx.server
下記のURLアクセス
実行イメージ
自作ライブラリ
基本はElixirで使えるようにラップしてます
lib/three_web/live/cg/cg_helper.ex
defmodule ThreeWeb.Cg.CgHelper do
use Phoenix.LiveView
def add_cube(socket, name, x, y, z, color) do
push_event(socket, "addCube", %{name: name, x: x, y: y, z: z, color: color})
end
def add_plane(socket, name, x, y, color) do
push_event(socket, "addPlane", %{name: name, x: x, y: y, color: color})
end
def rotation(socket, name, x, y, z) do
push_event(socket, "rotation", %{name: name, x: x, y: y, z: z})
end
def position(socket, name, x, y, z) do
push_event(socket, "position", %{name: name, x: x, y: y, z: z})
end
def load_model(socket, name, path) do
push_event(socket, "loadModel", %{name: name, path: path})
end
def get_bone(socket, name) do
push_event(socket, "getBone", %{name: name})
end
+ def set_blend_shape(socket, name, key, value) do
+ push_event(socket, "setBlendShape", %{name: name, key: key, value: value})
+ end
def rotation_bone(socket, name, bone_name, x, y, z) do
push_event(socket, "rotationBone", %{name: name, bone_name: bone_name, x: x, y: y, z: z})
end
def load_texture(socket, name, path) do
push_event(socket, "loadTexture", %{name: name, path: path})
end
def set_texture(socket, obj_name, texture_name) do
push_event(socket, "setTexture", %{obj_name: obj_name, texture_name: texture_name})
end
@doc """
Three.jsシーンにCanvasテクスチャでテキストを表示する平面オブジェクトを追加します。
"""
def add_text_plane(socket, name, text_content, font_size, text_color) do
push_event(socket, "addTextPlane", %{
name: name,
textContent: text_content,
fontSize: font_size,
textColor: text_color
})
end
@doc """
既存のテキスト平面オブジェクトの文字内容とスタイルを更新します。
"""
def set_text_plane_text(socket, name, new_text_content, font_size, text_color) do
push_event(socket, "setTextPlaneText", %{
name: name,
newTextContent: new_text_content,
fontSize: font_size,
textColor: text_color
})
end
@doc """
Three.jsシーンから指定された名前のオブジェクトを削除します。
"""
def remove_object(socket, name) do
push_event(socket, "removeObject", %{name: name})
end
def set_size(socket) do
push_event(socket, "setSize", %{})
end
end
前回からの追加差分
set_blend_shape
アバターの表現する関数
set_blend_shape(socket, name, key, value)
- socket: ソケット
- name: 3Dオブジェクトの名前 (文字列)
- key: 表現するキー 「あ」の口なら aa
- value: 値 例: 1 (口を全開に開くなら1 閉じるなら0)
キーの例
アバターによって違いますが、下記は動作する可能性あります
vrmのバージョンによってはキーが違います
| キー | 意味 |
|---|---|
| aa | あの口 |
| ih | いの口 |
| ou | うの口 |
| ee | えの口 |
| oh | おの口 |
| happy | 喜び |
| angry | 怒り |
| sad | 悲しみ |
| relaxed | 落ち着き・通常 |
サンプルプログラム
口とウインクするサンプル
lib/three_web/live/cg/index.ex
defmodule ThreeWeb.CgLive.Index do
use ThreeWeb, :live_view
import ThreeWeb.Cg.CgHelper
def mount(_params, _session, socket) do
Process.send_after(self(), :update, 500)
socket =
socket
|> assign(data: initialization_character_data())
|> load_model("test", "images/test.vrm")
{:ok, main(socket)}
end
# @impl true
def handle_info(:update, socket) do
Process.send_after(self(), :update, 250)
{:noreply, main(socket)}
end
def handle_event("load_model", %{"name" => "test", "status" => "completion"}, socket) do
socket =
socket
|> position("test", 0, -1.4, 4.5)
|> position("test", 0, -1.4, 4.5)
|> rotation("test", 0, 3.1, 0)
|> rotation_bone("test", "J_Bip_R_UpperArm", -1.0, 1.2, 0.5)
|> rotation_bone("test", "J_Bip_L_UpperArm", -1.0, -1.2, -0.5)
|> set_blend_shape("test", "aa", 0.2)
|> set_blend_shape("test", "blink", 1.0)
{:noreply, socket}
end
defp initialization_character_data() do
0
end
defp main(socket) do
character_data = update(socket.assigns.data)
socket
|> set_blend_shape("test", "aa", character_data)
|> set_blend_shape("test", "blink", character_data)
|> assign(data: character_data)
end
defp update(1), do: 0
defp update(0), do: 1
end
このライブラリーを改造するなら
この2ファイルをいじれば、関数を増やせます
ソース