商品サンプル画像
バンダイ(BANDAI) UNION ARENA プレシャスブースターパック 勝利の女神:NIKKE【PC02BT】 (BOX)10パック入り
商品ページ
Amazon
収益広告(自動登録)
サクラ度:△(要確認)
商品サンプル画像
D.C.Ⅱ.S.S.~ダ・カーポⅡセカンドシーズン~(TV番組)
商品ページ
Amazon
非収益広告(手動登録)
サクラ度:○(問題なし)
商品サンプル画像
ホットウィール(Hot Wheels) カーカルチャー スリル クライマーズ メルセデス・ベンツ 300 SEL 6.8 AMG 乗り物おもちゃ ミニカー 3歳から ブラック JKF20
商品ページ
Amazon
収益広告(自動登録)
サクラ度:△(要確認)
商品サンプル画像
バンダイ(BANDAI) ガンダムカードゲーム ブースターパック Phantom Aria[GD04] (BOX)24パック入り
商品ページ
Amazon
収益広告(自動登録)
サクラ度:△(要確認)
商品サンプル画像
バンダイ(BANDAI) ONE PIECEカードゲーム スタートデッキ 赤 モンキー・D・ルフィ【ST-31】(2個セット)
商品ページ
Amazon
収益広告(自動登録)
サクラ度:△(要確認)
記事の概要
three.js・three-vrm.jsを使用して、VRoidをWebページ上に表示する Part-02
作成日:2025-04-14
最終更新日:2025-04-15
記事の文字数:7753
VRoidWebツール情報技術
本記事のトピック
  • 概要
  • three-vrmのupdate処理をまず呼び出す
  • カメラ目線にする
  • ポーズの変更方法(vroidposeデータから変更する)
  • 表情の変更方法
  • 口の形の変更方法
  • 変なテクスチャが表示されてしまう問題
  • 解像度問題の対応
  • vrm.update処理の中身について
  • サンプルコードはこちら
  • vroidposeにまつわる問題点
three.js・three-vrm.jsを使用して、VRoidをWebページ上に表示する Part-02
概要

three.js・three-vrm.jsを使用して、VRoidをWebページ上に表示する方法を載せています。
こちらはPart-02となり、Part-01の内容を前提としたものになっています。

今回は以下のコード例を載せています。
Part-01のコードがベースなので、「/* 追加 start */~/* 追加 end */」という形で、追加部分を明記しています。

今回紹介するコード例

  • three-vrmのupdate処理をまず呼び出す
  • カメラ目線にする
  • ポーズの変更方法(vroidposeデータから変更する)
  • 表情の変更方法
  • 口の形の変更方法
  • 変なテクスチャが表示されてしまう問題
  • 解像度問題の対応

また、今回も例によって、実際に動作確認できる(であろう)サンプルコードを下部に載せています。

three-vrmのupdate処理をまず呼び出す

今回行う内容(例えばカメラ目線にする)の中で、three-vrmが用意しているupdate処理を毎フレーム行うことでモデルに反映されるものがあります。

そのため事前準備として、animateメソッドの中でVRoidのアップデート処理を呼び出しておきましょう。

