Camera positioning in speckle-viewer

Hello Speckle Community :slight_smile:

currently I am working on a project using the SpeckleViewer. One of the requirements is that the camera position of the viewer has to be at a certain angle after the viewer has finished initializing. I have already figured out how to rotate and zoom with the camera after initializing but right now I’m kinda stuck at changing the actual position of the camera afterwards.
I have already tried to change the camera position through the cameraHandler but the actual position didnt really change.
This is how I am trying it right now but the set-function doesnt really do much. I’m new to the viewer and have tried to solve it by sticking to Cristis demo here: https://github.com/specklesystems/speckle-server/blob/main/packages/viewer/src/modules/Viewer.js

And this is my sourcecode:

viewer.loadObject(props.speckleUrl).then(async () => {
			viewer.interactions.rotateTo("bottom");
			viewer.cameraHandler.controls.zoom(60);
			viewer.cameraHandler.camera.position.set(
				-74.71723272424681,
				-155.54465036691263,
				-73.90207775447588
			);

It would be really great if someone could help me understand the camera of the viewer a little bit better :slight_smile:

thanks in advance!

1 Like

Hey @christopher.menzel
Welcome to the Speckle community! Feel free to Introduce yourself to everyone if you haven’t already and are willing to share.

If the camera position changes, the scene will need to re-render to have an effect. Depending on the surrounding code you may not be triggering that within the async event.

I’m not sure which demo you are looking at, but it could be as simple as adding viewer.needsRender = true for example.

5 Likes

Hello @jsdbroughton,

thank you for your support.

I have tried your solution and set viewer.needsRender to true after changing the camera position, but i don’t see any changes in viewer after that.

Is it the right way to set the camera positions with viewer.cameraHandler.camera.position.set() or should I use a another method to set the camera position?

Hey, sorry for the late reply - we’re on a company retreat! There is actually a method that should take care of all this for you - it’s not very nicely exposed yet as we still need to cleanup these parts.

You’re on the right track. Here’s what i use:

window.__viewer.interactions.setLookAt(
  { x: this.camToSet[0], y: this.camToSet[1], z: this.camToSet[2] }, // position
  { x: this.camToSet[3], y: this.camToSet[4], z: this.camToSet[5] } // target
)

There’s an optional argument called transition, in case you want to not “teleport” the camera there.

Otherwise, we’re using the excellent CameraControls lib. You can access them via viewer.cameraHandler.controls.

3 Likes

Hi @dimitrie,

thanks for your reply :slight_smile:

viewer.interactions.setLookAt() works fine and I was able to set the camera position, but now I have one other problem.

Currently I zoom with viewer.cameraHandler.controls.zoom(), but this is not so optimal and I want to replace it with viewer.cameraHandler.controls.dollyTo().

If dollyTo() is called I can see that the viewer.cameraHandler.controls.distance changes, but it takes no effect in the viewer.

Hm, this is a bit strange. I’ve just tried this in a local viewer, and it works!

__viewer.cameraHandler.controls.dollyTo(10, true)

You can run the above in the console on any speckle page with the viewer and a loaded model and it zooms in as expected. Maybe share your code so we can have a deeper look if the problem persists?

1 Like

Hi @dimitrie,

sorry for the late reply, finally I got dollyTo() to work but it still don’t work as expected.

dollyTo() and zoom() are “zooming” into the middle of the loaded model and I need to point the camera to a specific object.

I found viewer.interactions.zoomToObject() but could not figure out how to use it yet.

I got the object from object-doubleclicked event, wrote it to a json file and passed it zoomToObject() but this does nothing.

What do I have to pass to zoomToObject() to make it work? :slight_smile:

thanks in advance!

ah, then if it’s a specific object, zoomToObject is indeed your friend!

zoomToObject( target, fit = 1.2, transition = true ) {
    const box = new THREE.Box3().setFromObject( target )
    this.zoomToBox( box, fit, transition )
  }

where target should be your threejs object! This might be tricky, depending on wether you get your object from an actual interaction event or not.

You could write a zoomToObjectId function, which would go through the scene and find the specific object for you. I can give it a shot if this is what you’re looking for.

2 Likes

You could write a zoomToObjectId function, which would go through the scene and find the specific object for you. I can give it a shot if this is what you’re looking for.

I would appreciate it very much, it seems to be exactly what I need. :slight_smile:

EDIT: In the meantime i tried following.

const zoomToObjectId = (id: string) => {
			viewer.scene.traverse(function (obj: { uuid: string }) {
				if (obj.uuid === id) {
					try {
						viewer.interactions.zoomToObject(obj);
						console.log(obj);
					} catch (e: any) {
						console.log(e);
					}
				}
			});
		};

This logs me now my object to the console but it still not zoom to the object.

Maybe you have an idea what i am doing wrong? :slight_smile:

1 Like

Sorry for the late reply, took me some time to get back to this! I’ve quickly hacked something in the viewer:

  // InteractionsHandler.js
  zoomToObjectId( id ) {
    let obj = this.viewer.sceneManager.allObjects.find( o => o.uuid === id )
    if( obj ) this.zoomToObject( obj )
    else console.warn( `No object with id of ${id} found.` )
  }

This seems to work! I’ll try and publish a new release with this quick feature addition, and will update the thread here.

2 Likes

Okay, it’s published on npm: @speckle/viewer - npm - so you should be able to update it as a dependency :new:

3 Likes