isl-org / Open3D

Open3D: A Modern Library for 3D Data Processing
http://www.open3d.org
Other
11.47k stars 2.31k forks source link

How to sync up the cameras of multiple sceneWidgets in gui? #6385

Open Niroi opened 1 year ago

Niroi commented 1 year ago

Checklist

My Question

I'm currently trying to sync up the camera of multiple viewport inside a single window, meaning if i rotate the camera on one viewport the cameras of all other viewport move synchronized with it. I used the implementation from this issue. I've multiple things looking at the documentation but can't create a working solution.

jpsm-at-deec commented 12 months ago
#!/usr/bin/env python

import open3d as o3d
import open3d.visualization.gui as gui
import numpy as np

def make_box():
    box = o3d.geometry.TriangleMesh.create_box(1, 2, 4)
    box.compute_vertex_normals()
    return box

def main():
    gui.Application.instance.initialize()

    mat = o3d.visualization.rendering.MaterialRecord()
    mat.base_color = (1.0, 0.0, 0.0, 1.0)
    mat.shader = "defaultLit"

    singlebox = make_box()

    w = gui.Application.instance.create_window("Two scenes", 1025, 512)
    scene1 = gui.SceneWidget()
    scene1.scene = o3d.visualization.rendering.Open3DScene(w.renderer)
    scene1.scene.add_geometry("cube1", singlebox, mat)
    scene1.setup_camera(60, scene1.scene.bounding_box, (0, 0, 0))
    scene2 = gui.SceneWidget()
    scene2.scene = o3d.visualization.rendering.Open3DScene(w.renderer)
    #mat.base_color = (0.0, 0.0, 1.0, 1.0)
    scene2.scene.add_geometry("cube1", singlebox, mat)
    scene2.setup_camera(60, scene2.scene.bounding_box, (0, 0, 0))

    w.add_child(scene1)
    w.add_child(scene2)

    scene1.look_at([0,0,3], [9,9,3], [0,0,1])
    scene2.look_at([0,0,3], [-7,-7,3], [0,0,1])

    def on_layout(theme):
        print('s')
        r = w.content_rect
        scene1.frame = gui.Rect(r.x, r.y, r.width / 2, r.height)
        scene2.frame = gui.Rect(r.x + r.width / 2 + 1, r.y, r.width / 2, r.height)

    def on_m_event(something):
        cam = scene2.scene.camera.get_model_matrix()
        fov = scene2.scene.camera.get_field_of_view()
        m = cam
        rot = m[:3, :3]
        pos = m[:3, 3]
        camera_dir = np.dot(rot, np.array([[0],[0],[-1]])).squeeze()
        camera_up = np.dot(rot, np.array([[0],[1],[0]])).squeeze()

        newpos = np.array([-pos[0],-pos[1],pos[2]])
        newcamera_dir = np.array([-camera_dir[0],-camera_dir[1],camera_dir[2]])

        newcamera_up = np.array([-camera_up[0],-camera_up[1],camera_up[2]])
        scene1.look_at(newpos + newcamera_dir, newpos, newcamera_up)
        scene1.force_redraw()

        if something.type == gui.MouseEvent.Type.BUTTON_DOWN:
            print("[debug] mouse:", (something.x, something.y))
        return gui.Widget.EventCallbackResult.IGNORED

    w.set_on_layout(on_layout)
    scene1.set_on_mouse(on_m_event)
    scene2.set_on_mouse(on_m_event)

    gui.Application.instance.run()

if __name__ == "__main__":
    main()

I tried something like this