Collision between camera and objects in A-Frame - three.js

I've been trying to develop a VR experience using aframe on google cardboard. The player in this game will get point deduction and knock-back when collide with vehicle (car1). Initially I tried to apply static-body and dynamic-body and define the script when collide occurs. However, it's not working as intended.
I'm out of ideas and really don't understand why I cant get the knock-back.
Need some help from A-Frame experts and developers
Thanks in advance!
<a-scene stats physics="debug:true;
<a-entity id='player' camera="active: true" look-controls wasd-controls
data-aframe-default-camera static-body>
<a-text id="score" value="Score" position="-0.2 -0.5 -1" color="black" width="5" anchor="left"></a-text>
</a-entity>
<a-entity id='car1' obj-model="obj:#car_obj;mtl:#car_mtl" dynamic-body></a-entity>
</a-scene>
<script>
let score = 0;
let hit = false
const knockback= () => {
clearTimeout(resetId)
$("#player").body.position.set(0, 0.6,-4)
$("#player").body.velocity.set(0, 5,0)
$("#player").body.angularVelocity.set(0, 0,0)
hit = false
}
on($("#player"), 'collide', (e) => {
const car1 =$("#car1")
if (e.detail.body.id == car1.body.id){
hit = true
score = score + 1
$("#score").setAttribute('text','value','Score '+score)
}
})
</script>

Related

How can I add 2d text to three.js (already tried sprites, fontLoader, etc)?

I'm to add 2d text as labels next to an object, as shown in the image. I've tried sprites (which, as far as I understand, don't work in newer versions of three.js), fontLoader, and a couple of rendering mechanisms--but I have not had any success, unfortunately.
I see that I can use CSS3D, but I'm not sure what to grab from the sample codes. If someone could point me in the right direction, I would appreciate it.
Image showing what I'm trying to achieve
If anyone has any advice, I would greatly appreciate it.
The following are some key parts of my code:
<script src="https://unpkg.com/three#0.132.2/build/three.min.js"></script>
<script src="https://unpkg.com/three#0.132.2/examples/js/loaders/GLTFLoader.js"></script>
<script src="https://unpkg.com/three#0.132.2/examples/js/loaders/DRACOLoader.js"></script>
<script src="https://unpkg.com/three#0.132.2/examples/js/controls/OrbitControls.js"></script>
<canvas id="c"></canvas>
window.addEventListener('load', init);
function init() {
const width = window.innerWidth;
const height = window.innerHeight;
const canvasElement = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({
canvas: canvasElement,
});
renderer.setSize(width, height);
const scene = new THREE.Scene();
scene.background = new THREE.Color( 0xf5e8c6 );
loader.load('js/PricklyPearObject/scene.gltf', (gltf) => {
const model = gltf.scene;
model.scale.set( 0.1,0.1,0.1);
model.position.set(-2, 0, 0);
scene.add(model);
});
I tried using sprites, fontloader, and an approach using render but could not get them to work.
I'll show you a quick and easy way to achieve this when no experience with coding. You can use "Model Viewer". Go to: https://modelviewer.dev/
Click their Editor shown in the pic ->>
Then, drag your glTF or GLB model to the scene.
Then click "Edit" button, then "Add Hotspot" button. Add the text as a label. See the pic below:
Then you can setup the camera (initial position etc.), improve the lights and shadow, or add styles and customize the material.
When you are happy with your model, copy the "snippet code" to add it to your HTML (without forgetting to add the scripts), or "download the scene" as a Three.js project and check the code and run it with simply "Go Live" button in VS Code.
Hope it helps.

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.

Modify a cloned entity in aframe

I am coding my second aframe project in order to better understand how the framework works. For a forest, I defined a prototype tree
<a-entity id="tree">
<a-cylinder id="cylinder" radius="0.3" height="5" color="#754" position="0 2.5 0"></a-cylinder>
<a-cone radius="2" height="4" color="#6d4" position="0 7 0"></a-cone>
</a-entity>
Then I clone this tree with the help of this script:
<a-entity clone="#tree" position="2 0 0"></a-entity>
Cloning works fine. But how can I modify the radius of the cylinder? Or is there a better way to clone entities in aframe?
In order to move forward, I defined a dedicated component for a tree:
<script>
AFRAME.registerComponent('tree', {
schema: {
height: {type: 'number', default: 9.0},
crown: {type: 'number', default: 2.0},
trunk: {type: 'number', default: 0.3}
},
init: function () {
let trunk = document.createElement('a-cylinder');
trunk.setAttribute('radius', this.data.trunk);
trunk.setAttribute('height', this.data.height * 5.0/9.0);
trunk.setAttribute('color', "#754");
trunk.object3D.position.y += this.data.height * 5.0/18.0;
this.el.appendChild(trunk);
let crown = document.createElement('a-cone');
crown.setAttribute('radius-bottom', this.data.crown);
crown.setAttribute('height', this.data.height * 4.0/9.0);
crown.setAttribute('color', "#6d4");
crown.object3D.position.y += this.data.height * 14.0/18.0;
this.el.appendChild(crown);
}
});
</script>
The component then can be instantiated and its parameters modified:
<a-entity tree></a-entity>
<a-entity tree="crown: 4; trunk: 0.7; height: 12" position="3 0 0"></a-entity>
However, this solution follows the Class/Instance paradigm and not the Prototype-Pattern. And in an educational context, a solution that hides the javascript from students would be preferable.
Notice that A-Frame follows an entity component paradigm: different than class/instance or prototype inheritance. Your tree component configures an entity as a tree and other additional components can modify or add that initial configuration. You can expose students to the pattern. The A-Frame documentation is a good starting point

aframe mouseup on sphere

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.

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.

Resources