jeromeetienne / AR.js

Efficient Augmented Reality for the Web - 60fps on mobile!
MIT License
15.79k stars 2.22k forks source link

GeoAR: camera.components['gps-camera'] is undefined #626

Closed smuddy closed 4 years ago

smuddy commented 4 years ago

Usage: ar.js - geo Ar with Angular & Cordova

First I created a min site (without Angular) based on the example code (examples/basic) and ported it to cordova -> evertything works fine.

Then I copied the code into a fresh Angular App and all markers are glued to the camera.

After some debugging I noticed, that in the component registration of gps-entity-place the component gps-camera is not registered on the camera.

      var camera = document.querySelector('a-camera, [camera]');
      if (camera.components['gps-camera'] === undefined) {
        return;  // Undefined, so it returns here...
      }

But it should be there. The complete scene is

<a-scene
  cursor='rayOrigin: mouse; fuse: true; fuseTimeout: 0;'
  raycaster="objects: [gps-entity-place];"
  vr-mode-ui="enabled: false"
  embedded
  arjs='sourceType: webcam; sourceWidth:1280; sourceHeight:960; displayWidth: 1280; displayHeight: 960; debugUIEnabled: false;'>

  <a-camera gps-camera="minDistance: 20;" rotation-reader>
  </a-camera>

  <a-image
    gps-entity-place="latitude: 51.97250529; longitude: 10.96151222;"
    name="test"
    scale="20, 20"
    alpha-test="0.5"
    src="./assets/map-marker.png"
  ></a-image>
</a-scene>

aframe.js and aframe-ar.js are loaded in the <head> schemas: [CUSTOM_ELEMENTS_SCHEMA] is set in the Angular module.

Query of the camera components: document.querySelector('a-camera, [camera]').components

What could be the reason for this behaviour? Where else can I debug to find the reason?

nicolocarpignoli commented 4 years ago

Hi can you please try to query select also the gps-entity-place entity where you query select for the gps-camera? So I can see if it's a problem with gps-camera or simply every location based component has not been appended to the DOM.

nicolocarpignoli commented 4 years ago

also, can you show me full HTML code, so I can see also imports?

smuddy commented 4 years ago

Hi,

"query select also the gps-entity-place where you query select for the gps-camera" - you mean at the breakpoint in aframe-ar.js? At the time in the init function of AFRAME.registerComponent('gps-entity-place',...),: this.el is the <a-image> and when I select it from the DOM: document.querySelector('a-image') does return the same value. document.querySelector('a-image').components returns:

