THREE JS get (world) rotation from matrixWorld - javascript

How do I get the world rotation of an Object3D in three.js?
I know how to get the world position of an Object3D from object.matrixWorld, but how do I get the world rotation of an object?
I need this for the following problem: I have a hierarchical Object structure like this:
var obj1 = new THREE.Object3D();
obj1.x = 200;
obj1.rotation.x = 0.1;
scene.add(obj1);
var obj2 = new THREE.Object3D();
obj2.y = -400;
obj2.rotation.y = 0.21;
obj1.add(obj2);
var obj3 = new THREE.Object3D();
obj3.z = -200;
obj3.rotation.x = 0.1;
obj3.rotation.y = -0.1;
obj2.add(obj3);
Now I want to make my camera look at obj3 orthogonally in a certain distance. When My Objects are not rotated, this works like this:
var relativeCameraOffset = new THREE.Vector3(0, 0, 500); // 500 is z-distance from my object
var cameraOffset = relativeCameraOffset.applyMatrix4(obj3.matrixWorld);
camera.position = cameraOffset;
When only my last child is rotated I get what I want when I add this line
camera.rotation = obj3.rotation;
But when all parent Elements are rotated this is not working. So I'm looking for a way to get the world "orientation" of my 3D object.
Thanks.

One way to get the "world" rotation is as follows:
const position = new THREE.Vector3(); // create one and reuse it
const quaternion = new THREE.Quaternion();
const scale = new THREE.Vector3();
mesh.matrixWorld.decompose( position, quaternion, scale );
You can then set your camera orientation like so:
camera.quaternion.copy( quaternion );
Important: if you are going to access matrixWorld directly, you have to make sure it is updated. The renderer typically does this for you in the render loop. If, however, you are between render calls, and need to force an update of the matrix, you can do so with
mesh.updateWorldMatrix( true, false );
EDIT: There is another method that is now available. Check the source code so you see what it is doing.
Object3D.getWorldQuaternion( targetQuaternion );
three.js r.147

If you just want to link camera with obj3, you can just do this:
obj3.add(camera);

Use mesh.getWorldPosition() to get world position, and mesh.getWorldRotation() to get it's rotation.

Related

How do I properly render a big texture on a small mesh in Three.js?

I have a problem with rendering texture on a small plane. Let's say I generate a texture from html, no metter how, but I have an html rendered as Image, now I want to render it on a small plane (display) which hangs near the instrument in VR space. The instrument is really tiny in compare to other objects, but in the same time it is really close to the screen, so it looks not so small.
const DISPLAY_TARGET_WIDTH = 0.2;
const display = new THREE.Mesh(
new THREE.PlaneGeometry(DISPLAY_TARGET_WIDTH, 1),
DEFAULT_DISPLAY_MATERIAL,
);
So when I render the html on this display I get a very bloored unreadable image.
One of the ways is to increase the basic size of the element, but probabbly there is some LOD-like-way of solution. Can somebody help to solve this issue? Thanks!
I found that if I initially give a normal size to the object, than scale it to the small size it works fine for me without any textures blure.
export const DISPLAY_TARGET_WIDTH = 2000;
const display = new THREE.Mesh(
new THREE.PlaneGeometry(DISPLAY_TARGET_WIDTH, DISPLAY_TARGET_WIDTH),
DEFAULT_DISPLAY_MATERIAL,
);
display.scale.setScalar(0.01);
const texture = new THREE.Texture(displayImage);
texture.anisotropy = 16;
texture.wrapS = texture.wrapT = THREE.MirroredRepeatWrapping;
texture.minFilter = THREE.LinearFilter;
texture.magFilter = THREE.LinearFilter;
texture.generateMipmaps = false;
texture.needsUpdate = true;
this.display.material = new THREE.MeshLambertMaterial({map: texture, side: THREE.DoubleSide});

Three.js object returns wrong values for position/rotation/scale

I'm having a three.js object in my scene, which you can rotate/scale/move with the THREE.TransformControls. After positioning the object in the scene, the values of rotation/position/scale should be saved. I'm getting the values like this :
// Position
$scope.scene.updateMatrixWorld(true);
var position = new THREE.Vector3();
position.getPositionFromMatrix( $scope.object.matrixWorld );
// Rotation
var rotation = new THREE.Euler();
$scope.object.getWorldRotation(rotation);
// Size
var size = new THREE.Box3().setFromObject($scope.object);
var x = (size.max.x - size.min.x);
var y = (size.max.y - size.min.y);
var z = (size.max.z - size.min.z);
So, when I'm saving the values and reload the scene with the new values, the object looks really different than it should. So, I think, the functions deliver the wrong values for rotation/scale/position. For example, the size.z variable should always be 0, but when saving (and printing the value in the console) it gets an other value.
Does anyone have an idea why ?
Thanks for helping.
Three.js offers a matrix decomposition function: https://threejs.org/docs/#api/math/Matrix4.decompose
Here's an example of how to use it:
var translation = new THREE.Vector3();
var rotationQ = new THREE.Quaternion();
var scale = new THREE.Vector3();
myObject.matrixWorld.decompose(translation, rotationQ, scale);
Then if you want to save the rotation as an Euler:
var rotationE = new THREE.Euler().setFromQuaternion(rotationQ.normalize());
three.js r88

THREE JS position from matrixWorld is same as local position

I've imported a collada file from Cinema4D with a tree of parented objects. When I get an object's world position like so:
var thing = scene.getObjectByName("thing");
thing.updateMatrixWorld();
var worldPos = new THREE.Vector3();
worldPos.setFromMatrixPosition(thing.matrixWorld);
it is the same as thing.position, which the docs say is local position. I know this object has a parent with a non-zero position. When I try the same thing without updateMatrixWorld(), the world position is zero. How can I get the correct world position?
I needed to updateMatrixWorld() for each parent of my object, which I did like this:
function updateWorldMatrices (object)
{
var parent = object;
while (parent.parent != null)
{
parent.updateMatrixWorld();
parent = parent.parent;
}
}

Create Dynamic Body using cocos 2d js and Chipmunk

I am fairly new to cocos 2d and chipmunk. So far i have managed to create a static object and add collision handler to it. But i want to create a dynamic.
this.space = space;
this.sprite = new cc.PhysicsSprite("#rock.png");
var body = new cp.StaticBody();
body.setPos(pos);
this.sprite.setBody(body);
this.shape = new cp.BoxShape(body,
this.sprite.getContentSize().width,
this.sprite.getContentSize().height);
this.shape.setCollisionType(SpriteTag.rock);
this.space.addStaticShape(this.shape);
spriteSheet.addChild(this.sprite);
But i want to create a dynamic body similarly which moves for example by:
cp.v(310, 0), cp.v(0, 0)
This is very basic I know but I would grateful if someone would help me with this. Also if you have good documentation in of cocos 2d and chipmunk in JS. do share it. Thanks
Here you go:
//Add the Chipmunk Physics space
var space = new cp.Space();
space.gravity = cp.v(0, -10);
//Optionally add the debug layer that shows the shapes in the space moving:
/*var debugNode = new cc.PhysicsDebugNode(space);
debugNode.visible = true;
this.addChild(debugNode);*/
//add a floor:
var floor = new cp.SegmentShape(this.space.staticBody, cp.v(-1000, 10), cp.v(1000, 0), 10);
//floor.setElasticity(1);
//floor.setFriction(0);
space.addStaticShape(floor);
//add a square to bounce
//the Sprite
var mySprite = cc.PhysicsSprite.create("res/something.png");
gameLayer.addChild(mySprite);
//the Body
var size = mySprite.getContentSize();
var innertialMomentum = 1; //Use Infinity if you want to avoid the body from rotating
var myBody = new cp.Body(innertialMomentum , cp.momentForBox(innertialMomentum , size.width, size.height));
mySprite.setBody(myBody);
space.addBody(myBody);
//myBody.p = cc.p(xxx, yyy); //To alter the position of the sprite you have to manipulate the body directly, otherwise it won't have the desired effect. You can also access it by mySprite.body
//the Shape
var myShape = new cp.BoxShape(myBody, size.width, size.height);
//myShape.setElasticity(1);
//myShape.setFriction(0);
space.addShape(myShape);
//Apply your desired impulse
//mySprite.body.applyImpulse(cp.v(ix,iy), cp.v(rx,ry)); // Where the first vector is for the impulse strength and direction and the second is for the offset between the center of the object and where you want the impulse to be applied.

Drawing images from an array

I'm currently working on drawing up a tilemap using a set of images loaded inn to an array.
I've defined a tile as an object like this:
function tile(gfx){
this.tile = gfx;
this.drawSelf = function(x,y)
this.tile.x = x;
this.tile.y = y;
}
Then I filled up an array with several tile objects which through the debugger displays correctly.
Now when I start drawing up the images using this code:
for (var x = 0; x < mapArray.length; x++){
xN = 183 + (50*x);
mapArray[x].drawSelf(xN, 134);
gameStage.addChild(mapArray[x].tile);
mapArray[x].tile.visible = true;
}
The problem is that all the "objects" in the array recive the same x and y coords. So what i suspect is that every single object in the array referes to each other.
What I'm trying to do is create a 20x10 map of tiles. And I need to be able to refer to each tile as a single object.
Shout out if I'm not making sense.
If you create all the tiles like this :
var gfx = new ...
for (...) {
mapArray[x].tile = new tile(gfx);
}
Then all of them share the same gfx object.
You should change your initialization like this :
for (...) {
var gfx = new ...
mapArray[x].tile = new tile(gfx);
}

Categories