Three.js imported object different starting positions - three.js

I'm new to Three.js and I have a problem. I've imported external 3D object (.obj extension) and I add it to my scene. I want to set newly imported object at (0, 0, 0) position, so I use:
obj.position.set(0, 0, 0);
I expect that object would be placed at 0 point of each axis from axis helper. However it doesn't happen. Object is placed at its own position:
Why is that happening and how can I set object position to (0, 0, 0) and make it appear right at 0 point of each axis?

You can try to center your imported object(s) at the origin like so:
const aabb = new THREE.Box3().setFromObject( obj );
const center = aabb.getCenter( new THREE.Vector3() );
obj.position.x += ( obj.position.x - center.x );
obj.position.y += ( obj.position.y - center.y );
obj.position.z += ( obj.position.z - center.z );
The idea is to compute the axis-aligned bounding box of the object and use its center property for the actual centering.

Related

How to set pivot point for an arrow-like shape

I'm creating this arrow-like shape with three.js:
let planeShape = new THREE.Shape()
planeShape.moveTo(0, 0)
planeShape.lineTo(3, 1)
planeShape.lineTo(0, 2)
planeShape.lineTo(1, 1)
planeShape.lineTo(0, 0)
var geometry = new THREE.ShapeGeometry( planeShape )
// Appropriate rotation or translation should take place here
var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } )
var mesh = new THREE.Mesh( geometry, planeMaterial )
scene.add( mesh )
And I want to be able to use mesh.lookAt(position) so that the tip of the arrow ends up pointing the specified position. However, I haven't been able to set an appropriate pivot point. I think I'm having problems because I'm creating the arrow shape points in 2D but I end up with a 3D object losing track of my origin point.
Here's an example of what I want to accomplish: https://threejs.org/examples/misc_lookat.html
After var geometry = new THREE.ShapeGeometry( planeShape ) add
geometry.translate(0, -1, 0); // center with x-axis
geometry.rotateY(-Math.PI * 0.5); // align with z-axis to use with lookAt()

Solar system using Three js animation

