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!
Related
I am new to three.js. I was wondering if there is a function like move towards from unity in it? A function that we can use to move our object from it's current position to some Vector3.
Thanks.
I actually managed to solve this.
Here it is for anyone else stuck on this.
But you have to make sure that the object is a child of a THREE.Group and you move the THREE.Group instead of the object because the function doesn't behave right if the object's rotation is changed.
var targetPosition = new THREE.Vector3(x,y,z);
var objectToMove;
var group = new THREE.Group();
group.add(objectToMove);
var targetNormalizedVector = new THREE.Vector3(0,0,0);
targetNormalizedVector.x = targetPosition.x - group.position.x;
targetNormalizedVector.y = targetPosition.y - group.position.y;
targetNormalizedVector.z = targetPosition.z - group.position.z;
targetNormalizedVector.normalize()
Then you can use this line anywhere to move the object towards the target position.
group.translateOnAxis(targetNormalizedVector,speed);
This will work similar to the Vector3.MoveTowards function in unity. Just make sure the rotation of the THREE.Group is always set to 0 on x,y and z.
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
I am using JSModeler to display OBJ files. It internally uses THREE.JS and creates a PerspectiveCamera. What I need is to limit the movement of the camera on the Y axis so not to go underneath the object. I know how to do this with THREE.OrbitControls but this doesn't work with JSModeler. Is there a way to directly control the camera movement? Thanks.
jsmodeler creates its own set of controls which it stores in JSM.navigation object.
viewer = new JSM.ThreeViewer ();
camera_object = viewer.navigation.camera
The drawLoop function takes in values in this viewer.navigation.camera and renders them on the canvas. So, suppose if you change the values in the viewer.navigation.camera, and call drawCallback(), the changes would get rendered.
viewer.navigation.camera.eye.x = 1; // Any value you want
viewer.navigation.camera.eye.y = 1; // Any value you want
viewer.navigation.camera.eye.z = 1; // Any value you want
viewer.navigation.drawCallback();
I'm trying to track the position of an object so I can draw a trail behind it in p5.js.
I'm moving the object around the screen with the translate() and rotate() functions, and in order to draw a trail I was going to store the object's position after each update in an array. I'm aware there was something like what I'm asking for in processing 3, the model X, Y and Z functions, but as far as I can tell these haven't been implemented in the javascript version yet.
Even accessing the canvas's current transform matrix is proving problematic, and at this point I'm considering a redesign to omit the transform part of the api until this functionality is added.
So my question basically is: is there any way to determine the screen(canvas) coordinates of (0, 0) after applying a bunch of transforms?
I have a solution for this problem here:
https://github.com/ChristerNilsson/Transformer
The drawingContext actually tracks this, you can query it and map back to p5 coordinates. If you're not needing this in an inner loop it will likely be cheaper than tracking everything in a extra stack paralleling what the Canvas engine is doing anyway. And this is defined by the spec, so you can rely on it.
https://html.spec.whatwg.org/multipage/canvas.html#transformations (see the end of this chapter where the transformation semantics are defined).
2D version:
// a c e
// b d f
// 0 0 1
// x_new = a x + c y + e
// y_new = b x + d y + f
// origin - current point - is then at:
// x = a.0 + c.0 + e = e
// y = b.0 + c.0 + f = f
// However, the context has media coordinates, not p5. taking
// the distance between points lets use determine the
// scale assuming x and y scaling is the same.
let matrix = drawingContext.getTransform();
let x_0 = matrix['e'];
let y_0 = matrix['f'];
let x_1 = matrix['a'] + matrix['e'];
let y_1 = matrix['b'] + matrix['f'];
let media_per_unit = dist(x_0, y_0, x_1, y_1);
let p5_current_x = x_0 / media_per_unit;
let p5_current_y = y_0 / media_per_unit;
You should make all the transformations inside push() and pop() and store the location inside that itself so the location gets pushed into the array every frame.
And no, you can not get the canvas coordinates of (0,0) after a bunch of transforms because translate shifts the origin(0,0) of the canvas to a new point and then that point becomes the new origin.
To draw a trail, you can store the history of the object's location vector in an array. You can implement it in the update function of your animated object class. To do this, you can store P5Vector(this.pos.x, this.pos.y) and push it into an array everytime the function is called in the draw loop, then you can draw a circle or line whatever you want for the trail looping through this array.
Suppose history is an array with last 100 positions(vector objects) of the animated object, in the draw loop you can :
for(var i=0; i<obj.history.length; i++)
{
var loc = obj.history[i];
ellipse(loc.x, loc.y, 15, 15);
}
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.