Skip to content
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

Camera "zoom to all" target center of pysical model upon IFC import #34

Closed
Krande opened this issue Feb 4, 2021 · 9 comments
Closed
Assignees
Labels
enhancement New feature or request

Comments

@Krande
Copy link

Krande commented Feb 4, 2021

Hi

I am looking for a way that would move the camera to "zoom to all" (target the volumetric center of imported elements) and use that as a Orbitcontrol center upon import of IFC. This would make life a lot easier when it comes to viewing our IFC models that have a coordinate system that starts on a particular elevation. It should be noted that our exported model units are by default in millimeters. I've tried to follow a couple of examples I found online, but I am definitively doing this wrong.

I tried to modify example "00" by simply adding the following snippet of code to the "pick()" method in the "scene-picker.js" file in order to find a way to move the camera to the object I am clicking on. Note that I have little experience with threejs, so I might be violating some basic rules :)

...
pickedObject.material = pickedObjectMaterial;
console.log(pickedObject._Data);

// Code for setting camera target to picked object
var target = pickedObject.geometry.boundingSphere.center;

console.log(target);

//camera.position.set(target);
camera.position.set(target+new THREE.Vector3(10,10,10));
camera.lookAt(new THREE.Vector3(target));
//camera.updateProjectionMatrix();

When I click on a beam (floating in the middle of nowhere as shown below) I end up apparently lost in space :)

image

All I see is the grey background and I am unable to see my beam and I've lost sight of the grid making it difficult to figure out where I am :(

image

The updated camera does however seem to be corrupt or broken in some (as shown in the console logging of the "camera"displaying NA values in the x,y,z coordinates)

image

I might be way off here, so it is much appreciated if anyone have any suggestions on where I ought to be looking or guidance on how I should debug or any related tips :) And any tips for where I should look to implement the same functionality as a final event after IFC import would also be much appreciated.

Great project btw :)

Best Regards
Kristoffer

@agviegas
Copy link
Collaborator

agviegas commented Feb 4, 2021

Hey,

I also had this topic on my mind the other day. It be a great contribution to the example!
Here we are dealing with two separate topics.

  1. Is there a way to center the camera at the selected object?
  2. Is there a way to center the camera at the geometric center of the scene when an IFC is imported?

Maybe we can start with the first topic (as I think it is more important) and then think about the second one. Your implementation is not working because for the example I am using smooth zoom. This object controls the camera and is represented by the controls object (in three-scene.js), and it can be controled using its target attribute. Something like this should work:

function pick(camera, controls) {
  
[...]
      console.log(pickedObject._Data);

      const pos = getCenterPoint(pickedObject);
      controls.target.set(pos.x, pos.y, pos.z);
    }
  }
  canUserPick = false;
}

function getCenterPoint(mesh) {
  var geometry = mesh.geometry;
  geometry.computeBoundingBox();
  var center = new THREE.Vector3();
  geometry.boundingBox.getCenter( center );
  mesh.localToWorld( center );
  return center;
}

With this, the camera should look at the selected object, but the transition is really abrupt. We have several options,for me, the ideal behaviour would be that when clicking on an object, the camera does not move, but if I later try to orbit, the centre of orbit is that object. Hopefully this makes sense. 😅 This is the behaviour in a lot of 3d apps, including Revit and BIMvision. I'm not sure if the following can be done, as I haven't tried it, but it's an idea. Feel free to try anything else you come up with!

This means changing the target to the selected object, and then compensating the rotation of the camera with the angle that form the projection of both objects to the camera. This is just considering the horizontal rotation; then, we also have to calculate the height difference between both target objects and compensate it with a vertical rotation.

image

(Behold my amazing mouse-drawn sketch). Alfa is the horizontal rotation, Beta is the vertical rotation.

This way we can hopefully get the abovementioned behavior.

There are also other cool functionalities we can implement (here or in another issue):

  • Camera animation that moves the camera to the selection.
  • Camera animation that makes zoom extent to the scene.

@agviegas
Copy link
Collaborator

agviegas commented Feb 4, 2021

If you prefer to stick with the "zoom extent" functionality, you can forget about picking and create a new button that gets all the bounding boxes or centers of the meshes in the scene (using, for example, the getCenterPoint logic of my previous comment), and calculate with trigonometry the position of the camera so that it targets at the central point of the scene and has all the objects within its angle view.

@agviegas agviegas added the enhancement New feature or request label Feb 4, 2021
@Krande
Copy link
Author

Krande commented Feb 5, 2021

Awesome! Thanks for the detailed suggestion.

Now when I click on an object the camera moves slightly and the rotation center is set to that object and I can easily zoom to it.

image

The only change to your suggestion was to use controls.target = getCenterPoint(pickedObject); instead of controls.target.set(..); which resulted in an error (see error messages below).

// scene-picker.js
function pick(camera, controls) {
  if (canUserPick && importedIFC.children) {
    if (pickedObject) {
      pickedObject.material = pickedObjectSavedMaterial;
      pickedObject = undefined;
    }

    raycaster.setFromCamera(pickPosition, camera);
    const intersectedObjects = raycaster.intersectObjects(importedIFC.children);
    if (intersectedObjects.length) {
      pickedObject = intersectedObjects[0].object;
      pickedObjectSavedMaterial = pickedObject.material;
      pickedObject.material = pickedObjectMaterial;
      console.log(pickedObject._Data);
      // Slight modification of proposal (even though this suggestion results in printed warning)
      controls.target = getCenterPoint(pickedObject);
    }
  }
  canUserPick = false;
}

// Proposed function as is
function getCenterPoint(mesh) {
  var geometry = mesh.geometry;
  geometry.computeBoundingBox();
  var center = new THREE.Vector3();
  geometry.boundingBox.getCenter( center );
  mesh.localToWorld( center );
  return center;
}
// three-scene.js (reference to pick)
[...]
pick(camera, controls);

For some reason controls.target.set(..) gave me an error (shown below) so I opted for controls.target = getCenterPoint(pickedObject);.

image

The controls.target = getCenterPoint(pickedObject); does however print a warning about the target.set being immutable, but at least it works. I am guessing there is a better way of handling this?

image

I agree that moving the camera while picking is not ideal. The instant camera-jump whilst clicking on items in the viewer looses its charm after a few clicks :) So I propose that this particular functionality could be implemented as a specific key or special keypress combination as opposed to part of the "pick" method. Maybe it could be a part of the "smooth-zoom.js" lib?

Let me know what you think,

Best regards
Kristoffer

@agviegas
Copy link
Collaborator

agviegas commented Feb 6, 2021

In your case controls.target.set(..) is not working because I made a mistake in the definition of the controls in three-scene.js. 😅 Now it should work.
image
Yes, I agree. We can assign the extend to selection functionality to a button or keyboard press. Hopefully, you can wrap this functionality in a separate file / module like extend-to-selection.js (maybe doing the selected object global, as we probably want to access this object from different places in the application), so even though we bind it to a specific button, other users of the library can easily change / plug / unplug it.

PD: Only making the extend to selection functionality would be really nice already, but if you make this transition animated, it would be spectacular. 😉 Just an idea.

@Krande
Copy link
Author

Krande commented Feb 10, 2021

Sounds like a plan! I will try to find time to work on it in the coming days. It will take me a while before I can build something that's worth a pull request, so if you have a plan ready for implementation, you can just start and I can chime in:)

Best regards
Kristoffer

@agviegas
Copy link
Collaborator

agviegas commented Mar 8, 2021

Hey @Krande! Is there any news on this? The library suffered some breaking changes, but they should not affect what you are doing, as IFC.js is now focused on having this kind of code. Just remember to pull the latest changes, which have been drastic.🙂 Also, if you still plan to do this, feel free to drop a draft PR to let us help you. Cheers!

@Krande
Copy link
Author

Krande commented Mar 9, 2021

Hello! Sorry, I haven't had time to look more into this:( If you have a plan of how to implement this I think you will have a solution up and running much faster than what I can deliver :)

@agviegas
Copy link
Collaborator

This was already solved by @Voffknur.

@ghost
Copy link

ghost commented Sep 8, 2022

Hi @agviegas! Sorry, I'm not sure I understood your last comment, is this zoom to all or extend to selection a method that's available through the web-ifc-viewer API? I'm investigating this topic but I didn't find any solution out of the box.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants