😸

AR.jsでWebARしてみる(10) Line between two markers

2020/10/14に公開

はじめに

WebARで分かったことメモしていく

参考

Line between two markers (line.html)を勉強する

デモ

  • 以下の環境で動作を確認
    • iOS 13.7 Safari
    • Android 9 Chrome
    • Windows10 Firefox 81.0.1

ソース

参考で紹介したサイトのLine between two markers (line.html)のソース

<!doctype HTML>
<html>
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
<script src="js/aframe.min.js"></script>
<script src="js/aframe-ar.js"></script>
<body style="margin: 0px; overflow: hidden;">

<script>
// store visibility data in object;
//  can only draw line when both are visible.
let markerVisible = { m0: false, m1: false };

AFRAME.registerComponent('registerevents', {
    init: function () 
    {
        let marker = this.el;
        marker.addEventListener('markerFound', function() {
            markerVisible[ marker.id ] = true;
        });
        marker.addEventListener('markerLost', function() {
            markerVisible[ marker.id ] = false;
        });
    }
});

AFRAME.registerComponent('run', {
    init: function()
    {
        this.m0 = document.querySelector("#m0");
        this.m1 = document.querySelector("#m1");
        this.p0 = new THREE.Vector3();
        this.p1 = new THREE.Vector3(); 
        
        this.geometry = new THREE.Geometry();
        this.geometry.vertices.push( new THREE.Vector3(-1,-1,-1) );
        this.geometry.vertices.push( new THREE.Vector3( 1, 1, 1) );
        this.material = new THREE.LineBasicMaterial( {color: 0xFF0000} );
        this.line = new THREE.Line( this.geometry, this.material );
        let scene = document.querySelector('a-scene').object3D;
        scene.add( this.line );
    },
    tick: function (time, deltaTime) 
    {
        if ( markerVisible["m0"] && markerVisible["m1"] )
        {
            this.m0.object3D.getWorldPosition(this.p0);
            this.m1.object3D.getWorldPosition(this.p1);
            this.geometry.vertices[0] = this.p0;
            this.geometry.vertices[1] = this.p1;
            this.geometry.verticesNeedUpdate = true;
            this.line.visible = true;
        }
        else
        {
            this.line.visible = false;
        }
    }
});
</script>

<a-scene embedded vr-mode-ui="enabled: false;" arjs="debugUIEnabled: false; detectionMode: mono_and_matrix; matrixCodeType: 3x3;">
    <a-assets>
	<img id="grid" src="images/border.png" />
    </a-assets>

    <a-marker type="barcode" value="0" id="m0" registerevents>
        <a-plane position="0 0 0" 
                 rotation="-90 0 0"
                 material="color: white; transparent: true; opacity: 0.10;">
        </a-plane>
    </a-marker>

    <a-marker type="barcode" value="1" id="m1" registerevents>
        <a-plane position="0 0 0" 
                 rotation="-90 0 0"
                 material="color: white; transparent: true; opacity: 0.10;">
        </a-plane>
    </a-marker>
    <a-marker type="pattern" url="data/kanji.patt" id="baseMarker" ></a-marker>
    <a-entity camera></a-entity>
    <a-entity run></a-entity>
</a-scene>
</body>
</html>

確認したこと

処理概要

マーカーを認識したときにtrue、見失った場合にfalseを設定

marker.addEventListener('markerFound',function(){markerVisible[marker.id]=true;});
marker.addEventListener('markerLost,function(){markerVisible[marker.id]=false;});

markerVisible["m0"],["m1"]の両方がtrueのときに線を描画し、falseだと線を見えなくする

if ( markerVisible["m0"] && markerVisible["m1"] ){ /*線を描画*/ }
else{ /*線を見えなくする*/ }

線を描画する処理はここ。object3D.getWorldPositionでマーカーの位置(座標)を取得して、this.geometry.verticesで線の両端の座標を設定して、geometry.verticesNeedUpdatetrueにして情報更新するフラグを立てて、visibletrueにしてオブジェクトを見えるようにしてる。

this.m0.object3D.getWorldPosition(this.p0); // マーカー座標を取得
this.m1.object3D.getWorldPosition(this.p1);
this.geometry.vertices[0] = this.p0; // 線の座標を設定
this.geometry.vertices[1] = this.p1;
this.geometry.verticesNeedUpdate = true; // 更新してフラグをたてる
this.line.visible = true; // 見えるようにする

imgタグは使ってない

imgタグは使ってないので削除可能

<a-assets>
    <img id="grid" src="images/border.png" />
</a-assets>

線を3本にしてみた

追加した2本の線の座標設定に苦戦しました。this.geometry2.vertices[0].x でX座標の値を設定しましたが、もっとスマートな設定方法ありそう。

<!doctype HTML>
<html>
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
<script src="js/aframe.min.js"></script>
<script src="js/aframe-ar.js"></script>
<body style="margin: 0px; overflow: hidden;">

<script>

let markerVisible = { m0: false, m1: false };

AFRAME.registerComponent('registerevents', {
    init: function () 
    {
        let marker = this.el;
        
        marker.addEventListener('markerFound', function() {
            markerVisible[ marker.id ] = true;
        });
        marker.addEventListener('markerLost', function() {
            markerVisible[ marker.id ] = false;
        });
    }
});

AFRAME.registerComponent('run', {
    init: function()
    {
        this.m0 = document.querySelector("#m0");
        this.m1 = document.querySelector("#m1");
        this.p0 = new THREE.Vector3();
        this.p1 = new THREE.Vector3(); 
        
        this.geometry1 = new THREE.Geometry();
        this.geometry1.vertices.push( new THREE.Vector3(-1,-1,-1) );
        this.geometry1.vertices.push( new THREE.Vector3( 1, 1, 1) );
        this.geometry2 = new THREE.Geometry();
        this.geometry2.vertices.push( new THREE.Vector3(-1,-1,-1) );
        this.geometry2.vertices.push( new THREE.Vector3( 1, 1, 1) );
        this.geometry3 = new THREE.Geometry();
        this.geometry3.vertices.push( new THREE.Vector3(-1,-1,-1) );
        this.geometry3.vertices.push( new THREE.Vector3( 1, 1, 1) );
        this.material1 = new THREE.LineBasicMaterial( {color: 0xFF00FF} );
        this.material2 = new THREE.LineBasicMaterial( {color: 0x00FF00} );
        this.material3 = new THREE.LineBasicMaterial( {color: 0x0000FF} );
        this.line1 = new THREE.Line( this.geometry1, this.material1 );
        this.line2 = new THREE.Line( this.geometry2, this.material2 );
        this.line3 = new THREE.Line( this.geometry3, this.material3 );
        let scene = document.querySelector('a-scene').object3D;
        scene.add( this.line1 );
        scene.add( this.line2 );
        scene.add( this.line3 );
    },
    tick: function (time, deltaTime) 
    {
        if ( markerVisible["m0"] && markerVisible["m1"] )
        {
            this.m0.object3D.getWorldPosition(this.p0);
            this.m1.object3D.getWorldPosition(this.p1);
            this.geometry1.vertices[0] = this.p0;
            this.geometry1.vertices[1] = this.p1;
            this.geometry1.verticesNeedUpdate = true;
            this.line1.visible = true;

            this.m0.object3D.getWorldPosition(this.p0);
            this.m1.object3D.getWorldPosition(this.p1);
            
            this.geometry2.vertices[0].x = this.p0.x + 0.1;
            this.geometry2.vertices[0].y = this.p0.y + 0.1;
            this.geometry2.vertices[0].z = this.p0.z + 0.1;
            this.geometry2.vertices[1].x = this.p1.x + 0.1;
            this.geometry2.vertices[1].y = this.p1.y + 0.1;
            this.geometry2.vertices[1].z = this.p1.z + 0.1;

            this.geometry2.verticesNeedUpdate = true;
            this.line2.visible = true;

            this.geometry3.vertices[0].x = this.p0.x - 0.1;
            this.geometry3.vertices[0].y = this.p0.y - 0.1;
            this.geometry3.vertices[0].z = this.p0.z - 0.1;
            this.geometry3.vertices[1].x = this.p1.x - 0.1;
            this.geometry3.vertices[1].y = this.p1.y - 0.1;
            this.geometry3.vertices[1].z = this.p1.z - 0.1;

            this.geometry3.verticesNeedUpdate = true;
            this.line3.visible = true;
        }
        else
        {
            this.line1.visible = false;
            this.line2.visible = false;
            this.line3.visible = false;
        }
    }
});

</script>

<a-scene embedded vr-mode-ui="enabled: false;" arjs="debugUIEnabled: false; detectionMode: mono_and_matrix; matrixCodeType: 3x3;">
    <a-marker type="barcode" value="0" id="m0" registerevents>
        <a-plane position="0 0 0" 
                 rotation="-90 0 0"
                 material="color: white; transparent: true; opacity: 0.10;">
        </a-plane>
    </a-marker>

    <a-marker type="barcode" value="1" id="m1" registerevents>
        <a-plane position="0 0 0" 
                 rotation="-90 0 0"
                 material="color: white; transparent: true; opacity: 0.10;">
        </a-plane>
    </a-marker>
    
    <a-marker type="pattern" url="data/kanji.patt" id="baseMarker" ></a-marker>
    <a-entity camera></a-entity>
    <a-entity run></a-entity>
</a-scene>
</body>
</html>

Discussion