Position laser-controls entity after camera rotation - aframe

I have the following code for the laser controls which are perfectly positioned when the camera looks straight ahead after entering VR mode.
<a-entity position="0.25 1.25 -0.2" class="laser-controls">
<a-entity laser-controls="hand: right" line="color: red"></a-entity></a-entity>
The issue is: when I rotate my head (camera), I would like to let the controls follow my head rotation smoothly (I have some code which looks if the rotation is greater than 110 degrees). I don't want the controllers be part of the camera since they should keep their own independent rotation. What I like is the behaviour of the controller model in Oculus Home (Gear VR).
How can I achieve this is my custom component, let's say in my tick function, which is called every two seconds (that code works already).
Thanks!

How about using getAttribute() to check the rotation of the camera component and the laser control's entity? Then you could check if the difference exceeds 110 degrees or not:
let angle = laser.getAttribute('rotation');
if (camera.getAttribute('rotation').y - laser.getAttribute('rotation').y>110){
angle.y++;
laser.setAttribute('rotation',angle);
} else if(camera.getAttribute('rotation').y - laser.getAttribute('rotation').y<-110){
angle.y--;
laser.setAttribute('rotation',angle);
}
UPDATE
If You want to position Your controller near Your head You can:
1.Instead of angle.y++/-- change it to Your camera's rotation. You can also change its x/y position close to the camera ( like camera.position.x + 0.5 )
2.But the above is instant, if You want to make it smooth, You could use the animation component, when the delta degree is >110 deg, set the animation attributes to move to the camera component location/rotation, emit a beginning event, disable the rotation check, listen for the animation end event, and enable the check. a bit like this:
init: function(){
this.check = true;
let check = this.check;
animationel.addEventListener('animationend',function(){
check = true;
});
},tick(){
if(this.check){
if(rotationCheck()){
this.check = false;
}
}
}

Related

On mesh click, ArcRotateCamera focus on

