I am new in A-frame using version 0.9.0,trying to make website with 360 degree image in a-sky and multiple images on scene ,i need to show cursor only in VR mode , when cursor stop on a-image firing click event
and attach new a-image ,now there is problem when trying to enter vr mode multiple times and exit ,first time enter vr mode the cursor appear with no problem then when exit from vr mode and trying to enter one more time cursor disappear
var prvImage =document.querySelector("#previewImage");
prvImage.object3D.visible = false;
AFRAME.registerComponent('vr-cursor',
{
init:function()
{
let cursor = document.createElement('a-cursor');
this.el.sceneEl.addEventListener('enter-vr', function()
{ document.querySelector('#camera').appendChild(cursor);
cursor.setAttribute('fuse','true');
cursor.setAttribute('geometry', 'primitive: ring; radiusInner: 0.02; radiusOuter: 0.03');
prvImage.object3D.visible = true;
console.log("enter-vr");
});
this.el.sceneEl.addEventListener('exit-vr',function()
{ document.querySelector('#camera').removeChild(cursor);
prvImage.object3D.visible = false;
console.log("exit-vr");
});
}
});
AFRAME.registerComponent('cursor-listener',
{
init:function()
{
var imageSrc =this.el.getAttribute('src');
this.el.addEventListener('click', function (evt) {
console.log('I was clicked at:33 ');
prvImage.setAttribute('src',imageSrc);
prvImage.setAttribute('width','1');
prvImage.setAttribute('height','1');
prvImage.setAttribute('position','15 , 18, 18');
prvImage.object3D.scale.set(18, 18, 18);
prvImage.object3D.position.set(-1.101, 0.850 ,-10.83185);
});
}
});
<a-scene>
<a-sky src="#first-image" shadow="receive:true;"></a-sky>
<a-entity id="camera" camera="userHeight: 1.6" look-controls cursor="rayOrigin: mouse" vr-cursor>
</a-entity>
<a-image class="s1" src="#image1" position="16.508 2.524 -28.964" width="1" height="1" scale="20 20 18" material="transparent: true" geometry="" rotation="" cursor-listener></a-image>
<a-image class="s1" src="#image2" position="-1.63094 3.60811 -35.51375" width="1" height="1" scale="13.8 20.02 20" material="transparent: true" geometry="" rotation="" visible="" cursor-listener></a-image>
<a-image class="s1" src="#image3" position="-22.92895 2.5243 -28.96362" width="1" height="1" scale="23.79 19.93 20" material="transparent: true" geometry="" rotation="" visible="" cursor-listener></a-image>
<a-image id="previewImage"></a-image>
</a-scene>
Related
I wanna replicate what this guy does.
Basically, you go back and forth from one corner of your room to another and rotate the scene when you reach the guardian fence.
https://repl.it/#tetegithub/aframe#index.html
<!DOCTYPE html>
<html>
<head>
<script src="https://aframe.io/releases/1.1.0/aframe.min.js">
</script>
</head>
<body>
<a-scene>
<a-box id="box" position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9"></a-box>
<a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane>
<a-sky color="#ECECEC"></a-sky>
<a-entity id="rig" rotation="0 0 0">
<a-entity id="camera" camera look-controls></a-entity>
<!-- *** -->
<a-entity id="leftHand"
hand-tracking-controls="hand: left;modelColor:#E9967A;"
onpinchstarted="rig.object3D.rotation.x +=Math.Pi;"></a-entity>
<!-- *** -->
<a-entity id="rightHand" hand-tracking-controls="hand: right;modelColor:#E9967A"></a-entity>
</a-entity>
</a-scene>
</body>
</html>
I've added "onpinchstarted" event in the left hand's tag in the hope that when I pinch with my left hand the camera rig will rotate. And it doesn't.I think I have to somehow work with the event listeners and handlers but all the docs I read look like they are written for the robots. Any advice appreciated.
Does the rotation work if you trigger it outside of the event listener?
I see you're referring to "rig" in onpinchstarted, does "rig" exist as a variable in that scope?
One solution would be to start with a helper function that does the rotation, then run it in the console to confirm it works. Then, attach it to the scene via a javascript instead of html (doesn't have to be a component, but it might be easier to reuse).
The docs are unclear if onpinchstarted would work vs pinchstarted https://aframe.io/docs/1.1.0/components/hand-tracking-controls.html#events_pinchended
Well, I came up with a sort of a solution by dissecting the example project.
rig.js
AFRAME.registerComponent('rig', {
init: function () {
this.bindMethod();
this.el.sceneEl.addEventListener('pinchstarted', this.onPinchStarted);
},
//I still don't get what this thing does.
bindMethod: function () {
this.onPinchStarted = this.onPinchStarted.bind(this);
},
onPinchStarted: function () {
this.el.setAttribute('rotation', {y: this.el.getAttribute('rotation').y + 30});
},
});
index.html
<script src="rig.js"></script>
<a-entity rig>
<a-entity camera look-controls position="0 1 0"></a-entity>
<a-entity hand-tracking-controls="hand: left; modelColor:#E9967A;"></a-entity>
<a-entity hand-tracking-controls="hand: right; modelColor:#E9967A;"></a-entity>
</a-entity>
Now I want the rig to yaw the same amount the camera has rotated while I was holding the pinch with my left hand.
And I made it work after a while thanks to this person.
index.html
<script src="rotator.js"></script>
<a-entity id="rig">
<a-camera></a-camera>
<a-entity
oculus-touch-controls="hand: left;"
hand-tracking-controls="hand: left; modelColor:#E9967A;"
rotator="rig: #rig"
></a-entity>
<a-entity
oculus-touch-controls="hand: right;"
hand-tracking-controls="hand: right; modelColor:#E9967A;"
rotator="rig: #rig"
></a-entity>
</a-entity>
As web XR hand tracking in the Oculus Browser where I test it is still experimental and unstable I added touch controllers' grip buttons.
rotator.js
/* global AFRAME, THREE */
AFRAME.registerComponent("rotator", {
schema: {
rig: { type: "selector" },
},
init: function() {
this.bindMethods();
this.el.addEventListener("pinchstarted", this.onPinchStarted);
this.el.addEventListener("pinchended", this.onPinchEnded);
this.el.addEventListener("gripdown", this.onPinchStarted);
this.el.addEventListener("gripup", this.onPinchEnded);
this.rig = this.data.rig;
this.box = this.data.box;
this.box2 = this.data.box2;
this.camera = this.el.sceneEl.camera.el;
this.axisY = new THREE.Vector3(0, 1, 0);
},
bindMethods: function() {
this.onPinchStarted = this.onPinchStarted.bind(this);
this.onPinchEnded = this.onPinchEnded.bind(this);
},
onPinchStarted: function() {
this.trigger = 1;
this.oldCameraAngle = this.camera.getAttribute("rotation").y;
},
tick: function() {
if (this.trigger == 1) {
var angleDifference = THREE.Math.degToRad(
this.oldCameraAngle - this.camera.getAttribute("rotation").y );
this.oldCameraAngle = this.camera.getAttribute("rotation").y;
var cameraPosition = new THREE.Vector3();
cameraPosition.setFromMatrixPosition(this.camera.object3D.matrixWorld);
this.rig.object3D.position.add( cameraPosition.negate() );
this.rig.object3D.position.applyAxisAngle( this.axisY, angleDifference );
this.rig.object3D.position.add( cameraPosition.negate() );
this.rig.object3D.rotateOnAxis( this.axisY, angleDifference );
}
},
onPinchEnded: function() {
this.trigger = 0;
}
});
GitHub link and the version published on my website.
The A-Frame camera docs say to create a HUD like this:
<a-entity camera look-controls>
<a-entity geometry="primitive: plane; height: 0.2; width: 0.2" position="0 0 -1"
material="color: gray; opacity: 0.5"></a-entity>
</a-entity>
However, this causes the HUD element to be clipped by in-game objects. Normally HUDs are rendered on a separate layer above all the other game objects. Is there a simple way to fix this?
You have to:
Set renderer.sortObjects = true;
Set a the render order of the entity this.el.object3D.renderOrder = 100;
Disable the material depth test material.depthTest = false;
I created a simple overlay component that easily applies the above to any entity.
AFRAME.registerComponent("overlay", {
dependencies: ['material'],
init: function () {
this.el.sceneEl.renderer.sortObjects = true;
this.el.object3D.renderOrder = 100;
this.el.components.material.material.depthTest = false;
}
});
<a-entity camera look-controls wasd-controls position="0 1.6 0">
<a-plane id="hud" overlay rotation="0 0 0" position="0 0 -2" width="1" height="1" color="purple" shadow></a-plane>
</a-entity>
Example on glitch
I am new to A-Frame and still trying to figure everything out! I'm currently constructing a 3D space and would like to create a guided experience for visitors by providing dots on the floor for them to click and be transported to that position. I found this code online which is perfect but I can't get it to work.
Here is the link to my project on Glitch: https://glitch.com/~museum-exhibit-demo
This is the code for my camera:
<a-entity position="1.8 -1.1 3" rotation="0 90 0" id="pov">
<a-camera universal-controls="movementControls: checkpoint" checkpoint-controls="mode: animate">
<a-entity cursor position="0 0 -1" geometry="primitive: ring; radiusInner: 0.01; radiusOuter: 0.015;" material="color: #CCC; shader: flat;"> </a-entity>
</a-camera>
</a-entity>
And this is the code for the cylinder:
<a-cylinder checkpoint radius="0.1.5" height="0.01" position="-0.164 0.111 2.363" color="#39BB82"></a-cylinder>
Can anyone spot where I'm going wrong?
UPDATE:
I just read the current source of aframe-extra and it seems that nothing is broken! In fact there was a backward-incompatible change in the new versions. Rather than the old syntax of:
universal-controls="movementControls: checkpoint;"
Now this new syntax should be used:
movement-controls="controls: checkpoint;"
But keep in mind that since version 3.2.7, the movement offset is calculated on all 3 XYZ axis and therefore the camera will move to the center of the checkpoint. If you want to preserve the height (y) then simply add the code below above line 83:
targetPosition.y = position.y;
Here is a complete working example:
<html>
<head>
<meta charset="utf-8">
<title>Checkpoint Control with AFrame 1.2.0</title>
<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>
</head>
<body>
<a-scene stats>
<!-- CAMERA -->
<a-entity position="0 0 0" id="pov">
<a-camera camera="active: true; spectator: false;" look-controls="pointerLockEnabled:true" movement-controls="controls: checkpoint;" checkpoint-controls="mode: animate; animateSpeed: 10" wasd-controls="enabled: false;" position="0 1.6 22">
<a-cursor></a-cursor>
</a-camera>
</a-entity>
<!-- CHECKPOINTS -->
<a-cylinder checkpoint radius="0.5" height="0.01" position="0 0 20" color="#FF0000"></a-cylinder>
<a-cylinder checkpoint radius="0.5" height="0.01" position="0 0 16" color="#FF0000"></a-cylinder>
<a-cylinder checkpoint radius="0.5" height="0.01" position="0 0 12" color="#FF0000"></a-cylinder>
<a-cylinder checkpoint radius="0.5" height="0.01" position="0 0 8" color="#FF0000"></a-cylinder>
</a-scene>
</body>
</html>
Information below this line is not valid anymore.
As Piotr already mentioned, the new releases of Aframe-Extra are somehow broken!
Using an older version everything will work again.
Below is a working example with Aframe-extra version 3.2.7.
Once the page is fully loaded, click on the screen to lock the cursor, then point the cursor (tiny ring) at a red circle and click.
I also noted few additional options just in case:
spectator: false (switch between 1st and 3rd person view)
pointerLockEnabled:true (hide the mouse)
mode: animate (the other option is teleport)
animateSpeed: 10 (well... adjusts the animation speed)
wasd-controls="enabled: false;" (otherwise user can move around via WASD/arrow keys)
Code:
<html>
<head>
<meta charset="utf-8">
<title>Checkpoint Control with AFrame 1.2.0</title>
<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/donmccurdy/aframe-extras#v3.2.7/dist/aframe-extras.min.js"></script>
</head>
<body>
<a-scene stats>
<!-- CAMERA -->
<a-entity position="0 0 0" id="pov">
<a-camera camera="active: true; spectator: false;" look-controls="pointerLockEnabled:true" universal-controls="movementControls: checkpoint;" checkpoint-controls="mode: animate; animateSpeed: 10" wasd-controls="enabled: false;" position="0 1.6 22">
<a-cursor></a-cursor>
</a-camera>
</a-entity>
<!-- CHECKPOINTS -->
<a-cylinder checkpoint radius="0.5" height="0.01" position="0 0 20" color="#FF0000"></a-cylinder>
<a-cylinder checkpoint radius="0.5" height="0.01" position="0 0 16" color="#FF0000"></a-cylinder>
<a-cylinder checkpoint radius="0.5" height="0.01" position="0 0 12" color="#FF0000"></a-cylinder>
<a-cylinder checkpoint radius="0.5" height="0.01" position="0 0 8" color="#FF0000"></a-cylinder>
</a-scene>
</body>
</html>
This won't answer the question, but should solve your problem.
You can substitute the checkpoint-controls with a simple animation system:
you click on a cylinder
you animate the camera from the current position to the cylinder
Which could be implemented like this:
// use a system to keep a global track if we are already moving
AFRAME.registerSystem('goto', {
init: function() {
this.isMoving = false
}
})
// this component will have the actual logic
AFRAME.registerComponent('goto', {
init: function() {
let camRig = document.querySelector('#rig')
// upon click - move the camera
this.el.addEventListener('click', e => {
// check if we are already moving
if (this.system.isMoving) return;
// lock other attempts to move
this.system.isMoving = true
// grab the positions
let targetPos = this.el.getAttribute("position")
let rigPos = camRig.getAttribute("position")
// set the animation attributes.
camRig.setAttribute("animation", {
"from": rigPos,
"to": AFRAME.utils.coordinates.stringify({x: targetPos.x, y: rigPos.y, z: targetPos.z}),
"dur": targetPos.distanceTo(rigPos) * 750
})
camRig.emit('go')
})
// when the animation is finished - update the "shared" variable
camRig.addEventListener('animationcomplete', e=> {
this.system.isMoving = false
})
}
})
with a setup like this:
<!-- Camera with locked movement --/>
<a-entity id="rig" animation="property: position; startEvents: go">
<a-camera look-controls wasd-controls-enabled="false"></a-camera>
<a-entity>
<!-- Cylinder node --/>
<a-cylinder goto></a-cylinder>
You can see it working in this glitch.
I just started developing with a-frame, please excuse if the answer is obvious.
In my project I would like to get the position of a-sky where the user is looking at. Therefor I implemented a raycaster within the camera, which works fine so far.
HTML
<a-camera listener>
<a-entity raycaster="far: 1000" position="0 -0.9 0" rotation="0 0 0"></a-entity>
</a-camera>
<a-sky follow-intersection
id="sky"
src="#skybox-image">
</a-sky>
TS
AFRAME.registerComponent("follow-intersection", {
init: function() {
this.el.addEventListener("raycaster-intersected", evt => {
this.intersectingRaycaster = evt.detail.el.components.raycaster;
});
this.el.addEventListener("raycaster-intersected-cleared", () => {
this.intersectingRaycaster = null;
});
},
tick: function(t) {
if (!this.intersectingRaycaster) {
return;
}
const intersection = this.intersectingRaycaster.getIntersection(this.el);
if (intersection) {
let point = intersection.uv;
console.log(point.x, point.y);
}
So far this works fine, the problem is that after I set the cursor in the scene (which is needed for the project)
<a-scene
cursor="rayOrigin: listener"
>
I always get the intersections with the cursor, which are not wanted.
How can I only get the intersections of the camera? Thank you!
I don't think the cursor in a-scene is needed. You could just do:
<a-camera listener>
<a-entity cursor raycaster="far: 1000" position="0 -0.9 0" rotation="0 0 0"></a-entity>
</a-camera>
I am using the a-frame components for a WebVR application. The camera has look-controls with a cursor to let the user pick an object. And when the event is fired I wish to change the camera position. This is what I have done. A camera is defined in the scene.
<a-entity id="cam" camera="userHeight: 1.6" look-controls>
<a-entity cursor="fuse: true; fuseTimeout: 500" position="0 0 -1" geometry="primitive: ring; radiusInner: 0.02; radiusOuter: 0.03" material="color: black; shader: flat">
</a-entity>
</a-entity>
I have a box with a listener as follows
<a-box box-listener color="tomato" position="1 0 3" depth="1" height="1" width="1"></a-box>
When the user moves the cursor to the box and holds for half a second, the event gets fired. The event script is as follows:
AFRAME.registerComponent('box-listener', {
init: function() {
this.el.addEventListener('click', function(evt) {
var cam = document.getElementById("cam");
var campos = cam.getAttribute("position");
campos.x = 1; // some random change.
var camrot = cam.getAttribute("rotation");
camrot.x = 0;
camrot.y = 0;
camrot.z = 0; // setting it back to looking straight ahead
var look = cam.getAttribute("look-controls");
look.enabled = false;
cam.setAttribute('look-controls',look);
cam.setAttribute("position", campos);
cam.setAttribute("rotation", camrot);
look.enabled = true;
cam.setAttribute('look-controls',look);
});
}
});
By putting logs I find that the values are getting updated in the camera element however nothing changes on the screen.
where am I going wrong? Does the camera element need to be refreshed?
Thanks,
Raj