Apply quaternion is not a function - javascript

I need some light on this question I'm trying to set vertices of a geometry using a quaternion and
geometry.attributes.position.array[x].applyQuaternion(quaternion)
is not working as expected
I know this implementation as changed in the passed and I suspect that the problem is that
geometry.vertices[x]
is not available anymore
some one on this ?

The method .applyQuaternion() is only available in Vector3(), not in a simple number. You cannot perform 7.applyQuaternion() with a number. In this context, it doesn't make sense to apply a 3D rotation to a 1-dimensional value.
First, make sure you create a Vector3 with the XYZ coordinates of the vertex you're trying to manipulate by using the BufferAttribute.get... method:
// Create quaternion
const quat = new THREE.Quaternion();
quat.setFromAxisAngle( /* ... */ );
// Position attribute
const posAttrib = geometry.getAttribute('position');
// Let's get the XYZ components of the 7th vertex in the geometry
const twistVec = new THREE.Vector3(
posAttrib.getX(7),
posAttrib.getY(7),
posAttrib.getZ(7)
);
// Now that you've created a Vec3, you CAN apply a quaternion
twistVec.applyQuaternion(quat);

Related

Get object position in a three.js scene dynamically

I am new to threejs.
I have scene with an object in it which we can move around the scene on all the XYZ Axis using TransformControls.js.
When I translate/move the object inside the scene using mouse click and drag on any of the axis (i.e X,Y,Z). I want to get the updated X,Y,Z position co-ordinates of that particular object inside the scene.
I use mesh.position.set( 0, 0, 0 ); to set position of the object prior rendering the scene, But I am not able to find how to get the dynamic position of an object inside a scene.
Eventually I want to save the updated position co-ordinates after the transform operation and re-render the scene with the object at the updated position co-ordinates when the user comes back to the page or does a page refresh.
Any pointers would be very helpful.
Thank you
THREE.TransformControls requires a few steps to use.
Create your THREE.TransformControls object
Add it to your scene
Attach it to the object you wish to manipulate
var xformControl = new THREE.TransformControls(camera, renderer.domElement);
scene.add(xformControls);
// assuming you add "myObj" to your scene...
xformControl.attach(myObj);
// and then later...
xformControl.detatch();
Attaching the control to an object will insert a manipulation "gizmo" into the scene. Dragging the various parts of the gizmo will perform different kinds of transformations. After you are done transforming the part with the gizmo, checking mesh.position should reflect the new position.
Additional information for clarity:
The position of the object will not be updated until you use the "gizmo" to move it. Example:
Your object is in the scene at (10, 10, 10)
xformControl.attach(yourObject)
The "gizmo" is created at (10, 10, 10)
Your object remains at (10, 10, 10)
Use the "gizmo" to translate the object in +Y direction
Your object will now have an updated position
console.log(yourObject.position.y > 10); // true
I might be too late, but you can get the updated value by using TransformControls' objectChange event.
Example code:
const transformControls = new TransformControls(camera, renderer.domElement);
transformControls.addEventListener('objectChange', (e) => {
console.log(e.target.object.position.x);
})
first answer is not correct, it should be:
onst transformControls = new TransformControls(camera, renderer.domElement);
transformControls.addEventListener('objectChange', (e) => {
console.log(e.target.object.position.x);
})

How to Change a Box's dimensions/size after creation?

One can easily create a THREE.BoxGeometry where you have to pass arguments when creating as three separated arguments for width, height, and depth.
I would like to create any and all THREE[types]() with no parameters and set the values after that.
Is there a way to set the dimensions/size of the box geometry after creation (possibly buried in a Mesh already too)? other then scaling etc.
I couldn't find this in the documentation if so, otherwise maybe a major feature request if not a bug there. Any thoughts on how to classify this? maybe just a documentation change.
If you want to scale a mesh, you have two choices: scale the mesh
mesh.scale.set( x, y, z );
or scale the mesh's geometry
mesh.geometry.scale( x, y, z );
The first method modifies the mesh's matrix transform.
The second method modifies the vertices of the geometry.
Look at the source code so you understand what each scale method is doing.
three.js r.73
When you instantiate a BoxGeometry object, or any other geometry for that matter, the vertices and such buffers are created on the spot using the parameters provided. As such, it is not possible to simply change a property of the geometry and have the vertices update; the entire object must be re-instantiated.
You will need to create your geometries as you have the parameters for them available. You can however create meshes without geometries, add them to a scene, and update the mesh's geometry property once you have enough information to instantiate the object. If not that, you could also set a default value at first and then scale to reach your target.
Technically, scaling only creates the illusion of an updated geometry and the question did say (other then scaling). So, I would say a better approach would be to reassign the geometry property of your mesh to a new geometry.
mesh.geometry = new THREE.BoxGeometry(newSize, newSize, newSize)
With this approach you can update any aspect of the geometry including width segments for example. This is especially useful when working with non box geometries like cylinders or spheres.
Here is a full working example using this approach:
let size = 10
let newSize = 20
// Create a blank geometry and make a mesh from it.
let geometry = new THREE.BoxGeometry()
let material = new THREE.MeshNormalMaterial()
let mesh = new THREE.Mesh(geometry, material)
// Adding this mesh to the scene won't display anything because ...
// the geometry has no parameters yet.
scene.add(mesh)
// Unless you intend to reuse your old geometry dispose of it...
// this will significantly reduce memory footprint.
mesh.geometry.dispose()
// Update the mesh geometry to a new geometry with whatever parameters you desire.
// You will now see these changes reflected in the scene.
mesh.geometry = new THREE.BoxGeometry(size, size, size)
// You can update the geometry as many times as you like.
// This can be done before or after adding the mesh to the scene.
mesh.geometry = new THREE.BoxGeometry(newSize, newSize, newSize)