I'm using ArcRotateCamera, when I click on mesh, I have to focus camera on
var camera = new BABYLON.ArcRotateCamera("Camera", -Math.PI / 2, Math.PI / 2, 300, BABYLON.Vector3.Zero(), scene);
camera.setTarget(BABYLON.Vector3.Zero());
// on mesh click, focus in
var i = 2;
var pickInfo = scene.pick(scene.pointerX, scene.pointerY);
if (pickInfo.hit) {
pickInfo.pickedMesh.actionManager = new BABYLON.ActionManager(scene);
pickInfo.pickedMesh.actionManager.registerAction(
new BABYLON.ExecuteCodeAction(BABYLON.ActionManager.OnPickTrigger,
function (event) {
camera.position = (new BABYLON.Vector3(pickInfo.pickedPoint.x, pickInfo.pickedPoint.y, camera.position.z + i));
i += 2;
})
);
}
this code changes mesh's z position but don't makes it in the center of screen
There are a few things that can be changed in your code.
1st - what you are doing is executing a code action after a click, instead of simply running the code in the callback after a pick has occurred. You are registering a pick action (technically user click) on right on the first frame, but only if the mouse was found in the right location at the right moment. My guess is that it didn't work every time (unless you scene is covered with meshes :-) )
2nd - you are changing the camera's position, instead of change the position to which it is looking. Changing the camera's position won't result in what you want (to see the selected mesh), it will move the camera to a new position while still focusing on the old position.
There are a few ways to solve this. The first is this:
scene.onPointerDown = function(evt, pickInfo) {
if(pickInfo.hit) {
camera.focusOn([pickInfo.pickedMesh], true);
}
}
The ArcRotate camera provides focusOn function that focuses on a group of meshes, while fixing the orientation of the camera. this is very helpful. You can see a demo here:
https://playground.babylonjs.com/#A1210C#51
Another solution would be to use the setTarget function:
https://playground.babylonjs.com/#A1210C#52
Which works a bit differently (notice the orientation change of the camera).
Another thing - use the pointer events integrated in Babylon, as they are saving you the extra call for a scene pick. pointer down is executed with the pickinfo integrated in the function, so you can get the picking info of the current pointer down / up / move each frame.
**** EDIT ****
After a new comment - since you want to animate the values, all you need to do is store the current values, calculate the new ones, and animate the values using the internal animation system (documentation here - https://doc.babylonjs.com/babylon101/animations#basic-animation) . There are many ways to achieve this, I took an old function and modernized it :-)
Here is the demo - https://playground.babylonjs.com/#A1210C#53

Aframe How do I simulate a 6dof controller on the Oculus GO controller using the touchpad to move the controller forward, back, left, and right?

enter image description hereWhat if we could simulate 6dof control on the Oculus Go controller? Imagine that we turn the controller 3d model into a hand, it still just rotates, but imagine that we use the touchpad to move the hand foward, left, right, or backwards in space, the touch pad gives you movement along a z and x axis in space, but the accelerometer/gyro gives you a y and x axis. so the accelerometer/gyro serves as the arm, and the touch pad serves as the hand/wrist, a hand that can move forward and back and only twist left and right, and grip with the trigger, the hand can't tilt up or down but the arm can make up for that. So how do I build this?
There is https://www.npmjs.com/package/aframe-thumb-controls-component that provides events for pressing thumbpad in directions (e.g., thumbupstart, thumbleftend).
Write a component that listens to those events, sets a property (e.g., this.buttons.left = true, then the tick handler needs to update the this.el.object3D.position based on which buttons are held down.
Also need to take into consideration the direction the camera is facing. https://github.com/aframevr/aframe/blob/master/src/components/wasd-controls.js is a good starting point is it is similar, where it listens to key downs and translates position. Just need to modify to use thumb-controls instead.
More hints:
<script src="https://unpkg.com/aframe-thumb-controls-component#1.1.0/dist/aframe-thumb-controls-component.min.js">
AFRAME.registerComponent('thumb-movement-controls', {
init: function () {
this.buttons = {
left: false, right: false, up: false, down: false
};
this.el.addEventListener('thumbleftstart', () => {
this.buttons.left = true;
});
this.el.addEventListener('thumbleftend', () => {
this.buttons.left = false;
});
},
tick: function () {
// Really simplified movement. Does not take into account camera heading or velocity / time, but wasd-controls shows how.
if (this.buttons.left) {
this.el.position.x -= 0.001;
}
}
});
<a-entity daydream-controls thumb-controls thumb-movement-controls></a-entity>

aframe adjust camera rotation on mobile

Using Aframe how I can change the camera rotation manually so it works on mobile and still use look-controls?
I've tried via the html attribute like so:
document
.querySelector('[camera]')
.setAttribute('rotation', { x: 0, y: deg, z: 0 })
This works fine on desktop however on mobile the look-controls component seems to reset the camera rotation to previous value.
I've setup a demo the issue here, which changes rotation & disables look-controls. Then I set a timeout which re-ables look-controls after 1 sec. https://embed.plnkr.co/WA1rKucPk0cGffrbfrTh/
Pressing any of the html buttons rotates you to a an object and disables the look-controls. 1 sec later the control are re-abled. If you try this on mobile, you'll notice the camera rotates, then 1 sec its reverts when the look-controls are enabled.
Is there some offset I need to reset on mobile too, the lookcontrols.yawObject perhaps?
Put the camera inside an entity:
<a-entity rotation="0 0 0">
<a-camera></a-camera>
</a-entity>
Then rotate the entity instead of the camera.
you need to change the look-controls.js a little bit to make it works,because when on mobile it will not get rotation attribute from the camera entity
function updateOrientation in look-controls.js:
if (sceneEl.isMobile) {
// On mobile, do camera rotation with touch events and sensors.
rotation.x = radToDeg(hmdEuler.x) + radToDeg(pitchObject.rotation.x);
rotation.y = radToDeg(hmdEuler.y) + radToDeg(yawObject.rotation.y);
rotation.z = radToDeg(hmdEuler.z);
}

Three.js - how to make objects with different positions look at Orthographic camera using vectors?

Three.js 76
I start to use Orthographic camera instead Perspective - has some troubles.
I use stemkoski's shader-glow for point animation in scene: he created some sphere and then use shader for it transparancy, i just add animation to it.
function animatePoints() {
var alphas;
var count;
var time;
let j = 0;
while ( animatedPoints[j] ) {
let threeGlow = animatedPoints[j];
let finishAnimation = threeGlow.meta.state.finishAnimation;
let itFinished = 0;
let pointGlowMat = threeGlow.material;
let pointGlowGeom = threeGlow.geometry;
// ########## make glow look at camera
pointGlowMat.uniforms.viewVector.value = new THREE.Vector3().subVectors( threeGlow.position, camera.position);
alphas = pointGlowGeom.attributes.alpha;
count = alphas.count;
time = 0.001* Date.now();
if ( finishAnimation ) {
....
} else {
....
}
alphas.needsUpdate = true;
j++;
}
}
Main goal - to make glow look at camera. When camera was perspective i use solution with subtracts two vectors - camera position and glow position, so it look like glow looking at camera.
pointGlowMat.uniforms.viewVector.value = new THREE.Vector3().subVectors( camera.position, threeGlow.position );
But now, when i use Orthographic camera this solution doesn't work correctly.
The problem is that now the glow should look not at camera position point, it should look at plane of the camera.
I make some pic scheme for that situation:look it, it very useful
So for each new glow (it's positions of course different) i must get new red vector, to make each glow look at orto cam.
Any ideas?
What you need to do to get the red vector in your image, is project vector sub on the vector representing the direction in which the camera is looking.
I think this is what you need:
pointGlowMat.uniforms.viewVector.value = new THREE.Vector3()
.subVectors( camera.position, threeGlow.position )
.projectOnVector( camera.getWorldDirection() );
One way to make an object "look at" an orthographic camera by using this pattern:
object.quaternion.copy( camera.quaternion );
The object's view direction will be perpendicular to the camera's projection plane.
This approach is appropriate if neither the object nor the camera have a rotated parent.
three.js r.84

QGraphicsItem : emulating an item origin which is not the top left corner

My application is using Qt.
I have a class which is inheriting QGraphicsPixmapItem.
When applying transformations on these items (for instance, rotations), the origin of the item (or the pivot point) is always the top left corner.
I'd like to change this origin, so that, for instance, when setting the position of the item, this would put actually change the center of the pixmap.
Or, if I'm applying a rotation, the rotation's origin would be the center of the pixmap.
I haven't found a way to do it straight out of the box with Qt, so I thougth of reimplementing itemChange() like this :
QVariant JGraphicsPixmapItem::itemChange(GraphicsItemChange Change, const QVariant& rValue)
{
switch (Change)
{
case QGraphicsItem::ItemPositionHasChanged:
// Emulate a pivot point in the center of the image
this->translate(this->boundingRect().width() / 2,
this->boundingRect().height() / 2);
break;
case QGraphicsItem::ItemTransformHasChanged:
break;
}
return QGraphicsItem::itemChange(Change, rValue);
}
I thought this would work, as Qt's doc mentions that the position of an item and its transform matrix are two different concepts.
But it is not working.
Any idea ?
You're overthinking it. QGraphicsPixmapItem already has this functionality built in. See the setOffset method.
So to set the item origin at its centre, just do setOffset( -0.5 * QPointF( width(), height() ) ); every time you set the pixmap.
The Qt-documentation about rotating:
void QGraphicsItem::rotate ( qreal angle )
Rotates the current item
transformation angle degrees clockwise
around its origin. To translate around
an arbitrary point (x, y), you need to
combine translation and rotation with
setTransform().
Example:
// Rotate an item 45 degrees around (0, 0).
item->rotate(45);
// Rotate an item 45 degrees around (x, y).
item->setTransform(QTransform().translate(x, y).rotate(45).translate(-x, -y));
You need to create a rotate function, that translate the object to the parent's (0, 0) corner do the rotation and move the object to the original location.

Resources