And the fully loaded HTML Code: (I extracted gps-camera and gps-entity-place for better debugging from aframe-ar.js, but it didn't work either before the extraction)

<html class="" lang="en">
<head>
  <meta charset="utf-8">
  <title>Ar</title>
  <base href="./">
  <meta content="width=device-width, initial-scale=1, minimum-scale=1, mxaimum-scale=1, user-scalable=no"
        name="viewport">

  <link href="favicon.ico" rel="icon" type="image/x-icon">
  <!--  <script src='https://aframe.io/releases/0.9.2/aframe.min.js'></script>
    <script src='https://raw.githack.com/jeromeetienne/AR.js/master/aframe/build/aframe-ar.min.js'></script>-->
  <meta aframe-injected="" content="yes" name="mobile-web-app-capable">
  <meta aframe-injected="" content="black" name="theme-color">
  <script src="./scripts/aframe.js"></script>
  <style data-href="src/style/aframe.css" type="text/css">html.a-fullscreen {
    bottom: 0;
    left: 0;
    position: fixed;
    right: 0;
    top: 0
  }

  html.a-fullscreen body {
    height: 100%;
    margin: 0;
    overflow: hidden;
    padding: 0;
    width: 100%
  }

  html.a-fullscreen .a-canvas {
    width: 100% !important;
    height: 100% !important;
    top: 0 !important;
    left: 0 !important;
    right: 0 !important;
    bottom: 0 !important;
    position: fixed !important
  }

  html:not(.a-fullscreen) .a-enter-vr {
    right: 5px;
    bottom: 5px
  }

  :-webkit-full-screen {
    background-color: transparent
  }

  .a-hidden {
    display: none !important
  }

  .a-canvas {
    height: 100%;
    left: 0;
    position: absolute;
    top: 0;
    width: 100%
  }

  .a-canvas.a-grab-cursor:hover {
    cursor: grab;
    cursor: -moz-grab;
    cursor: -webkit-grab
  }

  canvas.a-canvas.a-mouse-cursor-hover:hover {
    cursor: pointer
  }

  .a-inspector-loader {
    background-color: #ed3160;
    position: fixed;
    left: 3px;
    top: 3px;
    padding: 6px 10px;
    color: #fff;
    text-decoration: none;
    font-size: 12px;
    font-family: Roboto, sans-serif;
    text-align: center;
    z-index: 99999;
    width: 204px
  }

  @keyframes dots-1 {
    from {
      opacity: 0
    }
    25% {
      opacity: 1
    }
  }

  @keyframes dots-2 {
    from {
      opacity: 0
    }
    50% {
      opacity: 1
    }
  }

  @keyframes dots-3 {
    from {
      opacity: 0
    }
    75% {
      opacity: 1
    }
  }

  @-webkit-keyframes dots-1 {
    from {
      opacity: 0
    }
    25% {
      opacity: 1
    }
  }

  @-webkit-keyframes dots-2 {
    from {
      opacity: 0
    }
    50% {
      opacity: 1
    }
  }

  @-webkit-keyframes dots-3 {
    from {
      opacity: 0
    }
    75% {
      opacity: 1
    }
  }

  .a-inspector-loader .dots span {
    animation: dots-1 2s infinite steps(1);
    -webkit-animation: dots-1 2s infinite steps(1)
  }

  .a-inspector-loader .dots span:first-child + span {
    animation-name: dots-2;
    -webkit-animation-name: dots-2
  }

  .a-inspector-loader .dots span:first-child + span + span {
    animation-name: dots-3;
    -webkit-animation-name: dots-3
  }

  a-scene {
    display: block;
    position: relative;
    height: 100%;
    width: 100%
  }

  a-assets, a-scene audio, a-scene img, a-scene video {
    display: none
  }

  .a-enter-vr-modal, .a-orientation-modal {
    font-family: Consolas, Andale Mono, Courier New, monospace
  }

  .a-enter-vr-modal a {
    border-bottom: 1px solid #fff;
    padding: 2px 0;
    text-decoration: none;
    transition: .1s color ease-in
  }

  .a-enter-vr-modal a:hover {
    background-color: #fff;
    color: #111;
    padding: 2px 4px;
    position: relative;
    left: -4px
  }

  .a-enter-vr {
    font-family: sans-serif, monospace;
    font-size: 13px;
    width: 100%;
    font-weight: 200;
    line-height: 16px;
    position: absolute;
    right: 20px;
    bottom: 20px
  }

  .a-enter-vr-button, .a-enter-vr-modal, .a-enter-vr-modal a {
    color: #fff
  }

  .a-enter-vr-button {
    background: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20245.82%20141.73%22%3E%3Cdefs%3E%3Cstyle%3E.a%7Bfill%3A%23fff%3Bfill-rule%3Aevenodd%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Ctitle%3Emask%3C%2Ftitle%3E%3Cpath%20class%3D%22a%22%20d%3D%22M175.56%2C111.37c-22.52%2C0-40.77-18.84-40.77-42.07S153%2C27.24%2C175.56%2C27.24s40.77%2C18.84%2C40.77%2C42.07S198.08%2C111.37%2C175.56%2C111.37ZM26.84%2C69.31c0-23.23%2C18.25-42.07%2C40.77-42.07s40.77%2C18.84%2C40.77%2C42.07-18.26%2C42.07-40.77%2C42.07S26.84%2C92.54%2C26.84%2C69.31ZM27.27%2C0C11.54%2C0%2C0%2C12.34%2C0%2C28.58V110.9c0%2C16.24%2C11.54%2C30.83%2C27.27%2C30.83H99.57c2.17%2C0%2C4.19-1.83%2C5.4-3.7L116.47%2C118a8%2C8%2C0%2C0%2C1%2C12.52-.18l11.51%2C20.34c1.2%2C1.86%2C3.22%2C3.61%2C5.39%2C3.61h72.29c15.74%2C0%2C27.63-14.6%2C27.63-30.83V28.58C245.82%2C12.34%2C233.93%2C0%2C218.19%2C0H27.27Z%22%2F%3E%3C%2Fsvg%3E) 50% 50%/70% 70% no-repeat rgba(0, 0, 0, .35);
    border: 0;
    bottom: 0;
    cursor: pointer;
    min-width: 50px;
    min-height: 30px;
    padding-right: 5%;
    padding-top: 4%;
    position: absolute;
    right: 0;
    transition: background-color .05s ease;
    -webkit-transition: background-color .05s ease;
    z-index: 9999
  }

  .a-enter-vr-button:active, .a-enter-vr-button:hover {
    background-color: #666
  }

  [data-a-enter-vr-no-webvr] .a-enter-vr-button {
    border-color: #666;
    opacity: .65
  }

  [data-a-enter-vr-no-webvr] .a-enter-vr-button:active, [data-a-enter-vr-no-webvr] .a-enter-vr-button:hover {
    background-color: rgba(0, 0, 0, .35);
    cursor: not-allowed
  }

  .a-enter-vr-modal {
    background-color: #666;
    border-radius: 0;
    display: none;
    min-height: 32px;
    margin-right: 70px;
    padding: 9px;
    width: 280px;
    right: 2%;
    position: absolute
  }

  .a-enter-vr-modal:after {
    border-bottom: 10px solid transparent;
    border-left: 10px solid #666;
    border-top: 10px solid transparent;
    display: inline-block;
    content: '';
    position: absolute;
    right: -5px;
    top: 5px;
    width: 0;
    height: 0
  }

  .a-enter-vr-modal a, .a-enter-vr-modal p {
    display: inline
  }

  .a-enter-vr-modal p {
    margin: 0
  }

  .a-enter-vr-modal p:after {
    content: ' '
  }

  [data-a-enter-vr-no-headset].a-enter-vr:hover .a-enter-vr-modal, [data-a-enter-vr-no-webvr].a-enter-vr:hover .a-enter-vr-modal {
    display: block
  }

  .a-orientation-modal {
    background: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20xmlns%3Axlink%3D%22http%3A//www.w3.org/1999/xlink%22%20version%3D%221.1%22%20x%3D%220px%22%20y%3D%220px%22%20viewBox%3D%220%200%2090%2090%22%20enable-background%3D%22new%200%200%2090%2090%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20points%3D%220%2C0%200%2C0%200%2C0%20%22%3E%3C/polygon%3E%3Cg%3E%3Cpath%20d%3D%22M71.545%2C48.145h-31.98V20.743c0-2.627-2.138-4.765-4.765-4.765H18.456c-2.628%2C0-4.767%2C2.138-4.767%2C4.765v42.789%20%20%20c0%2C2.628%2C2.138%2C4.766%2C4.767%2C4.766h5.535v0.959c0%2C2.628%2C2.138%2C4.765%2C4.766%2C4.765h42.788c2.628%2C0%2C4.766-2.137%2C4.766-4.765V52.914%20%20%20C76.311%2C50.284%2C74.173%2C48.145%2C71.545%2C48.145z%20M18.455%2C16.935h16.344c2.1%2C0%2C3.808%2C1.708%2C3.808%2C3.808v27.401H37.25V22.636%20%20%20c0-0.264-0.215-0.478-0.479-0.478H16.482c-0.264%2C0-0.479%2C0.214-0.479%2C0.478v36.585c0%2C0.264%2C0.215%2C0.478%2C0.479%2C0.478h7.507v7.644%20%20%20h-5.534c-2.101%2C0-3.81-1.709-3.81-3.81V20.743C14.645%2C18.643%2C16.354%2C16.935%2C18.455%2C16.935z%20M16.96%2C23.116h19.331v25.031h-7.535%20%20%20c-2.628%2C0-4.766%2C2.139-4.766%2C4.768v5.828h-7.03V23.116z%20M71.545%2C73.064H28.757c-2.101%2C0-3.81-1.708-3.81-3.808V52.914%20%20%20c0-2.102%2C1.709-3.812%2C3.81-3.812h42.788c2.1%2C0%2C3.809%2C1.71%2C3.809%2C3.812v16.343C75.354%2C71.356%2C73.645%2C73.064%2C71.545%2C73.064z%22%3E%3C/path%3E%3Cpath%20d%3D%22M28.919%2C58.424c-1.466%2C0-2.659%2C1.193-2.659%2C2.66c0%2C1.466%2C1.193%2C2.658%2C2.659%2C2.658c1.468%2C0%2C2.662-1.192%2C2.662-2.658%20%20%20C31.581%2C59.617%2C30.387%2C58.424%2C28.919%2C58.424z%20M28.919%2C62.786c-0.939%2C0-1.703-0.764-1.703-1.702c0-0.939%2C0.764-1.704%2C1.703-1.704%20%20%20c0.94%2C0%2C1.705%2C0.765%2C1.705%2C1.704C30.623%2C62.022%2C29.858%2C62.786%2C28.919%2C62.786z%22%3E%3C/path%3E%3Cpath%20d%3D%22M69.654%2C50.461H33.069c-0.264%2C0-0.479%2C0.215-0.479%2C0.479v20.288c0%2C0.264%2C0.215%2C0.478%2C0.479%2C0.478h36.585%20%20%20c0.263%2C0%2C0.477-0.214%2C0.477-0.478V50.939C70.131%2C50.676%2C69.917%2C50.461%2C69.654%2C50.461z%20M69.174%2C51.417V70.75H33.548V51.417H69.174z%22%3E%3C/path%3E%3Cpath%20d%3D%22M45.201%2C30.296c6.651%2C0%2C12.233%2C5.351%2C12.551%2C11.977l-3.033-2.638c-0.193-0.165-0.507-0.142-0.675%2C0.048%20%20%20c-0.174%2C0.198-0.153%2C0.501%2C0.045%2C0.676l3.883%2C3.375c0.09%2C0.075%2C0.198%2C0.115%2C0.312%2C0.115c0.141%2C0%2C0.273-0.061%2C0.362-0.166%20%20%20l3.371-3.877c0.173-0.2%2C0.151-0.502-0.047-0.675c-0.194-0.166-0.508-0.144-0.676%2C0.048l-2.592%2C2.979%20%20%20c-0.18-3.417-1.629-6.605-4.099-9.001c-2.538-2.461-5.877-3.817-9.404-3.817c-0.264%2C0-0.479%2C0.215-0.479%2C0.479%20%20%20C44.72%2C30.083%2C44.936%2C30.296%2C45.201%2C30.296z%22%3E%3C/path%3E%3C/g%3E%3C/svg%3E) center/50% 50% no-repeat rgba(244, 244, 244, 1);
    bottom: 0;
    font-size: 14px;
    font-weight: 600;
    left: 0;
    line-height: 20px;
    right: 0;
    position: fixed;
    top: 0;
    z-index: 9999999
  }

  .a-orientation-modal:after {
    color: #666;
    content: "Insert phone into Cardboard holder.";
    display: block;
    position: absolute;
    text-align: center;
    top: 70%;
    transform: translateY(-70%);
    width: 100%
  }

  .a-orientation-modal button {
    background: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20xmlns%3Axlink%3D%22http%3A//www.w3.org/1999/xlink%22%20version%3D%221.1%22%20x%3D%220px%22%20y%3D%220px%22%20viewBox%3D%220%200%20100%20100%22%20enable-background%3D%22new%200%200%20100%20100%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20fill%3D%22%23000000%22%20d%3D%22M55.209%2C50l17.803-17.803c1.416-1.416%2C1.416-3.713%2C0-5.129c-1.416-1.417-3.713-1.417-5.129%2C0L50.08%2C44.872%20%20L32.278%2C27.069c-1.416-1.417-3.714-1.417-5.129%2C0c-1.417%2C1.416-1.417%2C3.713%2C0%2C5.129L44.951%2C50L27.149%2C67.803%20%20c-1.417%2C1.416-1.417%2C3.713%2C0%2C5.129c0.708%2C0.708%2C1.636%2C1.062%2C2.564%2C1.062c0.928%2C0%2C1.856-0.354%2C2.564-1.062L50.08%2C55.13l17.803%2C17.802%20%20c0.708%2C0.708%2C1.637%2C1.062%2C2.564%2C1.062s1.856-0.354%2C2.564-1.062c1.416-1.416%2C1.416-3.713%2C0-5.129L55.209%2C50z%22%3E%3C/path%3E%3C/svg%3E) no-repeat;
    border: none;
    height: 50px;
    text-indent: -9999px;
    width: 50px
  }

  .a-loader-title {
    background-color: rgba(0, 0, 0, .6);
    font-family: sans-serif, monospace;
    text-align: center;
    font-size: 20px;
    height: 50px;
    font-weight: 300;
    line-height: 50px;
    position: absolute;
    right: 0;
    left: 0;
    top: 0;
    color: #fff
  }</style>
  <style data-href="src/style/rStats.css" type="text/css">.rs-base {
    background-color: #333;
    color: #fafafa;
    border-radius: 0;
    font: 10px monospace;
    left: 5px;
    line-height: 1em;
    opacity: .85;
    overflow: hidden;
    padding: 10px;
    position: fixed;
    top: 5px;
    width: 300px;
    z-index: 10000
  }

  .rs-base div.hidden {
    display: none
  }

  .rs-base h1 {
    color: #fff;
    cursor: pointer;
    font-size: 1.4em;
    font-weight: 300;
    margin: 0 0 5px;
    padding: 0
  }

  .rs-group {
    display: -webkit-box;
    display: -webkit-flex;
    display: flex;
    -webkit-flex-direction: column-reverse;
    flex-direction: column-reverse;
    margin-bottom: 5px
  }

  .rs-group:last-child {
    margin-bottom: 0
  }

  .rs-counter-base {
    align-items: center;
    display: -webkit-box;
    display: -webkit-flex;
    display: flex;
    height: 10px;
    -webkit-justify-content: space-between;
    justify-content: space-between;
    margin: 2px 0
  }

  .rs-counter-base.alarm {
    color: #b70000;
    text-shadow: 0 0 0 #b70000, 0 0 1px #fff, 0 0 1px #fff, 0 0 2px #fff, 0 0 2px #fff, 0 0 3px #fff, 0 0 3px #fff, 0 0 4px #fff, 0 0 4px #fff
  }

  .rs-counter-id {
    font-weight: 300;
    -webkit-box-ordinal-group: 0;
    -webkit-order: 0;
    order: 0;
    width: 54px
  }

  .rs-counter-value {
    font-weight: 300;
    -webkit-box-ordinal-group: 1;
    -webkit-order: 1;
    order: 1;
    text-align: right;
    width: 35px
  }

  .rs-canvas {
    -webkit-box-ordinal-group: 2;
    -webkit-order: 2;
    order: 2
  }

  @media (min-width: 480px) {
    .rs-base {
      left: 20px;
      top: 20px
    }
  }</style>
  <script src="./scripts/aframe-ar.js"></script>
  <script src="./scripts/aframe-ar-gps-camera.js"></script>
  <script src="./scripts/aframe-ar-gps-entity-place.js"></script>

  <link href="styles.3ff695c00d717f2d2a11.css" rel="stylesheet">
  <style></style>
