Screen Smoothing (Retro-Games mode)

Ok, I will try now to give you more information.
Here two screens of the current result (as you see I could set the Nearest Neighbor 4x pixelation for the bacground texture, but I should set it even for main character and for invisible scene, otherwise when an obstacle cover the actor it’s possible to see the lack of pixelation):

Current Result:

Wireframe and visible scene:

Here my code
[java]
@Override
public void simpleInitApp() {

    initKeys();
    assetManager.registerLocator("/", FileLocator.class);



    // Static background
    renderViewPort = renderManager.createPreView("Render", getCamera());
    renderViewPort.setClearFlags(true, true, true);
    Quad quad = new Quad(1, 1);
    viewPort.setClearFlags(false, true, false);
    Geometry render = new Geometry("Render", quad);
    render.setMaterial(assetManager.loadMaterial("Materials/Sala_2.j3m"));

    // Texture is 320x180 (screen is 4x, 1280x720)
    Texture2D tex = (Texture2D) getAssetManager().loadTexture("Textures/Sala_2.png");
    tex.setMagFilter(MagFilter.Nearest);
    tex.setMinFilter(MinFilter.Trilinear);
    render.getMaterial().setTexture("Texture", tex);
    renderRootNode = new Node("HD-RenderRootNode");
    renderRootNode.attachChild(render);
    renderViewPort.attachScene(renderRootNode);

    AmbientLight al = new AmbientLight();
    al.setColor(ColorRGBA.White.mult(0.9f));
    rootNode.addLight(al);



    BlenderKey roomKey = new BlenderKey("Models/SH_Home_p2/SH_Home_p2.blend");
    roomKey.setFixUpAxis(false);
    Material hide = assetManager.loadMaterial("Materials/Unshaded.j3m");
    hide.getAdditionalRenderState().setDepthWrite(true);
    hide.getAdditionalRenderState().setColorWrite(false);



    sceneNode = new Node("SceneNode");
    Spatial sceneSpatial = (Spatial) assetManager.loadModel(roomKey);
    sceneSpatial.setMaterial(hide);
    sceneNode.attachChild(sceneSpatial);

    cameraNode = (CameraNode) sceneNode.getChild("Camera_Sala_2");
    Quaternion rot3 = cameraNode.getLocalRotation();
    cameraNode.setLocalRotation(new Quaternion(-rot3.getZ(), rot3.getW(), rot3.getX(), -rot3.getY()));



    rootNode.attachChild(sceneNode);



    Spatial playerSpat = (Spatial) assetManager.loadModel("Models/SH_Anim/SH_Anim.mesh.j3o");


    // Player material
    List<Spatial> playerSubSpatList = (List<Spatial>) ((Node) playerSpat).getChildren();
    List<Geometry> playerGeomList = new ArrayList<Geometry>();
    for (Spatial s : playerSubSpatList) {
        playerGeomList.add((Geometry) s);
    }

    for (Geometry g : playerGeomList) {
        Material m = g.getMaterial();
        m.getAdditionalRenderState().setWireframe(true);
    }

    playerNode = new Node("Player");
    playerNode.attachChild(playerSpat);

    playerNode.setLocalTranslation(0f, 0f, 0.02f);
    playerNode.scale(0.4f);



    AnimControl control = playerSpat.getControl(AnimControl.class);
    control.addListener(this);
    try {
        channel = control.createChannel();
        channel.setAnim("SH_Walk");
        channel.setTime(0);
        channel.setSpeed(0);

    } catch (Exception e) {
        e.printStackTrace();
    }

    rootNode.attachChild(playerNode);



}

public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {
}

public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {
}

@Override
public void simpleUpdate(float tpf) {

    renderRootNode.updateGeometricState();
    renderRootNode.updateLogicalState(tpf);

    // Static cameras are taken from the blend file, in blend file resolution is set to 320x180, so viewport is extended 4x
    getCamera().copyFrom(cameraNode.getCamera());
    getCamera().setViewPort(0, 4, 0, 4);

    Quaternion rot = playerNode.getWorldRotation();
    Vector3f direction = new Vector3f();
    rot.mult(Vector3f.UNIT_Y.negate(), direction);

    Quaternion rot2 = playerNode.getWorldRotation().add(new Quaternion().fromAngleAxis(FastMath.HALF_PI / 2, Vector3f.UNIT_Z.negate()));
    Vector3f sideDirection = new Vector3f();
    rot2.mult(Vector3f.UNIT_Y.negate(), sideDirection);

    Ray rayFront = new Ray(new Vector3f(playerNode.getLocalTranslation().x, playerNode.getLocalTranslation().y, playerNode.getLocalTranslation().z + 0.0f), direction.normalize());
    Ray rayBack = new Ray(playerNode.getLocalTranslation(), direction.negate().normalize());

    checkCollision(rayFront, "Front", frontWalk, tpf, 0.5f, true);
    checkCollision(rayBack, "Back", backWalk, tpf, 0.5f, true);

    playerNode.rotate(0.0f, 0.0f, rotation * tpf);


}    

[/java]

Maybe in this case I could leave the render viewport in this way, and attach a pixelation filter for player and scene, but I got some problem using the filter with multuples viewport, and also the filter effect it seems a bit aliased (there’s a smoothed pixelation). Otherwise I don’t know how to do this

The nearest trick can’t work for what you want. Texture will be pixelated, but the size of texels can vary across the screen depending of their resolution, and can’t work if the model is not textured… For your effect you need an homogeneous size of pixels across the screen. that’s why the filter way is IMO a better solution.

You said you had trouble with filters and multiple viewports. what troubles?
Then, why do you need multiple viewports?

For multiviewport the problem of pixelation filter is that this doesn’t work, I don’t know why… I tried in this way.

PixelationFilter filter = new PixelationFilter();
FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
fpp.addFilter(filter);
viewPort.addProcessor(fpp);

I’m not sure if I really need multiviewport, but I asked some monthes ago how to render a 3d player and scene on a pre-rendered background and everyone suggested me multiviewport. (If it is possibile with only one viewport would be better)

Here the effect of pixelation is this, in addiction to the error it’s possibile to see that pixelation is a bit aliased (my antialiasing is disabled), there’s a way to have a clear pixelation without this smoothing? Would be fantastic!

looks like a clearing issue.
Anyway to have a fix background texture there is a better solution yes.
It involves shaders but, I can give you the code.

First create a 1x1 quad, and a geometry to hold it.
Put it in the scene graph (anywhere) and place it in the sky bucket.
then for the material use this mat def and shaders :

background.j3md

MaterialDef Background {

    MaterialParameters {
        Texture2D Texture
        Color Color        
    }

    Technique {
        VertexShader GLSL100:   MatDefs/Post/Post.vert
        FragmentShader GLSL100: MatDefs/background.frag

        WorldParameters {
            WorldViewProjectionMatrix
        }

        Defines {
            COLOR : Color
        }

    }

}

background.frag

uniform sampler2D m_Texture;

#ifdef COLOR
    uniform vec4 m_Color;
#endif
varying vec2 texCoord;

void main() {
      gl_FragColor = texture2D(m_Texture, texCoord);       
      #ifdef COLOR
        gl_FragColor *= m_Color;
      #endif
      gl_FragColor.a = 1.0;
}

Pass your texture as the material parameter “Texture”.
You can even pass an optional Color parameter to tint the texture.

All in one viewport, then use the filter solution for the pixelization and it should be fine.

here is the java code to initialize it
[java]
Quad q = new Quad(1,1);
Geometry background = new Geometry(“Background”, q);
Material mat = new Material(“path to the j3md file”);
mat.setTexture(“Texture”, yourBackgroundText);
background.setMaterial(mat);
background.setQueueBucket(RenderQueue.Bucket.Sky);
rootNode.attachChild(background);
[/java]

EDIT : this can only work with nightly. 3.0 post.vert was different., if you’re using 3.0
use this vert shader
background.vert

attribute vec4 inPosition;
attribute vec2 inTexCoord;
varying vec2 texCoord;

void main() {  
    vec2 pos = inPosition.xy * 2.0 - 1.0;
    gl_Position = vec4(pos, 0.0, 1.0);    
    texCoord = inTexCoord;
}

Hi Nehon, thanks for your help, very kind of you!
I tried in this way, and I almoust solved… I saw almoust becouse now I couldn’t keep the scene invisible…

Here I think is the problem

[java]
BlenderKey roomKey = new BlenderKey(“Models/SH_Home_p2/SH_Home_p2.blend”);
roomKey.setFixUpAxis(false);
Material hide = assetManager.loadMaterial(“Materials/Unshaded.j3m”);
hide.getAdditionalRenderState().setDepthWrite(true);
hide.getAdditionalRenderState().setColorWrite(false);

    sceneNode = new Node("SceneNode");
    Spatial sceneSpatial = (Spatial) assetManager.loadModel(roomKey);
    sceneSpatial.setMaterial(hide);
  

    sceneNode.attachChild(sceneSpatial);

    cameraNode = (CameraNode) sceneNode.getChild("Camera_Sala_2");
    Quaternion rot3 = cameraNode.getLocalRotation();
    cameraNode.setLocalRotation(new Quaternion(-rot3.getZ(), rot3.getW(), rot3.getX(), -rot3.getY()));

    rootNode.attachChild(sceneNode);


    Quad q = new Quad(1, 1);
    Geometry background = new Geometry("Background", q);
    Material mat = new Material(assetManager, "MatDefs/Background.j3md");
    mat.setTexture("Texture", (Texture2D) getAssetManager().loadTexture("Textures/Sala_2.png"));
    background.setMaterial(mat);
    background.setQueueBucket(RenderQueue.Bucket.Sky);
    rootNode.attachChild(background);

[/java]

Ai you can see I’ve to “draw” only depth for 3D scene, and not the color, but the result is this (image in the top), If i leave the “hide” material to not draw depth is ok, but… I need depth! :D:

