Change parent of component and keep position - three.js

I am using AR.js and have a sphere positioned in the marker component.
<body style="margin : 0px; overflow: hidden;">
<a-scene vr-mode-ui="enabled: false" embedded="" arjs="sourceType: webcam; debugUIEnabled: false;">
<a-marker markerhandler id="marker" emitevents="true" cursor="rayOrigin: mouse" preset="hiro">
<a-sphere id="sphere" color="green" radius="0.3" position="0 1 0" ></a-sphere>
</a-marker>
<!-- use this <a-entity camera> to support multiple-markers, otherwise use <a-marker-camera> instead of </a-marker>-->
<a-entity camera="" id="camera">
<a-entity geometry="primitive: plane; height: 0.1; width: 0.1" position="0.4 -0.2 -1"
material="color: gray; opacity: 0.5"></a-entity>
<a-entity id="sphere-button" geometry="primitive: plane; height: 0.1; width: 0.1" position="-0.4 -0.2 -1"
material="color: green; opacity: 0.5"></a-entity>
</a-entity>
</a-scene>
</body>
When #sphere-button is clicked, the sphere should dettach from
and attach to the camera.
During the relocation in the DOM, the position should stay the
same, but it does not. I tried this:
let v = new THREE.Vector3();
v.copy(sphere.object3D.position);
sphere.object3D.localToWorld(v);
camera.object3D.worldToLocal(v);
sphere.parentNode.removeChild(entity);
camera.appendChild(sphere);
entity.setAttribute('position', v);
How do i correctly translate the position between the two parents a-camera and a-marker?

For reparenting, I'd do it at three.js level for now and not use the DOM. Detaching and attaching on DOM atm will re-init everything and would be a mess.
let v = new THREE.Vector3();
v.copy(sphere.object3D.position);
sphere.object3D.localToWorld(v);
camera.object3D.worldToLocal(v);
camera.object3D.add(sphere.object3D);
sphere.object3D.position.copy(v);

I've tried a different approach, using object3D.attach (as suggested by #prisoner849 in a comment) to get the position, rotation, etc. of the Three object related to the intended parent, and then cloning the entity using that position, rotation,... under the intended parent (finally, removing the original entity).
You can have a look at a component implementing this approach in this answer to "AFrame: reparenting an element keeping its world position, rotation".

Related

Unmount aFrame on Sveltekit

I'm running an AR application inside Sveltekit with aFrame and AR.js. The augmented reality runs fine with some details. My problem is that when I exit the component (I go to another page) it stays mounted and the webcam stays on. At the moment what I do is to use the onDestroy hook and every time I exit I remove the video tag generated by AR.js. This works partially but I would like to know if there is another way to disassemble. Any help is welcome.
This is my code
<script>
//componente para sombra en camera background
AFRAME.registerComponent("apply-shadowmaterial", {
init: function() {
// grab the mesh
let mesh = this.el.getObject3D("mesh");
// keep the reference to the old material
let tmp = mesh.material;
// assign the new material
mesh.material = new THREE.ShadowMaterial({ opacity: 0.1 });
mesh.receiveShadow = true;
// free memory
tmp.dispose();
}
});
</script>
<a-scene id="escena" class="a-frame" gesture-detector physicallyCorrectLights="true" vr-mode-ui="enabled: false" embedded arjs ="sourceType: webcam; trackingMethod: best; detectionMode: mono; sourceWidth:2048; sourceHeight:1536; displayWidth: 2048; displayHeight: 1536" always-fullscreen renderer="precision: high; antialias: false; logarithmicDepthBuffer:true; colorManagement: true" loading-screen="dotsColor: #DBDADA; backgroundColor: #282828">
<a-assets>
<a-asset-item id="blackM" src={`${storeData.assets.vectorFile}`}></a-asset-item>
<!-- <a-asset-item id="blueM" src="/Blue.glb"></a-asset-item>
<a-asset-item id="orangeM" src="/Orange.glb"></a-asset-item> -->
</a-assets>
<a-entity id="luzdirectional" light="type: directional; color: #DDD; groundColor: #DDD; intensity: 0.2; castShadow:true; target:#marcador; shadowCameraBottom:-6.0; shadowCameraTop:6.0; shadowCameraLeft:-6.0; shadowCameraRight:6.0; " position="-5.0 6.520 5.127">
</a-entity>
<a-marker id="marcador" raycaster="objects: .clickable" emitevents="true" cursor="fuse: false; rayOrigin: mouse;" type='pattern' url='/hiro.patt' smooth='true' smoothCount='3' smoothTolerance='0.01' smoothThreshold='2'>
<a-plane id="planosombras" position="0 -0.2 0" height="500" width="500" rotation="-90 0 0" apply-shadowmaterial></a-plane>
<a-entity
id="plato"
position="0 0 0"
rotation="0 60 0"
scale="0.1 0.1 0.1"
gltf-model={`${storeData.assets.vectorFile}`}
shadow="receive: true; cast: true"
animation__pos="property:position; from:0 0 0; to:-6 0 0; dur: 1000; startEvents:pos"
animation__scale="property:scale; from:0.1 0.1 0.1; to:0 0 0; dur: 1000; startEvents:scale"
class="clickable"
gesture-handler
>
</a-entity>
</a-marker>
<a-entity id="camera" camera="far:10000.00; fov:80.00; near:0.005">
</a-entity>
<a-entity id="luz" light="type: ambient; color: #DDD; groundColor: #DDD; intensity: 0.6" position="0 2 0">
</a-entity>
</a-scene>
</div>

AR.js aframe object show also without pointing marker

In my AR project I use arjs with aframe to make my gltf object visibe when I point with my phone camera on my hiro pattern:
<script src="https://aframe.io/releases/1.0.4/aframe.min.js"></script>
<!-- include ar.js for A-Frame -->
<script src="https://jeromeetienne.github.io/AR.js/aframe/build/aframe-ar.js"></script>
<script src="https://unpkg.com/aframe-orbit-controls#1.2.0/dist/aframe-orbit-controls.min.js"></script>
<body style='margin : 0px; overflow: hidden;'>
<a-scene embedded arjs>
<!-- define your gltf asset -->
<!--This is for add a text-->
<!--<a-text value="Hello, World!"></a-text>-->
<!--This is for add an image-->
<!--<a-image src="another-image.png"></a-image>-->
<a-assets>
<a-asset-item id="tree" src="models/gltf/manovella.gltf"></a-asset-item>
</a-assets>
<a-entity gltf-model="#tree" position="0 0 0" rotation="0 90 0" scale="10 10 10"></a-entity>
<a-entity camera look-controls orbit-controls="target: 0 1.6 -0.5; minDistance: 0.5; maxDistance: 180; initialPosition: 0 5 15">
<!-- define a camera which will move according to the marker position -->
<a-marker-camera preset='hiro'></a-marker-camera>
</a-entity>
</a-scene>
</body>
when I point to my marker all was done, the problem is then also when I start my app without pointing to any market the object appears and when I no longer see the marker in the frame, the object remains on the screen.
How can I manage my gltf show/hide only related to my marker?
So many thanks in advance
Your object should be inside your marker. Try to use this in your scene:
<a-assets>
<a-asset-item id="tree" src="models/gltf/manovella.gltf"></a-asset-item>
</a-assets>
<!-- define a camera which will move according to the marker position -->
<a-marker-camera preset='hiro'><a-entity gltf-model="#tree" position="0 0 0" rotation="0 90 0" scale="10 10 10"></a-entity></a-marker-camera>
<a-entity camera look-controls orbit-controls="target: 0 1.6 -0.5; minDistance: 0.5; maxDistance: 180; initialPosition: 0 5 15"></a-entity>

AR.js and aframe manage my .gltf position and dimensions

I am new to ar.js and Aframe, i wrote a simple code form displat on a hito pattern a gltf objct:
<!-- include A-Frame obviously -->
<script src="https://aframe.io/releases/1.0.4/aframe.min.js"></script>
<!-- include ar.js for A-Frame -->
<script src="https://jeromeetienne.github.io/AR.js/aframe/build/aframe-ar.js"></script>
<body style='margin : 0px; overflow: hidden;'>
<a-scene embedded arjs>
<!-- define your gltf asset -->
<a-assets>
<a-asset-item id="tree" src="models/gltf/manovella.gltf"></a-asset-item>
</a-assets>
<a-entity gltf-model="#tree"></a-entity>
<!-- define a camera which will move according to the marker position -->
<a-marker-camera preset='hiro'></a-marker-camera>
</a-scene>
</body>
All works dine, my object become visible but is so small and wrong positioned:
i try to search in aframe documentation about a-asset-item but cannot find anityng about position dimension and rotation.
Someone can help me for understand how manage apparence of my object?
So many thanks in advance
All <a-entity> elements in A-Frame have position, rotation and scale components that you can use to manage your model like any entity. You can use them like this :
<a-entity gltf-model="#tree" position="0 3 0" rotation="0 90 0" scale="3 3 3"
If you didn't read it yet, there are lots of information on A-Frame documentation, you can start with this guide for the fondamentals.

Aframe Trigger Animation of Element through event-component & proxy-component

