Skip to content

ianpetrarca/hen-model-aframe-component

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

64 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

screen shot 2017-08-07 at 12 18 15 pm screen shot 2017-08-07 at 12 18 15 pm screen shot 2017-08-07 at 12 18 15 pm

Hic et nunc 3D Model Aframe Component

Use 3D Models from hic et nunc in your Aframe WebXR Scenes!

hic et nunc is a decentralized NFT marketplace built on the Tezos blockchain. This Github repo is a guide for using user-created 3D Models in WebXR experiences using Aframe. This comeponent uses a REST request message described in this API Guide.

This component is added to GLTF model Aframe entity

      <a-gltf-model hen-model="
                    scale:3;
                    animated:true;
                    reflection:true;
                    url:https://www.hicetnunc.xyz/objkt/128211">
      </a-gltf-model>

Code Examples

CDN Link

 <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> 
 <script src="https://cdn.jsdelivr.net/npm/regenerator-runtime@0.13.7/runtime.min.js"></script>
 <script src="https://cdn.jsdelivr.net/gh/ianpetrarca/hen-model-aframe-component@main/src/js/components/hen.js"></script>

Using the Component

Axios and Regenerator Runtime are required to use the API portion of this component**

<html>
  <head>
    <!--  API Scripts    -->
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> 
    <script src="https://cdn.jsdelivr.net/npm/regenerator-runtime@0.13.7/runtime.min.js"></script>
    <!--  Aframe and Aframe Extras Library    -->
    <script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
    <script src="https://cdn.jsdelivr.net/gh/donmccurdy/aframe-extras@v6.1.1/dist/aframe-extras.min.js"></script>
    <!--  Hen-Aframe Component Hosted on CDN    -->
     <script src="https://cdn.jsdelivr.net/gh/ianpetrarca/hen-model-aframe-component@main/src/js/components/hen.js"></script>
  </head>
  <body>
    <!--  Aframe Scene with color management and high refresh rate enabled  -->
    <a-scene renderer="antialias: true;colorManagement: true;physicallyCorrectLights: true;highRefreshRate:true">
      <!-- Camera, Lighting and Sky -->
      <a-entity light="type: ambient; color: #BBB;intensity:1"></a-entity>
      <a-entity light="type: directional; color: #FFF; intensity: 0.6" position="-0.5 1 1"></a-entity>
      <a-camera position="0 1.6 0" look-controls="pointerLockEnabled:true" fov="50"></a-camera>
      <a-sky color="black"></a-sky>
      <!-- Hen-3D Component       -->
      <a-gltf-model hen-model="scale:3;animated:true;reflection:true;url:https://www.hicetnunc.xyz/objkt/128211" 
      position="0 1 -3"> </a-gltf-model>
     </a-scene>
  </body>
</html>

Component Schema

