0

Aka Can I have a 3d scene that is in front of the main scene without it being clipped.

Aka The front of my weapon keeps getting hidden by the scene in my game

Situation

I have a 3d scene, rendered by JMonkey, and additionally have 3d weapons held by the player. Additionally the player may stand so close to walls that they may (if treated realistically) stick the end of their gun through the wall. This means that if the gun is placed "by dead reckoning" in the scene so it looks right the end of the gun gets clipped off and looks stupid.

Because this is a 3d object (that may be rotated or moved) I can't just use a 2d image and put it in the gui layer

Richard Tingle
  • 16,906
  • 5
  • 52
  • 77

1 Answers1

0

Create an additional camera and view port to support these additional graphics

In JMonkeyEngine its possible to have more than one viewport and layer them on top of each other to provide the described effect. Each viewport is internally 3d, but the view ports themselves layer over the top of each other.

Code example

Main class to get things set up

public class Example extends SimpleApplication {

    public static void main(String[] args){
        Example app = new Example();
        app.start(); // start the game
    }

    @Override
    public void simpleInitApp() {
        //this represents the "real world" in this example
        Box b = new Box(1, 1, 1);
        Geometry geom = new Geometry("Box", b);
        Material mat = new Material(assetManager,"Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.Blue);
        geom.setMaterial(mat);
        rootNode.attachChild(geom);

        this.stateManager.attach(new UnderGui());
    }
}

An UnderGui layer, that has a 3d scene between the gui layer and the main 3d scene

/**
 * The under gui is for things like the held tool. Things that are kind of 3d but also want to be "over" everything
 * else
 */
public class UnderGui extends AbstractAppState {

    private Node root;

    public UnderGui() {

    }

    @Override
    public void initialize(AppStateManager stateManager, Application app )

    {
        root = new Node( "Under gui viewport Root" );

        Camera originalCam = app.getCamera();

        Camera cam = new Camera(originalCam.getWidth(), originalCam.getHeight());
        //the default camera is an orthoganal camera, use the main cam to copy sensible camera properties
        cam.setParallelProjection(originalCam.isParallelProjection());
        cam.setFrustum(originalCam.getFrustumNear(), originalCam.getFrustumFar(), originalCam.getFrustumLeft(), originalCam.getFrustumRight(),originalCam.getFrustumTop(), originalCam.getFrustumBottom()  );
        cam.setFov(originalCam.getFov());
        //camera is looking in a +Z direction. -X is right, +X is left. +Y is up

        ViewPort view = app.getRenderManager().createMainView("Under gui ViewPort", cam);
        view.setEnabled(true);
        view.setClearFlags(false, true, false);
        view.attachScene( root );

        root.attachChild(createWeapon(app.getAssetManager()));

    }

    /**
     * This just creates a red box to be a "weapon" as an example
     * @return
     */
    private Geometry createWeapon(AssetManager assetManager){
        Box b = new Box(1, 1, 1); // create cube shape
        Geometry geom = new Geometry("Box", b);  // create cube geometry from the shape
        Material mat = new Material(assetManager,
                "Common/MatDefs/Misc/Unshaded.j3md");  // create a simple material
        mat.setColor("Color", ColorRGBA.Blue);   // set color of material to blue
        geom.setMaterial(mat);                   // set the cube's material
        geom.setLocalTranslation(-2,0,2);
        return geom;
    }

    @Override
    public void render(RenderManager rm) {
        root.updateGeometricState();
    }

    @Override
    public void update( float tpf ) {
        root.updateLogicalState(tpf);
    }
}

This can also be used for any "ability to see through walls" overlay

Alternative bad solution; setDepthTest

You can also just put the weapon in the main scene and set geometry.getMaterial().getAdditionalRenderState().setDepthTest(false);. However this is a less good option because it requires the weapon to constantly be moved as the camera changes position and direction and can only cope with "simple" 3D overlays as if 1 part of the weapon is in front of another part (e.g. the stock is in front of the trigger) which bit is rendered is random, as you've asked JME not to do any depth testing

Richard Tingle
  • 16,906
  • 5
  • 52
  • 77