tag:crieit.net,2005:https://crieit.net/tags/A-Frame/feed 「A-Frame」の記事 - Crieit Crieitでタグ「A-Frame」に投稿された最近の記事 2020-09-01T23:08:37+09:00 https://crieit.net/tags/A-Frame/feed tag:crieit.net,2005:PublicArticle/16045 2020-09-01T23:08:37+09:00 2020-09-01T23:08:37+09:00 https://crieit.net/posts/A-Frame-VR-5f4e55e505ae0 A-FrameでVR選手ロッカーを作ってみた話 <p><a href="https://crieit.now.sh/upload_images/c757f121bd19245f1a30d36c3424b0625f4e4eb3ed4c2.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/c757f121bd19245f1a30d36c3424b0625f4e4eb3ed4c2.jpg?mw=700" alt="" /></a></p> <h2 id="①NextJSでaframe-reactを動かす"><a href="#%E2%91%A0NextJS%E3%81%A7aframe-react%E3%82%92%E5%8B%95%E3%81%8B%E3%81%99">①NextJSでaframe-reactを動かす</a></h2> <h3 id="aframe-react"><a href="#aframe-react">aframe-react</a></h3> <p>ReactJSでAFrameを動かすときはこれ。<br /> <a target="_blank" rel="nofollow noopener" href="https://github.com/supermedium/aframe-react">aframe-react</a></p> <p>NextJSは一部SSR(サーバサイドレンダリング)が走るので、クライアントで動作する状態になってからロードする必要がある。<br /> 参考: <a target="_blank" rel="nofollow noopener" href="https://github.com/michaltakac/aframe-next-static/blob/master/pages/index.js">aframe-next-static</a></p> <p>windowというグローバル変数が使えるようになればクライアント側で動作する状態なので、レンダリング完了フラグで管理する。</p> <pre><code class="javascript">if (typeof window !== "undefined") { require("aframe"); setRendered(true); } </code></pre> <h2 id="②aframe-reactで書いてみる"><a href="#%E2%91%A1aframe-react%E3%81%A7%E6%9B%B8%E3%81%84%E3%81%A6%E3%81%BF%E3%82%8B">②aframe-reactで書いてみる</a></h2> <p>aframeは配置するものが多いと意外とソースが長くなるので、<br /> 1個のLockerを構成する単位でコンポーネント化しました。<br /> 選手の情報をAPIから取得して、奇数と偶数の場合で振り分けています。</p> <pre><code class="html">if (!rendered || !teamMembers) { return <></>; } return ( <Scene //device-orientation-permission-ui="enabled: true" > {teamMembers.map((member,idx)=>( <> {idx%2 === 0 ?<RightLocker member={member} x={3 - idx*0.35} y={0} z={1.7+idx*0.35} rot_x={0} rot_y={0} rot_z={0}/> :<LeftLocker member={member} x={-idx*0.35} y={0} z={idx*0.35} rot_x={0} rot_y={0} rot_z={0}/> } </> ))} <Entity primitive="a-sky" material="color: #555" /> <Entity camera look-controls wasd-controls position="3 1 2"/> </Scene> ); </code></pre> <p><code>a-sky</code>は背景、<code>camera</code>はカメラの初期位置を定義しています。</p> <p>これがRightLockerのソースです。<br /> プログラム的に難しいことはないのですが、<br /> 座標や光源の調整などが結構面倒でした。<br /> (..planeって光透過すんの?)</p> <pre><code class="javascript">import { Entity } from "aframe-react"; import { Player } from "../../model/typedef"; type diff={ x:number, y:number, z:number, rot_x:number, rot_y:number, rot_z:number, member:Player } const RightLocker:React.FC<diff> = ({x,y,z,rot_x,rot_y,rot_z,member}) => { return ( <> <Entity geometry=<span>{</span><span>{</span> primitive: "plane", width:1, height:2<span>}</span><span>}</span> material=<span>{</span><span>{</span> src: "/images/wood.jpg",alphaTest:0.1 <span>}</span><span>}</span> position=<span>{</span><span>{</span> x: x+0.7, y: y, z: z-4.3<span>}</span><span>}</span> rotation=<span>{</span><span>{</span> x: rot_x, y: -135+rot_y, z: rot_z <span>}</span><span>}</span> /> <Entity primitive="a-image" height="2" //geometry=<span>{</span><span>{</span> primitive: "plane", width:1, height:2<span>}</span><span>}</span> material=<span>{</span><span>{</span> src: "/images/wood.jpg", transparent:false<span>}</span><span>}</span> position=<span>{</span><span>{</span> x: x+0.7, y: y, z: z-5 <span>}</span><span>}</span> rotation=<span>{</span><span>{</span> x: rot_x, y: rot_y-45, z: rot_z <span>}</span><span>}</span> /> <Entity primitive="a-image" height="2" //geometry=<span>{</span><span>{</span> primitive: "plane", width:1, height:2<span>}</span><span>}</span> material=<span>{</span><span>{</span> src: "/images/wood.jpg"<span>}</span><span>}</span> position=<span>{</span><span>{</span> x: x, y: y, z: z-4.3 <span>}</span><span>}</span> rotation=<span>{</span><span>{</span> x: rot_x, y: rot_y-45, z: rot_z <span>}</span><span>}</span> /> <Entity geometry=<span>{</span><span>{</span> primitive: "box", width:0.5, height:0.3<span>}</span><span>}</span> material=<span>{</span><span>{</span> color:'gray' <span>}</span><span>}</span> position=<span>{</span><span>{</span> x: x+0.5, y: y-1, z: z-4.5 <span>}</span><span>}</span> rotation=<span>{</span><span>{</span> x: rot_x, y: rot_y-45, z: rot_z <span>}</span><span>}</span> /> <Entity primitive="a-image" height="1.5" width="0.8" //geometry=<span>{</span><span>{</span> primitive: "plane", width:1, height:2<span>}</span><span>}</span> material=<span>{</span><span>{</span> src: member.ogp_image<span>}</span><span>}</span> position=<span>{</span><span>{</span> x: x+0.7, y: y, z: z-4.3<span>}</span><span>}</span> rotation=<span>{</span><span>{</span> x: rot_x, y: -135+rot_y, z: rot_z <span>}</span><span>}</span> /> <Entity primitive="a-light" light=<span>{</span><span>{</span>type:"spot"<span>}</span><span>}</span> material=<span>{</span><span>{</span>color:'yellow'<span>}</span><span>}</span> position=<span>{</span><span>{</span> x: x+0.3, y: y+1.3, z: z-4.5 <span>}</span><span>}</span> rotation=<span>{</span><span>{</span> x: rot_x-90, y: rot_y-10, z: rot_z-10 <span>}</span><span>}</span> /> </> ); }; export default RightLocker; </code></pre> <h2 id="DEMO"><a href="#DEMO">DEMO</a></h2> <p>まだ本サイトにはデプロイしていませんが、<code>team/[チームID]/vr_locker</code>で各チームのVRロッカーを見ることができます。<br /> - <a target="_blank" rel="nofollow noopener" href="https://deploy-preview-19--cap-baseball-info.netlify.app/team/67/vr_locker">キャップ野球情報局・VRロッカー</a></p> ckoshien tag:crieit.net,2005:PublicArticle/15332 2019-08-18T15:51:04+09:00 2019-08-18T15:51:43+09:00 https://crieit.net/posts/A-Frame-VR-5d58f5583988c A-FrameでVRモードに切り替える方法を追加する <p>A-Frameはページ表示時にはVRモードではなくブラウザで表示するための通常の3Dモードで描画されており、右下のメガネボタンをクリックするとVRモードに切り替わる。</p> <p>ただしこれを使わなくても適宜自由にVRモードに切り替えたりVRモードから脱出したりすることができる。</p> <p>具体的にはsceneコンポーネントにそれらのメソッドが用意されている。</p> <h2 id="VRモードに切り替えるメソッド"><a href="#VR%E3%83%A2%E3%83%BC%E3%83%89%E3%81%AB%E5%88%87%E3%82%8A%E6%9B%BF%E3%81%88%E3%82%8B%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89">VRモードに切り替えるメソッド</a></h2> <p>例えばボタンをクリックしたときなどにVRモードに切り替えたい場合は下記のような形。</p> <pre><code class="javascript">document.querySelector('a-scene').enterVR() </code></pre> <p>exitVRというメソッドもある。</p> <h2 id="イベント"><a href="#%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88">イベント</a></h2> <p>VRモードに切り替わったり出たりした場合にイベントが発生するのでそのタイミングで処理を入れることも出来る。具体的には<code>enter-vr</code>や<code>exit-vr</code>イベント。</p> <p>他にもフォグ(霧のようなエフェクト)を入れたりもできるためちらっとドキュメントを見てみると面白い。</p> <p><a target="_blank" rel="nofollow noopener" href="https://aframe.io/docs/0.9.0/core/scene.html">Scene – A-Frame</a></p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/15285 2019-07-28T23:30:51+09:00 2019-07-28T23:30:51+09:00 https://crieit.net/posts/aframe-super-keyboard-VR aframe-super-keyboardをVR内で動作させる <p>A-FrameのVR内で文字を入力させたいと思い探してみると<a target="_blank" rel="nofollow noopener" href="https://github.com/supermedium/aframe-super-keyboard">aframe-super-keyboard</a>というものが見つかった。しかし試してみるとどうもVR内ではうまく動かない。よく見るとデモもブラウザ上でしか動いていない。</p> <p>一応なんとか動かせたのでそのメモ。</p> <p><a href="https://crieit.now.sh/upload_images/9b96c3d4b9b876ae035fecd6b003731b5d3dae56e94fb.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/9b96c3d4b9b876ae035fecd6b003731b5d3dae56e94fb.png?mw=700" alt="" /></a></p> <h2 id="handを指定する"><a href="#hand%E3%82%92%E6%8C%87%E5%AE%9A%E3%81%99%E3%82%8B">handを指定する</a></h2> <p>super-keyboardコンポーネントの属性にhandというプロパティがある。これはデフォルトでは</p> <pre><code>[cursor], [vive-controls], [tracked-controls], [oculus-touch-controls], [windows-motion-controls], [hand-controls], [daydream-controls] [cursor] > [raycaster] </code></pre> <p>となっている。</p> <p>ということでもしかしたらデモも動く場合があるのかもしれない。ただ、コントローラのraycasterの階層の仕様が違ったり自分でraycasterを作っている場合は動かないので、ここを指定してあげる必要がある。</p> <p>僕の場合もraycasterを自分で定義していたのでその要素を指定した。</p> <h3 id="handに指定したものが複数あるとおかしくなる"><a href="#hand%E3%81%AB%E6%8C%87%E5%AE%9A%E3%81%97%E3%81%9F%E3%82%82%E3%81%AE%E3%81%8C%E8%A4%87%E6%95%B0%E3%81%82%E3%82%8B%E3%81%A8%E3%81%8A%E3%81%8B%E3%81%97%E3%81%8F%E3%81%AA%E3%82%8B">handに指定したものが複数あるとおかしくなる</a></h3> <p>super-keyboardの動作仕様として、キーボード画像のhoverしたところの位置を判定して色替えを行っている。それをそのままキーボードの入力としているため、複数の要素でhoverできたりするとどうもおかしくなるっぽい。というか、検索した最初の要素でしか動かないっぽいので、右手では動かないけど実は左手では動く、みたいなパターンもあるっぽい。</p> <p>うまく動かない場合は一度handの指定では一つの要素だけ存在するようにして試すとうまくいく可能性がある。</p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/15258 2019-07-18T22:03:57+09:00 2019-07-18T22:03:57+09:00 https://crieit.net/posts/A-Frame-5d306e3d1b914 A-Frameでコントローラの角度を正確に取得する <p>A-Frameでコントローラの向きに合わせて処理をしたい時があると思う。コントローラの動きに追従するメニューとかであれば子要素として表示すれば良いだけなので問題ないが、例えば銃を撃って弾を発射する場合などは完全に別オブジェクトとして生成する必要があるためコントローラの角度を取得してそれを利用して弾の角度を初期化したりする必要がある。</p> <p>A-Frameだとrotationという属性があるためそれでオブジェクトの角度を利用することもできるが、それだとうまくいかない。</p> <p><a href="https://crieit.net/posts/Oculus-Quest">Oculus Questのコントローラの角度が謎</a> でも書いている通り、rotationはうまく値が取れない。</p> <p>じゃあどうするかというと、A-Frameは内部的にはthree.jsが使われているため、そのあたりの機能を利用していく。</p> <p>A-Frameコンポーネント内で参照できる要素からは、下記のようにthree.jsのObject3Dが参照できるようになっている。</p> <pre><code class="javascript">this.el.object3D </code></pre> <p>これを利用すればA-Frame単体では難しいような3Dの操作もできるようになる。詳しい傾きについてはQuaternionを利用することができる。たとえば下記のような感じ。</p> <pre><code class="javascript"> const q = new Quaternion() const gunQuaternion = new Quaternion() this.el.object3D.getWorldQuaternion(gunQuaternion) q.multiply(gunQuaternion) bullet.object3D.applyQuaternion(q) </code></pre> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/15197 2019-07-03T22:06:49+09:00 2019-07-03T22:09:21+09:00 https://crieit.net/posts/Oculus-Quest Oculus Questのコントローラの角度が謎 <p>A-FrameでOculus Questのコントローラを使う場合、oculus-quest-controlsコンポーネントを使うことができる。この動きに連動して銃を撃つようなアクションを作っていたのだが、どうもどうやっても角度が合わない。そのためちょっと調べてみたところ謎の角度になっていることがわかった。</p> <h2 id="ベースの角度"><a href="#%E3%83%99%E3%83%BC%E3%82%B9%E3%81%AE%E8%A7%92%E5%BA%A6">ベースの角度</a></h2> <p>手を真下に下ろしているような状態がベースの角度となり、x, y, zともに0になる。</p> <h2 id="上下の動き"><a href="#%E4%B8%8A%E4%B8%8B%E3%81%AE%E5%8B%95%E3%81%8D">上下の動き</a></h2> <p>その状態からそのまま手を上に上げるとxの角度。段々と180に近づいていき、そのまま後ろに行くと-180度から-0に近づいていく。</p> <h2 id="左右の動き"><a href="#%E5%B7%A6%E5%8F%B3%E3%81%AE%E5%8B%95%E3%81%8D">左右の動き</a></h2> <p>次に真下の状態から左右方向に手を上げるとzの角度。手を右方向に上げていくと180に向かっていき、左方向に傾けると-180度に向かっていく。</p> <h2 id="yの傾き"><a href="#y%E3%81%AE%E5%82%BE%E3%81%8D">yの傾き</a></h2> <p>yの傾きは、手を真下に下ろしたまま手の位置を固定したまま自分が手を中心に回るような動きとなる。これがちょっと不思議。</p> <p>左回りに回転させると、段々と90度に近づいていく。ところが、90度を超えてからは今度はだんだんとそのまま0に近づいていく。右回りも同様で、段々と-90度に近づき、そこを経由して0に戻っていく。</p> <p>ここの挙動が他と変わっているおかげで連動して生成する物体の傾きがどうしてもうまくあわなかったっぽい。</p> <p>もしかしたら知っている人からすれば一般的な話なのかもしれないが、とりあえずメモ。</p> <p>ちなみにダンプは適当に<code>a-text</code>を配置してそれに値を<code>setAttribute('value', value)</code>して直接VR上で見た。</p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/15174 2019-06-29T22:02:34+09:00 2019-06-29T22:02:34+09:00 https://crieit.net/posts/Oculus-Quest-aframe-teleport-controls Oculus Questのコントローラでaframe-teleport-controlsを使う <p>A-Frameには <a target="_blank" rel="nofollow noopener" href="https://github.com/fernandojsg/aframe-teleport-controls">aframe-teleport-controls</a> という、VR空間内を近くにテレポートしつつ移動するためのコンポーネントがある。</p> <p>VR空間内は勝手に自分のカメラの位置が移動してしまうと乗り物酔いと同じ原理で酔ってしまう。そのためそれを避けるためテレポートが役立つ。</p> <p><a href="https://crieit.now.sh/upload_images/db533b3a0aed988d0281041f4b51b36b5d176052239d0.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/db533b3a0aed988d0281041f4b51b36b5d176052239d0.png?mw=700" alt="" /></a></p> <p>ただ、Oculus Questで試すとこのリポジトリにかかれているサンプルのコードだとデフォルトでは動かない。というのも、上記の画像のとおりにコントローラが違うためデフォルトで設定されているボタンが異なる。</p> <p>下記のようにボタンを例えばトリガーボタンに変更したりすれば動作するようになる。これで簡単にワープすることができる。</p> <pre><code class="html"> teleport-controls="cameraRig: #cameraRig; teleportOrigin: #head; button: trigger;" </code></pre> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/15163 2019-06-24T19:48:11+09:00 2019-06-25T09:12:57+09:00 https://crieit.net/posts/TypeScript-A-Frame TypeScriptでA-Frameのコンポーネントを書く <p>TypeScriptを使っているプロジェクトでA-Frameのコンポーネントを書く時の方法。まだざっと試したところなのでおかしなところがあれば適宜調整が必要かも。</p> <p>とりあえず型を入れる。</p> <pre><code>yarn add @types/aframe </code></pre> <p>これで適当なtsファイル内で<code>AFRAME.registerComponent</code>とかを実行しても未定義エラー等が発生しなくなるため定義できるようになる。</p> <p>また、下記のようにimportして実行する方法もある。</p> <pre><code class="typescript">import { registerComponent } from 'aframe' registerComponent('my-component', { </code></pre> <p>コンポーネント内部で使うパラメータはオブジェクト内に定義すればいい。JavaScriptの場合だと、initメソッド内で初期化したりするが、それだと型エラーになるので要定義。</p> <pre><code class="typescript">registerComponent('my-component', { hoge: true, fuga: 100, </code></pre> <p>というか、型定義のテストファイルに一通りのものが書かれている。</p> <p><a target="_blank" rel="nofollow noopener" href="https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/aframe/test/aframe-tests.ts">https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/aframe/test/aframe-tests.ts</a></p> <pre><code class="typescript">const Component = registerComponent('test-component', { schema: { myProperty: { default: [], parse() { return [true]; } }, string: { type: 'string' }, num: 0 }, init() { this.data.num = 0; this.el.setAttribute('custom-attribute', 'custom-value'); }, update() {}, tick() {}, remove() {}, pause() {}, play() {}, multiply(f: number) { // Reference to system because both were registered with the same name. return f * this.data.num * this.system!.data.counter; } }); </code></pre> <p>他にも色々書かれているのでこちらを参考にしていけばなんとかなるのではないかと思う。</p> <h2 id="プロパティの型を明示的に指定する場合は?"><a href="#%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%E3%81%AE%E5%9E%8B%E3%82%92%E6%98%8E%E7%A4%BA%E7%9A%84%E3%81%AB%E6%8C%87%E5%AE%9A%E3%81%99%E3%82%8B%E5%A0%B4%E5%90%88%E3%81%AF%EF%BC%9F">プロパティの型を明示的に指定する場合は?</a></h2> <p>事前にinterfaceを定義する感じ? ただこれだとメソッドも再定義しないといけないので非常に面倒。何か良い方法は無いのだろうか。</p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/15121 2019-06-17T23:27:42+09:00 2019-06-17T23:27:42+09:00 https://crieit.net/posts/A-Frame-VR A-FrameでVRラジコンを作る <p>前回3D空間でキーボード操作のラジコンを作ったが、それをOculusQuestのVR空間内でスティックで操作して遊べるようにしてみた。前回のは下記。</p> <p><a href="https://crieit.net/posts/A-Frame-5d06dabaa8db2">A-Frameでキーボード操作のラジコンを作ってみる</a></p> <p>これにスティックによる処理を追加していく。</p> <p><a href="https://crieit.now.sh/upload_images/3b22aacb23f3a5542c2d4be1d05aaf725d07a26a1847d.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/3b22aacb23f3a5542c2d4be1d05aaf725d07a26a1847d.png?mw=700" alt="" /></a></p> <h2 id="スティック操作による値を取得"><a href="#%E3%82%B9%E3%83%86%E3%82%A3%E3%83%83%E3%82%AF%E6%93%8D%E4%BD%9C%E3%81%AB%E3%82%88%E3%82%8B%E5%80%A4%E3%82%92%E5%8F%96%E5%BE%97">スティック操作による値を取得</a></h2> <p>左手右手の各コントロールコンポーネントはtracked-controlsというをベースとしており、これのaxismoveイベントを使うことでスティックの傾きを取得することができる。</p> <p>そのためイベント受信用のコンポーネントを作り、それをhand-controlsに割り当てれば取得することができる。例えば下記のような感じで左手用、右手用のcar-controller-left, car-controller-rightコンポーネントを作った場合は下記のようになる。</p> <pre><code class="html"> <a-entity hand-controls="left" mixin="controller" car-controller-left></a-entity> <a-entity hand-controls="right" mixin="controller" car-controller-right></a-entity> </code></pre> <p>コンポーネントは下記のような感じ。左手の上下でスピード、右手の左右でハンドルをさばく。</p> <pre><code class="javascript"> AFRAME.registerComponent('car-controller-left', { init: function () { this.el.addEventListener('axismove', function (e) { const car = document.querySelector('[car]').components.car car.onAxisMoveSpeed(e) }) } }) </code></pre> <p>あとはもう面倒になったので傾きも使わず前回作った処理をそのまま呼んでいるだけ。</p> <pre><code class="javascript"> onAxisMoveSpeed: function(e) { if (e.detail.axis[1] == 0) { this.speeding = null } else if (e.detail.axis[1] > 0) { this.speeding = 'down' } else if (e.detail.axis[1] < 0) { this.speeding = 'up' } }, onAxisMoveAngle: function(e) { if (e.detail.axis[0] == 0) { this.rotating = null } else if (e.detail.axis[0] > 0) { this.rotating = 'right' } else if (e.detail.axis[0] < 0) { this.rotating = 'left' } }, </code></pre> <h2 id="実際のもの"><a href="#%E5%AE%9F%E9%9A%9B%E3%81%AE%E3%82%82%E3%81%AE">実際のもの</a></h2> <p>実際にVR上でプレイしたものを録画したやつ。</p> <blockquote class="twitter-tweet"><p lang="ja" dir="ltr">VRでのスティック操作バージョン(モデル変える前に撮影したやつ) <a target="_blank" rel="nofollow noopener" href="https://t.co/9v34bxapMu">pic.twitter.com/9v34bxapMu</a></p>— だら🍔技術系投稿サービスや100の質問メーカー運営中 (@dala00) <a target="_blank" rel="nofollow noopener" href="https://twitter.com/dala00/status/1140624336404938752?ref_src=twsrc%5Etfw">June 17, 2019</a></blockquote> <p>GitHubページで実際に試せる。実機がない人はキーボードのWASDでもOK。</p> <p><a target="_blank" rel="nofollow noopener" href="https://dala00.github.io/a-frame-car-sample/">https://dala00.github.io/a-frame-car-sample/</a></p> <p>ソースはGitHubにもアップしてある。</p> <p><a target="_blank" rel="nofollow noopener" href="https://github.com/dala00/a-frame-car-sample">dala00/a-frame-car-sample: Car control sample with A-Frame</a></p> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p>めちゃくちゃ簡単なのでぜひみんなやってみましょう。</p> <p>次はFirebaseのRealtime Databaseいれてみんなで同時に部屋の中にいる、みたいなの試したい。</p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/15118 2019-06-17T09:49:25+09:00 2019-06-17T09:49:25+09:00 https://crieit.net/posts/A-Frame-5d06e395c8076 A-Frameのコンポーネント内で他のコンポーネントを参照する <p>A-Frameはコンポーネント単位で簡単に処理を書くことができるが、時には他の要素の座標等の情報を取得したいときなどがある。そういう場合は他のコンポーネントを参照する必要があるのだが、その方法が公式マニュアルに書かれていた。</p> <p><a target="_blank" rel="nofollow noopener" href="https://aframe.io/docs/0.9.0/core/component.html#accessing-a-component’s-members-and-methods">Accessing a Component’s Members and Methods</a></p> <p>具体的には例えば下記のようなfooコンポーネントを割り当てられた要素があるとする。</p> <pre><code class="html"><a-entity foo> </code></pre> <p>それにアクセスするには下記のような形。</p> <pre><code class="javascript">document.querySelector('[foo]').components.foo; </code></pre> <p>普通にquerySelectorで要素を取得する。その要素にcomponentsというプロパティがあるようなので、それ経由で参照できる。あとはそのコンポーネントの値を取得したりメソッドを呼んだりできる。</p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/15116 2019-06-17T09:11:38+09:00 2019-06-17T09:12:37+09:00 https://crieit.net/posts/A-Frame-5d06dabaa8db2 A-Frameでキーボード操作のラジコンを作ってみる <p>A-FrameでVR上で動くラジコンを作ってみようと思ったが、とりあえずブラウザ上でテストできないとデバッグ辛いかなと思い、まずはVRではなく普通にブラウザの3D空間上でキーボード操作ができるようにしてみた。</p> <p>単にVR機器を持ってない人もブラウザ上で体験できたらいいかなというのもあるし、そうでなくてもプログラムを変える度にOculus Questをつけたり外したりするのは結構面倒なので。</p> <p><a href="https://crieit.now.sh/upload_images/74af9bed096dc0e66c54258fc25122545d06d7cdde949.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/74af9bed096dc0e66c54258fc25122545d06d7cdde949.png?mw=700" alt="" /></a></p> <h2 id="キーボード操作の事前準備"><a href="#%E3%82%AD%E3%83%BC%E3%83%9C%E3%83%BC%E3%83%89%E6%93%8D%E4%BD%9C%E3%81%AE%E4%BA%8B%E5%89%8D%E6%BA%96%E5%82%99">キーボード操作の事前準備</a></h2> <p>デフォルトでWASDキーが空間移動に使われているので、下記の方法で無効にする。</p> <p><a href="https://crieit.net/posts/A-Frame">A-Frameでデフォルトのキーボード操作を無効にする</a></p> <h2 id="3Dモデル用のコンポーネントを作成"><a href="#3D%E3%83%A2%E3%83%87%E3%83%AB%E7%94%A8%E3%81%AE%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%82%92%E4%BD%9C%E6%88%90">3Dモデル用のコンポーネントを作成</a></h2> <p>とりあえず3Dモデルの位置や角度を調整したりするために、動かすオブジェクト用のコンポーネントを作成する。</p> <p>何をやっているかというと、キーボードイベントを設定し、キーが押されたらステータスを変更する処理を追加し、tickという常時呼ばれ続けるメソッドの中でそのステータスに応じて車を動かしている。</p> <pre><code class="javascript"> AFRAME.registerComponent('car', { init: function () { window.addEventListener('keydown', this.onKeyDown.bind(this)) window.addEventListener('keyup', this.onKeyUp.bind(this)) this.rotating = null this.speeding = null this.speed = 0.0 }, onKeyDown: function (e) { if (e.keyCode == 65) { this.rotating = 'left' } else if (e.keyCode == 68) { this.rotating = 'right' } else if (e.keyCode == 87) { this.speeding = 'up' } else if (e.keyCode == 83) { this.speeding = 'down' } }, onKeyUp: function (e) { if (e.keyCode == 65 && this.rotating == 'left') { this.rotating = null } else if (e.keyCode == 68 && this.rotating == 'right') { this.rotating = null } else if (e.keyCode == 87 && this.speeding == 'up') { this.speeding = null } else if (e.keyCode == 83 && this.speeding == 'down') { this.speeding = null } }, tick: function () { if (this.speeding != null) { const direction = this.speed > 0 ? 1 : -1 if (this.rotating == 'left') { this.el.object3D.rotateY(direction * Math.PI / 120) } else if (this.rotating == 'right') { this.el.object3D.rotateY(direction * -Math.PI / 120) } } if (this.speeding == 'up') { this.speed = Math.min(this.speed + 0.02, 0.2) } else if (this.speeding == 'down') { this.speed = Math.max(this.speed - 0.02, -0.2) } const position = this.el.getAttribute('position') const rotation = this.el.getAttribute('rotation') const angle = Math.PI * rotation.y / 180 position.x += this.speed * Math.sin(angle) position.z += this.speed * Math.cos(angle) this.el.setAttribute('position', position) if (this.speed > 0) { this.speed = Math.max(this.speed - 0.01, 0) } if (this.speed < 0) { this.speed = Math.min(this.speed + 0.01, 0) } } }) </code></pre> <p>あとはこれを実際の3Dモデルに紐付けるだけ。</p> <pre><code class="html"> <a-obj-model src="#car-obj" mtl="#car-mtl" car></a-obj-model> </code></pre> <p>下記が実際にブラウザ上で試してるところ。</p> <blockquote class="twitter-tweet"><p lang="ja" dir="ltr">a-frameでラジコンのサンプルみたいなの。VRでやりたいんだけどデバッグつらそうなのでとりあえずキーボード操作でできるように。 <a target="_blank" rel="nofollow noopener" href="https://t.co/Zc7w4xz64V">pic.twitter.com/Zc7w4xz64V</a></p>— だら🍔技術系投稿サービスや100の質問メーカー運営中 (@dala00) <a target="_blank" rel="nofollow noopener" href="https://twitter.com/dala00/status/1140237676722810880?ref_src=twsrc%5Etfw">June 16, 2019</a></blockquote> <p>GitHubページで実際に試せる。WASDキーで操作。</p> <p><a target="_blank" rel="nofollow noopener" href="https://dala00.github.io/a-frame-car-sample/">https://dala00.github.io/a-frame-car-sample/</a></p> <p>ソースはGitHubにもアップしてある。</p> <p><a target="_blank" rel="nofollow noopener" href="https://github.com/dala00/a-frame-car-sample">dala00/a-frame-car-sample: Car control sample with A-Frame</a></p> <h2 id="物理エンジンを使う場合"><a href="#%E7%89%A9%E7%90%86%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%B3%E3%82%92%E4%BD%BF%E3%81%86%E5%A0%B4%E5%90%88">物理エンジンを使う場合</a></h2> <p>今回は物理エンジンを使っておらず、直接計算して要素の属性を更新する方法で試している。物理エンジンを使う場合、内部の角度やvelocityを利用して動かす形にする必要があるので今回の形では動かせない。</p> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p>とりあえずブラウザ上でキーボードを使って操作できるようにした。VR用にスティック操作などを入れる場合はデバッグが必要な箇所が多いと非常に大変なので、このようにして基本的な処理はなるべく使いまわすことでなるべく簡単に開発ができるようにした感じ。</p> <p>スティック操作ももうできているのでまた近日中に記事を書く。</p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/15114 2019-06-17T06:45:17+09:00 2019-06-17T06:45:17+09:00 https://crieit.net/posts/A-Frame-5d06b86deaa28 A-Frameでキーボード操作を行う <p>A-Frameでkeydownやkeyup等のキーボードイベントを使ってブラウザ上で3D空間上の何かしらのオブジェクトを操作したりする方法。VRモードではなく、その前のブラウザモードでも何かしらの操作をできるようにしておきたい場合など。</p> <h2 id="操作用のコンポーネントを作成"><a href="#%E6%93%8D%E4%BD%9C%E7%94%A8%E3%81%AE%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%82%92%E4%BD%9C%E6%88%90">操作用のコンポーネントを作成</a></h2> <p>下記のように、キーボードイベントをトラッキングしたコンポーネントを作成する。とくにいい方法があるわけではなさそうなので直接windowのイベントを利用する。</p> <pre><code class="javascript"> AFRAME.registerComponent('key-controllable', { init: function () { window.addEventListener('keydown', this.onKeyDown.bind(this)) window.addEventListener('keyup', this.onKeyUp.bind(this)) </code></pre> <p>実際の処理は通常のWebのプログラミングと同様。</p> <pre><code class="javascript"> onKeyDown: function (e) { if (e.keyCode == 65) { this.rotating = 'left' } } </code></pre> <p>ちなみにWASDキーを使いたい場合は前提として、デフォルトではWASDキーがカメラの移動に使用されているため下記の方法で無効にしておく必要がある。</p> <p><a href="https://crieit.net/posts/A-Frame">A-Frameでデフォルトのキーボード操作を無効にする</a></p> <p>あとはこれを動かしたいオブジェクトに指定する。</p> <pre><code class="html"><a-box key-controllable> </code></pre> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/15113 2019-06-17T06:28:39+09:00 2019-06-17T06:28:39+09:00 https://crieit.net/posts/A-Frame A-Frameでデフォルトのキーボード操作を無効にする <p>A-FrameはVRモードに入る前のブラウザ表示モードだと、キーボードのWASDキーを使って空間を移動することができるようになっている。これはデフォルトで<code>wasd-controls</code>コンポーネントが有効になっているため。</p> <p>便利ではあるのだが、ブラウザ上でもWASDキーで何かしらの操作をしたい場合には邪魔になってしまうため、無効にする必要がある。下記のようにカメラに<code>wasd-controls-enabled</code>属性を指定することで無効にできる。</p> <pre><code class="html"><a-camera wasd-controls-enabled="false"> </code></pre> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/15100 2019-06-12T22:28:14+09:00 2019-06-14T07:38:28+09:00 https://crieit.net/posts/A-Frame-Super-Hands-VR A-FrameのSuper HandsでVR空間のオブジェクトを掴んでみる <p>A-Frameという、マークアップとJavaScriptを使ってOculus Quest等のブラウザだけでVRアプリケーションを作ることのできるフレームワークがあります。</p> <p>サンプルなどを試してみると本当に簡単にVR空間を作ることができて面白いのですが、やはりWebエンジニアとしてはただ物を配置するだけではなく色々とインタラクティブにVR空間で遊べるようにしてみたいと感じます。</p> <p>とくにOculus Questのようなコントローラは物を掴んだりという操作が非常にすべてが直感的で、VRをはじめてみて一番の衝撃でもありました。なんとかそのあたりを簡単にできるようにしたいと思い調べてみたところ、下記のライブラリが見つかりました。</p> <h2 id="Super Hands"><a href="#Super+Hands">Super Hands</a></h2> <p><a target="_blank" rel="nofollow noopener" href="https://github.com/wmurphyrd/aframe-super-hands-component">wmurphyrd/aframe-super-hands-component: 👐All-in-one natural hand controller, pointer, and gaze interaction library for A-Frame</a></p> <p>公式のマニュアルでも紹介されており、恐らく簡単にコントローラを使えるようにしてくれているのだと思います。</p> <p>実際に上記のページのサンプルを試してみました。</p> <p><a href="https://crieit.now.sh/upload_images/7acd26c9fa4d2d46370d8e514f588d615d00fc61c5d5d.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/7acd26c9fa4d2d46370d8e514f588d615d00fc61c5d5d.jpg?mw=700" alt="" /></a></p> <p>こんな感じで手が表示され、青いボックスを掴んだり、両手で掴むと拡大縮小することもできます。GitHubのREADMEを見るとわかりますが、ソースもたったこれだけです。</p> <pre><code class="html"> <a-scene> <a-assets></a-assets> <a-entity> <a-camera></a-camera> <a-entity sphere-collider="objects: a-box" super-hands hand-controls="left"></a-entity> <a-entity sphere-collider="objects: a-box" super-hands hand-controls="right"></a-entity> </a-entity> <a-box hoverable grabbable stretchable draggable dropppable color="blue" position="0 0 -1"></a-box> </a-scene> </code></pre> <h2 id="注意点"><a href="#%E6%B3%A8%E6%84%8F%E7%82%B9">注意点</a></h2> <p>多分ですが、ローカルやCodePenなどでもうまく動かなかった気がします。手のモデルを読み込んでいるのでとりあえずサンプルのHTMLをどこかWeb上にアップしてアクセスして試さないとダメっぽいです。</p> <p>ですのでもしかしたら公式で紹介しているコントローラなどでもうまく手を使ったりすることができるのかもしれません。</p> <p>ちなみにサーバーアップされているサンプルが下記です。(対応端末でないと手は出てきません)</p> <p><a target="_blank" rel="nofollow noopener" href="https://wmurphyrd.github.io/aframe-super-hands-component/examples/physics/">https://wmurphyrd.github.io/aframe-super-hands-component/examples/physics/</a></p> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p>とにかくA-Frameでできることのサンプルやプレビュー画像がWeb上に不足しているので、何かしら試したら投稿していってみたいと思います。</p> だら@Crieit開発者