WebGPUライブラリ「UltraMotion3D」で3DのサンプルWebコンテンツを動かしてみよう

キャラクターをマウスで移動させる
今度はサンプルコード「bone.html」をコーディングし、マウスの左ドラッグでキャラクターを平行移動したり、右ドラッグでキャラクターを回転させたりします(図2)。マウスだけでなくスマホのタッチにも対応させますが、筆者は最新のAndroidを持っていないため、Androidで動作確認は行っていません。
マウスクリックやタッチを取得するには「イベントリスナー」に関数を登録します。または直接「onmousedown」「onmousemove」「onmouseup」イベントに関数を登録します。ここでは「document」にイベントリスナーをセットしているためクライアント領域のどこでもイベントをキャッチできますが、<canvas>だけにイベントリスナーを登録すれば<canvas>タグ上だけでイベントをキャッチできます。
これも「models」→「Character.js」ファイルを見れば分かると思いますが、「Character」クラスは「BoneModel3D」クラスから派生したクラスでボーンアニメーションする3Dモデルを扱います。「BoneModel3D」クラスが「Model3D」クラスから派生しているだけあって、前のページと同様に扱うことができます。
・サンプルコード「bone.html」<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>UltraMotion3D</title> <meta name="viewport" content="width=device-width"> <link href="css/main.css" rel="stylesheet" type="text/css" /> <link href="css/mobile.css" rel="stylesheet" type="text/css" media="only screen and (max-width:480px)" /> <script src="lib/Material.js"></script> <script src="lib/Vector3D.js"></script> <script src="lib/Matrix3D.js"></script> <script src="lib/Model3D.js"></script> <script src="lib/BoneModel3D.js"></script> <script src="lib/WGSL.js"></script> <script src="lib/UltraMotion3D.js"></script> <script src="models/Character.js"></script> <script type="text/javascript"> let _model; let _pos = new Vector2D(0,0); let _clickL = false; let _clickR = false; function init() { _model = new Character(); _model.pos.y = -150; if ( 'ontouchend' in document ) { document.addEventListener('touchstart',onMouseDown,false); document.addEventListener('touchmove',onMouseMove,false); document.addEventListener('touchend',onMouseUp,false); } else { document.onmousedown = onMouseDown; document.onmousemove = onMouseMove; document.onmouseup = onMouseUp; document.oncontextmenu = function () { return false; } } } function draw() { _camera.lookAt(new Vector3D(0,0,500),new Vector3D(0,0,0),new Vector3D(0,1,0)) _model.draw(); } function onMouseDown(event) { _pos = getPos(event); switch ( event.button ) { case 0: _clickL = true; break; case 1: break; case 2: _clickR = true; break; } } function onMouseMove(event) { pos = getPos(event); if ( _clickL ) { _model.pos.x += pos.x-_pos.x; _model.pos.y += _pos.y-pos.y; } if ( _clickR ) { _model.rotate.addX(pos.y-_pos.y); _model.rotate.addY(pos.x-_pos.x); } _pos = pos; } function onMouseUp(event) { _clickL = false; _clickR = false; } </script> </head> <body onload='initWebGPU("CanvasAnimation");'> <canvas id="CanvasAnimation" width="2000" height="1000"></canvas> <div id="container"> <header> <h1>UltraMotion3D</h1> <nav> <a href="index.html">HOME</a> <a href="bone.html">BONE</a> <a href="texture.html">TEXTURE</a> <a href="about.html">ABOUT</a> </nav> </header> <div id="space"></div> <h2>メニュー</h2> <ul> <li><a href="index.html">HOME</a></li> <li><a href="bone.html">BONE</a></li> <li><a href="texture.html">TEXTURE</a></li> <li><a href="about.html">ABOUT</a></li> </ul> <footer> <h3>このサイトは2023年から<a href="http://vexil.jp" target="_blank">Vexil.jp</a>がテストしています。</h3> </footer> </div> </body> </html>
【サンプルコードの解説】
UltraMotion3Dライブラリの読み込みは前ページの通りです。3Dキャラクターは「models」→「Character.js」を読み込みます。
「_model」変数にキャラクターモデル(「models」→「Character.js」ファイルで宣言されたCharacterクラス)のインスタンスを代入し、(X,Y,Z)位置座標を(0,-150,0)にセットします。
スマホの場合('ontouchend' in document)、イベントリスナーで「touchstart」に「onMouseDown」関数を、「touchmove」に「onMouseMove」関数を、「touchend」に「onMouseUp」関数を登録します。
パソコンの場合、onmousedownにonMouseDown関数を、onmousemoveにonMouseMove関数を、onmouseupにonMouseUp関数を登録し、右クリックメニューを非表示にします。
draw関数のdrawメソッドで_modelを描画します。
マウスが押されたりタッチが始まったらonMouseDown関数が呼ばれ、マウス座標を「_pos」変数に取得し、左クリックか右クリックのフラグをtrueにセットします。よく考えるとスマホのタッチを考慮していませんでした。Androidをお持ちの方はタッチフラグを実装してみてください。
マウスやタッチが動いたらonMouseMove関数が呼ばれ、左ドラッグ中はマウスが動いただけキャラのXY座標を平行移動し、右ドラッグ中はマウスが動いただけキャラをXY回転させます。
マウスやタッチが離されたら左右クリックのフラグをfalseにします。
今何をすべきか考えたとき、どうせやるなら与えられた仕事だけでも全力でやりたいところですが、記事を書いているうちに少し作業をこなすだけになってきていることがあります。基本に立ち返ると、みんなを「アッ」と驚かせるようなこと、「その手があったか!」と思わず唸らせるようなことをしたいというのがあります。それが記事でも「Back to the basic!」。ゲームエンジン全盛期の今、フルスタックで3Dリアルタイムレンダリングを解説する記事は、それに当たるのではないでしょうか。