The blender scene has not got any material, I just set the unshaded without color drawing.

Do you think is a viewport flags cleaning problems? Thank you very much again for all the support!

Actually you need to disable depth test on the background material. You’ll have some overdraw, but considering your requirements it can’t be avoided.

Sorry in which sense I will have some overdraws? I tried and now I can see the background, but player is covered :(. Do you think is it possibile to solve it keepeing one viewport?

You could also setup a custom GeometryComparator that makes sure to sort your things properly. Or just put your background in the sky bucket if it’s just a flat image.

Sorry pspeed but I cannot understand. Now I already tried to put background as flat image as Nehon suggest, but in this way scene is not invisible but black. I don’t know why… because if I set depth write flag = false scene become invisible… but I don’t understand why depth is “painted” like a black color in the scene… :
With setDepthTest(false) scene become transparent, but even player (I don’t know why) become insivible (I think is rendered before the scene).

With GeometryComparator there are some example about it? I tried to read the javadoc but it seems a bit poor.

Thanks and thanks again!

Have you tried putting your background in the sky bucket?

Mhh yeah ok…the character is not drawn :stuck_out_tongue:

You have to understand how things work, opaque bucket is rendered front to back to avoid overdraw.
When a geometry is rendered to the scene it writes it’s depth in the depth buffer. When rendering another geometry a depth test is done on the depth buffer to check if the pixel being drawn is visible or behind an already drawn geometry. Of course if it’s behind another geometry, it get discarded, which avoid a lot of overdraw (see it as a way to draw each pixel of the screen only once).

The sky bucket is painted after the opaque bucket with a depth forced to 1 (the farthest away from the cam). this allows to paint the sky only in the remaining “holes” of the scene.

In your case it might be better to paint the background before everything with a depth forced to 1 and have everything else drawn over (that’s why I said there would be some overdraw but not really an issue).

The problem is your background is rendered after everything with no depth test so it’s just rendered over everything :p. So I just take away my advice of disabling depth test on the background.

What pspeed is talking about is to make your own comparator that would place your background geometry before everything else in the opaque bucket.
To do this you need to invoke viewPort.getQueue().setgeometryComparator(yourComparator);
yourComparator just needs to extends OpaqueComparator, call the super in the compare method, but if one of the geometry is your background it has to be first.
Also you’ll need to have the depth forced to 1. You can do it in the frag shader, by adding this line at the end : gl_FragDepth = 1.0;

@pspeed , actually this is the perfect use case for custom buckets “I want a bucket rendered before the opaque bucket with depth forced to 1”.

@nehon said: @pspeed , actually this is the perfect use case for custom buckets "I want a bucket rendered before the opaque bucket with depth forced to 1".

Yep, we are slowly collecting them, I think.

Great great great! Now is working well! I do not know how to thank you, is nice now that can I see the first steps of my little remake of a old style survival horror, many thanks again.

With two viewports it was a bitt difficult to manage the dynamic camera / background changing based on the area walked by the player, now it will be more manageble this stuff.

@pspeed said: Yep, we are slowly collecting them, I think.

Is the ability to create custom buckets going to be added to JME? And if it is, will we be able to reorder the existing for whatever diabolical reason we might have to do so?

@t0neg0d said: Is the ability to create custom buckets going to be added to JME? And if it is, will we be able to reorder the existing for whatever diabolical reason we might have to do so?

It’s on my to-do list. It’s kind of a long process to add it without breaking everything… and I won’t be getting to it particularly soon. The more use-cases we collect for it the more motivating it is, though. And the more cases we have to check against the implementation.

Regarding the current bucket ordering, I don’t know yet. But it seems that adding your own buckets and then never using the current ones would achieve the same result. API access to the custom buckets is a few steps down on the “rework buckets” list so I don’t know how that folds out yet.

Hello everyone!
I could go ahead with development, and what I obtained is a little home with 7 different locations, that are framed automatically (and background rendered) when the player passes over some areas, here a video:

[video]http://www.youtube.com/watch?v=TJR7P3sODWQ#t=14[/video]

Now I want to start GUI implementation, for that gui I need to rendere a semi-transparent quad over the screen (the best would be to pause the game and see the paused game scene throught the semi-transparent gui).
Above that gui main elements will be some widgets (I will study how to manage it) and 3D Models (object of inventory).

I tried to add a new ViewPort (with create post view), create a background in this view, a rotating cube and attache the node (with these childs) to the viewport (and in simpleupdate update geometrical and logical state of this node). But nothing happens, I just want to say if, considering I’m using that opaque bucket for background there are some stuffs that I’ve to do in addition. Is the GUI bucket already rendered in front of the opaque bucket?

Many thanks again

PS: I know I’m talking about a stuff that is different than the topic, but I continued here because I wanted to say if there’s something to consider (for GUI creation) if i used custom buckets

maybe youre doing a more advanced gui than what i think youre describing, but why dont you just use the gui view port that is already there?

btw your game is looking pretty goood. good job.