Bounding box that is parallel to the camera - three.js

My problem is how to define the camera location, given a lookAt vector, when the camera is not on the z axis, so it captures all objects according to its fov and aspect.
I think I need to get a bounding box of my objects that is perpendicular to the camera's lookAt and top and bottom front and back edges are parallel to the xz plane. Then the back of the bounding box is the 'far' plane and I can calculate the distance from it (or fov) and set the camera accordingly.
My question is, how to get such a bounding box (Box3 instance), given some objects on the scene and the lookAt vector ?

My question is, how to get such a bounding box (Box3 instance), given some objects on the scene and the lookAt vector ?
Instances of THREE.Box3 are axis-aligned bounding boxes. No matter how the camera is rotated, it is not possible to generate a different bounding box for a given set of 3D objects.
Maybe you can use a quite common approach 3D viewers which ensures to always display an imported 3D object in the viewport. Exemplary code from the open source glTF viewer looks like this:
const aabb = new THREE.Box3().setFromObject( object );
const center = aabb.getCenter( new THREE.Vector3() );
const size = aabb.getSize( new THREE.Vector3() ).length();
// centering object
object.position.x += ( object.position.x - center.x );
object.position.y += ( object.position.y - center.y );
object.position.z += ( object.position.z - center.z );
// update camera
camera.near = size / 100;
camera.far = size * 100;
camera.updateProjectionMatrix();
camera.position.copy( center );
camera.position.x += size / 2.0;
camera.position.y += size / 5.0;
camera.position.z += size / 2.0;
camera.lookAt( center );

Related

Align mesh and object bounding boxes with helper axes

The bounding box doesn't seem to be aligned with the 3d mesh. This is the reason. Can you please give me some tips on how should I rotate the bounding box so that it's properly aligned with 3d mesh?
This is the screenshot of the 3d mesh and misaligned object bounding box:
Things I've tried:
Tried the approach of offsetting center position from object.
Tried to remove the rotation and translation of the object before calling 'setFromObject'.
Tried to rotate the box directly.
You can try to use the center point of the model's AABB in order to offset it as requested. The code for this looks like so:
const box = new THREE.Box3().setFromObject( model );
const center = box.getCenter( new THREE.Vector3() );
object.position.x += ( object.position.x - center.x );
object.position.y += ( object.position.y - center.y );
object.position.z += ( object.position.z - center.z );

three.js: Limiting camera's rotation

I'm working with three.js, attempting to model a real world camera. As such, I'd like to limit its axis of rotation to 90 degrees along x and y axises.
Is there a simply way to do this? My current code isn't working particularly well (and goes crazy when you attempt to move the camera past the X and Y boundaries simultaneously)
if(xRot != null && xRot != undefined){
camera.rotateX(xRot);
}
if(yRot != null && yRot != undefined){
camera.rotateY(yRot);
}
if(camera.rotation.x < minCameraRotX){
camera.rotation.x = minCameraRotX;
}else if (camera.rotation.x > maxCameraRotX){
camera.rotation.x = maxCameraRotX;
}
if(camera.rotation.y < minCameraRotY){
camera.rotation.y = minCameraRotY;
}else if(camera.rotation.y > maxCameraRotY){
camera.rotation.y = maxCameraRotY;
}
Any advice would be greatly appreciated!!!
I actually managed to find a solution by checking some of the existing code in a Three.js demo for a library called PointerLock. The idea is to actually stack multiple objects inside each other: start with an object that moves horizontally (the yaw object), place another object inside the yaw object that moves vertically (the pitch object), and then place the actual camera inside the pitch object.
Then, you only rotate the outside objects (yaw and pitch) along their respective axises, so if you rotate both, they'll self-correct. For example, if you rotate the yaw 45 degrees along the y-axis (making it turn to the right) and then rotate the pitch 45 degrees (making it turn downward), the pitch will go 45 degrees downward from the yaw's already rotated position.
Given that the camera is inside both, it just points wherever the yaw and pitch direct it.
Here is the code
/*
* CAMERA SETUP
*
* Root object is a Yaw object (which controls horizontal movements)
* Yaw object contains a Pitch object (which controls vertical movement)
* Pitch object contains camera (which allows scene to be viewed)
*
* Entire setup works like an airplane with a
* camera embedded in the propellor...
*
*/
// Yaw Object
var yawObject = new THREE.Object3D();
// Pitch Object
var pitchObject = new THREE.Object3D();
// Camera Object
var camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
// Max Camera angles (in radians)
var minCameraRotX = 0.5;
var maxCameraRotX = 0.5;
var minCameraRotY = 1;
var maxCameraRotY = 1;
// Setup
yawObject.add( pitchObject );
pitchObject.add( camera );
scene.add(yawObject);
...
var rotateCamera = function(xRot, yRot, zRot){
yawObject.rotation.y += yRot;
pitchObject.rotation.x += xRot;
// Enforce X-axis boundaries (rotates around y-axis)
yawObject.rotation.y = Math.max( minCameraRotY, Math.min( maxCameraRotY, yawObject.rotation.y ) );
// Enforce Y-axis boundaries (rotates around x-axis)
pitchObject.rotation.x = Math.max( minCameraRotX, Math.min( maxCameraRotX, pitchObject.rotation.x ) );
}
Here is the source code I referenced: https://github.com/mrdoob/three.js/blob/acda8a7c8f90ce9b71088e903d8dd029e229678e/examples/js/controls/PointerLockControls.js
Also, this is sort of cheesy, but this little plane cartoon helped me visual exactly what was going on in my setup

Why isn't my raycast intersecting anything?

I have this code, designed to find the mesh the user is clicking on:
// scene and camera are defined outside of this code
var mousePoint = new THREE.Vector2();
var raycaster = new THREE.Raycaster();
var intersections;
function onClick(event) {
mousePoint.x = event.clientX;
mousePoint.y = event.clientY;
raycaster.setFromCamera(mousePoint, camera);
intersections = raycaster.intersectObjects(
scene.children);
}
Yet every time I click, intersections comes back as an empty array, with nothing getting intersected. What am I doing wrong?
From the three.js documentation for Raycaster (emphasis mine):
.setFromCamera ( coords, camera )
coords — 2D coordinates of the mouse, in normalized device coordinates (NDC)---X and Y components should be between -1 and 1.
camera — camera from which the ray should originate
Updates the ray with a new origin and direction.
Therefore, when setting the coordinates of mousePoint, instead of setting x and y directly to event.clientX and event.clientY, they should be converted to this coordinate space:
// calculate mouse position in normalized device coordinates
// (-1 to +1) for both components
mousePoint.x = (event.clientX / window.innerWidth) * 2 - 1;
mousePoint.y = (event.clientY / window.innerHeight) * -2 + 1;

LIBGDX / OpenGL : Reducing the size of everything

This could be the worse question ever asked however that would be a cool achievement.
I have created a 3D world made of cubes that are 1x1x1 (think Minecraft), all the maths works great etc. However 1x1x1 nearly fills the whole screen (viewable area)
Is there a way I can change the ViewPort or something so that 1x1x1 is half the size it currently is?
Code for setting up camera
float aspectRatio = Gdx.graphics.getWidth() / Gdx.graphics.getHeight();
camera = new PerspectiveCamera(67, 1.0f * aspectRatio, 1.0f);
camera.near = 0.1f; // 0.5 //todo find out what this is again
camera.far = 1000;
fps = new ControlsController(camera , this, stage);
I am using the FirstPersonCameraController and PerspectiveCamera to try and make a first person game
I guess the problem is:
camera = new PerspectiveCamera(67, 1.0f * aspectRatio, 1.0f);
An standard initialization of your camera could be (based on this tutorial):
camera = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
// ...
Note how the width and height of the camera is nearly (if not the same) of the width and height of the native gdx window dimension. In your case you set this size to 1 (the same size of your mesh). Try with a bigger viewport dimension to allow your mesh be smaller (in perspective), something like:
/** Not too sure since is a perspective view, but play with this values **/
float multiplier = 2; // <- to allow your mesh be a fraction
// of the size of the viewport of the camera
camera = new PerspectiveCamera(67, multiplier * aspectRatio, multiplier );

THREE.JS: Get object size with respect to camera and object position on screen

I am newbie to 3D programming, I did started to explore the 3D world from WebGL with Three.JS.
I want to predetermine object size while I change the camera.position.z and object's "Z" position.
For example:
i have a cube mesh at size of 100x100x100.
cube = new THREE.Mesh(
new THREE.CubeGeometry(100, 100, 100, 1,1,1, materials),
new THREE.MeshFaceMaterial()
);
and cam with aspect ratio of 1.8311874
camera = new THREE.PerspectiveCamera( 45, aspect_ratio, 1, 30000 );
I want to know size (2D width & height) of that cube object on screen when,
camera.position.z = 750;
cube.position.z = 500;
Is there is any way to find it/predetermine it?
You can compute the visible height for a given distance from the camera using the formulas explained in Three.js - Width of view.
var vFOV = camera.fov * Math.PI / 180; // convert vertical fov to radians
var height = 2 * Math.tan( vFOV / 2 ) * dist; // visible height
In your case the camera FOV is 45 degrees, so
vFOV = PI/4.
(Note: in three.js the camera field-of-view FOV is the vertical one, not the horizontal one.)
The distance from the camera to the front face (important!) of the cube is 750 - 500 - 50 = 200. Therefore, the visible height in your case is
height = 2 * tan( PI/8 ) * 200 = 165.69.
Since the front face of the cube is 100 x 100, the fraction of the visible height represented by the cube is
fraction = 100 / 165.69 = 0.60.
So if you know the canvas height in pixels, then the height of the cube in pixels is 0.60 times that value.
The link I provided shows how to compute the visible width, so you can do that calculation in a similar fashion if you need it.

Resources