function animate() { requestAnimationFrame(animate); /* 追加 start */ // VRoid自動アップデート const deltaTime = 1 / 60; // 本当は毎フレームごとに計算した方が良いと思うけど、概ね1/60秒で動くと思うので vrm.update(deltaTime); // これが大切 /* 追加 end */ renderer.render(scene, camera); }

最後の方でこのvrm.updateについて簡単にまとめますが、色んな自動計算を行ってくれているようです。

また、この追加とともにvrmの初期化のあたりで、以下を入れておいてください。
これも後述しますが、これをしないと後の手順で行う「ポーズの変更」がVRoidに反映されないはずです

// VRMモデルを設定してシーンに追加 vrm = gltf.userData.vrm; scene.add(vrm.scene); /* 追加 start */ // 姿勢はvroidposeに従って制御するので、自動制御はOFFにする vrm.humanoid.autoUpdateHumanBones = false; /* 追加 end */
カメラ目線にする

VRoidをカメラ目線にします。
より正しく言えば、vrmの初期化時にVRoidの注視点をカメラに設定します。

// カメラ設定を反映 controls.update(); /* 追加 start */ // VRMをカメラ目線にする vrm.lookAt.target = camera; vrm.lookAt.autoUpdate = true; // 初期値だとあまりカメラに目を向けないようになっているので、補正する vrm.lookAt.applier.rangeMapHorizontalInner.outputScale = 20; vrm.lookAt.applier.rangeMapHorizontalOuter.outputScale = 20; vrm.lookAt.applier.rangeMapVerticalDown.outputScale = 20; vrm.lookAt.applier.rangeMapVerticalUp.outputScale = 20; /* 追加 end */ animate();

行数で言うとたった6行で完了(後は前項のvrm.updateを呼び出す必要あり)。

最初の2行が「VRoidがカメラを見る」(VRoidの眼球をカメラに向ける)というものになります。まぁそのままですね。

最後の4行ですが、デフォルト設定だとそんなにカメラを見てくれなくて、微妙に違う場所を見ている感じになってしまいます(一旦この行を消して試してみると分かりやすいです)。

そのため、カメラに目を向ける補正値を大きくすることでカメラ目線になるようにします。あまりに大きい値にすると今度は行き過ぎてしまうので丁度いい値を探すと良いと思います。

ポーズの変更方法(vroidposeデータから変更する)

VRoidのポーズを変更します。
手動で設定するのも良いですが、vroidposeファイルを使用するのが楽だと思うのでその方法で書きます。

/* 追加 start */ // ポーズデータを読み込んだら、それをvrmに適用する document.getElementById("poseDataInput").addEventListener('change', (event)=>{ const file = event.target.files[0]; if(file && vrm){ // ファイルを読み込む const reader = new FileReader(); reader.onload = () => { const poseData = JSON.parse(reader.result); const bonePose = poseData.BoneDefinition; // ボーンごとに保持する for (const boneName in bonePose) { const lowerBoneName = boneName.charAt(0).toLowerCase() + boneName.slice(1); // ポーズデータとVRMボーンの名前を同じにするために、ローワーキャメルにする // vrmにポーズを適用 const vrmBone = vrm.humanoid.getRawBoneNode(lowerBoneName); if(vrmBone){ const quat = bonePose[boneName]; vrmBone.quaternion.set(quat.x, quat.y, -quat.z, -quat.w); } } }; reader.readAsText(file); } }); /* 追加 end */

html側でもファイルを読み込めるようにする

<input type="file" id="poseDataInput" accept=".vroidpose">

ファイルを読み込む処理が入っているので若干行数多めですが、肝心のポーズを変更する処理は「vrmBone.quaternion.set(quat.x, quat.y, -quat.z, -quat.w)」の一行のみです。

もしこの処理を入れても、上手くいかないようであれば最初のvrm.update処理の中で記述した「vrm.humanoid.autoUpdateHumanBones = false;」と言うのを忘れているのではないかと思います。

ところでthree-vrmで読み込んだvroidモデル情報には「rawBone」と「normalizedBone」という二つのボーン情報が入っています。
・rawBone:threejsが持っている大元のボーン情報。本処理で書き換えてるのはこっち。
・normalizedBone:three-vrmjsによってvrm用に正規化されたボーン情報。

vrm.updateメソッドを呼び出すと、このnormalizedBoneからrawBoneに自動的にいい感じにボーンを設定してくれます。

なので逆に言うと、vrm.updateメソッドを使ってしまうとrawBoneを書き換えても勝手にnormalizedBone情報からrawBone側を勝手に書き換えてしまい、元のポーズに戻ってしまいます。「vrm.humanoid.autoUpdateHumanBones = false;」とすることで、その書き換えをさせないようにしています。

本処理ではrawBoneを使っていますが、normalizedBoneを使うことで、vrm側の設定違い(軸やポジションの違い)を補正してrawBone側に設定してくれるようです。なので、normalizedBoneを使う方が無難ではあるかと思います。

normalizedBoneを使いたい場合は上のコードの「vrm.humanoid.getRawBoneNode(lowerBoneName)」を「vrm.humanoid.getNormalizedBoneNode(lowerBoneName)」としたうえで、「vrm.humanoid.autoUpdateHumanBones = false;」を消せば良いです。

また、「手の形」は反映されません。これは元のvroidposeデータを見れば分かると思いますが、手だけはボーンではなくテンプレートを指定して設定されているためです。テンプレートを手のボーンに変換しないとVRoidには反映できないかなと思います。

表情の変更方法

表情変更も簡単です。

/* 追加 start */ // 表情変更 document.getElementById("expressionOn").addEventListener('click', (event)=>{ if(!vrm) return; vrm.expressionManager.setValue('relaxed', 1.0); }); document.getElementById("expressionOff").addEventListener('click', (event)=>{ if(!vrm) return; vrm.expressionManager.setValue('relaxed', 0.0); }); /* 追加 end */

html側で切り替えできるようにする

<input type="button" id="expressionOn" value="笑う"> <input type="button" id="expressionOff" value="笑わない">

実質「vrm.expressionManager.setValue('relaxed', 1.0);」の一行のみです。

setValueの引数に、「表情」と「変更の度合い」を設定すれば良くて、もし怒りと悲しみを0.5ずつ設定したいときは「setValue('sad', 0.5)」「setValue('angry', 0.5)」にすれば良いだけです。

ちなみにVRoidStudioで作ったモデルであれば、以下の表情が設定できると思います。
・relaxed
・sad
・angry
・happy
・Surprised
・neutral

口の形の変更方法

口の形の変え方はほぼ表情変更と同じです。

/* 追加 start */ // 口の開け閉め document.getElementById("mouthOpen").addEventListener('click', (event)=>{ if(!vrm) return; vrm.expressionManager.setValue('aa', 1.0); }); document.getElementById("mouthClose").addEventListener('click', (event)=>{ if(!vrm) return; vrm.expressionManager.setValue('aa', 0.0); }); /* 追加 end */

html側で切り替えできるようにする

<input type="button" id="mouthOpen" value="口を開ける"> <input type="button" id="mouthClose" value="口を閉じる">

実質「vrm.expressionManager.setValue('aa', 1.0);」の一行のみです。

表情変更とほぼ同じですね。

ちなみにVRoidStudioで作ったモデルであれば、以下の口の形が設定できると思います。
・aa
・ih
・ou
・ee
・oh

変なテクスチャが表示されてしまう問題

Part-01では、モデルの首の下や背中部分に不自然に黒いテクスチャが出現していたかと思います。

これというのは実は服のテクスチャに、「ほぼ透明に近いけど透明ではない部分」があり、それが不透明度1.00(最大)として表示されてしまっていたためです。

しかし、恐らく現状のコードであれば多分透明になっていると思います。

一番最初に行った「vrm.update」メソッドがこの部分をいい感じにしてくれているようで、それによって透明になっているようです。
なので、現状対応不要なのですが、vrm.updateメソッドの処理をすべて行うとは限らない(後述)ので、一応個別に設定したい場合の方法を書きます。

// VRMモデルを設定してシーンに追加 vrm = gltf.userData.vrm; scene.add(vrm.scene); /* 追加 start */ Object.values(vrm.materials).forEach((val) => { if(val?.uniforms?.alphaTest?.value !== undefined){ val.uniforms.alphaTest.value = 0.02; // これ以上の不透明度のテクスチャは不透明になる。初期値は0。 } }); /* 追加 end */

テクスチャは複数あるので、ループで回す必要はありますが、肝心の個別設定は「val.uniforms.alphaTest.value = 0.02;」の一行のみで設定できます。

このalphaTest.valueという値が閾値になっており、これ以上の不透明度のテクスチャは不透明度1.00(最大)として表示されるようです。初期値は0なので、ごくわずかでもテクスチャに不透明な場所があるとそれが不透明度1.00(最大)として表示されてしまうということです。

vrm.updateメソッド内で行われているテクスチャ関連の自動更新処理がこのalphaTestの値をいい感じに変更してくれるようなので、vrm.updateメソッドをきちんと呼んでいればこの問題は多分起こらないと思います。

解像度問題の対応

スマホなどの高解像度の端末で表示すると、綺麗にcanvasが表示されず若干崩れて表示されることがあります。

まぁ原因は解像度が高いから、とそれ以上でもそれ以下でも無いですが、解像度の設定も容易にできます。

// canvasの用意 renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize( canvasWidth, canvasHeight ); /* 追加 start */ renderer.setPixelRatio(window.devicePixelRatio); // 解像度の高い端末でも綺麗に表示されるようにする /* 追加 end */ document.body.appendChild(renderer.domElement);

window.devicePixelRatioの値が、Android端末だと大体3.5倍くらいなのですが、割と顕著に処理が重くなります。もちろん元のcanvasサイズが大きければ更に重くなります。

実際にはwindow.devicePixelRatioの値をそのまま設定するのではなく、「Math.min(window.devicePixelRatio, 2.0)」などとすることで、上限値を設けた方が良いと思います。

vrm.update処理の中身について

何度も話に出てくる「vrm.update」メソッドについて、簡単に書いておきます。

このメソッドですがざっくり以下のことをやっているようです(更に深堀りすると複雑になるので、更に細かく見たい場合は御自身でご確認ください)。

// normalizedBoneから、rawBoneを更新する if(this.autoUpdateHumanBones){ this._normalizedHumanBones.update(); } // モデルの目を注視点(現在の設定ではカメラ)に向ける if(this.lookAt){ this.lookAt.update(t); } // モデルの表情を更新 if(this.expressionManager){ this.expressionManager.update(); } // ボーンの連動関係があれば更新する if (this.nodeConstraintManager) { this.nodeConstraintManager.update(); } // モデルのボーンを更新 if (this.springBoneManager) { this.springBoneManager.update(e); } // モデルのマテリアルを更新 if (this.materials) { this.materials.forEach(n => { if (n.update) { n.update(e); } }); }

今回の所で言うと、this.lookAt.updateメソッドはかなり関係します。カメラ目線にする際、カメラをターゲットにするだけで良かったですが、それはこのメソッドのおかげです。

コード量を減らすためにvrm.updateメソッドはきちんと利用するべき(というかそうしないならthree-vrmを使う意味が……)だとは思いますが、毎フレーム呼ばれている処理なので不要な処理はなるべく呼びたくないという人もいると思います。そういう方はvrm.updateメソッドの中身を見て個別に呼び出すのが良いかと思います。

サンプルコードはこちら

サンプルコードはPart-01と同じ場所(GitHub)にあります。

vroidposeにまつわる問題点

vroidposeデータはVRoidStudio用のポーズデータですが、前述の通り「手の形」はそのままではボーンに反映されない問題があります。
こちらは対応がまだできるのですが、「SpineControlPointDeltaPosition」という独自の設定をボーンに反映するのが難しいです。

何か良い対応方法が思いつけば記事にするかもしれません。

コメントログ
※コメントは最新50件が表示されます
コメント投稿




画面下部の「コンタクト」からも連絡可能です。
管理人ツイート
商品サンプル画像
ポケモンカードゲーム MEGA 拡張パック ニンジャスピナー BOX
商品ページ
Amazon
収益広告(自動登録)
サクラ度:△(要確認)
商品サンプル画像
バンダイ(BANDAI) ONE PIECEカードゲーム エクストラブースター EGGHEAD CRISIS【EB-04】 (BOX)24パック入り
商品ページ
Amazon
収益広告(自動登録)
サクラ度:△(要確認)
商品サンプル画像
バンダイ(BANDAI) ONE PIECEカードゲーム スタートデッキ 紫 シャーロット・カタクリ【ST-34】(2個セット)
商品ページ
Amazon
収益広告(自動登録)
サクラ度:△(要確認)
商品サンプル画像
塗るだけでシールになる! シール液 ぺたりん 大容量25g 復活剤 日本製 粘着復活 水性 速効性 簡単 強粘着 こどもも安心 粘着剤 接着剤 手作り シール しーる ぷっくりシール 付箋 復活 粘着 接着 ボンド 刷毛 乾燥 手作りシール ステッカ
商品ページ
Amazon
収益広告(自動登録)
サクラ度:△(要確認)
管理人作品宣伝
【MMDアークナイツ】from Y to Y with ソラ
動画 / 最終更新:2022-10-02
「from Y to Y」を歌って踊るソラです。…「from Y to Y」を歌って踊るソラです。

YouTubeで閲覧するニコニコ動画で閲覧する利用素材等の詳細情報
ジグソーパズル風パズルゲーム
Webサイト / 最終更新:2025-01-23
ジグソーパズル風パズルゲームです。自分で画像を設定してパズルにできます。…ジグソーパズル風パズルゲームです。自分で画像を設定してパズルにできます。

HPで閲覧する利用素材等の詳細情報
作品一覧はこちら
関連ページ
OpenAI API:Webサーチモードで参考にしてほしいURLを送っても無視されることがある問題について
最終更新日:2025-12-07
このページのポイントWebサーチでも、まずは「プロンプトだけ」を読んで「解釈」される「前提として見て…
記事を閲覧する
不思議の幻想郷 TODR:装備の印の組合せシミュレーションツール
最終更新日:2025-11-30
概要本ページは『不思議の幻想郷 TOD RELOADED.』の印考慮用のツールページです。基本事項固…
記事を閲覧する
逆転裁判3:あやめさんのナルホド君への呼び方にある3つの伏線
最終更新日:2025-11-26
このページのポイント呼び方ひとつに3つも伏線あるなんてスゲーネタバレ注意本ページには「逆転裁判3」の…
記事を閲覧する
VRoidナビゲーター:質問機能を強化しました
最終更新日:2025-11-25
このページのポイントVナビの質問機能がいま開いているページを参照するようになった必要な情報をネット上…
記事を閲覧する
JavaScriptでアナログ時計とデジタル時計を表示するコード
最終更新日:2025-05-29
概要 最近アナログ時計を使ったので、アナログ時計を表示するJavaScriptコードを載せます。 …
記事を閲覧する
three.js・three-vrm.jsを使用して、VRoidをWebページ上に表示する Part-03
最終更新日:2025-04-20
概要 three.js・three-vrm.jsを使用して、VRoidをWebページ上に表示する方…
記事を閲覧する
three.js・three-vrm.jsを使用して、VRoidをWebページ上に表示する Part-02
最終更新日:2025-04-15
概要 three.js・three-vrm.jsを使用して、VRoidをWebページ上に表示する方…
記事を閲覧する
three.js・three-vrm.jsを使用して、VRoidをWebページ上に表示する Part-01
最終更新日:2025-04-13
概要 three.js・three-vrm.jsを使用して、VRoidをWebページ上に表示する方…
記事を閲覧する
GIF / APNG(アニメーション付きPNG)ファイル解析ページ
最終更新日:2025-03-31
ファイル読込・操作 以下に調べたいファイルを読み込ませてください。 ファイル情報 カラーパレットを…
記事を閲覧する
gifler.js仕様メモ
最終更新日:2025-03-23
本ページの趣旨 「gifler.js」という、gifアニメーションをcanvasに簡単に表示できる…
記事を閲覧する
本サイトのタグ一覧
NovelAIR18VRoidWebサイト作成Webツールととモノ。るろうに剣心アークナイツアークナイツ-ステージ攻略日記アズールレーンアズールレーン-日記ウマ娘ギャラリーゲームデビラビローグネットスラング系プログラミングホラーポケットタウン怪談気ままな日記逆転裁判情報技術情報技術-WebAPI知的財産権統合戦略白夜極光本サイトについて魔王スライム様がんばる!漫画
人気記事
ととモノ。3:各学科の強みを一覧化
最終更新日:2025-10-12
スコア:1493.8582 pt
このページのポイントどの学科が良いかすぐに分かる各学科のどのような点が良いか分かる各役割で欲しいスキ…
記事を閲覧する
ポケットタウン_パズル一覧
最終更新日:2025-05-02
スコア:799.3500 pt
グレーのピースの数 (Number of gray pieces):検索グレーピースの数を入力して、…
記事を閲覧する
TRICK-本物っぽい霊能力者
最終更新日:2025-02-06
スコア:649.8711 pt
概要 TRICKは基本的にインチキ霊能力者のインチキを暴いていく話ですが、中にはトリックでは説明が…
記事を閲覧する
メイド・オブ・ザ・デッド-攻略お助け情報
最終更新日:2024-05-01
スコア:531.5940 pt
ネタバレ注意! 本ページは『メイド・オブ・ザ・デッド』の情報を記録しているものです。 攻略の参考に…
記事を閲覧する
剣と魔法と学園モノ。2G - パーティ編成確認ツール
最終更新日:2024-05-09
スコア:432.0000 pt
ツール概要 ととモノ。2Gのパーティ編成を考える際に使うツールです。 あくまでストーリークリアまで…
記事を閲覧する
剣と魔法と学園モノ。3 前作からの変更点
最終更新日:2025-10-12
スコア:344.2016 pt
概要 もうそろそろ「ととモノ。3」のリマスターが出るので、自分自身のための振り返りと言う意味も込め…
記事を閲覧する
剣と魔法と学園モノ。3 - パーティ編成確認ツール
最終更新日:2025-09-23
スコア:332.3457 pt
ツール概要 ととモノ。3のパーティ編成を考える際に使うツールです。 攻略本や攻略wikiを参考にし…
記事を閲覧する
ヒカルの碁で、なぜ佐為は消えたのか
最終更新日:2025-04-21
スコア:310.1655 pt
概要 ヒカルの碁で佐為が消えた理由について、「ヒカルの才能を目覚めさせるという役割を終えたから」と…
記事を閲覧する
最新記事
鉄鍋のジャン:ジャンのいいところ
最終更新日:2026-02-16
ネタバレ注意※本記事にはネタバレが含まれます。このページのポイントジャンは本当にクズなのかジャンのい…
記事を閲覧する
るろうに剣心-各キャラの持つ正義
最終更新日:2026-01-12
このページのポイントこんな人向けるろ剣を読んだことないけど知ってる人軽く読んだことがある人伝えたいこ…
記事を閲覧する
逆転裁判1:真犯人まとめと悪質度
最終更新日:2025-12-15
概要 逆転裁判1(蘇る込み)に出てくる犯人たちを、やったことや動機なんかを整理して「悪質度」を点数…
記事を閲覧する
OpenAI API:Webサーチモードで参考にしてほしいURLを送っても無視されることがある問題について
最終更新日:2025-12-07
このページのポイントWebサーチでも、まずは「プロンプトだけ」を読んで「解釈」される「前提として見て…
記事を閲覧する
商品サンプル画像
バンダイ(BANDAI) ONE PIECEカードゲーム スタートデッキ 赤黒 サボ【ST-35】(2個セット)
商品ページ
Amazon
収益広告(自動登録)
サクラ度:△(要確認)