Does anyone perhaps know the animation component property that I would add to a model in a scene to make it 'rotate' 360° (as in, when a car rotates on a circular platform at a motor show or something)? Would ideally be adding it to this and would hope to be able to make looping true or false:
<a-entity gltf-model="#id" scale="0.5 0.5 0.5" rotation="0 90 0" animation__scale="property: scale; dir: alternate; dur: 200; easing: easeInSine; loop: false; to: 1.2 1 1.2">
</a-entity>
Had a look at the anime.js readme but couldn't seem to find it.
Thank you
You can use the basic animation component:
<a-animation attribute="rotation"
dur="2000"
fill="forwards"
to="0 360 0"
repeat="indefinite"
easing="linear"
></a-animation>
The attribute is rotation, set the angle to 0 360 0, and set the easing to linear so it is smooth.
or use ngoKevin's animation component:
animation__rot="property:rotation;
dur:3000;
to:0 360 0;
loop: true;
easing:linear;"
check it out here: https://jsfiddle.net/gL0pkgz7/.
Related
i'm kinda new to aframe
i have a question : with the aframe-position-spherical-component, i managed to position my element in 360deg
but how can i "curve" my element? (to match the sphering display) (btw my element are
<html>
<head>
<script src="/lib/aframe.min.js"></script>
<script src="https://unpkg.com/aframe-position-spherical-component/index.js"></script>
</head>
<body>
<a-scene>
<a-image src="/static/cat.jpeg" width="3" height="1.5" rotation="0 180 0" position-spherical="10 90 180"></a-image>
</a-scene>
</body>
</html>
first attempt to solve this :
for now i managed to get something near what i want, but the value were found manually and aren't perfect
<a-curvedimage src="/static/cat.jpeg" width="3" height="1.5" theta-length="64" radius="3" theta-start="-32" rotation="0 180 0" position-spherical="10 90 180"></a-curvedimage>
second attempt (with the a-sphere solution) :
kinda work, but image are mirrored, and adding a click event like to show an image bigger is difficult to achieve
<a-assets>
<img id="cat" src="/static/cat.jpeg" />
</a-assets>
<a-box scale="0.1 0.1 0.1" color="red"></a-box>
<a-sphere radius="10" geometry="phiLength: 20; thetaLength: 14.12; thetaStart: 65" rotation="0 210 0" material="side: back; shader: flat; src: #cat"></a-sphere>
<a-sphere radius="10" geometry="phiLength: 20; thetaLength: 14.12; thetaStart: 65" rotation="0 240 0" material="side: back; shader: flat; src: #cat"></a-sphere>
<a-sphere radius="10" geometry="phiLength: 20; thetaLength: 14.12; thetaStart: 65" rotation="0 270 0" material="side: back; shader: flat; src: #cat"></a-sphere>
<a-sphere radius="10" geometry="phiLength: 20; thetaLength: 14.12; thetaStart: 65" rotation="0 300 0" material="side: back; shader: flat; src: #cat"></a-sphere>
<a-curvedimage> is based on a cylinder (source) so it may not fit well.
So how about actually using the sphere geometry ?
tldr fiddle here
Geometry
You could make it look like a <a-curvedimage> using theta and psi properties of a sphere:
<a-sphere geometry='thetaStart: 45; thetaLength: 45; psiLength: 45'></a-sphere>
This should result in a <a-curvedimage>ish plane, but also curved in the vertical axis. Play around with the psi and theta to see more triangle, or diamond shaped geometries.
Fitting into a sphere
This seems like a job for a custom component ! If you didn't use them before, check out the link, otherwise the component below simply copies the sphere radius and position and uses their values for the image.
AFRAME.registerComponent('foo', {
schema: {
// we'll use it to provide the sphere
target: {type: selector}
},
init: function() {
let sphere = this.data.target
// make sure the sphere radius and transform is identical:
this.el.setAttribute('radius', sphere.getAttribute('radius'))
this.el.setAttribute('position', sphere.getAttribute('position'))
}
})
And simply use it like this:
<!-- the background with some position and radius -->
<a-sphere id='background'></a-sphere>
<!-- the inner sphere -->
<a-sphere foo='target: #background'></a-sphere>
Z-Fighting
You should notice that the image is not visible, or it's distorted. By now we have two spheres with identical size and transforms so the renderer won't know which one is in front of the another.
You could deal with this easily - by changing the radius for the inner sphere:
this.el.setAttribute('radius', sphere.getAttribute('radius') * 0.95)
Or you could move the inner sphere a bit towards the center - like in the provided fiddle:
// grab the inner sphere's mesh
let mesh = this.el.getObject3D('mesh')
// we need an axis - I'd substract the mesh's center from the spheres center
let axis = sphere.getAttribute('position').clone()
axis.add(mesh.geometry.boundingSphere.center.clone().multiplyScalar(-1))
axis.normalize();
// move the inner sphere a bit along the axis
this.el.object3D.translateOnAxis(axis, 0.05)
Enlarging the image on click
Usually we'd use the scale attribute, but here we can manipulate the phi and theta values to make the image bigger. Also you should bring the image to front when enlarged, to prevent z-fighting between images:
this.el.addEventListener('click', e => {
this.clicked = !this.clicked
// preset values depending if the image is clicked or not
let thetaLength = this.clicked ? 65 : 45
let thetaStart = this.clicked ? 35 : 45
let psiLength = this.clicked ? 65 : 45
let psiStart = this.clicked ? -10 : 0
let scale = this.clicked ? 0.95 : 1
// apply the new geometry
this.el.setAttribute('geometry', {
'thetaLength': thetaLength,
'thetaStart': thetaStart,
'phiLength': psiLength,
'phiStart' : psiStart
})
this.el.setAttribute('radius', sphere.getAttribute('radius') * scale)
})
fiddle here. It would be better to keep these values in variables (base value, and a delta), but i hope this way it's easier to get the idea.
I'm trying to rotate an object on click and I'm using cursor listener to catch the touch event.
Currently I'm using animation-component.js for animating the object. However, even though im able to animate the button with loop: true but begin:click is not working
<a-entity cursor-listener id="butt"
position="-.0.4 -0.1 0.5"
obj-model="obj: #but"
scale="1 1 1"
rotation="0 0 0"
animation__rotate="begin:click; property: rotation; to: 0 360 0 "
>
Read the API. There is no begin property.
https://github.com/ngokevin/kframe/tree/master/components/animation#api
There is a startEvents property.
I am trying to animate an individual vertex of a triangle primitive in a-frame using the animation tag and am having some strange results
In one case, If I try to animate as I would expect to, changing the x,y,z values like so...
<a-triangle
vertex-a="-1 1 -5"
vertex-b="-1 1 -10"
vertex-c="4 1 -10"
color="blue"
material="side: double">
<a-animation
attribute="vertex-b"
from="-1 1 -10"
to="-1 5 -10"
dur="4000"
>
</a-animation>
</a-triangle>
Fiddle https://jsfiddle.net/k7fbmo9k/
...I get the following error
'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is
NaN. The "position" attribute is likely to have NaN values.'
However, If I only offer a single value like so..
<a-triangle
vertex-a="-1 1 -5"
vertex-b="-1 1 -10"
vertex-c="4 1 -10"
color="blue"
material="side: double">
<a-animation
attribute="vertex-b"
from="1"
to="5"
dur="4000"
>
</a-animation>
</a-triangle>
Fiddle https://jsfiddle.net/k7fbmo9k/1/
..it seems to 'work' as in no errors and there is animation but I have no control over it.
Am I doing something wrong?
Thanks for any advice as ever
I have a solution. Using the animation component https://www.npmjs.com/package/aframe-animation-component
the vertices will animate as expected. See example below
<a-triangle
vertex-a="-1 1 -5"
vertex-b="-1 1 -10"
vertex-c="4 1 -10"
color="blue"
material="side: double"
animation="property: vertex-b; to: -1 5 -10; dur: 1000">
</a-triangle>
Try attribute="geometry.vertexB". It might not work to animate the primitive attributes, so we animate the geometry component directly.
Otherwise, if you are comfortable enough, it is better to animate vertices at a more advanced level for performance. You can use a vertex shader.
Or you can manipulate the vertices manually:
var geometry = triangleEl.getObject3D('mesh').geometry;
geometry.attributes.position[0] += 0.1;
geometry.attributes.position[1] += 0.1;
geometry.attributes.position[2] += 0.1;
geometry.attributes.position.needsUpdate = true;
And to animate, do it in a tick handler:
AFRAME.registerComponent('animate-vertex', {
tick: function (t) {
// Animate vertex position until desired position using `t` to interpolate time.
}
});
I'm currently trying to animate a camera's rotation in a scene. The animation should occur after looking at a circle for 1 second.
The problem is that the bottom of the scene don't seem reachable after the animation, althrough that it is before the animation occured.
I tried first to animate the camera, then a container of the camera. The second option produced an other problem, it seems that all the sky is displaced and I don't understand how to "correct" that.
Video of the problem when the animation is on the camera
Here are two codepens :
Animation on the camera
<script src="https://aframe.io/releases/0.6.1/aframe.min.js"></script>
<script src="https://unpkg.com/aframe-animation-component/dist/aframe-animation-component.min.js"></script>
<a-scene>
<a-assets>
<img id="city" src="https://cdn.aframe.io/360-image-gallery-boilerplate/img/city.jpg" data-position="0 0 0" alt="Table de conférence">
</a-assets>
<a-sky src="#city" rotation="0 0 0"></a-sky>
<a-circle position="-8 -5 2"
rotation="90 0 0"
geometry="radius: 1;"
material="side: double;"
>
</a-circle>
<a-entity id="camera-container" rotation="0 100 0">
<a-entity id="camera" look-controls camera="fov: 80; userHeight: 0" wasd-controls="enabled: false;">
<a-animation attribute="rotation"
dur="1000"
begin="animation__fuse-complete"
from="-31.2 4 0"
to="2 5.5 0"
></a-animation>
<a-entity id="cursor" cursor="fuse: true; fuseTimeout: 100"
position="0 0 -1"
geometry="primitive: ring; radiusInner: 0.013; radiusOuter: 0.02"
material="color: #000; shader: flat"
animation__fuse="startEvents: fusing;
property: scale;
dur: 1000;
to: 0.4 0.4 0.4"
animation__fuseed="startEvents: animation__fuse-complete;
property: scale;
dur: 1;
to: 1 1 1"
>
</a-entity>
</a-entity>
</a-entity>
Animation on a container
<script src="https://aframe.io/releases/0.6.1/aframe.min.js"></script>
<script src="https://unpkg.com/aframe-animation-component/dist/aframe-animation-component.min.js"></script>
<a-scene>
<a-assets>
<img id="city" src="https://cdn.aframe.io/360-image-gallery-boilerplate/img/city.jpg" data-position="0 0 0" alt="Table de conférence">
</a-assets>
<a-sky src="#city" rotation="0 0 0"></a-sky>
<a-circle position="-8 -5 2"
rotation="90 0 0"
geometry="radius: 1;"
material="side: double;"
>
</a-circle>
<a-entity id="camera-container" rotation="0 100 0">
<a-animation attribute="rotation"
dur="1000"
begin="animation__fuse-complete"
from="0 100 0"
to="30 100 0"></a-animation>
<a-entity id="camera" look-controls camera="fov: 80; userHeight: 0" wasd-controls="enabled: false;">
<a-entity id="cursor" cursor="fuse: true; fuseTimeout: 100"
position="0 0 -1"
geometry="primitive: ring; radiusInner: 0.013; radiusOuter: 0.02"
material="color: #000; shader: flat"
animation__fuse="startEvents: fusing;
property: scale;
dur: 1000;
to: 0.4 0.4 0.4"
animation__fuseed="startEvents: animation__fuse-complete;
property: scale;
dur: 1;
to: 1 1 1">
</a-entity>
</a-entity>
</a-entity>
</a-scene>
How to correctly animate the rotation of the camera ?
I'm on Windows 10, with Chrome 59, A-Frame 0.6.1 and aframe-animation-component
Thank you in advance and have a nice day !
I came across a similar problem with being unable to reach the bottom rotation position after executing setAttribute on the camera rotation. Here is what I think is happening:
The problem arises because the rotation on the X-axis changes via code, moving from 0 to 30 degrees without there being a corresponding head motion. As a result, 30 degrees are lost off of the lower limit of -90 degrees.
I think that there is a strong intention in the design of A-Frame that visual angles that arise via head position remain consistent. If you are looking straight ahead and suddenly the angle is 30 degrees higher, yet you haven't moved your head, everything will be askew. You'd have to look downward 30 degrees to see "straight ahead", etc.
It is easy to try and code these discontinuities when A-Frame is viewed through a desktop monitor rather than a visor. I think the "solution" is going to have to be to design some way to have the camera return to its starting position when you run your animation so that it doesn't lose its correspondence to the player's head.
I am trying to detect collision of two boxes in A-FRAME v. 0.5.0. I use raycaster example:
https://aframe.io/docs/0.5.0/components/raycaster.html#whitelisting-entities-to-test-for-intersection
but for me it only works with cursor intersecting one of the meshes.
As it is written, raycaster detects when line created from a starting point to a certain direction intersects desired mesh (here marked with a collidable class). It appears that start of this collision-detecting line is somehow set on the camera or on a cursor but not on one of the boxes. How to reassign this starting point?
Before initializing scene I added component:
AFRAME.registerComponent('collider-check', {
dependencies: ['raycaster'],
init: function () {
console.log("we have component");
this.el.addEventListener('raycaster-intersected', function () {
console.log('Player hit something!');
});
},
});
and then A-FRAME entities
<a-entity id="player" collider-check >
<a-entity id="rc"
raycaster="objects: .collidable"
geometry="primitive: box; width: 0.5; height: 4; depth: 0.5"
material="shader: flat; color:gray"
position="0 -0.9 0"
rotation="90 0 0" ></a-entity>
</a-entity>
<a-entity id="inmotion" class="collidable"
geometry="primitive: box; width: 0.5; height: 4; depth: 0.5"
position="1 0 0"
material="shader: flat; color: #00CCDD">
<a-animation id="canim"
attribute="position"
dur="2000"
from ="-2 -1 0"
to="2 0 0.5"
fill="forwards"
direction="alternate"
repeat="indefinite">
</a-animation>
</a-entity>
Here is jsfiddle with the example;
https://jsfiddle.net/Suiseki/9ggs6x4m/2/
Using the raycaster is one way to check for collisions in 3D space, but it's best if one of those shapes is a ray/line. If you have two 3D objects, it's easier to use bounding box or bounding sphere collisions, without a raycaster. Here are example implementations of each:
aabb-collider
sphere-collider
Both will file hit events on the elements when they collide. Example usage, for a slightly different case.