Rotate object around the world axis

I found several different supposedly working ways to rotate an object around the world axis but all of them kept rotating the object around it's own axis instead of rotating it around the world's. So, what's the proper way to rotate an object around the world's axis?
If I wasn't clear about the problem here's a drawing that represents my problem
Edit: Sorry I should have specificated in the question as well that I'm using Three.js
Edit2:
//camera is the object I want to rotate
//I also found a method that uses Euler but the result was far from the expected
/**Method 1**/
//Found this somewhere here in so
var rotateAroundWorldAxis = function(object, axis, radians) {
var rotWorldMatrix;
rotWorldMatrix = new THREE.Matrix4();
rotWorldMatrix.makeRotationAxis(axis.normalize(), radians);
rotWorldMatrix.multiply(object.matrix);
object.matrix = rotWorldMatrix;
object.rotation.setFromRotationMatrix(object.matrix);
}
//this is how I call the method
rotateAroundWorldAxis(camera, new THREE.Vector3(0,1,0), movementX*-0.001);
rotateAroundWorldAxis(camera, new THREE.Vector3(1,0,0), movementY*-0.001);
/**Method 1**/
/**Method 2**/
//I've also tried this method
var q = new THREE.Quaternion();
q.setFromAxisAngle( new THREE.Vector3(0,1,0), movementX*-0.001 ); // axis must be normalized, angle in radians
camera.quaternion.multiplyQuaternions( q, camera.quaternion );
/**Method 2**/
//movementX and movementY are values provided by the mouse movement using the pointerlock.
//These values works as I've tried them using rotateOnAxis
Use quaternions.
var rotateAroundWorldAxis = function(object, axis, radians) {
var rotation = new THREE.Quaternion();
rotation.setFromAxisAngle ( axis, radians );
object.quaternion.multiply(rotation);
}
rotateAroundWorldAxis(myObject, THREE.Vector3(0,1,0), movementX*-0.001);
I believe your problem before with the quaternion method is multiplying the quaternions in the wrong order so you rotate around global the Y axis, then perform the local rotation, which ultimately rotates in the local Y axis.
I ended up using the FirstPersonControls class. I had to make a few changes to the class though

Issue aligning faces in Three.JS from two seperate objects

I'm having an issue in my three.js code.
I am trying to align two objects by selecting two faces and have the second face (and object) rotate to match the normal vector of the first object's selected face.
So far I have:
var normalMatrix = new THREE.Matrix3().getNormalMatrix( object.matrixWorld );
var worldNormal = face.normal.clone().applyMatrix3( normalMatrix ).normalize();
var normalMatrixRef = new THREE.Matrix3().getNormalMatrix( objectRef.matrixWorld );
var worldNormalRef = faceRef.normal.clone().applyMatrix3( normalMatrixRef).normalize();
where: object is my object that will be rotated, face is the selected face of that object, objectRef is the stationary object reference and faceRef is the normal of the object I want to match.
Prior to doing
object.lookAt(worldNormalRef);
, I am trying either
object.up = new THREE.Vector3(0,0,1);
object.up = worldNormal;
object.up = face.normal;
and neither work.
Either object.up cases are not working as they should. When I do the action, the target object (the one to be rotated) does rotate, but does not align the faces correctly. It is arbitrary but somehow is linked to objects current rotation (ie: sometimes it rotates along (0,1,0) or simliar, othertimes if I pre-rotate the object it just rotates a slight bit.
In theory lookAt uses a world vector which my faceRef is, and as long as I set the 'up' correctly, it should work but it dosen't.
Any ideas?
I found the issue in my code, I hope it can help somebody in the future.
The
object.lookAt(worldNormalRef);
needs instead to be modified to add the new face normals to the current object's postition for the lookAt to function correctly:
//create a point to lookAt
var newPoint = new THREE.Vector3(
object.position.x + worldNormalRef.x,
object.position.y + worldNormalRef.y,
object.position.z + worldNormalRef.z
);
object.up = face.normal;//Z axis up
object.lookAt(newPoint );
Also note that the object.up should be set as above to the face.normal (the face I want to align to the reference object's face), and not to the worldNormal set above (I will delete this part of my code).

three js getting coordinates of mesh.lookAt(object);

I have scene,meshes and target object.
When i set up
mesh.lookAt(object)
mesh correctly facing of object.
How can i repeat this rotation of mesh on another mesh, to force another mesh facing the same direction (not the same object, but the same orientation as a first mesh have)?
How can i get rotation coordinates of first mesh?
How can i get this coordinates without need of creating mesh and order mesh.lookAt(object). That mean only to calculate this coordinates without need to use it on some object?
UPDATE:
Only possible solution is to create new THREE.Object3D() and use object.lookAt(target). Then repeat rotation for all later loaded object like: new_object.rotation.set(object.rotation.x,object.rotation.y,object.rotation.z)
You will create only one Object, not a lot of unuseful Vector3-s.
Do not use new_object.rotation = object.rotation it is functional solution, but a variables stay connected. Change of object rotation, will update new_object.rotation too (renderer is updating all values each frame).
You can set the local rotation of the other meshes to the local rotation of the mech facing in the correct direction.
anyOtherMesh.rotation = mesh.rotation;
what about a
lookAt( new THREE.Vector3( target.position.x, target.position.y, target.position.z )
?

Categories

Resources