Add support for reverse perspective rendering

Create issue
Issue #80 resolved
Mario Koerner created an issue

I tried to set up a scene with reverse perspective viewing geometry, where the projection rays converge "behind" the scene. I used the normal SoPerspectiveCamera, but changed

  • the position (moved along the projection direction to a point behind the scene)
  • near, far and focal distance (set to negative values to set up a view frustum "behind" the camera)
  • orientation (rotated camera by 180 degree around the z axis to compensate the image flip induced by the negative near distance)

Example: Scene with cube at origin

Perspective camera:

  • position: 0 0 10
  • orientation: 0 0 1 0
  • nearDistance: 1
  • farDistance: 20
  • focalDistance: 10

Reverse perspective camera:

  • position: 0 0 -10
  • orientation: 0 0 1 3.14159
  • nearDistance: -20
  • farDistance: -1
  • focalDistance: -10

Only one small change to function get_perspective_projection() in SbDPViewVolume.cpp was necessary to render the scene with reverse perspective viewing geometry. Since OpenGL clips in homogeneous space (before computing the perspective division), it assumes that the homogeneous w coordinate in clip space is positive. With the reversed setup, the scene is on the positive z axis of the camera coordinate system, thus the w coordinate in clip space is negative when using the standard OpenGL projection matrix. This can be compensated by multiplying the whole projection matrix by -1 if the near distance is negative.

With this change, the scene is rendered with the expected viewing geometry (see attached images and scene graph). The render state is also set up in a convenient manner, e.g.

  • the view volume direction points from scene foreground to background
  • the camera space orientation (after applying the viewing matrix) is consistent with the normal perspective case (negative z axis points from foreground to background, y axis points upwards), so lighting also works fine
  • the world space picking ray points from scene foreground to background

By changing 3 more lines of code (functions SbProjector::verifyProjection(), SbSphereProjector::isPointInFront() and SbCylinderProjector::isPointInFront) at least the standard manipulators (TrackballManip, TransformBoxManip) are also working nicely with reverse perspective viewing geometry.

I can provide my changes on a forked branch. It would be great, if Coin would support reverse perspective projections by merging them to the main branch.

Comments (7)

  1. Thomas Moeller

    Mario,

    Thank you for the enhancement proposal and the detailed description. I support this idea. But can you please add some code snippets or a diff file? There doesn't seem to be a Coin fork in your repositories.

    Thank you,

    Thomas

  2. Roy Walmsley

    Mario,

    I too support this idea. Can you also bear in mind that there should be some documentation comments, particularly with respect to describing the basic camera setup required (as you have done above) to achieve this. The top of the SoPerspectiveCamera.cpp file would seem to be the best place.

    Now I have been looking at this some more and wondering ...

    How it might be implemented for VRML (and my extensions to X3D). In VRML there is the Viewpoint node. X3D has the Viewpoint and OrthoViewpoint nodes. None of them has support for setting anything other than the position, orientation and field of view of the cameras.

    Should we introduce a new node - SoReversePersepctiveCamera (perhaps derived from SoPerspectiveCamera) with the defaults modified for the field settings.

    Comments please.

    Roy

  3. Mario Koerner reporter

    Hi Thomas and Roy,

    I will commit my changes and create a pull request as soon as I find some time. I will also add documentation to SoPerspectiveCamera.cpp.

    Roy: I think it would be possible to derive a SoReversePerspectiveCamera class from SoPerspectiveCamera. It should be sufficient to override the getViewVolume() function that derives the view volume as already sketched in my original post:

    RevPerspCam.jpg

    vv.position = cam.position + (cam.nearDist + cam.farDist) * cam.direction
    vv.orientation = cam.orientation * rotation(0 0 1 pi)
    vv.nearDist = -cam.farDist
    vv.farDist = -cam.nearDist
    vv.focalDist = cam.focalDist - (cam.nearDist + cam.farDist)
    

    With that setup, one could just copy the field values from a normal perspective camera to a reverse perspective camera. It would also be possible to cast a SoReversePerspectiveCamera instance to SoPerspectiveCamera and handle it as a normal camera.

    What do you think? Would this solve your issue with the VRML viewpoints?

    Best, Mario

  4. Roy Walmsley

    Hi Mario,

    Thanks for the update. In some ways I like the idea of the SoReversePerspectiveCamera class. However, I need to look at all the changes you have mentioned above and see what the implications are.

    With respect to VRML this would tie in then with the possibility of adding a SoVRMLReversePerspectiveViewpoint node. A similar extension could be proposed for X3D then.

    Roy

  5. Log in to comment