I currently have the following code:
const scene = new THREE.Scene()
const root = new THREE.Group()
scene.matrixAutoUpdate = false
root.matrixAutoUpdate = false
scene.add(root)
I put the objects I want to move around under the root node. Next I want to set the root node to a certain position in 3D space using a Matrix4
The problem is that this has no effect:
root.matrix = translationMatrix
root.updateMatrixWorld()
and the following does an apply of my matrix, but it applies it on top of the existing transform instead of overwriting it.
root.applyMatrix(translationMatrix)
root.updateMatrixWorld()
How do I correctly replace the entire matrix by my own?
Looking into the code reveals that applyMatrix() decomposes the matrix into position, quaternion and scale. It might be important to set these properties manually:
root.matrix = translationMatrix;
root.matrix.decompose(root.position, root.quaternion, root.scale);
Another thing: updateMatrixWorld() won't do anything when matrixAutoUpdate or matrixWorldNeedsUpdate is set to false. Pass true as force parameter to update matrixWorld:
root.updateMatrixWorld(true);
Related
Trying to make a CHILD of an object look at a position (which is in global/world space)
Here's what I've got, but it doesn't work.
Direction of arrow seems to roam around in unpredictable directions.
Update (added example): https://jsfiddle.net/um8cxp3b/27/
makeArrowLookAt(obj, position) {
// obj.lookAt(position); // works PERFECTLY, but I want a child object to lookAt...
const posVector = new THREE.Vector3().copy(position); // copy
const localVector = obj.worldToLocal(posVector); // get local position offset
localVector.normalize(); // converts local offset to rotation... right?
// Apply the localised rotation to the object
obj.children[0].rotation.x = localVector.x;
obj.children[0].rotation.y = localVector.y;
obj.children[0].rotation.z = localVector.z;
}
(Note the child in this case is an arrowHelper to illustrate direction)
lookAt() does support transformed ancestors (assuming they are not non-uniformly-scaled). So it should be just:
obj.children[0].lookAt(position);
Assuming position is the target position in world space.
In my webapp I'm using ThreeJS scenes in different modals/popups/dialogs with different width/height ratios.
Furthermore, I want to use multiple user defined camera settings (rotation, position, lookAt etc.) among these different scenes.
Therefore, I save the camera object via camera.toJSON() when the user clicks a capture camera settings button.
(Before I did this, I saved just the object camera, but unfortunately these objects are quite big and slow down the performance while multiple camera objects get stored. Nevertheless, this approach worked, since I was able to copy all the desired values between the saved camera object and the currently used camera [e.g. current_camera.position.x=saved_camera.position.x and so on])
In every scene I want now to use the saved properties I tried the following:
let m = new THREE.Matrix4();
m.fromArray(saved_camera.object.matrix);
current_camera.applyMatrix(m)
current_camera.updateMatrix();
Unfortunately this doesn't work.
"normal" camera object
camera.toJSON() object
If you're comfortable using matrices, then you can turn off the matrix auto-update that three.js does during the render process, and keep the world matrix up-to-date yourself. (This includes any time you change the camera's orientation, so keep that in mind if you're using some form of mouse interaction to control the camera angle.)
First, turn off automatic matrix updating for your camera by setting the autoUpdateMatrix property to false. You can still use the convenience properties (position, rotation, scale), but you'll have to manually update the world matrix by calling camera.updateMatrixWorld(true);.
Finally, when you're ready to restore a particular camera orientation, simply copy the matrix values using the matrixWorld's copy method.
var origin = new THREE.Vector3();
var theCamera = new THREE.PerspectiveCamera(35, 1, 1, 1000);
theCamera.autoUpdateMatrix = false; // turn off auto-update
theCamera.position.set(10, 10, 10);
theCamera.lookAt(origin);
theCamera.updateMatrixWorld(true); // manually update the matrix!
console.log("Camera original matrix: ", theCamera.matrixWorld.elements.toString());
var saveMatrix = new THREE.Matrix4();
saveMatrix.copy(theCamera.matrixWorld);
// saveMatrix now contains the current value of theCamera.matrixWorld
theCamera.position.set(50, -50, 75);
theCamera.lookAt(origin);
theCamera.updateMatrixWorld(true); // manually update the matrix!
console.log("Camera moved matrix: ", theCamera.matrixWorld.elements.toString());
// theCamera.matrixWorld now holds a value that's different from saveMatrix.
theCamera.matrixWorld.copy(saveMatrix);
// Don't upate the matrix, because you just SET it.
console.log("Camera moved matrix: ", theCamera.matrixWorld.elements.toString());
// theCamera.matrixWorld once again contains the saved value.
<script src="https://threejs.org/build/three.js"></script>
Edit to address OrbitControls:
It looks like OrbitControls uses the convenience properties, rather than gathering the information from the matrix. As such, when you restore a camera position, you'll also need to restore those properties. This is easily done by using decompose on the matrix, and copying the resulting values into the appropriate properties:
var d = new THREE.Vector3(),
q = new THREE.Quaternion(),
s = new THREE.Vector3();
camera.matrixWorld.decompose( d, q, s );
camera.position.copy( d );
camera.quaternion.copy( q );
camera.scale.copy( s );
I am trying to write a function that creates a point cloud from mesh. I also want to control colors of every vertex of that point cloud. So far I tried to assign colors of geometry but colors doesnt being updated.
InteractablePointCloud_simug=function(object, editor){
var signals=editor.signals;
var vertexSize=0.3;
var pointMat= new THREE.PointsMaterial({size:vertexSize , vertexColors:THREE.VertexColors});
var colors=[];
var colorStep=0.1;
for (var i = 0; i < object.geometry.vertices.length; i++) {
colors.push(new
THREE.Color(colorStep*i,colorStep*i,colorStep*i));
};
//get points from mesh of original object
var points=new THREE.Points(object.geometry,pointMat);
//Update colors
points.geometry.colors=colors;
points.geometry.colorsNeedUpdate=true;
updatePosition();
//Add points object to scene
editor.addNoneObjectMesh(points);
}
I think this is probably doable on other video cards, but mine does not seem to like it.
Theoretically.. if your material color is white.. it should multiply times the vertex color ( which is basically like using the vertex color ), but since you did not specify black as your color, this is not the problem ).
If your code is not working on your computer ( not on mine either ), you will have to go nuclear... and just create a new selectedPointsGeometry and a new selectedPointsMesh
Grab a couple of vertices from the original.. copy them.. put them in a vertices array.. and run an update method ( you have to recreate the geo and mesh every time.. at least on my PC, I tried calling every single update method, and had to resort to recreating )
mind the coffee script. #anchor is the container
updateSelectedVertices: (vertices) ->
if #selectedParticles
#anchor.remove #selectedParticles
#pointGeometry = new THREE.Geometry()
#pointGeometry.vertices = vertices
#selectedParticles = new (THREE.PointCloud)(
#pointGeometry,
#selectedPointMaterial
)
#pointGeometry.verticesNeedUpdate = true
#pointGeometry.computeLineDistances()
#selectedParticles.scale.copy #particles.scale
#selectedParticles.sortParticles = true
#anchor.add #selectedParticles
selectedPointMaterial is defined elsewhere. Just use a different color ( and different size ).. than your non selected point cloud.
IE.. use black and size 5 for non selected point cloud , and use yellow and 10 for the selected one.
My other mesh is called #particles.. and I just have to copy the scale. (this is the non-selected point cloud)
Now my selected points show as yellow
I have a 3D scene with a bunch of CSS object that I want to rotate so that they are all pointing towards a point in the space.
My CSS objects are simple rectangles that are a lot wider than they are high:
var element = document.createElement('div');
element.innerHTML = "test";
element.style.width = "75px";
element.style.height = "10px";
var object = new THREE.CSS3DObject(element);
object.position.x = x;
object.position.y = y;
object.position.z = z;
Per default, the created objects are defined as if they are "facing" the z-axis. This means that if I use the lookAt() function, the objects will rotate so that the "test" text face the point.
My problem is that I would rather rotate so that the "right edge" of the div is pointing towards the desired point. I've tried fiddling with the up-vector, but I feel like that wont work because I still want the up-vector to point up. I also tried rotating the object Math.PI/2 along the y axis first, but lookAt() seems to ignore any prior set rotation.
It seems like I need to redefine the objects local z-vector instead, so that it runs along with the global x-vector. That way the objects "looking at"-direction would be to the right in the scene, and then lookAt() would orient it properly.
Sorry for probably mangling terminology, newbie 3D programmer here.
Object.lookAt( point ) will orient the object so that the object's internal positive z-axis points in the direction of the desired point.
If you want the object's internal positive x-axis to point in the direction of the desired point, you can use this pattern:
object.lookAt( point );
object.rotateY( - Math.PI / 2 );
three.js r.84
Im trying to move camera by changing its world matrix. But it doesen't seem to work. No matter what the camera wont move.
camera.matrixAutoUpdate = false
camera.matrixWorld = portal_view(camera,port1_quad,port2_quad)
i have tried using the matrixupdate = true but still nothing. What am i douing wrong ?
function portal_view(camera, src_portal, dst_portal) {
var inverse_view_to_source = new THREE.Matrix4().getInverse(camera.matrix).multiply(src_portal.matrix);
var new_mat = dst_portal.matrix.clone().multiply(inverse_view_to_source);
new_mat.makeRotationY(3.14);
return new_mat;
}
matrixWorld of an object is computed from its position, quaternion and scale. You cant directly change the 'matrixWorld' of an object. In other words, if you change the matrixWorld, the change wont be reflected on position of the object. You have to change the position of the camera.
What you can do is, extract the translation and rotation from the matrix and change the camera position and quaternion according to it.