-
-
Notifications
You must be signed in to change notification settings - Fork 35.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
"Fit all" (show all) feature #6784
Comments
Here is one related answer: http://stackoverflow.com/questions/14614252/how-to-fit-camera-to-object. (There are others.) In your case, the "object" could be a bounding box of the scene. |
Many thanks to you for this information. BTW, according to your formula, dist equation is:
But. I think it is good to have camera "show all" / "show object" commands as a build in feature, instead of pointing your users to formulas.. |
The aspect ratio of the window and the desired margin are factors in specifying what "show all" means. I am concerned that such a feature would be too restrictive. We currently provide |
You can ask user about those variables (window aspect etc) as function arguments. Or, if you think that the api will be too fat, you can put this feature in some helper class.. Or at least, if I have to do this feature by my own, please tell me which target this helper should affect - camera or camera controller (OrbitController? etc) in terms of easy switching between controllers during visualization. |
Sorry, I can't help you write your app. Use stackoverflow if you need help. |
I'm sorry, but ThreeJs is your application. And I ask advice how to modify
|
OK. Sorry. You have to be careful about changing the camera properties "behind the back" of the controller. If you want to add this feature, and you are using a controller, I expect it would be better to add it to the controller, which in turn calls a camera |
@pavelvasev are you suggesting something like
@WestLangley Would the aspect ratio of the camera be good enough? |
Suppose we had a method Would it move the camera? To where? Would it change the camera field-of-view? The zoom? The rotation? Would it change all four properties? What are the constraints on camera movement/orientation? Note that A method such as |
@mrdoob yes something like camera.focus( object )
@WestLangley I understand your skepticism about too many possible algorithms and no priorities on them. But ThreeJS can implement only one (or few) algorithm. And if somebody want another one, he can implement it's own using yours as a base. As for me, One algorithm might be:
where dist is calculated so bbox will fill the screen. |
The procedure suggested by @pavelvasev sounds good. But I would use a bounding sphere instead. It actually solves a common issue I've seen: People tend to "lose" their objects. Nothing renders on the screen, and it's just because the object is behind the camera. Having a method like this could be handy also for us to help people. |
That's fine, if you want. You need to use the bounding sphere of the object -- and all of its children. Also, you need to take into consideration the camera frustum. If you move the camera, the bounding sphere must remain between the near and far planes. ( You can't move in too close just to see a tiny object.) Also, it should work on orthographic and perspective cameras. And the view needs to fit both the width and height of the canvas, so the aspect ratios come into play. |
Yep, that's why I was asking if the |
This would be a nice convenience feature, but I agree with @WestLangley that it belongs to the application layer. In addition of the existing arguments, consider the lack of control over the camera movement / speed / tweening with this interface. Maybe a new helper would be the way to go? Using the "plugin" approach championed in #6782:
Usage:
I'm not sure if |
Yea, I was purposely vague. : - ) Maybe both. I am not sure. It depends on the use case, I think.... Like I said, I think this should be an application-level method -- for the same reason you wanted to move the Controls to the examples -- every user has his own requirements and constraints. |
Oh. Posted concurrently with @dubejf ... |
Yep yep. However, I think this one is closer to |
If this requires the |
@mrdoob The OP said this:
So he wants it to work with the controls. That is why I said it would have to be a controls method -- which could in turn, call a camera method. Finding a solution that satisfies the controls position/rotation constraints and the camera frustum constraints would be required. You are suggesting a simpler thing: just a camera method to help a user set the camera to view an object and its children. Such a method might be useful for the editor. That can be implemented, but it would be more like a utility -- the camera can be placed in front of the object, looking in the direction of the negative world z-axis, and set at a distance from the object so the entire object is rendered. Some users might not like that solution, however, as it involves moving the camera to a new place. |
Keep in mind that focusing controls on an object requires both camera and target to be positioned (the rotation center of controls). Therefore, implementing this on camera level would require camera to include |
Yep, I think that's ok.
Even if the OP was asking this to be added to the controls, I would first focus (no pun intended 😅) in the cameras and later sort out the controls. |
Probably it will be good (if possible) to split camera focus implementation
So somebody could use both parts and somebody only part 1… for example for
|
I must clarify. I mean that camera.focus method stays solid, but internally
|
One thing to consider is animated objects. Currently bone animations are done on GPU, which is a good thing, but it means we don't have a way to keep track of bounding box on CPU side easily, and recalculating is would be expensive. Also, depending on complexity of your object and frequency at which its BB changes - it could take a while to update. Finally, depending on camera angle, BB that you want would change, AABB in that respect would use camera space for axis alignment. hence why "lookAt" has survived from times of glut (i think), it is straight-forward in its function (what @WestLangley mentioned) and it has constant time complexity. |
I'm particularly interested in something like this myself for my work with ViziCities – there are situations where I have a Three.js scene within a HTML element that has strict dimensions and need to have the included objects fill that element (ideally with a definable padding / margin). Currently, I'm using a mish-mash of formulas based on the various StackOverflow posts but my lack of understanding or something else is causing it to be far too verbose and complicated for my needs. It's also not quite right for some reason, probably because I need a solution that accommodates both width and height of the element, plus needs to accommodate objects that can be very wide or very tall (buildings). Something like |
Just finished a demo implementation for a (bounding) box, using OrbitControl, that may be of use to readers, here: jsfiddle.net/gpolyn/k40c5du5 Edit: Don't mean to promote the demo as the basis for implementation, more as an illustration. |
Few thoughts from a newbie who recently hit this problem:
function autoFitTo( obj, camera, controls ) {
const boundingSphere = new Box3().setFromObject( obj ).getBoundingSphere();
const scale = 0.618; // object size / display size
const objectAngularSize = ( camera.fov * Math.PI / 180 ) * scale;
const distanceToCamera = boundingSphere.radius / Math.tan( objectAngularSize / 2 )
const len = Math.sqrt( Math.pow( distanceToCamera, 2 ) + Math.pow( distanceToCamera, 2 ) )
camera.position.set(len, len, len);
controls.update();
camera.lookAt( boundingSphere.center );
controls.target.set( boundingSphere.center.x, boundingSphere.center.y, boundingSphere.center.z );
camera.updateProjectionMatrix();
}
// Helpful: https://stackoverflow.com/questions/34098571/fit-3d-object-collada-file-within-three-js-canvas-on-initial-load
|
I'm agnostic on adding this to the library - certainly it's a useful function though. Here's my take on it, also setting the camera plane encompass the object, and optionally targeting the object centre with orbitControls and setting the zoom so that the far plane cutoff is never encountered. This is assuming a PerspectiveCamera. const fitCameraToObject = function ( object, offset, orbitControls ) {
const boundingBox = new THREE.Box3();
boundingBox.setFromObject( object );
const center = boundingBox.getCenter();
const size = boundingBox.getSize();
// get the max side of the bounding box
const maxDim = Math.max( size.x, size.y, size.z );
const fov = this.camera.fov * ( Math.PI / 180 );
let cameraZ = Math.abs( maxDim / 4 * Math.tan( fov * 2 ) );
// offset the camera as desired - usually a value of ~ 1.25 is good to prevent
// object filling the whole canvas
if( offset !== undefined && offset !== 0 ) cameraZ *= offset;
camera.position.set( center.x, center.y, cameraZ );
// set the far plane of the camera so that it easily encompasses the whole object
const minZ = boundingBox.min.z;
const cameraToFarEdge = ( minZ < 0 ) ? -minZ + cameraZ : cameraZ - minZ;
this.camera.far = cameraToFarEdge * 3;
this.camera.updateProjectionMatrix();
if ( orbitControls !== undefined ) {
// set camera to rotate around center of loaded object
orbitControls.target = center;
// prevent camera from zooming out far enough to create far plane cutoff
orbitControls.maxDistance = cameraToFarEdge * 2;
}
}; As mentioned above, there is an issue with animated object - this doesn't work as the position can be calculated on the GPU, so What about adding something like this to OrbitControls? |
They are both good options @looeee @smcllns . 2 problems:
Imagine a mesh for a hexagonal pencil and the camera is positioned on the line going through the lead of the pencil. Your bounding sphere is going to have the same diameter as the length of the pencil, so you will end up seeing a small hexagon in the middle of the viewport (the pencil). instead of that hexagon filling your entire viewport. You first need to transform coordinates of geometry vertices into view space (from world space), and only then compute the bounding box. |
@Usnul that's true - actually that was intentional, as I wrote the function to enable previewing models quickly using the OrbitControls, so as the camera rotates around the centre of the bounding box the full object will always be in view. It's a very common use case, hence my suggestion that this be added as a function of the controls. It could easily be changed to display your hypothetical hexagonal pencil end fullscreen though by changing const maxDim = Math.max( size.x, size.y, size.z ); to const maxDim = Math.max( size.x, size.y ); |
Hello, I've worked on camera centering and I manage to make it fit perfectly to the camera! https://codepen.io/bilouwan/project/full/XpgGOp/ Do you think this could be added to three.js? |
@WestLangley recently suggested that we add a @moroine I haven't examined yours in detail, but it seems rather complex. There are quite a few examples of this function in the wild, and here - I'd rather go for one of the simpler ones. People can expand it for their own use case. |
Yeah, there is a bunch of them, but I didn't find something satisfying in my use case when objects have spread around the scene. It's complicated, for sure but I'll try to explain the methodology and mathematical proof |
From my point of view, a "fit camera to object" method should not care about other objects in the scene. You should be able to pass in any object in your scene and a camera, and the camera will be transformed and updated in whatever way neccessary to fit the view to the object, based on the bounding box of that object. |
Yeah but here it's more about multiple objects, but I also think that this is overkill in many cases but the common approach with axis-aligned bounding box is kind of unpredictable depending on the camera orientation. |
I think we can leave dealing with that up to the user. We're not trying to create a game engine here. Rather, would be better to create a minimal function and document the limitations: // limitations:
// - doesn't set clipping planes
// - doesn't take into account animation
gameUtils.fitCameraToBoundingBox = function( object3D, camera ) { ... } Then the function is mainly just a bit of trigonometry that users may find problematic. In particular, I like adding this method because if you search for this, you'll find quite a few different answers around the internet, and quite a few are wrong. If we add this, then when the question comes up we can point to this and say "hey, here's one that we tested and with correct math". |
Dear ThreeJS developers!
Please implement "fit all" ("show all") feature to the camera and/or OrbitControl and other controls.
This feature is very missing thing.
To provide some help, here is implementation of same feature in X3dom:
https://github.com/x3dom/x3dom/blob/master/src/Viewarea.js#L1077
Also, there is "fit object" (e.g. show object) feature:
https://github.com/x3dom/x3dom/blob/master/src/Runtime.js#L631
Many thanks in advance.
Please do not refer me to other feature requests like #1095
If you deny to do this, please at least point me, where is it better to code it, e.g. in camera, or in OrbitControl/etc, to get them (camera and control) synchronized?
The text was updated successfully, but these errors were encountered: