Three.JS, changing the world position of a child 3D object - javascript

So basically I have a child object3D of a group Object3D, while the child object's [x,y,z] coordinates are shown relative to the object space of the parent object, I want to change the location of the child object within the 3D space. So first I get the child object's position relative to the world space.
var wrld_pos = childobject.matrixWorld.multiplyVector3(new THREE.Vector3);
This returns a three element vector of the child's position within the world space. Now I wish to set the position my self. So I create a three element vector.
var new_pos = THREE.Vector3();
new_pos.x = 1;
new_pos.y = 2;
new_pos.z = 3;
childobject.matrixWorld.setPosition(new_pos);
Provided the function definition for setPosition, it essentially it sets the last three elements of the object's world matrix to the values of the vector passed as an argument, thus changing the location of the object in world space. And to make sure that the matrix updates after these changes, I call the following functions.
childobject.matrixWorldNeedsUpdate = true;
childobject.updateMatrixWorld();
Now upon inspecting the new world matrix of the object I noticed that the setPosition function did nothing, nothing at all.
Why? If real code examples are needed, I will provide them. But the above should represent the application domain and syntax I used very accurately.

EDIT: Answer updated.
You want to change the world position of a child object.
Assuming the scene has no transform applied, one way to do what you want is to use the following pattern:
scene.attach( child ); // detach from parent and add to scene
child.position.set( x, y, z );
parent.attach( child ); // reattach to original parent
The Object3D.attach( child ) method adds the child object, while maintaining the child's world transform.
three.js r.132

This answer might help with the case. Remove child from parent, change normal position, then attach again.

If use attach for setting position in animation loop for moving objects you can get objects shaking.
For me best solution is:
let newPosition = new THREE.Vector3(1,2,3);
let parentPosition = new THREE.Vector3();
childobject.parent.getWorldPosition(parentPosition);
childobject.position.set(
newPosition.x-parentPosition.x,
newPosition.y-parentPosition.y,
newPosition.z-parentPosition.z
);
If you need position and rotation attach is the only way.

Related

Raycasting after dynamically changing Mesh in Three.js

I have a mesh cloned from another mesh. But after cloning, I translate and rotate it. And do a ray-casting a point to it but it is not working as expected. It is keep intersecting with the original position before translation and rotation. Sample code is as below
const raycaster = THREE.Raycaster()
const proposedModel = model.clone()
proposedModel.translateX(1)
proposedModel.translateY(1)
proposedModel.translateZ(1)
const q = new THREE.Quaternion(
-0.847,
-0.002,
-0.505,
0.168
)
proposedModel.applyQuaternion(q)
const point = new THREE.Vector3(1,1,1)
raycaster.set(point, new THREE.Vector3(1,1,1))
const intersects = raycaster.intersectObject(object) // It keep intersecting with original position
Glad if any help, Thanks!
Call updateMatrixWorld() from the mesh after transformation will solve the problem. Credit to #prisoner849
proposedModel.updateMatrixWorld()
The reason is
An object's matrix stores the object's transformation relative to the
object's parent; to get the object's transformation in world
coordinates, you must access the object's Object3D.matrixWorld.
When either the parent or the child object's transformation changes,
you can request that the child object's matrixWorld be updated by
calling updateMatrixWorld().
Check detail here https://threejs.org/docs/#manual/introduction/Matrix-transformations

Three.js: how to force update matrix after cloning? (to use with CSG ThreeBSP)

I'm trying to clone and then scale a mesh, but scaling does not seem to be working immediately on the cloned object, for programming purposes using CSG ThreeBSP. I think I should call a function after the scaling to force the matrix or other internal variables to recalculate immediately and not to wait for the full update loop on render side.
My code looks something like this:
var someMesh2 = someMesh1.clone();
someMesh2.scale.set(2,2,2);
someProgrammingOperation(someMesh2);
//It turns out that internally, someMesh2 still has the same properties (matrix?) as someMesh1 :(
What am I missing? Suggestions are also welcomed :)
object.matrix is updated for you by the renderer whenever you call renderer.render().
If you need to update the object matrix manually, call
object.updateMatrix();
and it will update the matrix from the current values of object.position, object.quaternion, and object.scale.
(Note that object.rotation and object.quaternion remain synchronized. When you update one, the other updates automatically.)
three.js r.84
In the end, my problem was that the CSG ThreeBSP object needed to work based on the Geometry of the object, not in the Mesh itself. I applied the scaling on the Geometry and it worked as expected.
There is a caveat though, that one should be careful as with the meshes and geometries instances, therefore is needed to do some cloning in order to keep the original objects as they were, as in the following example:
var clonedMesh = original.mesh.clone()
var clonedGeometry = clonedMesh.geometry.clone()
clonedMesh.geometry = clonedGeometry
clonedMesh.geometry.scale(2,2,2)
var someBsp = new ThreeBSP( clonedMesh )
var newMesh = someBspBsp.toMesh()
someScene.add newMesh

Webgl three.js Dependency of several objects