</head>
<body style="height: 668px; width: 890.667px; margin-left: -265px; margin-top: 0px;">
<app-root _nghost-eie-c0="" ng-version="8.2.11">
  <button _ngcontent-eie-c0="" style="width: 100%;">LOAD ALL</button>
  <a-scene _ngcontent-eie-c0="" arjs="sourceType: webcam; sourceWidth:1280; sourceHeight:960; displayWidth: 1280; displayHeight: 960; debugUIEnabled: false;" cursor="" embedded="" inspector=""
           keyboard-shortcuts=""
           raycaster="" screenshot="" vr-mode-ui="">
    <canvas class="a-canvas a-grab-cursor a-mouse-cursor-hover" data-aframe-canvas="true" height="2672"
            width="3564"></canvas>
    <div class="a-loader-title" style="display: none;">Ar</div>
    <a-entity aframe-injected="" camera="" look-controls="" position="" rotation="" wasd-controls=""></a-entity>
    <a-camera _ngcontent-eie-c0="" camera="" gps-camera="" look-controls="" position="" rotation="" rotation-reader=""
              wasd-controls=""></a-camera><!---->
    <a-image _ngcontent-eie-c0="" alpha-test="0.3" geometry="" gps-entity-place="" material=""
             name="Bistro und Backshop AmAirfurt" scale="" src="./assets/map-marker.svg"></a-image>
    <a-entity aframe-injected="" data-aframe-default-light="" light=""></a-entity>
    <a-entity aframe-injected="" data-aframe-default-light="" light="" position=""></a-entity>
  </a-scene>
