简体   繁体   中英

Aframe texture control over individual entities

I was wondering how to set a texture on an entity but only that entity and then be able to place more by selecting texture buttons I can't get my code to work properly but I wanted to make it function a little more like minecraft than the original minecraft aframe demo did. If anybody can get my code to work it would be a real help. All the script that is commented out was because I wanted to find a better way to do whatever I was trying. Essentially I want to pick a texture in the menu at the bottom and then use that texture on my entities.

 <!DOCTYPE html> <html> <head> <script src="https://aframe.io/releases/0.9.0/aframe.min.js"></script> <script src="https://unpkg.com/aframe-controller-cursor-component@0.2.x/dist/aframe-controller-cursor-component.min.js"></script> <script> /** * Snap entity to the closest interval specified by `snap`. * Offset entity by `offset`. */ AFRAME.registerComponent('snap', { dependencies: ['position'], schema: { offset: {type: 'vec3'}, snap: {type: 'vec3'} }, init: function () { this.originalPos = this.el.getAttribute('position'); }, update: function () { const data = this.data; const pos = AFRAME.utils.clone(this.originalPos); pos.x = Math.floor(pos.x / data.snap.x) * data.snap.x + data.offset.x; pos.y = Math.floor(pos.y / data.snap.y) * data.snap.y + data.offset.y; pos.z = Math.floor(pos.z / data.snap.z) * data.snap.z + data.offset.z; this.el.setAttribute('position', pos); } }); </script> <script>/** * Spawn entity at the intersection point on click, given the properties passed. * * `<a-entity intersection-spawn="mixin: box; material.color: red">` will spawn * `<a-entity mixin="box" material="color: red">` at intersection point. */ AFRAME.registerComponent('intersection-spawn', { schema: { default: '', parse: AFRAME.utils.styleParser.parse }, init: function () { const data = this.data; const el = this.el; el.addEventListener(data.event, evt => { // Create element. (element create below v const spawnEl = document.createElement('a-entity'); // Snap intersection point to grid and offset from center. (position) spawnEl.setAttribute('position', evt.detail.intersection.point); // Set components and properties. Object.keys(data).forEach(name => { if (name === 'event') { return; } AFRAME.utils.entity.setComponentProperty(spawnEl, name, data[name]); }); // Append to scene. el.sceneEl.appendChild(spawnEl); }); } });</script> <script> function startTimer(duration, display) { var timer = duration, minutes, seconds; setInterval(function () { minutes = parseInt(timer / 60, 10) seconds = parseInt(timer % 60, 10); minutes = minutes < 10 ? "0" + minutes : minutes; seconds = seconds < 10 ? "0" + seconds : seconds; display.textContent = minutes + ":" + seconds; if (--timer < 0) { timer = duration; } }, 1000); } window.onload = function () { var fiveMinutes = 60 * 10, display = document.querySelector('#time'); startTimer(fiveMinutes, display); }; </script> <style> .transparentBox { width: 200px; background-color: #6969697a; margin-right: 600px; border-radius: 10px; border: 2px solid black; } html { width: 800px; height: 600px; cursor: crosshair; } a-scene { cursor: crosshair; width: 800px; height: 600px; } body { cursor: crosshair; width: 800px; height: 600px; } .Container { margin-right: 8px; } </style> </head> <body> <!-- aframe overlay --> <div class="Container" style="position:relative;"> <!-- <a-scene id="updateMe" inspector="https://cdn.jsdelivr.net/gh/aframevr/aframe-inspector@master/dist/aframe-inspector.min.js"> --> <a-scene embedded> <a-assets> <img id="groundTexture" src="floor.jpg"> <img id="skyTexture" src="https://cdn.aframe.io/a-painter/images/sky.jpg"> <a-mixin id="voxel1" geometry="primitive: box; height: 0.6; width: 0.6; depth: 0.6" material="id: theImage; src: Box.jpg; color: #696969; roughness: 1; metalness: 0" snap="offset: 0.4 0.4 0.4; snap: 0.6 0.6 0.6" ></a-mixin> <a-mixin id="voxel2" geometry="primitive: box; height: 0.6; width: 0.6; depth: 0.6" material="id: theImage; src: Brick.jpg; color: #696969; roughness: 1; metalness: 0" snap="offset: 0.4 0.4 0.4; snap: 0.6 0.6 0.6" ></a-mixin> <a-mixin id="voxel3" geometry="primitive: box; height: 0.6; width: 0.6; depth: 0.6" material="id: theImage; src: Steel.jpg; color: #696969; roughness: 1; metalness: 0" snap="offset: 0.4 0.4 0.4; snap: 0.6 0.6 0.6" ></a-mixin> <a-mixin id="voxel4" geometry="primitive: box; height: 0.6; width: 0.6; depth: 0.6" material="id: theImage; src: Pcb.jpg; color: #696969; roughness: 1; metalness: 0" snap="offset: 0.4 0.4 0.4; snap: 0.6 0.6 0.6" ></a-mixin> <a-mixin id="voxel5" geometry="primitive: box; height: 0.6; width: 0.6; depth: 0.6" material="id: theImage; src: Grass.jpg; color: #696969; roughness: 1; metalness: 0" snap="offset: 0.4 0.4 0.4; snap: 0.6 0.6 0.6" ></a-mixin> <a-mixin id="voxel6" geometry="primitive: box; height: 0.6; width: 0.6; depth: 0.6" material="id: theImage; src: Ice.jpg; color: #696969; roughness: 1; metalness: 0" snap="offset: 0.4 0.4 0.4; snap: 0.6 0.6 0.6" ></a-mixin> <a-mixin id="voxel7" geometry="primitive: box; height: 0.6; width: 0.6; depth: 0.6" material="id: theImage; src: Fabric.jpg; color: #696969; roughness: 1; metalness: 0" snap="offset: 0.4 0.4 0.4; snap: 0.6 0.6 0.6" ></a-mixin> </a-assets> <a-obj-model rotation="-90 45 0" position="0 2 0" src="tinker.obj" mtl="obj.mtl"></a-obj-model> <a-cylinder id="ground" src="#groundTexture" radius="30" height="0.1"></a-cylinder> <a-sky id="background" src="#skyTexture" theta-length="90" radius="30"></a-sky> <!-- Camera. --> <a-camera fly="true" position="0 0.75 15" wasd-controls="acceleration: 20" wasd-controls-enabled="true" fov="90" reverse-mouse-drag="false"> <a-cursor id="Save1" intersection-spawn="event: click; mixin: voxel1"></a-cursor> <a-cursor id="Save2" intersection-spawn="event: click; mixin: voxel2"></a-cursor> <a-cursor id="Save3" intersection-spawn="event: click; mixin: voxel3"></a-cursor> <a-cursor id="Save4" intersection-spawn="event: click; mixin: voxel4"></a-cursor> <a-cursor id="Save5" intersection-spawn="event: click; mixin: voxel5"></a-cursor> <a-cursor id="Save6" intersection-spawn="event: click; mixin: voxel6"></a-cursor> <a-cursor id="Save7" intersection-spawn="event: click; mixin: voxel7"></a-cursor> </a-camera> </a-scene> <!-- /aframe overlay --> <center> <div style="position:absolute; margin-right:8px; top:0px; width:205px; height:180px; left:0px; z-index:1000;"> <div class="transparentBox"> <b><h1 color="#FFFFFF" id="time">10:00</h1></b> <p style="font-size:20px;font-family:monospace;margin-top:-20px;">Camera Height:</p> <h1><b><a>&uarr;</a>~~<a>&darr;</a></b></h1> <iframe src="250-milliseconds-of-silence.mp3" allow="autoplay" id="audio" style="display:none"></iframe> <audio autoplay loop id="track"> <source src="Magic_Scout_-_Cottages.mp3" type="audio/mpeg"> Your browser does not support the audio element. </audio><center> <button class="button" id="myBtn">Menu</button> </center> </div> <div id="myModal" class="modal"> <center> <!-- Modal content --> <div class="modal-content"> <span id="clickMe" type="button" value="clickme" onclick="startTimer()" class="close">&times;</span> <center> <p class="beginMenuText"><b>Welcome to SandBox!</b></p> <p class="Text">WASD to move, Space place blocks.</p> <p class="Text2">You have 10 min. before the game restarts and all is lost.</p> <p class="Text2point5">Have fun...</p> </center> <p class="Text3"><b><u>Credits:</u></b></p> <p class="Text4">All music by <b>Kevin MacLeod</b></p> <p class="Text5"><b>Aframe</b> by the Aframe authors.</p> <p class="Text6">(Licenced under the <b>MIT Licence</b>)</p> <p class="Text7">Inspiration from other <b>WebVR Projects.</b></p> <p class="Text8">Voxel textures can be changed using the menu at the <b>bottom</b>.</p> <p class="Text9"><b>Enjoy!</b></p> <div class="unmute" onclick="document.getElementById('track').muted = !document.getElementById('track').muted;$(this).toggleClass('mute')"></div> </div> </center> </div> <div class="textureMenu"> <div class="textureBox" id="Kill1" ><img src="Box.jpg" height="45" width="45"></div> <p class="spacer">~</p> <div class="textureBox" id="Kill2"><img src="Brick.jpg" height="45" width="45"></div> <p class="spacer">~</p> <div class="textureBox" id="Kill3"><img src="Steel.jpg" height="45" width="45"></div> <p class="spacer">~</p> <div class="textureBox" id="Kill4"><img src="Pcb.jpg" height="45" width="45"></div> <p class="spacer">~</p> <div class="textureBox" id="Kill5"><img src="Grass.jpg" height="45" width="45"></div> <p class="spacer">~</p> <div class="textureBox" id="Kill6"><img src="Ice.jpg" height="45" width="45"></div> <p class="spacer">~</p> <div class="textureBox" id="Kill7"><img src="Fabric.jpg" height="45" width="45"></div> </div> </div> </center> </div> </body> <head> <!--<script> document.getElementById('Kill1').addEventListener('click', function () { var mixinEl = document.getElementById('Save1'); if (mixinEl.getAttribute('mixin') === 'voxel') { mixinEl.setAttribute('mixin',: 'voxel1'); } }; </script> <script> document.getElementById('Kill2').addEventListener('click', function () { var mixinEl = document.getElementById('Save2'); if (mixinEl.getAttribute('mixin') === 'voxel') { mixinEl.setAttribute('mixin',: 'voxel2'); } }; </script> <script> document.getElementById('Kill3').addEventListener('click', function () { var mixinEl = document.getElementById('Save3'); if (mixinEl.getAttribute('mixin') === 'voxel') { mixinEl.setAttribute('mixin',: 'voxel3'); } }; </script> <script> document.getElementById('Kill4').addEventListener('click', function () { var mixinEl = document.getElementById('Save4'); if (mixinEl.getAttribute('mixin') === 'voxel') { mixinEl.setAttribute('mixin',: 'voxel4'); } }; </script> <script> document.getElementById('Kill5').addEventListener('click', function () { var mixinEl = document.getElementById('Save5'); if (mixinEl.getAttribute('mixin') === 'voxel') { mixinEl.setAttribute('mixin',: 'voxel5'); } }; </script> <script> document.getElementById('Kill6').addEventListener('click', function () { var mixinEl = document.getElementById('Save6'); if (mixinEl.getAttribute('mixin') === 'voxel') { mixinEl.setAttribute('mixin',: 'voxel6'); } }; </script> <script> document.getElementById('Kill7').addEventListener('click', function () { var mixinEl = document.getElementById('Save7'); if (mixinEl.getAttribute('mixin') === 'voxel') { mixinEl.setAttribute('mixin',: 'voxel7'); } }; </script>--> <style> .spacer { float: left; } .textureBox { width: 47px; height: 47px; border: 2px solid black; float: left; } .textureMenu { height: 50px; width: 412px; padding: 10px; background-color: #6969697a; border: 2px solid black; border-radius: 10px; display:inline-block; position: absolute; left: 200%; top: 313%; transform: translate(-50%, -50%); } .Text9 { font-size: 25px; font-family: monospace; margin-top: -13px; border-bottom: 2px dashed black; } .Text8 { font-size: 25px; font-family: monospace; margin-top: -13px; } .Text7 { font-size: 18px; font-family: monospace; margin-top: -13px; border-bottom: 2px dashed black; } .Text6 { font-size: 10px; font-family: monospace; margin-top: -20px; line-height: 1.3; } .Text5 { font-size: 15px; font-family: monospace; margin-top: -22px; line-height: 1.3; } .Text4 { font-size: 15px; font-family: monospace; margin-top: -27px; line-height: 1.3; } .Text3 { font-size: 20px; font-family: monospace; margin-top: -30px; line-height: 1.3; } .Text2point5 { font-size: 25px; font-family: monospace; margin-top: -30px; line-height: 1; } .Text2 { font-size: 25px; font-family: monospace; margin-top: -30px; line-height: 1; } .Text { font-size: 25px; font-family: monospace; margin-top: -40px; } .beginMenuText { font-size: 45px; font-family: monospace; margin-top: auto; border-bottom: 3px dashed black; } .unmute { background-image: url(http://franriavilla.in/images/unmute.png); background-size: cover; width: 35px; height: 30px; cursor: pointer; } .mute { background-image: url(http://franriavilla.in/images/mute.png); } /* The Modal (background) */ .modal { display: initial; /* Hidden by default */ position: fixed; /* Stay in place */ z-index: 1; /* Sit on top */ left: 0; top: 0; width: 100%; /* Full width */ height: 600px; /* Full height */ overflow: auto; /* Enable scroll if needed */ background-color: rgb(0,0,0); /* Fallback color */ background-color: rgba(0,0,0,0.65); /* Black w/ opacity */ width: 800px; margin-right: 8px; margin-top: 8px; } /* Modal Content/Box */ .modal-content { background-color: #94989e; margin-top: 8px; /* 15% from the top and centered */ padding: 20px; border: 1px solid #888; width: 500px; /* Could be more or less, depending on screen size */ border-radius: 20px; z-index: 20000; } /* The Close Button */ .close { color: #FFF; float: right; margin-top: -15px; font-size: 35px; font-weight: bold; } .close:hover, .close:focus { color: black; text-decoration: none; cursor: pointer; } </style> <script> // Get the modal var modal = document.getElementById('myModal'); // Get the button that opens the modal var btn = document.getElementById("myBtn"); // Get the <span> element that closes the modal var span = document.getElementsByClassName("close")[0]; // When the user clicks on the button, open the modal btn.onclick = function() { modal.style.display = "block"; } // When the user clicks on <span> (x), close the modal span.onclick = function() { modal.style.display = "none"; } // When the user clicks anywhere outside of the modal, close it window.onclick = function(event) { if (event.target == modal) { modal.style.display = "none"; } } </script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <style> .button { border-radius: 25px; font-size: 20px; color: white; background-color: #6969697a; border-color: white; } </style> </head> </html> 

Switching textures can be done in a couple of ways

  • aframe primitives, like <a-box> , or <a-sphere> entities are an easy case. Just change the material.src attribute

     el.setAttribute('material', 'src', newTexture) 
  • models can be quite harder to deal, as you need to switch the mesh.map.texture property (possibly on all childs, not only one mesh).

     var mesh = this.el.getObject3D('mesh') var loader = new THREE.TextureLoader(); loader.load( url, (texture) => { // onLoad callback mesh.material.map = texture mesh.material.needsUpdate = true this.switch = !this.switch } ) 


The Selection might be done in a milion ways.

At first i wanted to store the information about the texture, and access it when a <a-box> is clicked, but a simple way would be to have a couple of images

 <img class=".images" ....> <img class=".images" ....> 

and a component on each aframe primitive which would be:

detecting clicks on those images -> storing the information -> using it when we are clicked:

detecting clicks on images:

this.el.addEventListener('click', (e) => {
  if (!this.selectedTexture) {
  return
  }
  this.el.setAttribute("material", "src", this.selectedTexture)
})

applying texture when clicked:

 this.el.addEventListener('click', (e) => { if (!this.selectedTexture) { return } this.el.setAttribute("material", "src", this.selectedTexture) }) 

This fiddle contains all the above. Two boxes are switching textures by themselves, and the rest will apply the selected image as texture.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM