I use camera.matrixWorld.decompose() to get the current matrix of the AR camera like the following:
var position = new THREE.Vector3();
var quaternion = new THREE.Quaternion();
var scale = new THREE.Vector3();
camera.matrixWorld.decompose(position, quaternion, scale);
They are initialized to default (e.g. {x:0, y:0, z:0} for the position) when I press the AR Button. (https://threejs.org/examples/jsm/webxr/ARButton.js)
I wonder if it's possible to reset the matrix while the app is running without having to go back and repressing the AR button.
More details:
I would like to know if it's possible to reset the AR camera position to [0, 0, 0] as if restarting the AR session. For example, if I start the app while putting my phone on my desk, that position will be [0, 0, 0] and I can see a cube positioned at [0, 0, -3]. And if I move to my bed, I will no longer see the cube in front of me because it's still on my desk. If I restart the app, then I can see the cube on my bed since the default position [0, 0, 0] is on my bed. I wonder if it would be possible for a user to press a button to reset the position to [0, 0, 0] without having to restart the app.
Related
I currently have a VR camera attached to a dolly in order to allow for translation and rotation.
I'm trying to translate the dolly, based on gamepad inputs, relative to the orientation of the camera (which is linked to a VR headset.)
I'm also trying to avoid letting the dolly pitch up or down relative to the camera.
My current code looks something like this:
this.camerDirectionVector = new THREE.Vector3()
this.camera.getWorldDirection(this.cameraDirectionVector)
this.moveVec.y = 0
this.dolly.translateOnAxis(this.cameraDirectionVector, this.gamepad.axes[0] * this.moveSpeed)
This works great for moving the dolly in the direction the camera is pointing (minus y rotation).
What I can't figure out is how to also translate the dolly "left and right" relative to the camera based off an additional gamepad input.
Based on the comments on the question, I think I understand. If I don't, please leave a comment, and I'll update this answer.
My understanding is that you want to be able to move left and right, with respect to the camera, all without altering the dolly's up direction.
This is actually easier than it sounds, and is even easier because you are already comfortable translating along an axis.
First, understand that the camera has its own spatial frame of reference, where it sits at the origin, with a +Y up direction, and it looks down the -Z axis. With this in mind, you already know the "left" and "right" axes: -X (-1, 0, 0) and +X (1, 0, 0).
But the camera (especially in VR) might not be so nicely aligned in world space, so you need to convert these nice uniform axes into world axes. Three.js makes this very easy using Object3D.localToWorld.
(Note: Object3D.localToWorld is destructive to the input Vector3.)
Here's a function to get the world-aligned left axis:
const getLeftWorld = (function(){
const localLeft = new THREE.Vector3(-1, 0, 0);
return function(vectorRef){ // you can give it a vector to overwrite
let out = vectorRef || new THREE.Vector3();
out.copy(localLeft);
camera.localToWorld(out);
return out;
};
))();
You can create a similar function for the "right" axis.
With your new world-aligned left axis in hand, you can translate the dolly along it, using the "speed" given by your controller input. Translation won't change the pitch of the dolly, though it may change the elevation, depending on how the camera is tipped at the time of computation (but you can just zero-out the y component like you did before, if you want).
This is the solution that ended up working best for me. I've adapted it from Brian Peiris code here: https://github.com/brianpeiris/three-firstperson-vr-controls/blob/master/FirstPersonVRControls.js#L125
// Create a dolly
this.dolly = new THREE.Group()
this.dolly.add(this.camera)
this.scene.add(this.dolly)
// Some variables for movement translations
this.dummy = new THREE.Object3D()
this.dummyDirection = new THREE.Vector3()
this.ZAXIS = new THREE.Vector3(0, 0, 1)
this.moveSpeed = 0.075
// Get controller stick positions
const stickForwardBack = this.leftStick[3]
const stickLeftRight = this.leftStick[2]
// In THREE.js when using the WebXR API, the camera rotation will not update to match the headset orientation.
// You'll need to get pose information from the XRSession or get the xr camera using the following method.
const xrCamera = globals.renderer.xr.getCamera(this.camera)
this.dummy.position.set(0, 0, 0)
this.dummy.quaternion.copy(xrCamera.quaternion)
this.collapseY(this.dummy.quaternion)
// Translate the dummy object forwards/backwards left/right relative to the direction the camera is facing
this.dummy.translateZ(stickForwardBack * this.moveSpeed)
this.dummy.translateX(stickLeftRight * this.moveSpeed)
// Add the dummy position to the dolly
this.dolly.position.add(this.dummy.position)
// Flatten out up and down rotation
collapseY(quaternion) {
this.dummyDirection.set(0, 0, 1)
this.dummyDirection.applyQuaternion(quaternion)
this.dummyDirection.y = 0
this.dummyDirection.normalize()
quaternion.setFromUnitVectors(this.ZAXIS, this.dummyDirection)
}
(Hello, it's my first ever post here)
here's what I'd like to incorporate in this simple example:
I would like to make the background turn from light to dark gradually when the user is closer to a particular orientation – in this case (example above) the desired orientation is a steep angle so that the foreshortened anamorphic image looks like a regular skull (the value of the background indicating the angle user should aim for – kind of like playing Hot and Cold)
when the user reaches the desired orientation (the background is then accordingly 100% dark) I would like it to lock rotation and trigger a video file in the background or a pop up window.
I assume it has to do with accessing the camera rotation values inside OrbitControls and setting some kind of an Event?? i have no idea how to access it.
Any kind of help, suggestions to edit the thread or explanation would be greatly appreciated, thank you so much in advance!
You could use camera.position to calculate the best vantage point. First, you have to figure out what the desired position is (I'm not sure how the wooden board is being placed, but this position seems to be close to: { x: 6.8, y: 0.6, z: -1.8})
var vantagePoint = new THREE.Vector3(6.8, 0.6, -1.8);
var distance = 100;
var normalized = 1;
var endColor = new THREE.Color(0xff9900);
var startColor = new THREE.Color(0x0099ff);
scene.background = startColor;
animate() {
distance = vantagePoint.distanceTo(camera.position);
normalized = THREE.Math.smoothstep(distance, 5, 100); // Converts [1, 100] => [0, 1]
// Resets the color on each frame
startColor.set(0x0099ff);
startColor.lerp(endColor, normalized);
}
The closer to 0 you are, the closer you are to seeing the skull. You can then use that value to change the color of scene.background. Anything beyond 10 and you're 'cold', and you get hotter as you approach 0.
https://threejs.org/docs/#api/en/math/Vector3.distanceTo
Update:
You can then transform the distance to a normalized value in the range of [0, 1] by using Math.smoothstep(). Then interpolate the value of the colors with this normalized value using Color.lerp
I'm trying to achieve same rotation as in scene editor but with code so object always rotate around selected axis, however if I look at angles(x,y,z) in editor they changes quite randomly
![Local node axis][1]
I've tried to use quaternions, but can't get it working
PS. my bad was using rotation property instead of orientation both SCNVector4, have read doc properly)
Seems you was really close, you had to swap parameters in GLKQuaternionMultiply call. I used solution in https://stackoverflow.com/a/39813058/4124265 to achieve rotation only by Z axis:
let orientation = modelNode.orientation
var glQuaternion = GLKQuaternionMake(orientation.x, orientation.y, orientation.z, orientation.w)
// Rotate around Z axis
let multiplier = GLKQuaternionMakeWithAngleAndAxis(0.5, 0, 0, 1)
glQuaternion = GLKQuaternionMultiply(glQuaternion, multiplier)
modelNode.orientation = SCNQuaternion(x: glQuaternion.x, y: glQuaternion.y, z: glQuaternion.z, w: glQuaternion.w)
To rotate arround Y:
// Rotate around Y axis
let multiplier = GLKQuaternionMakeWithAngleAndAxis(0.5, 0, 1, 0)
glQuaternion = GLKQuaternionMultiply(glQuaternion, multiplier)
By setting the rotation property, the absolute rotation of the object is changed, rather than the relative rotation.
Here's some pseudo code
Compute the quaternion represents the relative rotation. I would use the GLKQuaternionMakeWithAngleAndAxis function to do so.
Apply the rotation to the orientation property:
let initial_object_orientation = rotateNode.orientation;
new_orientation = GLKQuaternionMultiply(rotation_quaternion, initial_object_orientation)
Assign the new orientation
rotatNode.orientation = new_orientation
Hope it helps.
I would like to rotate an object on a certain angle along Y axis.
Based on this answer How to rotate a Three.js Vector3 around an axis? I suppose to get an updated vector.
My code is :
var vec = new THREE.Vector3( 0,0,0 );
var axis = new THREE.Vector3( 0,1,0 );
var angle = Math.PI / 2;
vec.applyAxisAngle( axis, angle );
I'm using r67 and it returns me 0,0,0. I've tried r69 as well and it is returns me the same. I'm not quiet ready to move to r69. Could you guys tell me please how to do the same thing but using r67. Thanks.
Your are rotating vector (0, 0, 0) which is center and whatever angle you use to rotate center around any axis you will always get (0, 0, 0). Just imagine you are doing simple 2d rotation. After all, rotation around Y axis can be viewed as 2d rotation in X-Z plane.
Try with some other values for vec variable, for example (1, 0, 0) or (0, 0, 1) and you will see results
I'm trying to enable a user to pan up/down and left/right an object in OpenGL ES. I'm using GLKit for all of the drawing and movement. I've enabled touch events to track how the user wants to move the object. I'm using GLKMatrix4Translate to slide the pan the object, but it has a rotational component to it as well for some reason.
I gather the translation points from the user's touch and store them in a CGPoint:
CGPoint center;
I use center.x and center.y for the X and Y positions I want to translate to. I perform the translation with this line:
GLKMatrix4 modelViewMatrix = GLKMatrix4Translate(GLKMatrix4Identity, center.x, center.y, 0.0f);
Any ideas?
I figured out what the problem was here. I stopped using GLKMatrix4Translate and replaced that with GLKMatrix4MakeLookAt. GLKMatrix4MakeLookAt allows you to move the camera around which gives the effect I was looking for.
Simply using this code results in the same problem I was already seeing. The model rotates as it pans.
GLKMatrix4MakeLookAt(0, 0, 7,
center.x, center.y 0,
0, 1, 0);
What this is saying is that you want the camera to always look at (0,0,7) with the center at (center.x, center.y, 0) with the y-axis pointing up. The pointing of the eye is the problem. If the model is rotating (which it is), you need to point the eye at the newly rotated point.
Replacing the above with the code below seems to do the trick.
GLKMatrix4MakeLookAt(rotation.x, rotation.y, 7,
center.x, center.y, 0,
0, 1, 0);