model-viewer icon indicating copy to clipboard operation
model-viewer copied to clipboard

Offsetting the model in canvas without changing perspective

Open eyaler opened this issue 11 months ago • 0 comments

In my very specific use case, I had a model view with a specific perspective I could not change, which caused a visually asymmetric alignment. I wanted to offset the model in the canvas to make it look centered initially. I tried many things before finding the working solution I am sharing here. Specifically, I could not find a responsive CSS solution. Also it is quite difficult to trigger a view update without resetting the frame (tried e.g. updateProjectionMatrix, queueRender, requestUpdate, updateBoundingBox... nothing worked). I would like to see a more integrated way to do this. My solution has the issue of showing the model jumping on load, it requires zoom control to be enabled, and i did not test it with panning. But it is minimal, responsive, and preserve user orbit control. BTW, my solution is only for horizontal offset... Replace the .07 with your desired horizontal shift fraction.

Image

<model-viewer onload="align(this, .07)" ...

function align(mv, dx) {
    const scene = mv[Object.getOwnPropertySymbols(mv).find(e => e.description == 'scene')]
    new ResizeObserver(() => {
        scene.camera.filmOffset = scene.camera.getFilmWidth() * dx
        mv.zoom(.001 * Math.sign(mv.zoomSensitivity))  // Trigger a view update without resetting the framing. Requires zoom to not be disabled and not be at maximum zoom-in
    }).observe(mv)
}

Edit: Multiplying by the sign of the zoom sensitivity is for the edge case where you set the zoom sensitivity to be negative and you start at maximum zoom-out

Might be related: https://github.com/google/model-viewer/discussions/4733

eyaler avatar Feb 08 '25 13:02 eyaler