Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Camera controls based on object bounding box?

Normal orbit controls from three.js is perfect for round object, but not good for long object (especially when zoom close), I'm looking for a solution to solve that.

It's hard to describe in words, please view this webgl example from Google (zoom in maximum to see): https://www.google.com/o3d/shopping/viewer/360?q=ymMBhK8fu3C&o3ds=use_3d enter image description here

This is top view illustration of what I'm looking for: enter image description here

I was thinking about use based on default OrbitControls, continuous cast ray from camera to bounding box and keep a constant distance, but the problem is the camera always looking at the center of object, unlike in the above example (cam only rotate when reaching to the corner of object).

Any ideas would be greatly appreciated.

like image 849
Ben Mack Avatar asked Mar 04 '17 02:03

Ben Mack


1 Answers

As you pointed out, using the existing THREE.OrbitControls and modifying the target does not work as the camera wouldn't look perpendicularly at the bounding box.

I tried different things, with quite bad results but here's my work.
In every solution I tried, I always had to compute (in any order) :

  1. the position of the camera ;
  2. the direction of the camera.

In any case, the camera must rotate around something. So, all my solutions are more or less based on the THREE.OrbitControls, which acts as, say, "the current state of the rotation" and handles all DOM events stuff for me.


Looking at the closest point on the AABB

The idea is the following :

  • The camera rotates ;
  • the closest point on the AABB from the camera is where the camera should look at (direction) ;
  • a certain distance d is used to push the camera away from this point (position).

There are 2 cases :

  1. The border
    closest point on a border

  2. The corner
    closest point on a corner

Tested on this (very tricky) fiddle. Still need to fix top and bottom faces though (rotation singularity).


Raycasting on a bounding volume

This is the idea you described in the question :

  • Create a bounding volume the camera should follow ;
  • raycast the camera position on this BV ;
  • the new position of the camera is the intersection point ;
  • the new direction of the camera is the normal of the intersected face.

I tried it with a subdivided box geometry with rounded borders and corners so that the camera rotates at angles.

Raycasting on a BV

Considering the smoothness of the surface, the result could have been very convenient. Unfortunately, the camera sharply changes direction when the normal of the intersection changes, causing unpleasant bumps in the motion.

See this (tricky again) fiddle.

To fix this, we can linearly interpolate the normal along the triangle, but this requires the normals to be computed in such a way that every normal of a vertex is the average of the normals of the faces this vertex belongs to.

Normals interpolated along a face

Note that this solution is quite heavy (raycasting a lot of faces) and may requires some pre-processing to create the BV.


Changing the basis of the classical Orbit Controls

This is not exactly what you're looking for but it's also suitable for long objects and, honestly, that's the less tricky solution I made.

The idea is to modify the basis on which the classical THREE.OrbitControls operates so that the position is modified but the direction remains unchanged, like the following :

New basis for orbit control

I sort of did it with a customized version : THREE.BasisOrbitControls. Take a look at this fiddle.

var basis = new THREE.Matrix4();
basis.makeScale(2.0, 3.0, 4.0); // my object is very long and a bit tall

var controls = new THREE.BasisOrbitControl(camera, basis, renderer.domElement);

Note that the resulting motion of the camera is described by an ellipsoid.


Hope this helped, I'm really interested in a clean solution too.

like image 79
neeh Avatar answered Sep 28 '22 23:09

neeh