Two views of the same scene running in separate windows?

I’ve been trying to create two windows, each of which shows a unique view of the same scene, with one camera’s heading rotated 90 degrees with respect to the other’s viewpoint, but in the same location.

The behavior I am trying to achieve is a “cockpit effect”, as if I have one screen showing the straight ahead view and a second screen where you can see out the left side of the cockpit. Each screen will get one window.

When I do this, I get some weird and undesirable behavior. The first “straight ahead view” window appears to render correctly, but the second “rotated view” window appears to have a major rendering error, as if it is trying to render two separate scenegraphs simultaneously.

It is also critical that I create/edit a Lens object for each camera, given the particulars of my application.

Please note: There is also a scale node in -Z. My projected image is sent through a projector and in to a physical mirror, so I’m compensating for the view in the code. As far as I can tell, this is NOT relevant to this two-window problem.

Thank you in advance for any help you might provide.

My code thus far:

    #Code for creating first window and camera and lens
    prop = WindowProperties()
    base.setBackgroundColor(0, 0, 0)
    #DLP can handle 640,480
    prop.setSize(640, 480)
    prop.setUndecorated(True)
    prop.setOrigin(0,0) 
    prop.setTitle('Straight ahead view')
    base.setFrameRateMeter(True)
    base.win.requestProperties(prop) #update the view
#scaling node reqd to correct for models at different scales
    self.myScaleNode = render.attachNewNode("myScaleNode")
    self.myScaleNode.setScale(0.1)

    #FOV setting based on projector capabilities
    #640/480 = 4/3
    #FOV = 27 degrees horizontal, based on measurements of projected image at set distance

    base.camLens.setAspectRatio(4/3)
    base.camLens.setFov(27)

    camNP = cameraLocation.attachNewNode('camNP')
    #Scale -1 in Z-dir corrects for mirror image of projector
camNP.setScale(1,1,-1)        
self.camNPRef = camNP
    base.camera = camNP

    #2nd Camera creation and nodeling
    altWindow = base.openWindow()
    prop = WindowProperties()
    prop.setSize(640,480)
    prop.setOrigin(640,0)
    prop.setUndecorated(True)
    prop.setTitle('Rotated View')
    altWindow.requestProperties(prop)
    
    
    #2nd camera lens creation and setup
    displayRegion = altWindow.makeDisplayRegion(0,1,0,1)
    altCam = Camera('altcam')
    altCamNP = NodePath(altCam)
    myLens = PerspectiveLens()
    myLens.setAspectRatio(4/3)
    myLens.setFov(27)
    altCam.setLens(myLens)
    displayRegion.setCamera(altCamNP)

    altCamNP.reparentTo(cameraLocation)
    altCamNP.setH(90)

Actually, I suspect this is precisely the problem. When you apply a negative scale, you change the coordinate system from right-handed to left-handed, and invert the winding order of all of the polygons, effectively turning everything inside-out. This can make the scene look awfully weird.

It’s possible to correct this by applying a CullFaceAttrib.makeReverse() attribute, but it’s probably easier just to use:

altWindow.setInverted(True)

instead of scaling the camera.

David

The main window has the -Z scaling, but it appears to render correctly (and did so in the experiments I was doing with only the “straight ahead view”). The rotated view has no -Z scaling active.

I did replace the -Z scaling in the main window with the setInverted and it mirrors and flips the image upside down (I think). However, the secondary view seemed to be better. However, it still appears almost like there are two versions of the scenegraph being rendered in the secondary window, as if an image is drawn and then another version, slightly shifted, is drawn on top of that. Very strange.

What I would like to do is take another approach at window creation. If one wanted to set up two windows, each showing a view of the scene but one camera rotated 90 degrees from the other, and also set the lens properties for each camera, what is the “cleanest” way to do that? I’m tempted to start from some known clean implementation and then embroider it with the particulars of my application. At the very least, it might show what I’m adding that breaks that windowing code.

What you have done looks clean enough to me, and in fact when I run it, it appears to work fine. When I put a smiley in front of the camera I see it in both windows without troubles.

So, either (a) I’m not using a sophisticated enough model to see the problems you’re reporting, or (b) the problems you’re reporting are due to driver issues with opening two windows.

Some drivers do have issues with multiple windows, though I’ve never seen one distort the rendering in the second window. Do you really need two windows, or can you achieve the desired results with one big window divided into two DisplayRegions?

David

That may in fact be the case. I’m running this simulation on a macbook pro with an ATI card. I had to change some setting in the code to not use the default graphics pathway and use directx9 or something like that because of driver issues with my card. I have not yet tried to run this code on another machine. I will check that out.

The reason multiple windows is convenient is that these two views are actually piped through two separate picoprojectors that appear to a PC as separate monitors. It should be possible though, to use a single window that is 2 x 640 wide and put its upper left corner at (0,0). This will then span both monitors, with 640 pixels to each window.

When creating a new viewing window, you specify the display region, correct? I wrote:

 displayRegion = altWindow.makeDisplayRegion(0,1,0,1) 

but this is to modify the newly created window. If I return to a single window but have both virtual cameras displaying to different parts of that window, how do you get access to the the DisplayRegion for the primary window base.win? Is there a “getDisplayRegion” command?

You can get a list of DisplayRegions already on the window with base.win.getActiveDisplayRegions(). This will include the DisplayRegion for render, the one for render2d, and (if you have it enabled) the one for the fps meter.

To find a particular DisplayRegion, it’s usually easier to ask the camera. base.cam.node().getDisplayRegion() will return the DisplayRegion for render. base.cam2d.node().getDisplayRegion() will return the DisplayRegion for render2d.

You can then shrink these DisplayRegions to half their size with displayRegion.setDimensions(0, 0.5, 0, 1), which is the left half of the window. When you create the new DisplayRegion, you will do it with (0.5, 1, 0, 1), which is the right half of the window.

You might also want to put:

aspect-ratio 1.333

in your Config.prc to force the aspect ratio to a fixed value, so it doesn’t try to adjust itself to the full width of your window.

David