Rendering Order Question [Solved]

Hi guys, I’m back with a few more questions :slight_smile: I am making a map based off of the BO3 map Nacht Der Untoten. I have done this to try to have a reference for how a good map feels, looks, and also plays. I also wanted to look in detail at different tricks they used though out to make the game run smoother. There is something in particular that I noticed in the game that I wanted to try to replicate.

The thing I noticed is that a players arms (first person) seemed to be rendered after every single thing so that they will never be clipping into walls and other things. I was wondering if there is some way to do this in jme3 so my persons outstretched arms don’t clip through my walls.

I would assume it would have something to do with buckets but my understanding is that those are for things like transparency, the sky, opaque things and not for the render order of things within the buckets. Any ideas on how to get this done?

Thanks for the help in advance guys :slight_smile:

Yes, you can do this in jme3. There are many ways. An obvious way would be to put the arms in a post view. See com.jme3.renderer.RenderManager#createPostView()

1 Like

Thanks for the help thus far sgold. So far I’ve made a ViewPort and made it have a transparent background but I’ve gotten stuck on the actual attaching of a spatial to it. In my simpleInitApp method I attached a Node that I would use to attach all my spatials to this view port. However, when my player is initialized and I try to attach my players arm geometry to that node and it says I am modifying the scene from a different thread. I don’t know where I should try to attach the spatials. The only area that seems to work is inside the simpleInitApp method itself unlike the rootNode where I can add new spatials to a scene from anywhere. :confused:

1 Like

JME automatically manages the viewports that it creates (SimpleApplication does this)… for the viewports you create on your own, you must manage them.

Try searching the forum for something like ViewportAppState or something similar and you’ll find examples of calling updateLogicalState() and updateGeometricState() at the appropriate times and so on.

1 Like

I keep meaning to write a ViewportAppState or copy someone else’s. For now, I update the added scenes at the end of simpleUpdate(), like so:

    /**
     * additional scenes (besides rootNode and guiRoot) for rendering
     */
    final private static List<Spatial> addedScenes = new ArrayList<>(3);

    @Override
    public void simpleUpdate(float tpf) {
        super.simpleUpdate(tpf);
        /*
         * Update the logical/geometric state of all scenes other than
         * rootNode and guiNode. TODO: an app state for each view port
         */
        for (Spatial scene : addedScenes) {
            scene.updateLogicalState(tpf);
            scene.updateGeometricState();
        }
    }

Every time I invoke Viewport.attachScene(scene) I also do addedScenes.add(scene);

I’m doing something wrong here. So far I have made the app state and have made it so it updates my parent node for my ViewPort. I added my parent node when I initialize my app and then I attach my arms to the parent node when I initialize a player object but the arms are still not showing up :confused:

Also just another quick question. Do I have to do updateModelBound() whenever I do something such as rotate a spatial?

Heres all my code that I think is relevant to the post view (excluding the appstate).

In my init method

postViewCamera = new Camera(getCamera().getWidth(),getCamera().getHeight());

viewPortArm = renderManager.createPostView("viewPortArm", postViewCamera);
    
    viewPortArm.setBackgroundColor(new ColorRGBA(0,0,0,0));
    viewPortArm.attachScene(Main.closeNode);
    viewPortArm.setClearFlags(false, true, false);
    postViewAppState.addSpatial(closeNode);

In my method for loading my player arms model.

Spatial playerModel = Main.application.getAssetManager().loadModel(
       "Models/humanArms/humanArms.j3o");
       playerModel.setMaterial(Main.IMPOSSIBLE_MESH_MATERIAL); //Debugging material :)
       playerModel.rotate(0, RotationHandler.degreesToRadians(90), 0);
       Main.closeNode.attachChild(playerModel);

Thanks for the help thus far :slight_smile:

Note: simpleUpdate() happens for any regular root node controls are updated… so if you have syncing across your “scenes” then you will have problems.

It’s best to do these updates in simpleRender()… or at least the updateGeometricState(). It should be done as late as possible.

No.

As to the rest, what problem are you seeing now?

1 Like

The problem is that I’m not seeing anything right now. As of now I’ve made an appstate that calls those update methods for a parent node for my view port. I’ve attached my human arm model to the parent but nothing is showing up still. I am not sure if I need to attach lights to this node but my material is one that isn’t affected by lights anyways.

Also I tried moving my updateGeometricState to the simpleRender(RenderManager rm) method but it starts complaining about changing data from a different thread again.

Make sure your new viewport’s camera is actually looking at your object and stuff.

This comes up every couple of months or so. You might be able to find others who have gotten this working by searching the forum.

In particular, check the near plane of the camera’s frustum, as in viewPort.getCamera().getFrustumNear() If the arms are closer than the near plane, that would explain why they’re not rendered.

That shouldnt be an issue provided the frustum close is <= 1. Ill make the arms not rotate around where the camera is facing and have them be stationary at some point just to make sure they are in the scene. Ill let you know if it changes anything.

Sorry for the delayed responses on the post. School started this week :expressionless:

I haven’t read the entire post but wouldnt turning of depth testing have the same effect that the arms are always visible?

This does not enforce that is rendered last. While turning off the depth test would render it over any existing objects, later objects are rendered on top if they are nearer than the background.

Another idea is to put the arm in the translucent bucket in addition to disabling the depth test. Assuming there are no other translucent objects interfering, the arm is rendered last.

I should have mentioned this earlier but I want a post view for the arms because I am going to have the two view have different close frustums. I want a lower one for my main view because then I can’t look through objects I’m close to as easily and there isn’t that much distortion because of the hitbox surrounding my player preventing getting real close to things. I want my arm close frustum to be a little higher than the post view though because then the arms won’t get distorted as much as they are much closer.

Also, I think I’m not even attaching the spatials I have to the post view. What I had done before is attach a node to my postview and then after that attach spatials to my node but I tried simply directly attaching a spatial to the post view and it gave my the same thread error as before, even though I called the required update methods :frowning:

1 Like

Then you aren’t calling the update methods at the right time. But we can’t see that code from here.

1 Like

Here are all lines of code that relate to this post view. :thumbsup:

Lines relating to the postview in the main class.

public static Camera postViewCamera; 
public static PostViewAppState postViewAppState = new PostViewAppState();
public static ViewPort viewPortArm;

public void simpleInitApp() { 
//...
        viewPortArm = renderManager.createPostView("viewPortArm", postViewCamera);
        stateManager.attach(postViewAppState);
        stateManager.attach(new FirstPersonSpectorAppState());
        postViewCamera = new Camera(Main.application.getCamera().getWidth(),Main.application.getCamera().getHeight());
//...
       Spatial playerModel = Main.application.getAssetManager().loadModel(
       "Models/humanArms/humanArms.j3o");
        playerModel.setMaterial(POSSIBLE2_MESH_MATERIAL);
        
        viewPortArm.setBackgroundColor(new ColorRGBA(0,0,0,0));
        viewPortArm.attachScene(playerModel);
        postViewAppState.addSpatial(playerModel);
//...
}

public void simpleRender(RenderManager rm) {
        for (Spatial spatial: postViewAppState.getSpatials()) {
            spatial.updateGeometricState();
        }   
    }

This is the PostViewAppStateClass. I used it for updating the logic and storing the spatials that need to be updated.

private final static ArrayList<Spatial> addedSpatials = new ArrayList<>();

public ArrayList<Spatial> getSpatials() {
    return addedSpatials;
}
//...
 @Override
public void update(float tpf) {
    for (Spatial spatial : addedSpatials) {
        spatial.updateLogicalState(tpf);
    }
}

public void addSpatial(Spatial spatial) {
    addedSpatials.add(spatial);
}

There are also the FirstPersonSpectorAppState and another one in charge of rotating the camera. I’ve made sure I’ve gone through these appstates and where ever a line of code changes the position of the main camera that it also changes the position and rotation of my postview camera. Hopefully something (or a lack of something) jumps out at someone as to what is wrong. Thanks for the help thusfar. :slight_smile:

1 Like

Confused… why do you do this in simplerRender() on the app when you already have them in an app state that could be doing it?

The problem is in the code we can’t see. So you’ll have to put together a complete simple test case that illustrated the problem.

I can 100000000000000000000000000000000000000000000000000% guarantee that if updateLogicalState() and updateGeometricState() are called on the spatial before rendering that you will not get an error about it.

So, the problem is in your code.

I must have misunderstood what you meant here. I thought you were saying I should put my updateGeometricState() inside of my main classes simpleRender().

Anyways I have taken this line of code and shoved it back inside the appstate.

I also made a test case and things are still looking grim :frowning:

Main class

package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.renderer.Camera;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Geometry;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;



/**
 * This is the Main Class of your Game. You should only do initialization here.
 * Move your Logic into AppStates or Controls
 * @author normenhansen
 */
public class Main extends SimpleApplication {
    
    public static PostViewAppState postViewAppState = new PostViewAppState();
    public static Camera postViewCamera;
    
    public static void main(String[] args) {
        Main app = new Main();
        app.start();
    }

    @Override
    public void simpleInitApp() {
        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);
        //Camera direction 0 0 -1
        geom.setLocalTranslation(0, 0, -10);
        
        stateManager.attach(postViewAppState);
        postViewCamera = new Camera(getCamera().getWidth(),getCamera().getHeight());
        ViewPort viewPortArm = renderManager.createPostView("viewPortArm", postViewCamera);
        
        Material playerMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        playerMat.setColor("Color", ColorRGBA.Red);
        
        Spatial playerModel = getAssetManager().loadModel(
       "Models/humanTestModel.j3o");
        playerModel.setMaterial(playerMat);
        //Camera direction 0 0 -1
        playerModel.setLocalTranslation(0, 0, -5);
        
        viewPortArm.setBackgroundColor(new ColorRGBA(0,0,0,0));
        viewPortArm.attachScene(playerModel);
        playerModel.setLocalTranslation(0, 0, 0);
        postViewAppState.addSpatial(playerModel);

        viewPortArm.attachScene(playerModel);
        rootNode.attachChild(geom);
        System.err.println(getCamera().getDirection().toString());
    }

    @Override
    public void simpleUpdate(float tpf) {
        //TODO: add update code
    }

    @Override
    public void simpleRender(RenderManager rm) {
        
    }
}

PostViewAppState

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package mygame;

import com.jme3.app.Application;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.scene.Spatial;
import java.util.ArrayList;

/**
 *
 * @author Cats
 */
public class PostViewAppState extends AbstractAppState {
    private final static ArrayList<Spatial> addedSpatials = new ArrayList<>();
    
    public ArrayList<Spatial> getSpatials() {
        return addedSpatials;
    }
    
    @Override
    public void initialize(AppStateManager stateManager, Application app) {
        super.initialize(stateManager, app);
    }
    
    @Override
    public void update(float tpf) {
        for (Spatial spatial : addedSpatials) {
            spatial.updateLogicalState(tpf);
            spatial.updateGeometricState();
        }
    }
    
    @Override
    public void cleanup() {
        super.cleanup();
        //TODO: clean up what you initialized in the initialize method,
        //e.g. remove all spatials from rootNode
        //this is called on the OpenGL thread after the AppState has been detached
    }
    public void addSpatial(Spatial spatial) {
        addedSpatials.add(spatial);
    }
}

These are the only two classes in the project. From what I know this should make a red model of a human appear in front of the blue cube but its not :frowning:
Ill attach an image of the rendered view down below.

So, with that code you are getting an error about update?

This should be two separate loops and you should do the updateGeometricState() loop in app state’s render() method for full safety.

…but as long as you aren’t modifying the spatials from some other place, as you have it should work. It’s just that a lot of stuff is run after app state’s update and you would need to make sure not to modify the spatials then… easier just to do it as late as possible. (Not a problem in your test case but just a general approach.)

Edit: note that either way, you want to do two separate loops.