Repository: vispy/vispy

Issue:
SceneGraph: HowTo view single scene in different viewboxes
Using https://github.com/vispy/vispy/blob/master/examples/basics/scene/one_scene_four_cams.py to view a single scene in four different viewboxes doesn't work.

The scene is actually generated four times, not only once. There are reminders of multi-parenting commented out in the example, but this won't work any more (since removal of multi-parenting).

Is it possible to have one scene viewed from different angels (eg. top view, front view and side view) without recreating the scene four times?



Discussion:
Ahh crap, I thought we did a better job than that with the example :)

IIRC you should be able to have multiple views of the same object / scene, it was built into the big scenegraph update. It involved having a concept of "visual views". @campagnola knows the system better than I do, though.

Yeah, I read the different PRs and almost everything else from SceneGraph here, but there is no hint on howto accomplish that. It would be really nice if @campagnola could have a look. This scenegraph-ability is most-wanted here.

@Eric89GXL 

In example https://github.com/vispy/vispy/blob/master/examples/basics/visuals/line_prototype.py
I found something which seems to be the "visual view". It is shown there for a line visual.

I tried to get this running with the ImageVisual but had to change some code quick and dirty to get ImageVisual (view._method_used - freeze problem) running. I finally managed to get different views of one image visual on an app.Canvas.

Anyway this "visual view" works just for a single visual, not for a complete scene. 

@campagnola could you elaborate a bit on how to achieve simultaneous views of one scene. It should be possible, shouldn't it? In the meanwhile I try to get my scene into one visual. Any help very much appreciated!

Ping @Eric89GXL @campagnola

While working through open issues, is there any news on this? I would also have a look myself to figure something out. A bit of guidance or pointers what to consider and where to look is very much appreciated.

Unfortunately I don't have the time or the knowledge remaining to help :(

@Eric89GXL No worries! But is there some status on the whole project's whereabouts?

AFAIK none of the original main devs (@rougier @rossant @almarklein @campagnola) have much time to devote to VisPy currently

Yes, the current status is not clear

I don't think anyone is going to work on the project anytime soon, unfortunately

@kmuehlbauer, you are right that having multiple views was built into the visual system, but we stopped short of implementing this for the scenegraph as well. If you're interested in giving it a try, here's the basic idea:
- `Visual` is the class that does opengl drawing. It uses a `TransformSystem` to decide how to map from its own coordinates back to the screen. From any visual you can create a `VisualView`, which allows you to render the same visual using a different `TransformSystem`.
- `VisualNode` is the glue that makes visuals work inside the scenegraph, but it does not yet implement a `view()` method of its own. 
- You need to implement `VisualNode.view()`, which will return an instance of a new class called `ViewNode(Node)` (or similar). This new class will behave somewhat like `VisualNode`, except that there will not be a need for many subclasses like `VisualNode` has. Something like:
  
  ```
  class ViewNode(Node):
      def __init__(self, viewed_node):
          self._view = self.viewed_node.view()
      def draw(self):
          self._view.draw()
      def _update_trsys(self, event):
          # update self._view.transforms here
  ```
- This new class will contain a reference to a `VisualView`. It's `draw()` method will call the view's `draw()` method, and its `_update_trsys()` method will update the view's transform system.
- To make a view on an entire branch of the scenegraph, you would need to create a parallel graph constructed entirely of `ViewNode` instances. Ideally, this graph would automatically update itself to reflect changes in the original scenegraph branch.

Let's talk more if you'd like to give it a try.

Thanks @Eric89GXL, @rougier, @rossant for the status update.

@campagnola Thanks for explaining how this can be achieved. I'm using scenegraph quite often and also managed to get the `VisualView` working for one visual. I'll have to learn more how scenegraph and the `VisualNode` is working in order to completely follow your notes. 

But I'm not give in that fast. I'll come back for asking more detailed questions and appreciate your offer for help, @campagnola. 


Resolving patch:
diff --git a/examples/basics/scene/one_scene_four_cams.py b/examples/basics/scene/one_scene_four_cams.py
--- a/examples/basics/scene/one_scene_four_cams.py
+++ b/examples/basics/scene/one_scene_four_cams.py
@@ -8,11 +8,12 @@
 """
 Demonstrating a single scene that is shown in four different viewboxes,
 each with a different camera.
-"""
 
-# todo: the panzoom camera sometimes work, sometimes not. Not sure why.
-# we should probably make iterating over children deterministic, so that
-# an error like this becomes easier to reproduce ...
+Note:
+    This example just creates four scenes using the same visual.
+    Multiple views are currently not available. See #1124 how this could
+    be achieved.
+"""
 
 import sys
 
@@ -22,7 +23,7 @@
 canvas.size = 800, 600
 canvas.show()
 
-# Create two ViewBoxes, place side-by-side
+# Create four ViewBoxes
 vb1 = scene.widgets.ViewBox(border_color='white', parent=canvas.scene)
 vb2 = scene.widgets.ViewBox(border_color='white', parent=canvas.scene)
 vb3 = scene.widgets.ViewBox(border_color='white', parent=canvas.scene)
@@ -38,33 +39,16 @@
 grid.add_widget(vb4, 1, 1)
 
 # Create some visuals to show
-# AK: Ideally, we could just create one visual that is present in all
-# scenes, but that results in flicker for the PanZoomCamera, I suspect
-# due to errors in transform caching.
 im1 = io.load_crate().astype('float32') / 255
-#image1 = scene.visuals.Image(im1, grid=(20, 20), parent=scenes)
 for par in scenes:
     image = scene.visuals.Image(im1, grid=(20, 20), parent=par)
 
-#vol1 = np.load(io.load_data_file('volume/stent.npz'))['arr_0']
-#volume1 = scene.visuals.Volume(vol1, parent=scenes)
-#volume1.transform = scene.STTransform(translate=(0, 0, 10))
-
 # Assign cameras
 vb1.camera = scene.BaseCamera()
 vb2.camera = scene.PanZoomCamera()
 vb3.camera = scene.TurntableCamera()
 vb4.camera = scene.FlyCamera()
 
-
-# If True, show a cuboid at each camera
-if False:
-    cube = scene.visuals.Cube((3, 3, 5))
-    cube.transform = scene.STTransform(translate=(0, 0, 6))
-    for vb in (vb1, vb2, vb3, vb4):
-        vb.camera.parents = scenes
-        cube.add_parent(vb.camera)
-
 if __name__ == '__main__':
     if sys.flags.interactive != 1:
         app.run()


Test patch: