Parallel Projection

When I was looking at the cvs archives I noticed that there was a state simuler to the one that mojo described that was removed because it did not work.

Right there was a state to attempt to switch between Ortho2D and Projection which did not work at all because of Ortho2D being in screen space. Ortho3D is still in world space so it might work (although with the camera and render matrices, I don’t think it will).

Well, had some time this morning to code some stuff together. I am now less of a jME/OpenGL newbie… and tonight I thought I might as well package it up and show it here.



I decided to go with creating RenderState after all. In fact I think the result is rather elegant after all.



What I’ve done:

Added methods to camera to set Ortho and Ortho scale. You can have both a frustum and ortho defined at the same time. The renderer implementation (LWJGL in this case) will pass itself to LWJGLProjectionState, which when apply() of the RenderState is called, will retrieve the LWJGLCamera, and use the LWJGL specific methods to change from a frustum to an ortho. The object then renders as expected, in the right projection. So there’s no weird calls anywhere to check ProjectionState where it does not belong. All changes to the API for rendering in with a different projection are in the implementation specific part (where I think they belong).



So, the good:

  • Minimal API changes, just an extra render state, and new methods in Camera that add what we need without breaking anything.


  • RenderStates make it extremly easy to change the projection method for your objects, as well as switching between the modes.


  • All none frustum specific methods in Camera work for both projection methods, so most controls do too. Again, this makes it easy to switch between modes.


  • The editable terrain stuff I was working on now looks extra delicious



    The less good:


  • Culling isn’t implemented yet. It can be done without changing the Camera API though, native implementations (LWJGLCamera in this case) will just need to override countains(BoundingVolume) since they should know for what projection method to cull. The maths for doing the culling itself could of course still be AbstractCamera.


  • The number of methods for setting your ortho is a bit limited compared to frustum, need to generate some getters and setters. But perhaps also look into creating methods that will set both the ortho and the frustum to something with as much overlap as possible.


  • While I don’t think having both a setOrtho and setFrustum on 1 Camera is bad (in fact it makes sense to me), internally it’s a bit weird. Calling onFrustumChange when setOrtho is updated doesn’t seem very “OpenGL-like” or “Profesional API” to me. Would be on my list to refactor, don’t ask me to what though :þ An alternative would be implementing a system with multiple cameras, but I don’t think that’s really needed for jMe at this stage.



    The “not-good”:

    Both projection methods can be used at once now… I was hoping they’d render to the same depth buffer correctly, but… this doesn’t seem the case. Parallel is always on top it seems… (except when it’s… well… not). Might be an issue with translated coordinates. Might be an issue with me not understanding a thing about how this’s supposed to work in the first place.



    It’s not the end of the world though, in most cases you’d want to render everything parallel, or perspective with some parallel elements on it. Having a parallel world with with perspective elements in it seems to be harder though. If it’s impossible I can accept that, as long as I know WHY it is! }:-@



    To do… aside from tso much code so little time.
  • Write a better, simpeler test
  • Look into writing some methods that set frustum and ortho with maximum overlap and test with more input systemes (also see test).





    The test I have now is based on TestTerrainPage, the terrain has been reduced in size a bit so it can render on my awesome TNT2…



    From the Javadoc from my test:



    /**



    TestPerspectives shows the different Projection methods.

    These are set through the Renderstate ProjectionState



    This is for now just a temporary test, or more a demo if you like.

    As long as culling is not implemented this might be a problem. A quick

    fix would be to add some code at the first line of the contains() in AbstractCamera.


    bound = null


In the demo you can use the F and O key to switch between using a (F)rustum
and an (O)rtho for the Terrain node. When starting the demo look down
and you'll see two spheres and 2 spinning cubes. (Note: for now you will only see them if you switch to the Frustum or turn on Wireframe. As you move away or closer from them you'll see two of the object change their size depending on how far there are from the camera, while two others stay the same size. Also notice the way the cubes are drawn is different. Further below there is a nice terrainpage to look at and test the difference between parallel projection and perspective projection.

Then there is the small quad that is rendered in Ortho2D using ProjectionState rather than Renderer.setOrtho(). For now it's in the same bucket in the render queue as the other object though, so it'll likely disappear from sight at times.

You'll also notice that if you move "forward" (W) or "backward" (S) and you're in Ortho mode you don't seem to move at all (but the fog, lights etc. might). This is because traveling along the "Z-axis" of the direction that you are looking at only makes objects come closer or further away, which in the parallel perspective does not change the size of objects (unlike in the perspective mode).

To emulate getting closer to an object you can use the setOrthoScale method. Add this to the performAction() method of the KeyNodeForwardAction


if (node instanceof CameraNode) {
        Camera cam = ((CameraNode) node).getCamera(); 
        cam.setOrthoScale(cam.getOrthoScale()-(speed/10000));
        cam.update();


Change the - to + for KeyNodeBackwardAction. The (speed/10000) is at the moment more a wild guess than something cleverly calculated though...

Have fun!

@author Tijl Houtbeckers
*//

Well, that's me.. nice to meet you all :)

All and all, the code isn't fully ready, more testing should be done and a little polishing, and hopefully this will prove to be the right appraoch to this problem (I think it worked out pretty well). If you find anything wrong in the Javadocs let me know though. In any case, I hope it will mean I can do more for jME than just JmeException ;)

Here is the zip with all the changed and new classes:

http://www.mordax.nl/tijl_jme/jME_Projections_0.0.1.zip

PLEASE NOTE: The "fix" described above to disable culling is used in AbstractCamera in this zip (it's just one line to change back if you want). The changes to KeyNodeActions are not. Also, these changes are made to a CVS tree from a few days back. If any new RenderState has since been added to CVS or your local copy it will of course not work as it should.

changed classes:

Camera
added setOrtho()
added setOrthoScale()
added getOrthoScale()
added a JavaDoc comment to setFrustum()

AbstractCamera
added setOrtho()
added setOrthoScale()
added getOrthoScale()
Added Javadoc @see for setFrustumPerspective

LWJGLCamera
added setProjectionMethod()
added getProjectionMethod()
changed onChangeFrustum()
changed onChangeFrame()
changed constructor.

Renderer
added createProjectionState()

LWJGLRenderer
added createProjectionState()

DummyDisplaySystem
added createProjectionState()

new classes:

com.jme.scene.state.ProjectionState
com.jme.scene.state.lwjgl.LWJGLProjectionState
jmetest.projection.TestProjections

I have created an issue regarding parallel projection. It is already implemented and it works really fine:

I have chosen to put a flag into the camera, named parallelProjection. This made more sense to me than a renderstate, because I knew switching from parallel to prespective and right back from modeller applications…

SimpleGame now has an additional keybinding: F2 to toggle perspective/parallel view. Culling for parallel mode is implemented, too.



Any things that this solution lacks? Does mixing perspective and ortho3D really make sense?

If there are no objections/additions I’m going to commit that tomorrow.

forgot to post here: checked in!  :smiley:

please run any app derived from SimpleGame and hit F2 to test parallel projection…