aframe mouseup on sphere - three.js

following a partly sucessful answer to this question AFRAME position far away from camera
I'm trying to use a sphere around the camera to get a position around 100 from the camera.
I've added this sphere
<Entity
id='mouse-listener'
geometry='primitive: sphere;
radius: 100;
segmentsWidth: 64;
segmentsHeight: 64;'
position='0 0 0'
scale="-1 1 1"
material={{color: 'blue' }}
className='clickable'
events={{click: (e) => console.log(e)}}
/>
And my camera is as such
<Entity primitive='a-camera' id='camera' look-controls={`enabled:${isLookControlsEnabled}`} mouse-cursor mouse-zoom wasd-controls={wasdControls}>
I've tried adding the example listener component to the sphere entity
import AFRAME from 'aframe'
AFRAME.registerComponent('cursor-listener', {
init: function () {
this.el.addEventListener('click', function (evt) {
console.log('I was clicked at: ', evt.detail.intersection.point)
})
},
})
I just want to know the point on which it was clicked.

A-Frame comes with a mouse cursor. You add it as a separate entity:
<a-entity cursor="rayOrigin: mouse"></a-entity>
The events are mouseenter, mouseleave, click, mousedown, mouseup. Not onmouseup.

Related

Panning around globe until user interacts

Trying to loop around the globe until the user interacts with the map.
Locations are currently based on the flyTo example, as I'm still trying to get the functionality working. I'm struggling to make it animate smoothly, from point to point and loop.
Final version will ideally pan around the globe, and continue until user interacts.
map.on('load', () => {
for (const [index, coordinate] of cityCoordinates.entries()) {
setTimeout(() => {
map.easeTo({
center: coordinate,
duration: 10000
});
coordinate.push(coordinate.shift())
}, 2000 * index);
}
});
https://jsfiddle.net/r8fs2kbd/2/
I saw the animate along a path example, however I don't want the map to rotate or move altitude.

A-Frame Frustum Culling

How do I turn off frustum culling on a gltf model in A-Frame? I know in Three.js you can just traverse the object and add node.frustumCulled = false. I've tried
AFRAME.registerComponent('disable-culling', {
init: function(){
var object3D = this.el.sceneEl.object3D;
object3D.traverse((node) => {
node.frustumCulled = false
})
}
})
but that doesn't work. Does anyone have any idea? The entity is
<a-entity
id="ball"
scale="0.3 0.3 0.3"
position="0 0 -7"
gltf-model="#ballModel"
disable-culling
animation-mixer="clip: *; loop: once; clampWhenFinished: true;"
shadow>
</a-entity>
I had a similar problem which was solved with frustum culling -
el.addEventListener('model-loaded', () => {
const model = el.getObject3D('mesh');
model.traverse((node) => {
if (node.isMesh) {
node.frustumCulled = false;
}
});
});
I wonder if your solution didn't work simply because the model hadn't finished loading.
Go back with your 3D model to Blender, select your model on object mode and then press "ctrl A" - apply all transformations.
I just had this problem where animated models were getting culled before fully exiting the scene. In my case, the cause seemed to be that the object scale was too small. Once I scaled up the object up in Blender and re-exported the gltf file, the models were culled correctly.

Is it possible to append to an animated glb object in threejs/aframe?

I have an object moving about a scene, which I exported as a .glb (model A).
Within Aframe I'm playing the animation on model A using the animation-mixer tag and can see the object moving around. Now what I'm trying to do is append another model (model B), so that model B is also moving around the scene. However, model B just stays in place - at the specified model A position.
Is there a way to accomplish this in Threejs/Aframe?
I have revisited this technique and have the below code, so far, but the position of the model flickers between it's static position and where it's being set to in the tick.
<a-entity id="mantaray-path" gltf-model="#mantaray-path-glb" animation-mixer="timeScale: 1; loop: true;" pathanim></a-entity>
<a-entity id="mantaray" gltf-model="#mantaray-glb" animation-mixer="timeScale: 1;"></a-entity>
AFRAME.registerComponent("pathanim", {
init: function() {
this.el.addEventListener('model-loaded', this.update.bind(this));
},
tick: function() {
this.el.object3D.traverse(function(child) {
if (child.name == "mantaraypath") {
mantaray.object3D.position = child.position;
}
});
}
});

Camera position at runtime

I'm playing with a very basic a-frame scene.
I'm looking for info to get camera position at runtime.
Should I use a Component and three.js code?
How could I do it?
First, grab the camera entity (https://aframe.io/docs/core/entity.html#Retrieving-an-Entity). The camera entity will have the camera component attached as an HTML attribute.
document.querySelector('[camera]') or document.querySelector('a-scene').camera.el
Then use getAttribute to grab the position. This will return an {X, Y, Z} object.
document.querySelector('[camera]').getAttribute('position')
To be notified of every time the camera updates its position, we can use the componentchanged event (https://aframe.io/docs/core/entity.html#Listening-for-Component-Changes):
document.querySelector('[camera]').addEventListener('componentchanged', function (evt) {
if (evt.detail.name === 'position') {
console.log('Camera position went from', evt.detail.oldData, 'to', evt.detail.newData);
}
});
I have finally adopted this solution:
<script>
AFRAME.registerComponent('acceleration', {
tick: function() {
var altitude = (this.el.getAttribute('position').z);
}
})
</script>
<a-scene>
<a-entity position="0 0 150">
<a-entity id="myCamera" camera acceleration look-controls keyboard-controls></a-entity>
</a-entity>
</a-scene>
My last problem is I don't get absolute coordinates of camera, but thoses relative to the initiale camera position.

Threejs: Rendering scene in Div - Prevent scrolling of browser window, do zoom instead (OrbitControls.js)

I have written a new tool in three.js which deals with a cylinder in 3d and renders the cylinder values in the scene that is located within a DIV.
JS:
container = document.getElementById('zylinder_3d');
var sceneWidth = document.getElementById('zylinder_3d').offsetWidth;
var sceneHeight = document.getElementById('zylinder_3d').offsetHeight;
renderer.setSize(sceneWidth, sceneHeight);
container.appendChild(renderer.domElement);
HTML:
<div id="zylinder_3d"></div>
For the navigation I am using OrbitControls.js:
var controls = new THREE.OrbitControls(camera, renderer.domElement);
// rotate at startup
controls.rotateLeft(-0.1);
controls.rotateUp(-0.25);
controls.dollyOut(2.5); // zoom out
The problem is, that if I use the mouse to scroll (having the mouse on top of the canvas), the entire browser window scrolls down - instead of the expected zooming.
Is there any way I can force the scroll to happen only within the scene / the canvas. In best case when the mouse is on top of the canvas.
I have tried some stop scroll advices for Javascript here on stackoverflow, but these were on "normal" DIVs not for DIVs with canvas.
I have found the solution thanks to WestLangleys's comment above who pointed out the TrackBallControls:
Open OrbitControls.js and find lines:
function onMouseWheel( event ) {
if ( scope.enabled === false || scope.noZoom === true ) return;
Add right below:
event.preventDefault();
event.stopPropagation();
This is it!
It works now as expected: Zylinder 3D Demo
PS: Maybe this should be added to the original file?

Resources