I am creating a solar system using three js.In that I want to display some of the details on clicking on any objects.I have used object picking concepts.In that I am trying to get the objects which are intersecting with the
clicking.But I am unable get any objects which are intersecting.When I tried to print the objects in the intersects array I am getting as "undefined" and length of the intersects array as 0.
function mous(event) {
var vector = new THREE.Vector3(( event.clientX / window.innerWidth ) * 2 - 1, -( event.clientY / window.innerHeight ) * 2 + 1, 0.5);
vector = vector.unproject(camera);
raycaster = new THREE.Raycaster(camera.position, vector);
var intersects = raycaster.intersectObjects([orbitDir1,orbitDir2,orbitDir3,orbitDir4,orbitDir5]);
alert(intersects[0]);
alert(intersects.length);
}`
And here is the code for orbitDir.
geometry = new THREE.CircleGeometry(2.3, 100);
geometry.vertices.shift();
circle = new THREE.Line(
geometry,
new THREE.LineDashedMaterial({color: 'red'})
);
circle.rotation.x = Math.PI * 0.5 ;
tex = new THREE.ImageUtils.loadTexture("Mercury.jpeg") ;
planet = new THREE.Mesh(
new THREE.SphereBufferGeometry(0.3, 32, 32),
new THREE.MeshPhongMaterial({ map : tex})
);
planet.position.set(2.3, 0, 0);
scene.add(planet);
orbit = new THREE.Group();
orbit.add(circle);
orbit.add(planet);
orbitDir = new THREE.Group();
orbitDir.add(orbit);
//orbitDir.position.x += 0.1 ;
orbitDir.position.y += 4 ;
orbitDir.position.z += 5 ;
orbitDir.rotation.x +=2.3 ;
scene.add(orbitDir);
The code for »unprojection« and raycasting look fine, so I guess that the x and y values might not be right. You are using clientX and clientY which are the mouse coordinates relative to the upper left corner of the window. Those are only valid if your <canvas> is full page. If that is not the case, make sure to use mouse coordinates relative to the upper left edge of the <canvas>.
I think you can do the raycasting like that:
raycaster.intersectObjects(scene, true) //scan the whole scene recursive
docs
Probably the answer you are looking for is here
projector.unprojectVector( vector, camera.position );

Is there ANY way to have the three.js camera lookat being rendered off-center?

Is there a way to setup the Three.js renderer in such a way that the lookat point of the camera is not in the center of the rendered image?
To clarify: image a scene with just one 1x1x1m cube at ( 0, 0, 0 ). The camera is located at ( 0, 0, 10 ) and the lookat point is at the origin, coinciding with the center of the cube. If I render this scene as is, I might end up with something like this:
normal render
However I'd like to be able to render this scene in such a way that the lookat point is in the upper left corner, giving me something like this:
desired render
If the normal image is 800x600, then the result I envision would be as if I rendered a 1600x1200 image with the lookat in the center and then cropped that normal image so that only the lower right part remains.
Of course, I can change the lookat to make the cube go to the upper left corner, but then I view the cube under an angle, giving me an undesired result like this:
test.moobels.com/temp/cube_angle.jpg
I could also actually render the full 1600x1200 image and hide 3/4 of the image, but one would hope there is a more elegant solution. Does anybody know it?
If you want your perspective camera to have an off-center view, the pattern you need to use is:
camera = new THREE.PerspectiveCamera( for, aspect, near, far );
camera.setViewOffset( fullWidth, fullHeight, viewX, viewY, viewWidth, viewHeight );
See the docs: https://threejs.org/docs/#api/cameras/PerspectiveCamera
You can find examples of this usage in this example and this example.
three.js r.73
Here's a simple solution:
Assuming your cube is 4 x 4 x 4, at position 0, 0, 0:
var geometry = new THREE.BoxGeometry( 4, 4, 4 );
var material = new THREE.MeshBasicMaterial( { color: 0x777777 } );
var cube = new THREE.Mesh( geometry, material );
cube.position.set( 0, 0, 0 );
Get cube's position:
var Vx = cube.position.x,
Vy = cube.position.y,
Vz = cube.position.z;
Then deduct by 2 from x position, then add 2 to y and z position, and use the values to create a new Vector3:
var newVx = Vx - 2,
newVy = Vy + 2;
newVz = Vz + 2;
var xyz = new THREE.Vector3(newVx, newVy, newVz)
Then camera lookAt:
camera.lookAt(xyz);
Using console log, it would show that the camera is now looking at -2, 2, 2, which is the upper-left of your cube.
console.log(xyz);

convert Point3D To Screen2D get wrong result in three.js

I use function like this in three.js 69
function Point3DToScreen2D(point3D,camera){
var p = point3D.clone();
var vector = p.project(camera);
vector.x = (vector.x + 1) / 2 * window.innerWidth;
vector.y = -(vector.y - 1) / 2 * window.innerHeight;
return vector;
}
It works fine when i keep the scene still.
But when i rotate the scene it made a mistake and return wrong position in the screen.It occurs when i rotate how about 180 degrees.It shoudn't have a position in screen but it showed.
I set a position var tmpV=Point3DToScreen2D(new THREE.Vector3(-67,1033,-2500),camera); in update and show it with css3d.And when i rotate like 180 degrees but less than 360 , the point shows in the screen again.Obviously it's a wrong position that can be telled from the scene and i haven't rotate 360 degrees.
I know little about the Matrix,So i don't know how the project works.
Here is the source of project in three.js:
project: function () {
var matrix;
return function ( camera ) {
if ( matrix === undefined ) matrix = new THREE.Matrix4();
matrix.multiplyMatrices( camera.projectionMatrix, matrix.getInverse( camera.matrixWorld ) );
return this.applyProjection( matrix );
};
}()
Is the matrix.getInverse( camera.matrixWorld ) redundant? I tried to delete it and it didn't work.
Can anyone help me?Thanks.
You are projecting a 3D point from world space to screen space using a pattern like this one:
var vector = new THREE.Vector3();
var canvas = renderer.domElement;
vector.set( 1, 2, 3 );
// map to normalized device coordinate (NDC) space
vector.project( camera );
// map to 2D screen space
vector.x = Math.round( ( vector.x + 1 ) * canvas.width / 2 ),
vector.y = Math.round( ( - vector.y + 1 ) * canvas.height / 2 );
vector.z = 0;
However, using this approach, points behind the camera are projected to screen space, too.
You said you want to filter out points that are behind the camera. To do that, you can use this pattern first:
var matrix = new THREE.Matrix4(); // create once and reuse
...
// get the matrix that maps from world space to camera space
matrix.getInverse( camera.matrixWorld );
// transform your point from world space to camera space
p.applyMatrix( matrix );
Since the camera is located at the origin in camera space, and since the camera is always looking down the negative-z axis in camera space, points behind the camera will have a z-coordinate greater than zero.
// check if point is behind the camera
if ( p.z > 0 ) ...
three.js r.71
Like the example above but you can check vector.z to determine if it's in front.
var vector = new THREE.Vector3();
var canvas = renderer.domElement;
vector.set( 1, 2, 3 );
// map to normalized device coordinate (NDC) space
vector.project( camera );
// map to 2D screen space
vector.x = Math.round( ( vector.x + 1 ) * canvas.width / 2 ),
vector.y = Math.round( ( - vector.y + 1 ) * canvas.height / 2 );
//behind the camera if z isn't in 0..1 [frustrum range]
if(vector.z > 1){
vector = null;
}
To delve a little deeper into this answer:
// behind the camera if z isn't in 0..1 [frustrum range]
if(vector.z > 1){
vector = null;
}
This is not true. The mapping is not continuous. Points beyond the far
plane also map to z-values greater than 1
What exactly does the z-value of a projected vector stand for? X and Y are in normalised clipspace [-1,1] , what about z?
Would this be true?
projectVector.project(camera);
var inFrontOfCamera = projectVector.z < 1;
Since the camera is located at the origin in camera space, and since the camera is always looking down the negative-z axis in camera space, points behind the camera will have a z-coordinate greater than 1.
//check if point is behind the camera
if ( p.z > 1 ) ...
NOTICE: If this condition is satisfied, then the projected coordinates need to be centrosymmetric
{x: 0.233, y: -0.566, z: 1.388}
// after transform
{x: -0.233, y: 0.566, z: 1.388}

Rotation with negative scale

I'm creating a tool to rotate images in ThreeJs, but it doesn't work when dealing with negative scales.
The image is displayed in a Mesh created using a THREE.PlaneGeometry element and a material which maps to to correspongin image.
The tool is an object that has an element called gizmo (it's a small mesh) which is selected and dragged by the user to rotate the object.
To do the rotation I define an angle and an axis. The angle is defined by two vectors created using the the position of the gizmo (original and current) and the position of the Mesh.
var gizmoOriginalPosition = this.gizmoOriginalPosition.clone().applyMatrix4( this.matrixWorld );
var imagePosition = this.imageToTransformOriginalPosition.clone().applyMatrix4( this.imageToTransformParentOriginalMatrix );
var vector1 = gizmoOriginalPosition.sub( imagePosition ).normalize();
var vector2 = point.sub( imagePosition ).normalize();
var angle = Math.acos( vector1.dot( vector2 ) );
var axis = new THREE.Vector3( 0, 0, 1 );
var ortho = vector2.clone().cross( vector1 );
var _m = this.imageToTransformOriginalMatrix.clone();
this.tempMatrix.extractRotation( _m );
var q = new THREE.Quaternion().setFromRotationMatrix( this.tempMatrix );
var _axis = axis.clone().applyQuaternion( q );
var f = ortho.dot( _axis );
f = f > 0 ? 1 : -1;
angle *= -f;
var q = new THREE.Quaternion().setFromAxisAngle( axis, angle );
var Q = new THREE.Quaternion().multiplyQuaternions( this.imageToTransformOriginalQuaternion, q );
imageToTransform.quaternion.copy( Q );
The axis of rotation is always ( 0, 0, 1) because the Mesh is a plane in XY.
point is the new position of the gizmo using a plane of intersection.
The vectors to define the angle are in world coordinates. ortho is a vector to define the direction of the angle, so the Mesh rotates in the direction of the mouse pointer. I define the direction of the angle with the f value obtained using ortho and axis. The axis ( 0, 0, 1 ) is rotated so its direction is in world coordinates ( ortho is in world coordinates ).
This works as expected in almost every case, except when the Mesh has a negative scale in X and Y. Here the image rotates in the opposite direction to the mouse pointer.
Thanks.

Resources