I'm trying to trigger animations on other elements while a certain element is being looked at. So what I'm trying to achieve is: When I hover the ball, the text should fade in. And when I leave the ball, the text should fade out.
I was told this should be possible with the aframe-proxy-event-component but I couldn't find any example or documentation on how to use this.
The code looks something like that:
<script src="https://unpkg.com/aframe-animation-component#5.1.2/dist/aframe-animation-component.min.js"></script>
<script src="https://unpkg.com/aframe-event-set-component#4.0.0/dist/aframe-event-set-component.min.js"></script>
<script src="https://unpkg.com/aframe-proxy-event-component/dist/aframe-proxy-event-component.min.js"></script>
<a-mixin id="scaleUpMixin" animation__scale="property: scale; dur: 500; easing: easeInOutQuad; to: 1.5 1.5 1.5;"></a-mixin>
<a-mixin id="scaleDownMixin" animation__scale2="property: scale; dur: 500; easing: easeInOutQuad; to: 1 1 1;"></a-mixin>
<a-mixin id="fadeInText" animation__opacity="property: text.opacity; dur: 500; to: 1"></a-mixin>
<a-mixin id="fadeOutText" animation__opacity2="property: text.opacity; dur: 500; to: 0"></a-mixin>
<a-entity rotation="0 -10 0">
<!-- Planet -->
<a-sphere color="yellow" position="0 1.8 -5" radius="0.5" scale="1 1 1"
mixin="scaleUpMixin scaleDownMixin"
animation__scale="startEvents: mouseenter;"
animation__scale2="startEvents: mouseleave;">
</a-sphere>
<!-- Text -->
<a-text id="TextMercury" class="textbox" text="value: Merkur; align: center; color:#FFF" opacity="0" scale="0.8 0.8 0.8"
position="0 1.8 -1"> </a-text>
</a-entity>
Here's a live demo: https://gorgeous-badge.glitch.me/
An the code: https://glitch.com/edit/#!/gorgeous-badge?path=index.html:30:61
Thanks!
You need to attach the proxy-event component to the sphere. Its quite well documented (with an example) #github
If you have a button, you can redirect any event like this:
<a-box proxy-event="event: event; to: targetSelector; as: newname"></a-box>
<a-entity animation="(...) startEvents: newname"></a-entity>
Check it out in this fiddle.

a-frame navigation bar, that moves horizontal only

I need to know, how to creat a navigation bar with a pre, home and next button.
The bar should be under the cursor and follow it horizontal. so that you can click on the button when you look down.
I have already the 3 buttons and they move the cursor, but now they should only move horizontal and not vertical.
<a-assets>
<a-mixin id="pre" geometry="primitive: circle; radius: 0.1" material="color:blue; opacity:0.2"></a-mixin>
<a-mixin id="home" geometry="primitive: circle; radius: 0.1" material="color:green; opacity:0.2"></a-mixin>
<a-mixin id="next" geometry="primitive: circle; radius: 0.1" material="color:#fe0000; opacity:0.2"></a-mixin>
</a-assets>
<a-entity camera look-controls>
<a-cursor ></a-cursor>
<a-entity mixin="pre" position="-0.2 -0.5 -2"></a-entity>
<a-entity mixin="home" position="0.05 -0.5 -2"></a-entity>
<a-entity mixin="next" position="0.3 -0.5 -2"></a-entity>
</a-entity>
When You put the entity inside the cursor, it will move exactly like the cursor, unless You make a script blocking it in the desired position. However in my opinion, you should create a entity consisting of the buttons:
<a-entity id="button_wrapper" position="0 0 -3" camera-check>
<a-entity mixin="pre" position="-0.2 -0.5 -2"></a-entity>
<a-entity mixin="home" position="0.05 -0.5 -2"></a-entity>
<a-entity mixin="next" position="0.3 -0.5 -2"></a-entity>
</a-entity>
<a-entity id = "camera" camera look-controls>
<a-cursor >
</a-cursor>
</a-entity>
Having it this way, You can create a script moving the entity with the camera either moving the object when the camera changes, or moving it on tick():
AFRAME.registerComponent('camera-check', {
init: function () {
var rotation;
camera = document.querySelector('#camera');
camera.addEventListener('componentchanged', function(evt) {
if (evt.detail.name === 'rotation') {
// here You have your new rotation reference in evt.detail.newData
// and Your old rotation reference in evt.detail.oldData
this.el.setAttribute("rotation","0 "+evt.detail.newData.y+" 0");
}
});
},
tick: function(){
// this.el.setAttribute("rotation","0 "+document.querySelector('a-box').getAttribute("rotation").y)+" 0");
}
});
working fiddle here.

Resources