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

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);

Related

How to make THREE.OrbitControls spin a plane around Z-axis (& X-axis)

I have a PlaneGeometry & mesh, extent is X,Y, normal is Z-axis
And a camera centered above that plane looking down from +Z axis.
(basically looking down a the plane which is a topo/terrain map)
By default, OrbitControls will rotate the view around the X & Y axis.
(which is fairly useless in this case)
What [mostly] works is the rotate the scene around the X-axis scene.rotateX(-Math.PI/2)
and then drive the camera/view to be above the Z-axis.
After that, OrbitControls do the right thing:
vertical mouse tilts the view down to (or up from) the plane
horizontal mouse spins the plane around the z-axis (so can see from the other direction)
Two 'problems':
Is there an API to set the OrbitControl to be above the Z-axis?
(after scene.rotateX, the view is at elevation 0, looking across the plane)
I'd like to rotate the camera/view to above the Z-axis at altitude.
Is there an alternative way to get OrbitControls to select which axis to rotate?
(so without the scene.rotateX, the camera is in the right place)
There's a related fiddle (ignore the SpotLight): https://jsfiddle.net/4azo5bvf/65/
Edit:
const camera = new THREE.PerspectiveCamera( 60, w/h, 0.1, 100 );
camera.position.set(0, 0, 50);
camera.up.set(0, 0, 1); // <=== spin around Z-axis
const ob_controls = new THREE.OrbitControls(camera, canvas);
So we can mark this as 'answered' (thanks to #WestLangley)
The easy solution is to use camera.up.set(0, 0, 1)
Apparently, OrbitControls uses that to determine the rotatonal/axial orientation.
const camera = new THREE.PerspectiveCamera( 60, w/h, 0.1, 100 );
camera.position.set(0, 0, 50);
camera.up.set(0, 0, 1); // <=== spin around Z-axis
const ob_controls = new THREE.OrbitControls(camera, canvas);
After further review (and TerekC's answer in Three.JS rotate projection so that the y axis becomes the z-axis) changed to use:
THREE.Object3D.DefaultUp.set(0, 0, 1); // Z-axis up, and spinable

Three js: How to get normal of rotated plane

I am trying to get normal of rotated plane. My solution is to copy the updated plane then get normals.
It is working when I rotate by only 1 angle, but not works in rotating by 2 or 3 angles. jsFiddle
Green one is copied plane, purple one rotated plane.
enter image description here
How to solve this? Please help me
My copy function:
function copyPlane() {
let copyPlaneGeom = new THREE.PlaneGeometry(3, 3, 3);
copyPlaneGeom.rotateX(plane.rotation.x);
copyPlaneGeom.rotateY(plane.rotation.y);
copyPlaneGeom.rotateZ(plane.rotation.z);
let copyPlane = new THREE.Mesh(copyPlaneGeom, new THREE.MeshBasicMaterial({color: 0x00ff00}));
scene.add(copyPlane)
let normals = copyPlane.geometry.faces[0].normal
I think with that approach, you'll always get a vector of 0, 0, 1 because a plane's face normal is always (0, 0, 1) * objectRotation.
Instead, try starting with a Vector3 of 0, 0, 1, and then apply the object's rotation to it:
var originalNormal = new Vector3(0, 0, 1);
// Get the mesh rotation
var objRotation = plane.rotation;
// Apply mesh rotation to vector
originalNormal.applyEuler(objRotation);
now you have a Vector3 with the updated wold normal, instead of the local normal! Read about .applyEuler() here.

How to move an object in particular direction with specific distance in three.js

I need to move an object along directional vector through some distance. I fount translateOnAxis(vector, distance) of Object3D class. But I'm not able to understand how it works.
I've an object- sphere. I'm scaling it to look like ellipse. And setting position and direction. Now I need this object to move in the same direction which I'm setting it to, through some distance. When I apply it, I can't see the object. Can anybody suggest how it can be achieved?
var geometry = new THREE.SphereGeometry( radius, 64, 64, 0, -Math.PI );
geometry.applyMatrix( new THREE.Matrix4().makeScale( 1, 1, zScale ); //scaling it to look like ellipse
var direction = new THREE.Vector3( xDir, yDir, zDir);
var ellipse = new THREE.Mesh( geometry, material );
ellipse.lookAt(direction);
ellipse.position.set( xPos, yPos, zPos);
ellipse.translateOnAxis(direction, distance);
Your pasted code is buggy.
You're missing a ) on your applyMatrix line.
Are you using a debugger and observing console errors/warnings?

Coordinate system issue in three.js

I am working on a program in three.js. So I have a particle system loaded from a LAS file. It has a coordinate system. I have added a functionality which enables user to click on a particle, and it would add a bounding box to the scene. My aim is to find which particles lie inside this bounding box.
Code for adding bounding box at point p clicked by user:
var cubeGeometry = new THREE.BoxGeometry( 1, 1, 1 );
var cubeMaterial = new THREE.MeshLambertMaterial( { color:
0xffff00,wireframe: true } );
var cube = new THREE.Mesh( cubeGeometry, cubeMaterial );
cube.position.x = p.x;
cube.position.y = p.y;
cube.position.z = p.z;
scene.add(cube);
But I am facing an issue. The box created has a different coordinate axis orientation than particle system. It's Y axis is oriented in direction of particle system's Z axis. This causes containsPoint method to give wrong answer.
How to solve this issue?
Try this:
var e = new THREE.Euler( - Math.PI / 2, 0, 0 );
p.applyEuler( e );
This will apply a rotation of 90 degrees around the x-axis or a conversion from Z-up to Y-up.

Non-radial texture mapping over a ring geometry in WebGL using Three.js

I am trying to simulate image deformation effects using textures over 2D geomtries using the ThreeJS library. I want to apply a texture image over a hollow circle (basically, a ring built by the THREE.RingGeometry function) and obtain the results shown at this image:
Following I show the results I am obtaining in my scene both for the solid ring and its wireframed version:
The problem is that, as you see, the texture is been applied in a radial way, from the center of the ring to the outside. However, what I really need is to apply the texture image on a concentric circle way, as shown in the first image of this question.
The idea is to produce a deformed version of the original texture over a ring shape. I would like to know how this effect can be programmatically achieved through Three.js in such a way that the destination shape can be any arbitrary 2D geometry .
Following, there is the relevant code I am using to draw my scene:
var texture = THREE.ImageUtils.loadTexture('./images/texture.png');
var wireRing = new THREE.Mesh(new THREE.RingGeometry(10, 20, 50, 5, 0, Math.PI * 2), new THREE.MeshBasicMaterial({map: texture, wireframe: true}));
wireRing.position.set(-25, 50, 0);
scene.add(wireRing);
var ring = new THREE.Mesh(new THREE.RingGeometry(10, 20, 50, 5, 0, Math.PI * 2), new THREE.MeshBasicMaterial({map: texture}));
ring.position.set(25, 50, 0);
scene.add(ring);
You just need to change the UV mapping in RingGeometry like so:
uvs.push( new THREE.Vector2( o / thetaSegments, i / phiSegments ) );
Also, if you want to rotate the texture around the ring, you instantiate the RingGeometry by varying the thetaStart parameter:
var geometry = new THREE.RingGeometry( 10, 20, 50, 5, thetaStart, Math.PI * 2 );
three.js r.67

Resources