I have a problem with the dependency of objects. I want to make one object dependent on two other objects. If I change the position of one parent object (for example the y-Position), the dependent object (the child object) should rotate und should also move.
Here is a link where I realized it on a picture. On the left side is the initial state, on the right side the changed condition. The Cylinder should be dependent on the two boxes. That means that the cylinder is the child object and the boxes should be both parent objects of this child object.
I tried it with using parent and child properties, but I could not make the child object dependent on two parent objects.
Can someone help me?
This is my current code, but the lookAt Function does not work correctly.
//cube 1
var cube=new THREE.BoxGeometry(4,4,4);
var material=new THREE.MeshBasicMaterial ({ color: 0xffffff });
mesh1=new THREE.Mesh(cube,material);
mesh1.position.set(-2,2,0);
scene.add(mesh1);
//cube 2
var cube2=new THREE.BoxGeometry(2,2,2);
var material=new THREE.MeshBasicMaterial ({ color:0x000000 });
mesh2=new THREE.Mesh(cube2,material);
mesh2.position.x=6;
mesh2.position.y=2;
//mesh2.position.y=-2;
scene.add(mesh2);
//cylinder
var cylinder=new THREE.CylinderGeometry(1,1,6,30);
var material=new THREE.MeshBasicMaterial({ color:0xff3399 });
mesh3=new THREE.Mesh(cylinder,material);
mesh1.add(mesh3);
mesh3.lookAt(mesh2.position);
You need to two levels of hierarchy, eg:
cube1.add(cylinder)
cylinder.add(cube2)
Yeah, 2pha is right actually. I think what he actually needs is something like this (note you'll need to scale the cylinder or move the squares unless they are exactly cylinder height apart):
cylinder.position.x=cube1.position.x
cylinder.position.y=cube1.position.y
cylinder.position.z=cube1.position.z
cylinder.lookAt(cube2.position)
You may be able to do what you're after with the lookAt function on the Object3D class.
eg.
Add your cylinder as a child of cube1 so moving cube1 will also move the cylinder.
cube1.add(cylinder)
then when cube1 (or / and cube2) is moved call the lookAt function on cylinder to look at the cube2's position.
cylinder.lookAt(cube2.position)

cesium - moving billboards

I am testing Cesiumjs to see if it can reflect a near-real-time expreience - for example: position of airplanes.
For that, I need to draw billboards and make them move - which I know is possible with cesium, just not sure how.
The code looks like this:
var billboards = scene.primitives.add(new Cesium.BillboardCollection());
var billboard = {
image : '/path/to/logo.png',
position : Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883)
};
billboards.add(billboard);
My question is how do I change the position of the billboard. I couldn't find ant documentation that would explain.
I thought doing:
billboard.position = ... //new position
but how will cesium know that I've changed the position attribute unless it somehow turns that reference into a observable object.
So how do I update the location?
Thanks.
Cesium does indeed listen for changes to billboard.position
(source code here), so it is correct behavior for apps to simply write a new position.
Note that you must write the whole position at once, meaning you may not write to billboard.position.x. Instead, keep a "scratch" Cartesian3 around (don't create a new one every animation frame at 60fps), write to the x,y,z properties of your scratch variable, and then assign your scratch variable to billboard.position. You can see in the source that the assigned value will be cloned into another pre-existing Cartesian3, so you may immediately reuse the scratch variable.
Here's an example:
// Just once at app startup. Don't call "new" at 60fps.
var scratchCartesian3 = new Cesium.Cartesian3();
var ellipsoid = viewer.scene.mapProjection.ellipsoid;
function onTick() {
// This is safe to call at 60fps.
billboard.position = Cesium.Cartesian3.fromDegrees(
lon, lat, alt, ellipsoid, scratchCartesian3);
}
Also note that your question and the above answer are focused on the "Graphics Primitive" layer of the Cesium API. Cesium has one higher layer, called the "Entity" API, that you can use if you want Cesium to handle the concept of user-selectable objects with pop-up descriptions etc. Here's a Sandcastle demo showing how to add a billboard as a property of an entity, instead of as a primitive. This allows you to add other properties to the same entity, for example a name, description, label, 3D model, etc, and have them all be controlled from the same position property, and have Cesium take care of popup descriptions. The position property is more complex for entities than for primitives, for example it can be constant or sampled. This allows entities to change position over time when the timeline is shown.

2D screen position from 3D position using three.js

I have some 3D objects within a rotating parent object.
I'm adding a set of 2D "hotspots" which follow these object's screen position. I got this to successfully convert the child object's position to 2D:
// HOTSPOTS //
var v1,m1,p,hotspotX,hotspotY;
v1 = new THREE.Vector3();
m1 = new THREE.Matrix4();
m1 = childObject.matrixWorld;
v1.setFromMatrixPosition(m1);
p = projector.projectVector(v1, camera1);
hotspotX = (p.x + 1) / 2;
hotspotY = (-p.y + 1) / 2;
The problem is that rather than using the child object's origin as the hotspot location, I'd like to set it relative of it, i.e the hotspot's y might be childObject.y-10. I think this needs to happen prior to converting to matrix. Is there a way to do the same as matrixWorld, but from a vector instead of an object?
I could just create extra empty objects for each hotspot and set their positions exactly where I want them, however seeing as the childObjects are already there I'd rather use those if I can. All previous examples I've found use functions which are now deprecated. Hope this makes sense, I'm new to matrices.
Thanks!

Categories