AR-js-org / AR.js

Image tracking, Location Based AR, Marker tracking. All on the Web.
MIT License
5.46k stars 929 forks source link

AR portal with nft markers #253

Open noorfatma opened 3 years ago

noorfatma commented 3 years ago

Do you want to request a feature or report a bug?

What is the current behavior?

If the current behavior is a bug, please provide the steps to reproduce.

Please mention other relevant information such as the browser version, Operating System and Device Name

What is the expected behavior?

If this is a feature request, what is motivation or use case for changing the behavior?

I am trying to port the AR portal door for Hiro marker to be used with pinball nft markers. The door does not appear only spherical material appears. Here is my code.

<script src="https://cdn.rawgit.com/jeromeetienne/AR.js/1.5.0/aframe/examples/vendor/aframe/build/aframe.min.js"></script>
<script src='https://raw.githack.com/AR-js-org/AR.js/master/aframe/build/aframe-ar-nft.js'></script>

<script>
    window.onload = function() {
        AFRAME.registerComponent('videohandler', {
            init: function () {
                var marker = this.el.sceneEl;

                this.vid = document.querySelector("#vid");

                marker.addEventListener('markerFound', function () {
                    this.vid.play();
                }.bind(this));

        marker.addEventListener('markerLost', function() {
            this.vid.pause();
            this.vid.currentTime = 0;
        }.bind(this));
            }
        });
    };
</script>
<script>
  AFRAME.registerComponent('arjs-portal-door', {
  schema: {
    url : {   // Url of the content - may be video or image
      type: 'string',
    },
    doorWidth : { // width of the door
      type: 'number',
      default: 1,
    },
    doorHeight : {  // height of the door
      type: 'number',
      default: 2,
    },
  },
  init: function () {
    var _this = this

    var doorWidth = this.data.doorWidth
    var doorHeight = this.data.doorHeight
    var imageURL = this.data.url

    var portalDoor = new THREEx.Portal360(imageURL, doorWidth, doorHeight)
    this._portalDoor = portalDoor

    this.el.object3D.add(portalDoor.object3d)
  },
  tick: function(){
    this._portalDoor.update()
  }
})

AFRAME.registerPrimitive('a-portal-door', AFRAME.utils.extendDeep({}, AFRAME.primitives.getMeshMixin(), {
  defaultComponents: {
    'arjs-portal-door': {},
  },
  mappings: {
    'url': 'arjs-portal-door.url',
  }
}))
</script>
<script>
var THREEx = THREEx || {}

THREEx.Portal360 = function(videoImageURL, doorWidth, doorHeight){

  var doorCenter = new THREE.Group
  doorCenter.position.y = doorHeight/2
  this.object3d = doorCenter

  //////////////////////////////////////////////////////////////////////////////
  //    build texture360
  //////////////////////////////////////////////////////////////////////////////
  var isVideo = videoImageURL.match(/.(mp4|webm|ogv)/i) ? true : false
  if( isVideo ){
    var video = document.createElement( 'video' )
    video.width = 640;
    video.height = 360;
    video.loop = true;
    video.muted = true;
    video.src = videoImageURL;
    video.crossOrigin = 'anonymous'
    video.setAttribute( 'webkit-playsinline', 'webkit-playsinline' );
    video.play();

    var texture360 = new THREE.VideoTexture( video );
    texture360.minFilter = THREE.LinearFilter;
    texture360.format = THREE.RGBFormat;  
    texture360.flipY = false;   
  }else{
    var texture360 = new THREE.TextureLoader().load(videoImageURL)
    texture360.minFilter = THREE.NearestFilter;
    texture360.format = THREE.RGBFormat;
    texture360.flipY = false;   
  }

  //////////////////////////////////////////////////////////////////////////////
  //    build mesh
  //////////////////////////////////////////////////////////////////////////////

  // create insideMesh which is visible IIF inside the portal
  var insideMesh = this._buildInsideMesh(texture360, doorWidth, doorHeight)
  doorCenter.add(insideMesh)
  this.insideMesh = insideMesh

  // create outsideMesh which is visible IIF outside the portal
  var outsideMesh = this._buildOutsideMesh(texture360, doorWidth, doorHeight)
  doorCenter.add(outsideMesh)
  this.outsideMesh = outsideMesh

  // create frameMesh for the frame of the portal
  var frameMesh = this._buildRectangularFrame(doorWidth/100, doorWidth, doorHeight)
  doorCenter.add(frameMesh)
}
//////////////////////////////////////////////////////////////////////////////
//    Code Separator
//////////////////////////////////////////////////////////////////////////////
THREEx.Portal360.buildTransparentMaterial = function(){
  // if there is a cached version, return it
  if( THREEx.Portal360.buildTransparentMaterial.material ){
    return THREEx.Portal360.buildTransparentMaterial.material
  }
  var material = new THREE.MeshBasicMaterial({
    colorWrite: false // only write to z-buf
  })
  // an alternative to reach the same visual - this one seems way slower tho. My guess is it is hitting a slow-path in gpu
  // var material   = new THREE.MeshBasicMaterial();
  // material.color.set('black')
  // material.opacity   = 0;
  // material.blending  = THREE.NoBlending;

  // cache the material
  THREEx.Portal360.buildTransparentMaterial.material = material

  return material   
}

//////////////////////////////////////////////////////////////////////////////
//    Build various cache
//////////////////////////////////////////////////////////////////////////////
THREEx.Portal360.buildSquareCache = function(){
  var container = new THREE.Group
  // add outter cube - invisibility cloak
  var geometry = new THREE.PlaneGeometry(50,50);
  var material = THREEx.Portal360.buildTransparentMaterial()

  var mesh = new THREE.Mesh( geometry, material);
  mesh.position.x =  geometry.parameters.width/2 + 0.5
  mesh.position.y = -geometry.parameters.height/2 + 0.5
  container.add(mesh)

  var mesh = new THREE.Mesh( geometry, material);
  mesh.position.x = -geometry.parameters.width/2 + 0.5
  mesh.position.y = -geometry.parameters.height/2 - 0.5
  container.add(mesh)

  var mesh = new THREE.Mesh( geometry, material);
  mesh.position.x = -geometry.parameters.width/2 - 0.5
  mesh.position.y =  geometry.parameters.height/2 - 0.5
  container.add(mesh)

  var mesh = new THREE.Mesh( geometry, material);
  mesh.position.x = +geometry.parameters.width/2 - 0.5
  mesh.position.y =  geometry.parameters.height/2 + 0.5
  container.add(mesh)

  return container
}

//////////////////////////////////////////////////////////////////////////////
//    build meshes
//////////////////////////////////////////////////////////////////////////////

/**
 * create insideMesh which is visible IIF inside the portal
 */
THREEx.Portal360.prototype._buildInsideMesh = function(texture360, doorWidth, doorHeight){
  var doorInsideCenter = new THREE.Group

  // var squareCache = THREEx.Portal360.buildSquareCache()
  // squareCache.scale.y = doorWidth
  // squareCache.scale.y = doorHeight
  // doorInsideCenter.add( squareCache )

  var geometry = new THREE.PlaneGeometry(doorWidth, doorHeight)
  var material = THREEx.Portal360.buildTransparentMaterial()
  // var material = new THREE.MeshNormalMaterial()
  var mesh = new THREE.Mesh( geometry, material)
  mesh.rotation.y = Math.PI
  // mesh.position.z = 0.03
  doorInsideCenter.add( mesh )

  //////////////////////////////////////////////////////////////////////////////
  //    add 360 sphere
  //////////////////////////////////////////////////////////////////////////////
  // add 360 texture
  // TODO put that in a this.data
  var radius360Sphere = 10
  // var radius360Sphere = 1

  var geometry = new THREE.SphereGeometry( radius360Sphere, 16, 16).rotateZ(Math.PI)
  var material = new THREE.MeshBasicMaterial( {
    map: texture360,
    // opacity: 0.9,
    side: THREE.DoubleSide,
  });
  // var material = new THREE.MeshNormalMaterial()
  var sphere360Mesh = new THREE.Mesh( geometry, material );
  sphere360Mesh.position.z = -0.1
  sphere360Mesh.rotation.y = Math.PI
  doorInsideCenter.add(sphere360Mesh)

  return doorInsideCenter
}

/**
 * create outsideMesh which is visible IIF outside the portal
 */
THREEx.Portal360.prototype._buildOutsideMesh = function(texture360, doorWidth, doorHeight){
  var doorOutsideCenter = new THREE.Group

  //////////////////////////////////////////////////////////////////////////////
  //    add squareCache
  //////////////////////////////////////////////////////////////////////////////
  var squareCache = THREEx.Portal360.buildSquareCache()
  squareCache.scale.y = doorWidth
  squareCache.scale.y = doorHeight
  doorOutsideCenter.add( squareCache )

  //////////////////////////////////////////////////////////////////////////////
  //    add 360 sphere
  //////////////////////////////////////////////////////////////////////////////
  // add 360 texture
  var radius360Sphere = 10
  // var radius360Sphere = 1

  // build half sphere geometry
  var geometry = new THREE.SphereGeometry( radius360Sphere, 16, 16, Math.PI, Math.PI, 0, Math.PI).rotateZ(Math.PI)
  // fix UVs
/*  geometry.faceVertexUvs[0].forEach(function(faceUvs){
    faceUvs.forEach(function(uv){
      uv.x /= 2
    })
  })
  geometry.uvsNeedUpdate = true*/
  var material = new THREE.MeshBasicMaterial( {
    map: texture360,
    // opacity: 0.9,
    side: THREE.BackSide,
  });
  // var geometry = new THREE.SphereGeometry( radius360Sphere, 16, 16);
  // var material = new THREE.MeshNormalMaterial()
  var sphere360Mesh = new THREE.Mesh( geometry, material );
  sphere360Mesh.position.z = -0.1
  doorOutsideCenter.add(sphere360Mesh)

  return doorOutsideCenter
}

/**
 * create frameMesh for the frame of the portal
 */
THREEx.Portal360.prototype._buildRectangularFrame = function(radius, width, height){
  var container = new THREE.Group
  var material = new THREE.MeshNormalMaterial()
  var material = new THREE.MeshPhongMaterial({
    color: 'silver',
    emissive: 'green'
  })

  var geometryBeamVertical = new THREE.CylinderGeometry(radius, radius, height - radius)

  // mesh right
  var meshRight = new THREE.Mesh(geometryBeamVertical, material)
  meshRight.position.x = width/2
  container.add(meshRight)

  // mesh right
  var meshLeft = new THREE.Mesh(geometryBeamVertical, material)
  meshLeft.position.x = -width/2
  container.add(meshLeft)

  var geometryBeamHorizontal = new THREE.CylinderGeometry(radius, radius, width - radius).rotateZ(Math.PI/2)

  // mesh top
  var meshTop = new THREE.Mesh(geometryBeamHorizontal, material)
  meshTop.position.y = height/2
  container.add(meshTop)

  // mesh bottom
  var meshBottom = new THREE.Mesh(geometryBeamHorizontal, material)
  meshBottom.position.y = -height/2
  container.add(meshBottom)

  return container
} 

//////////////////////////////////////////////////////////////////////////////
//    update function
//////////////////////////////////////////////////////////////////////////////

THREEx.Portal360.prototype.update = function () {
  // determine if the user is isOutsidePortal
  var localPosition = new THREE.Vector3
  this.object3d.worldToLocal(localPosition)
  var isOutsidePortal = localPosition.z >= 0 ? true : false

  // handle mesh visibility based on isOutsidePortal
 /* if( isOutsidePortal ){
    this.outsideMesh.visible = true
    this.insideMesh.visible = false
  }else{
    this.outsideMesh.visible = false
    this.insideMesh.visible = true
  }*/
}
</script>

<style>
    .arjs-loader {
        height: 100%;
        width: 100%;
        position: absolute;
        top: 0;
        left: 0;
        background-color: rgba(0, 0, 0, 0.8);
        z-index: 9999;
        display: flex;
        justify-content: center;
        align-items: center;
    }

    .arjs-loader div {
        text-align: center;
        font-size: 1.25em;
        color: white;
    }
</style>

<body style='margin : 0px; overflow: hidden;'>
    <div class="arjs-loader">
        <div>Loading, please wait...</div>
    </div>
    <a-scene
        embedded arjs='trackingMethod: best;debugUIEnabled: false;'>

        <a-nft
            type='nft' url='https://arjs-cors-proxy.herokuapp.com/https://raw.githack.com/AR-js-org/AR.js/master/data/dataNFT/pinball'
            smooth="true" smoothCount="10" smoothTolerance="0.01" smoothThreshold="5"
        >
                  <a-portal-door url='360_topaz.png' position='50 150 0' scale='10 10 10' rotation='90 0 0'><a-portal-door>

        </a-nft>
    <a-camera-static/>
    </a-scene>

</body>

WhatsApp Image 2021-04-23 at 12 08 22 PM

Kelta-King commented 3 years ago

Can you provide the link to your GitHub repo where you have kept this project?

marcelosimonetti commented 2 years ago

hello, were you able to do it?