cognitedata / reveal

Cognite Reveal 3D viewer
https://cognitedata.github.io/reveal
Apache License 2.0
77 stars 19 forks source link

Camera Controls changes position very slowly over time #4614

Open joao-mbn opened 3 weeks ago

joao-mbn commented 3 weeks ago

Camera controls may become very slow over time, specially for zooming (dolly) and going sideways (truck). It happens with mouse, ASDW keys and touch screen. Pressing shift while controlling with ASDW will make it faster, but only in comparison to the other methods. It remains nonetheless slow.

I was able to consistently reproduce this by scrolling towards the horizon on the view, but it persists when I again focus towards nearby nodes (Gif 1). If I go back and forth, always focusing on the nodes, it gets very slow over time too (Gif 2).

Gif 1 Gif 2

If I reset the camera state with Cognite3DViewer setViewState method, it gets back to normal (Gif 1, when I click the Home button). Tests changing automaticControlsSensitivity and dollyFactor parameters didn't make a difference. We use the DefaultCameraManager without changing any parameter.

We ruled out memory or CPU problems by monitoring them while reproducing the bug, with no noticeable change in either. We tested in Windows machines and also with a Mac using an Apple Silicon chip (with Christian Flasshoff from Cognite), and it could be reproduced in all instances.

As for the relevant packages, we use:

{
  "dependencies": {
    "@cognite/reveal": "^4.14.1",
    "@cognite/sdk": "^8.3.0",
    "three": "^0.164.1",
  }  
}

As for configuring the Cognite3DViewer, we have basically this setup:

useEffect(() => {
    if (!client) return

    const widget = threeDWidgetRef
    if (!widget) return

    for (const children of widget.children) {
        if (children.tagName === 'CANVAS') {
            return
        }
    }

    const viewer = new Cognite3DViewer({
        sdk: client,
        domElement: widget,
        loadingIndicatorStyle: { placement: 'topRight', opacity: 1 },
    })

    setupViewer(viewer, client)
    setViewer(viewer)
    ;(async () => {
        const cadAndPointCloudModels = await getCadAndPointCloudModels(client)
        const image360Models = getImage360Models()

        const allModels = [...cadAndPointCloudModels, ...image360Models]
        setModels(allModels)
        defaultModelsConfig.current = allModels

        image360Models
            .filter((m) => m.visible)
            .forEach(({ name, space }) =>
                viewer.add360ImageSet('datamodels', { image360CollectionExternalId: name, space })
            )

        cadAndPointCloudModels
            .filter((m) => m.visible)
            .forEach(({ modelId, revisionId }) => viewer.addModel({ modelId, revisionId }))
    })()
}, [client, threeDWidgetRef])

function setupViewer(viewer: Cognite3DViewer, client: CogniteClient) {
    addPlane(viewer, client)
    addSky(viewer)
    addAxisTool(viewer)
    setupViewerResolution(viewer)
    setViewerState(viewer)
}

function addPlane(viewer: Cognite3DViewer, client: CogniteClient) {
    client.files.getDownloadUrls([{ externalId: 'ars_satellite_map' }]).then((urls) => {
        const planeUrl = urls[0]?.downloadUrl

        if (!planeUrl) return
        const plane = new THREE.Mesh(
            new THREE.PlaneGeometry(15000, 15000),
            new THREE.MeshBasicMaterial({ map: new THREE.TextureLoader().load(planeUrl) })
        )
        const scale = 0.0705
        plane.scale.set(scale, scale, scale)
        plane.position.set(1738.8, 6, -1181.3)
        plane.rotateX(-Math.PI / 2)

        viewer.addObject3D(plane)
    })
}

function addSky(viewer: Cognite3DViewer) {
    const skyBox = new THREE.Mesh(
        new THREE.SphereGeometry(5000, 15, 15),
        new THREE.MeshBasicMaterial({
            side: THREE.BackSide,
            map: new RGBELoader().load('sky.hdr'),
        })
    )
    skyBox.position.set(1738.8, 0, -1181.3)
    skyBox.rotateY(-Math.PI / 2)
    viewer.addObject3D(skyBox)
}

function addAxisTool(viewer: Cognite3DViewer) {
    new AxisViewTool(viewer, {
        faces: {
            xNegativeFace: { label: '-x', fontSize: 30 },
            xPositiveFace: { label: '+x', fontSize: 30 },
            yNegativeFace: { label: '-y', fontSize: 30 },
            yPositiveFace: { label: '+y', fontSize: 30 },
            zNegativeFace: { label: '-z', fontSize: 30 },
            zPositiveFace: { label: '+z', fontSize: 30 },
        },
        size: 60,
        position: {
            corner: Corner.BottomLeft,
            padding: new THREE.Vector2(10, 10),
        },
    })
}

function setupViewerResolution(viewer: Cognite3DViewer) {
    viewer.setResolutionOptions({ maxRenderResolution: 5e5, movingCameraResolutionFactor: 0.4 })
}

async function setViewerState(viewer: Cognite3DViewer) {
    viewer.setViewState({
        camera: { position: { x: 1517, y: 159, z: -948 }, target: { x: 1698, y: 22, z: -1143 } },
    })
}
christjt commented 2 weeks ago

Thank you for reporting, we will have a look.

haakonflatval-cognite commented 1 week ago

Hi, @joao-mbn - we are aware that the default camera manager have a few issues, and it seems that this is one of them. We do have another camera manager under works. You can try this one out by setting the "useFlexibleCameraManager" option to true in the options used to construct the Cognite3DViewer. Note that it's considered experimental, and we may change its behavior without warning, thus it's not recommended for production use yet

joao-mbn commented 1 week ago

Appreciate the feedback. Since we're going to put this in production soon, I'll better stick with the devil I know.

In any case, I'd love to know if the fix for this is on your schedule any time soon; or you have an idea of what's the problem, in case we have to roll-out our own camera manager.

haakonflatval-cognite commented 1 week ago

I see. Unfortunately we are currently not planning any improvements to the current camera manager. Rather, we aim to replace it by the new one in the next major version of Reveal

joao-mbn commented 1 week ago

I see, thanks.