Name Function Type Default
URL hic et nunc URL or OBJKT ID String
Reflection Adds Cubemap Reflection Boolean True
Scale Scale of Model Number 1
Animated Enable Model Animation Boolean True
//ASYNC REST API REQUEST
async function getTokenInfo(id){
    try {
        if(id.includes('xyz')){
          id = id.substring(32)
        }
        const res = await axios.get('https://api.better-call.dev/v1/tokens/mainnet/metadata?token_id=' + id.toString())
        return res.data[0]
    } catch (error) {
        return null
    }
  }
  
  AFRAME.registerComponent('hen-model', {
    schema: {
      url: {type:'string'}, //Hicetnunc.xyz URL or OBJKT ID input
      scale: {type:'number', default: 1}, //Scale of Model
      animated: {type:'boolean', default:true}, //Animate model
      reflection: {type:'boolean', default:true} //Animate model
    },
    init: function () {
  
      //Async Function to get IPFS Hash for OBJKT
      getTokenInfo(this.data.url).then((response) => {  
        let id = response.artifact_uri
        this.el.setAttribute('src','https://cloudflare-ipfs.com/ipfs/'+ id.slice(7,id.length))
      }).catch((response) => { 
          
      })
  
      //Turn on / off animation based on user input
      if(!this.data.animated){
        this.el.removeAttribute('animation-mixer');
      } else {
        this.el.setAttribute('animation-mixer', '')
      }

      if(!this.data.reflection){

      }else {
        this.el.setAttribute('cube-env-map', 'path: https://storage.googleapis.com/titanpointe/indoor/; extension: png; reflectivity: 1')
      }


    
      // Variables for capturing the roughness/metalness values of each material in the model
      this.metalMap = {}
      this.roughMap = {}
  
      //Functions for Material parameters
      this.prepareMap.bind(this) //Parse Materials
      this.traverseMesh.bind(this) //Apply Materials 
      
      //Loading Text
      var text = document.createElement('a-text');
      text.setAttribute('value','Loading...')
      text.setAttribute('position', {x: -.5, y: 0, z: 0});
      this.el.appendChild(text)

      //Loading Spinner Box
      var loadBox = document.createElement('a-entity')
      loadBox.setAttribute('geometry', {
        primitive: 'box',
        height: .25,
        width: .25,
        depth:.25
      });

      //Add Loadbox Animations
      loadBox.setAttribute('position', {x: 0, y: .5, z: 0});
      loadBox.setAttribute('material','wireframe','true');
      loadBox.setAttribute('animation', 'property: rotation; to: 0 360 360;loop:true;dir:alternate;dur:3000');
      this.el.appendChild(loadBox)

      this.el.addEventListener('model-loaded', evt => 
       {
        this.el.removeChild(text)
        this.el.removeChild(loadBox)
        this.scale();
        this.prepareMap()
        this.update()
      });

    },
    prepareMap: function() { //Parse Model Nodes for material information
      this.traverseMesh(node => {
          this.roughMap[node.uuid] = node.material.roughness
          this.metalMap[node.uuid] = node.material.metalness
      })
    },
    update: function () { //Traverse Mesh and apply material parameters and cubemap
      this.traverseMesh(node => {
        node.material.metalness = this.metalMap[node.uuid]
        node.material.roughness = this.roughMap[node.uuid] 
        
        if(!node.material.envMapIntensity==1){ //Check for unlit models that dont require cubemap
         this.el.removeAttribute('cube-env-map');
        }
  
      })
    },
    traverseMesh: function(func) { 
      //Traverse nodes and find actual meshes in GLTF/GLB File
      var mesh = this.el.getObject3D('mesh');
      if (!mesh) { return; }
       mesh.traverse(node => {
        if (node.isMesh) {
          func(node)
        }
      }); 
    }, 
    scale: function () {
      //Get Object Meshes
      const el = this.el;
      const span = this.data.scale;
      const mesh = el.getObject3D('mesh');
  
      if (!mesh) return;
  
      // Compute bounds.
      const bbox = new THREE.Box3().setFromObject(mesh);
  
      // Normalize scale.
      const scale = span / bbox.getSize().length();
      mesh.scale.set(scale, scale, scale);
  
      //Normalize Position
      mesh.position.set(0,0,0);
    }
  });
    
  

Hic et nunc Resources

hic et nunc

here and now

What is Hic Et Nunc?

Hic et nunc is a decentralized NFT marketplace built on the Tezos blockchain. It enables users to create, sell and interact with Tezos NFTs called OBJKTS. Each OBJKT holds a single artwork containing a 3d model, image, video, html snippet, glsl shader, etc. Hic et nunc lets creators limit how many digital versions of their work are in existence.

When a user uploads their content to hic et nunc, the actual file is uploaded to IPFS, a decentralized storage network. The other metadata is stored in the Tezos blockchain.

Contact

Created by @ianpetrarca - tz1LobSdhfUqYpMojXWHQLJPhFLEzUEd9JAn

About

Aframe WebXR component for using hic et nunc 3D Models

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published