Viewer API feature request: camera 'up' getting and setting


(Aleahy) #1

Hi, the Sketchfab Viewer API is awesome!

We've been using it to develop a multi-machine surround viewer for Sketchfab scenes on Liquid Galaxy.

We're missing a camera 'up' setter in setCameraLookAt().

All 3d engines set an 'up' somewhere. Unfortunately it's not accessible thru the current Sketchfab Viewer API.

Being able to control the camera up is needed for camera roll. For Galaxy we currently fake the roll using CSS transforms. It's a kludge, which kills draw performance as we need to scale the viewport or create a viewport much larger than the screen.

What we need is an 'up' setter for the CameraLookAt method. A getter would be good too!

eg. setCameraLookAt( eye, target, [up], [duration], [callback] )

api.setCameraLookAt(
    [ 0, 13, 10], // eye position (x,y,z)
    [ 0, 10,  0], // target to lookat
    [ 0,  0, -1], // up vector
    0.0           // animation duration in seconds
);

Every other 3d engine has a camera up or roll setting method (ThreeJS, SceneJS, ...). eg. this is Biodigital Human API.

human.send( 'camera.set', {
  position: { x: 20, y: 40, z: 0 },
  target: { x: 25, y: 2, z: 0 },
  up: { x: 0, y: 0, z: -1},
  animate: false
});

Cheers, Andrew | Liquid Galaxy Project


(Aleahy) #2

Bumping this topic.

Any chance of getting camera 'up' in the Viewer API? It's limiting 6DOF camera control.

Cheers, Andrew


(Shaderbytes) #3

The issue I see here is that there is currently no camera z-axis roll navigation in the viewer via the mouse and keyboard. So if they opened up this possibility in the viewer api and a programmer set such a camera rotation, how exactly does the user "unroll" it while navigating after this..? They cant. The viewer API has to function in conjunction with all user controls.

Camera orbiting in general does not ever really use z-axis/forward verctor rotation. Think of practically every 3rd and 1st person games ever created, the camera does not do rolling and doesnt provide a means to do so either. Except for flight simulation games. That is the only use case I can think of.


(Aleahy) #4

We're developing Viewer apps with 6DOF controllers like the 3DConnexion SpaceNavigator and VR headsets, and clustered screen/CAVE environments. At the moment we have to do some crappy workarounds with Viewer API which kill Sketchfab performance to the point of uselessness.

If the user doesn't have a device that takes advantage of 6DOF navigation then they shouldn't get stuck with an odd camera rotation in the first place.

It's unlikely a programmer is going accidentally set the camera in a weird way and not notice it for key/mouse users. A programmer can also add handlers for mouse/key to modify roll.

Under-the-hood all 3d game engines have camera 'up' or roll get/set, it may not be used often but it's there. It's most definitely there under-the-hood in sketchfab, so all I'm asking is to provide an API for it.

Cheers, Andrew


(Shaderbytes) #5

@aleahy

Hey Andrew , Sure for VR totally :slight_smile:

You could of coarse use the api rotate function and then rotate you very first matrix transform node, might be a better solution to your current hack. Obviously you need to invert the rotation value so it seems like the camera rotated and not the scene.

https://sketchfab.com/developers/viewer/functions#api-rotate

EDIT , of coarse you cant guarantee which vector is the forward vector of this first matrix transform node. That would probably depend on the rotation state when the model was uploaded

EDIT 2 .. might be too complicated anyway since the scene rotation value will need to be dependent on the current camera lookat


(Aleahy) #6

Yes I was looking at using api-rotate on the first node.
But the transforms started doing my head in :frowning:

As a work-around I'm using a CSS roll on the viewer iframe. But it's not performant as we must create an frame about 1.5x larger than the display for when the corners roll away and more canvas must be revealed.


(Shaderbytes) #7

they link to a matrix tool in the docs , http://glmatrix.net/

This is all hypothetical :

You need to poll getCameraLookAt in the sketchfab api

then create a vector3 axis by subtracting camera.target from camera.position and normalize it.

then call fromRotation in glmatrix and supply this axis as input. The angle value would then be the roll angle.

then call setMatrix in the sketchfab api and input this rotated matrix.

probably something more technical to handle here , I dont know the state of the original matrix , or the state of the static call to fromRotation in glmatrix.

but anyway something like that could possibly work .. I might test it myself later today just for fun :slight_smile:


(Shaderbytes) #8

Hey Andrew , my theory worked :slight_smile: @aleahy

http://www.shaderbytes.co.za/sketchfab/development/api/examples/example_9.html

Something extra as I expected, I used the rotate function which additionally accepted an input matrix which I had to setup and cache from the root matrix from the model. You need to do this because as I mentioned the model matrix might not be and identity matrix.

polling at 10 milliseconds

Still a bit hackish and not perfect either but was fun trying to see what could be done. Also I now realized there is no default injected matrix transform object in a scene. Seems to be dependent on import

var axis = vec3.create();
var roll = 0;
var rootMatrix = mat4.create();
var rootMatrixTemp = sketchfabAPIUtility.rootTransform.worldMatrix;
for (var i = 0; i < rootMatrixTemp.length; i++) {
    rootMatrix[i] = rootMatrixTemp[i];
}
function updateAxis(err, camera) {
    var target = vec3.create();
    var position = vec3.create();

    vec3.set(target, camera.target[0], camera.target[1], camera.target[2]);
    vec3.set(position, camera.position[0], camera.position[1], camera.position[2]);
    var axisTemp = vec3.create();
    vec3.subtract(axisTemp, position, target);
    vec3.normalize(axis, axisTemp);
    // console.log("axis: "+vec3.str(axis));
    var rotatedMatrix = mat4.create();
    mat4.rotate(rotatedMatrix, rootMatrix, roll, axis);
    sketchfabAPIUtility.api.setMatrix(sketchfabAPIUtility.rootTransform.instanceID, rotatedMatrix, null);
}

function updateRoll(value) {
    roll = parseFloat(value);
    roll = roll * (Math.PI / 180);
}
function pollCamera() {
    sketchfabAPIUtility.api.getCameraLookAt(updateAxis);
}
setInterval(pollCamera, 10);