I'm new on Three.js and despite a mechanical background, I can't find how quaternion works: it's like it always refers on local part referential and not the global one.
I've illustrated it here : http://jsfiddle.net/ehsktuj2/10/
function applyRotation(){
var redRotationQuaternion = new THREE.Quaternion();
redRotationQuaternion.setFromAxisAngle( new THREE.Vector3( 0, 1, 0 ), control.rotationSpeedRedY );
applyQuaternion(_cubeRed, redRotationQuaternion);
var greenRotationQuaternion = new THREE.Quaternion();
greenRotationQuaternion.setFromAxisAngle( new THREE.Vector3( 0, 0, 1 ), control.rotationSpeedGreenZ );
applyQuaternion(_cubeGreen, greenRotationQuaternion);
}
function applyQuaternion(cube, quaternion){
var cubeQuaternion = cube.quaternion;
cubeQuaternion.multiplyQuaternions(quaternion, cubeQuaternion);
cubeQuaternion.normalize();
}
The rotation quaternion of the green box is via the vector (0,0,1) but it's not in the global referential, it's the one of the projected referential of the green cube.
How can I project the quaternion back on the global referential? So that the green cube rotates via the (0,0,1) vector of the scene?
Related
I want to rotate a bone so it is aligned with a Vector3 (directionToTarget), I have:
const directionToTarget = new THREE.Vector3(random, random, random); //pseudocode randoms
directionToTarget.normalize();
var Hand2worldQ = new THREE.Quaternion();
this._anchor['LeftHandIndex1'].getWorldQuaternion(Hand2worldQ); // gets Lefthand bone quaternion
this._mesh.skeleton.bones[ 0 ].quaternion.set( SomeFunctionThatMakesVecintoQuarternion(directionToTarget );
// this._mesh.skeleton.bones inherits Hand2worldQ/LeftHand rotation
SomeFunctionThatMakesVec3intoQuarternion(directionToTarget ) is what i need
Object3D starts by looking down the 0, 0, 1 axis. You can use the Object3D.lookAt() method to make this object point towards your target vector. Then you can extract that rotation and use it for whatever else you need:
// Initialize an abstract object looking towards 0, 0, 1
const object3D = new THREE.Object3D();
// Rotate it so it looks towards the target xyz coordinates
object3D.lookAt(randomX, randomY, randomZ);
// This will now have the final rotation
const myQuaternion = object3D.quaternion;
console.log(myQuaternion);
So the inputs are three euler angles x,y,z in radians
I would like to convert this to a Vector location X,Y,Z with center as origin.
So if its possible to use https://threejs.org/docs/#api/en/math/Euler.toVector3 to get the Vector, i would like to know how. And also the alternate mathematical(sin/cos) solution is also appreciated.
so in this snippet axesHelper represents the angle and the cube should be at the location based on the euler.Use Dat gui to live edit the rotations.
//add Axis to represent Euler
const axesHelper = new THREE.AxesHelper( 5 );
scene.add( axesHelper );
//add cube to represent Vector
const geometry = new THREE.BoxGeometry( 0.1, 0.1, 0.1 );
const material = new THREE.MeshBasicMaterial( {color: 0x00ff00} );
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );
render()
const gui = new GUI();
const angles={
degX:0,
degY:0,
degZ:0,
}
gui.add( angles, 'degX',0,360,1 ).onChange(function(){
axesHelper.rotation.x=THREE.MathUtils.degToRad(angles.degX)
render()
updateEULtoAngle()
});
gui.add( angles, 'degY',0,360,1 ).onChange(function(){
axesHelper.rotation.y=THREE.MathUtils.degToRad(angles.degY)
render()
updateEULtoAngle()
});
gui.add( angles, 'degZ',0,360,1 ).onChange(function(){
axesHelper.rotation.z=THREE.MathUtils.degToRad(angles.degZ)
render()
updateEULtoAngle()
});
console.log(THREE.MathUtils.radToDeg( axesHelper.rotation.x))
console.log(THREE.MathUtils.radToDeg( axesHelper.rotation.y))
console.log(THREE.MathUtils.radToDeg( axesHelper.rotation.z))
function updateEULtoAngle(){
let eul= new THREE.Euler(
THREE.MathUtils.degToRad(angles.degX),
THREE.MathUtils.degToRad(angles.degY),
THREE.MathUtils.degToRad(angles.degZ)
)
let vec= new THREE.Vector3()
eul.toVector3(vec)
console.log(eul,vec)
cube.position.copy(vec)
}
fake visual representation
cube following the axes Y axis
related: but has problem with axis matching How to convert Euler angles to directional vector?
Euler.toVector3() does not do what you are looking for. It just copies the x, y and z angles into the respective vector components.
I think you should have a look at THREE.Spherical which is an implementation for using spherical coordinates. You can express a point in 3D space with two angles (phi and theta) and a radius. It's then possible to use these data to setup an instance of Vector3 via Vector3.setFromSpherical() or Vector3.setFromSphericalCoords().
im very not sure whats going on but
let vec = new THREE.Vector3(0, 0, 1).applyEuler(eul)
worked for me
also check this:
https://github.com/mrdoob/three.js/issues/1606
I'm trying to make a box in THREE that represents a box of 2x4 Legos, 24 pieces wide by 48 pieces long and and arbitrary number of pieces tall. I've generated a texture that shows this pattern using random colors:
I need to show two sides this cube, but the textures have to align so that the pieces on the edges are the same colors, like so (generated in Blender):
I'd really prefer not to make six images for a CubeTexture, particularly since four are not visible. Is it possible to flip the texture on one side so that they appear to align? (We're just going for visual effect here.)
Further, not all 3D rectangles will be cubes, but I can't quite figure out how to set the texture.repeat.x and texture.repeat.y so that the x is scaled correctly and the y is at the same scale, but just cuts off when the height of the object ends, like so:
Thanks!
You can flip an image by flipping the UVs.
You'll need to figure out which UVs correspond to the face you're trying to mirror, and which direction to flip them (not sure how your geometry is created).
Here's an example using a basic BoxBufferGeometry and modifying its uv attribute. (The face on the right is the mirrored-by-UV-flipping face.)
var textureURL = "https://upload.wikimedia.org/wikipedia/commons/0/02/Triangular_hebesphenorotunda.png";
// attribution and license here: https://commons.wikimedia.org/wiki/File:Triangular_hebesphenorotunda.png
var renderer = new THREE.WebGLRenderer({antialias:true});
document.body.appendChild(renderer.domElement);
renderer.setSize(500, 500);
var textureLoader = new THREE.TextureLoader();
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(28, 1, 1, 1000);
camera.position.set(50, 25, 50);
camera.lookAt(scene.position);
scene.add(camera);
camera.add(new THREE.PointLight(0xffffff, 1, Infinity));
var cubeGeo = new THREE.BoxBufferGeometry(20, 20, 20);
var uvs = cubeGeo.attributes.uv;
// originally:
// [0] = 0,1
// [1] = 1,1
// [2] = 0,0
// [3] = 1,0
// convert to:
// [0] = 1,1
// [1] = 0,1
// [2] = 1,0
// [3] = 0.0
uvs.setX(0, 1);
uvs.setY(0, 1);
uvs.setX(1, 0);
uvs.setY(1, 1);
uvs.setX(2, 1);
uvs.setY(2, 0);
uvs.setX(3, 0);
uvs.setY(3, 0);
uvs.needsUpdate = true;
var mat = new THREE.MeshLambertMaterial({
color: "white",
map: textureLoader.load(textureURL, function(){
animate();
})
});
var mesh = new THREE.Mesh(cubeGeo, mat);
scene.add(mesh);
function render() {
renderer.render(scene, camera);
}
function animate() {
requestAnimationFrame(animate);
render();
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/91/three.min.js"></script>
You can create six PlaneBufferGeometries assign the same material, and then position them to form a cube. Rotate them in 90deg increments until you reach the desired result. For performance reasons, you could merge these back into a single BufferGeometry.
You can export the model you made in blender, either using the THREE.js json exporter, or a format like OBJ or GLTF, and load and render it directly.
What you are talking about is simply having the UV's laid out the way you have them in blender.. so if you need that level of control.. it's probably easier to just load the model instead of trying to generate it.
If you use either three.js .json or .gltf, both exporters have an option to embed the textures directly in the export. This can make it easier to get things working quicker, at the expense of possibly less efficient storage.
Currently I am developing a FPS with three.js and pointerlockcontrols.
Using the code below I can shoot into any horizontal direction:
var direction = new THREE.Vector3( 0, 0, -1 );
var rotation = new THREE.Euler( 0, 0, 0, "XYZ" );
var cameraDirection = new THREE.Vector3(this.game.usermodel.root.children[0].position.x, this.game.usermodel.root.children[0].rotation._x, this.game.usermodel.root.children[0].position.z);
cameraDirection.copy( direction ).applyEuler( this.game.user.rotation );
var raycaster = new THREE.Raycaster(this.game.usermodel.root.children[0].position, cameraDirection);
But my code doesn't take the y-axis into account. The line below holds the pitch rotation:
this.game.usermodel.root.children[0].rotation._x
How can I apply this value so I can shoot along the y-axis (vertically into any direction) as well? Currently the bullet is going along a straight line.
Thanks in advance for your assistance.
If you are using PointerLockControls and you want to set a raycaster, you can use this pattern:
var direction = new THREE.Vector3();
var raycaster = new THREE.Raycaster(); // create once and reuse
...
controls.getDirection( direction );
raycater.set( controls.getObject().position, direction );
Do not set the camera position or rotation directly if you are using PointerLockControls.
three.js r.71
Investigating this a bit more, I finally came up with a workaround myself. It might not be the perfect way to do this, but it works.
It now works like this: I'm getting the basic mesh rotation and apply the euler, I then add the pitch rotation. In this way I pass the horizontal and vertical rotation into the raycaster.
var direction = new THREE.Vector3( 0, 0, -1 );
direction.copy( direction ).applyEuler( this.game.user.rotation );
direction.y = this.game.usermodel.root.children[0].rotation._x;
var raycaster = new THREE.Raycaster(this.game.usermodel.root.children[0].position, direction);
Everyone is still welcome to comment on this or come up with a more elegant solution.
I don’t understand how normals are computed in threejs.
Here is my problem :
I create a simple plane
var plane = new THREE.PlaneGeometry(10, 100, 10, 10);
var material = new THREE.MeshBasicMaterial();
material.setValues({side: THREE.DoubleSide, color: 0xaabbcc});
var mesh = new THREE.Mesh(plane, material);
mesh.rotateY(Math.PI / 2);
scene.add(mesh);
When I read the normal of this plane, I get (0, 0, 1).
But the plane is parallel to the z axis so the value is wrong.
I tried adding
mesh.geometry.computeFaceNormals();
mesh.geometry.computeVertexNormals();
but I still get the same result.
Did I miss anything ?
How can I get correct values for normals from threejs ?
Thanks.
Geometry normals are in object space. To transform them to world space, first make sure the object matrix is updated.
object.updateMatrixWorld();
(The renderer does this for you in each render loop, so you may be able to skip this step.)
Then, compute the normal matrix:
var normalMatrix = new THREE.Matrix3().getNormalMatrix( object.matrixWorld );
Now transform the normal to world space like so:
var newNormal = normal.clone().applyMatrix3( normalMatrix ).normalize();
three.js r.66