Access VR headset orientation in Three.js - three.js

How can I access the VR headset orientation in Three.js? The WebXRManager doesn't seem to provide a way to do this.

You can extract the orientation from the camera used for rendering the scene. Try the following when presenting:
const position = new THREE.Vector3();
const rotation = new THREE.Quaternion();
const scale = new THREE.Vector3();
// the following line extracts the position, rotation and scale in world space
camera.matrixWorld.decompose( position, rotation, scale );

Related

Three.js: How to rotate a Sphere on Axis using camera rotation values

I have a special control called SphericalControls. Its similar to OrbitControls, but it keeps camera at position 0,0,0 and instead rotates camera on x and y to look around a scene. It is placed in the middle of a SphereBufferGeometry which has a 360 equirectangular image projected upon it. The user can look around the 360 image, and as he does the camera x and y rotation values change.
When a user clicks a button, I need to take these x and y rotation values and rotate the sphere to the rotation of the camera. I then set camera back to x:0 and y:0.
The result is that the camera is reset and the 360 scene has now rotated to show the same rotation view that the camera was previously looking at. So to the user, the view stays basically static, just the values for camera.rotation and sphere rotation have swapped.
This works great if I offset the texture on the sphere:
sphereObj.material.map.wrapS = THREE.RepeatWrapping;
sphereObj.material.map.offset.x = ((camera.rotation.x) / (Math.PI * 2));
sphereObj.material.map.needsUpdate = true;
sphereObj.material.needsUpdate = true;
camera.rotation.set(0, 0);
// Success!
But what I need to do is not offset the texture, but rotate the entire geometry. I have tried:
var axis = new THREE.Vector3(0, 1, 0).normalize();;
var offsetRadian = ((camera.rotation.x) / (Math.PI * 2));
sphere.rotateOnAxis(axis, offsetRadian);
// Fail
But the result is that the sphere rotation is off by approx 30%. Any help is appreciated.
Every objects' rotational data is stored in their respective .quaternion object. Both camera and sphereObj have a quaternion, so what you could do is copy the camera's rotational data into the sphere:
// Get camera's rotation
targetRotation = camera.quaternion;
// Invert rotation
targetRotation.inverse();
// Set sphere's rotation
sphereObj.quaternion.copy(targetRotation);
camera.rotation.set(0, 0, 0);
I'm not entirely sure if you need the .inverse() line... if you're noticing the sphere is rotating in the opposite direction, just get rid of it to get the desired result.

Rotate orthographic camera (shadow camera) in Three.js

I'm trying to rotate a shadow camera by 45 degrees. I've managed to rotate the directional light it's attached to using the following code:
sunlight = new THREE.DirectionalLight(0xffffff, 1);
sunlight.position.x = -camera.position.x ;
sunlight.position.y = 300;
sunlight.position.z = camera.position.z ; //default; light shining from top
var vector = new THREE.Vector3;
vector.subVectors(scene.position, sunlight.position);
var q = new THREE.Quaternion();
q.setFromAxisAngle( vector.normalize(), Math.PI / 4 );
sunlight.applyQuaternion( q );
However the shadow camera does not rotate with the light as I'd expected. Trying to rotate the shadow camera itself using the same code does not work. How do I rotate an orthographic camera around its center point?
In the attached image the shadow camera can be seen as the orange square. The light is the black square, seen rotated 45 degrees. I need to apply the same rotation to the orange square as well, so the blue arrow is pointing north west.
Thanks in advance.
Directional lights in THREE.js don't behave like you'd expect. There is a light.target Vector3 parameter that the light Always points to.. so changing the lights rotation won't really do much. Try changing light.target to aim the light. To affect the roll of the shadow camera, you may be able to set the order of its euler with camera.rotation.order = "ZYX". Let me know if this helps.
#Joe Morgan

Lens Flare strange rotation while rotating camera

While rotating camera, lens flare has some rotation based on camera angle, please see this fiddle: http://jsfiddle.net/e4kf3u7t/1/
I want to avoid that, making lens flare always facing camera without rotation, like Sprite behavior: http://jsfiddle.net/e4kf3u7t/3/
Sample code:
var flareColor = new THREE.Color( 0xffffff );
var lensFlare = new THREE.LensFlare( textureFlare0, 200, 0.0, THREE.NormalBlending, flareColor );
lensFlare.position.y = 100;
lensFlare.position.z = 200;
scene.add(lensFlare);
The reason why I want to use Lensflare instead of Sprite is as you can see in fiddle, lens flare disappearing when it center hiding behind another geometry, Sprite doesn't act like that.

Artifacting/shaking occuring for THREE.Sprite() when animating orthographic camera

I've gotten sprites to work fine in my game engine, but I'm noticing some odd issues when moving the camera. Mainly, the sprites' pixels kind of 'shake' or go 'wavey' when the camera moves. You can see an example of this here (please watch in HD) http://youtu.be/om3EhKsGd9M
I'm setting the following properties on my sprite texture and sprite material, and my textures are 64 x 64 pixels in size:
spriteTexture.magFilter = THREE.NearestFilter;
spriteTexture.minFilter = THREE.NearestMipMapNearestFilter;
var spriteMaterial = new THREE.SpriteMaterial(
{
map:sheet,
useScreenCoordinates:true,
transparent:true,
side:THREE.DoubleSide,
});
Any ideas on a solution for this issue? I'd wager that this is somehow related to how the sprites are rendered when mapped into 3D space.

How do I use a Canvas texture on a 3D polygon face that is not a rectangle

I have a mesh with plane geometry that I texture with a 2D canvas element. This is working perfectly.
var landTexture = new THREE.Texture(land.canvas); // animated canvas element
var material = new THREE.MeshLambertMaterial({map: landTexture});
var plane = new THREE.Mesh( new THREE.PlaneGeometry( this.land_width, this.land_height ), material );
landTexture.needsUpdate = true;
landObject.add(plane);
The 2D canvas has an animated pattern which I want to use as a texture on a pentagon instead of a plane. How do I go about texturing more complex polygons, e.g. a pentagon, with a 2D canvas texture?
Edit: how I generate the pentagon
var pentagon = new THREE.Mesh( new THREE.CircleGeometry(this.land_width, 5), material );
Screenshot of the animated texture on PlaneGeometry and the same texture on a CircleGeometry with 5 sides. Notice the "stretched" canvas texture on the pentagon, which is not what I want. It should fit proportionally.
I think that the UVs are already set so that code such as:
var grid = new THREE.ImageUtils.loadTexture( 'images/uvgrid01.jpg' );
var pentagon = new THREE.Mesh( new THREE.CircleGeometry(50, 5), new THREE.MeshBasicMaterial({map:grid}) );
when the grid is the image:
will produce an image like:
Is that what you're looking for? Then all that is left is to update the texture repeatedly, and each time this is done, set the flag to update the material. I can go into more detail, but I would need to know how the canvas is being animated.

Resources