</app-root>
<script defer="" src="runtime.1720a40670866f12654e.js"></script>
<script defer="" nomodule="" src="polyfills-es5.59846ba406d92034bc34.js"></script>
<script defer="" src="polyfills.27e829e82a9e20a6f2da.js"></script>
<script defer="" src="main.8458a1d626bf7dc76743.js"></script>

<video autoplay="" id="arjs-video" muted="" playsinline=""
       style="width: 501px; height: 668px; position: absolute; top: 0px; left: 0px; z-index: -2; margin-left: -70.5px; margin-top: 0px;"></video>
</body>
</html>
nicolocarpignoli commented 4 years ago
  <script src="./scripts/aframe-ar.js"></script>
  <script src="./scripts/aframe-ar-gps-camera.js"></script>
  <script src="./scripts/aframe-ar-gps-entity-place.js"></script>

This won't work properly, as gps-camera and similar components for location-based are already imported with aframe-arjs.

check out imports like here: https://github.com/nicolocarpignoli/location-based-ar-tutorial/blob/master/static-on-html/index.html

smuddy commented 4 years ago

Hi, that's not the problem, I cut the registrations out of the aframe-ar.js to isolate the functions for better debugging. First I had imported the js files directly from git like in the examples, but the behavior was the same.

smuddy commented 4 years ago

I found the culprit:

<a-entity aframe-injected="" camera="" look-controls="" position="" rotation="" wasd-controls=""></a-entity>

Looks like AFrame adds a camera by default (aframe-injected), that I had not defined in my html code. So gps-entity-place takes the first match of 'a-camera, [camera]' which is the injected camera .

Perhaps you should select the camera by the gps-camera attribute. For me it solved the problem.

    if (this._cameraGps === null) {
      var camera = document.querySelector('[gps-camera]');  // changed selector from 'a-camera, [camera]'
      if (camera.components['gps-camera'] === undefined) {
        return;
      }
      this._cameraGps = camera.components['gps-camera'];
    }
nicolocarpignoli commented 4 years ago

Great @smuddy thanks! Can you make me a PR for this modify (querySelector)? Would be really appreciated

smuddy commented 4 years ago

Sure, as soon as I got the make-process running under Windows.

nicolocarpignoli commented 4 years ago

https://github.com/jeromeetienne/AR.js/pull/629

nicolocarpignoli commented 4 years ago

I have fixed that on version 2.0.8 (now it looks for the gps-camera using gps-camera attribute on the selector)