[SOLVED] Prevent rendering scene multiple times using MRT

Well you actually don’t have any issue, it’s just your way to render the outputs that was flawed.
Seems like a promising rendering pipeline :wink:

Edit: about your edit: mhh what?

If I change the brightness of the screenshot, then you can still see the world in the dark o.O

edit:
I set the glow output color this way

               glowMap = texture(m_GlowMap, texCoord);
		    #ifdef HAS_GLOWCOLOR
		      glowMap *= m_GlowColor;
		    #endif
		   
		    #ifdef GLOW_ONLY_AT_NIGHT
		      glowMap.rgb *= (vec3(1.0) - AmbientSum);
		    #endif
		    
		    glowMap.rgb *= vec3(glowMap.a);
		    
		    outFragColor[1] = glowMap;

hm I must say it was false alert. It still doesn’t work. It was a mistake by myself and i already had prepared the shader for displaying the depth texture. So I put the glow map into this shader and the sky was almost gone.

this was the fragment shader:

void main()
{
vec4 scene = texture2D(m_SceneTex, texCoord);

vec2 m_FrustumNearFar = vec2(1.0, 256.0);
float depthScene = (2.0 * m_FrustumNearFar.x) / (m_FrustumNearFar.y + m_FrustumNearFar.x - scene.r *  m_FrustumNearFar.y - m_FrustumNearFar.x));
      fragColor = vec4(depthScene, depthScene, depthScene, 1.0);

    //  fragColor = scene;
    }

the depth scaling in the shader has made the sky dark. The glow map still contains the sky, even with the TranslucentBucketFilter before/after/without the final filter… The only thing whats changes are the translucent geometries, but the sky is always present.

ok back to this.
I’m totally confused now. :stuck_out_tongue:
What was a false alert?
what’s inside the glow map for non glowing objects?

I’m so sorry :smiley: sometime I am overhasty.

All my outputs contains the sky bucket. It is ok that the first output texture contains the sky, but its also in the glow map and water mask. Maybe the problem is way I am render these outputs?

ok well maybe the issue is with the sky material. Does it render to the additional out colors?

the sky is a sphere geometry attached to the rootNode which is rendered in the skybucket. It is not a filter. And it only has one output (gl_FragColor)

yeah but it uses a material. Is that the standard sky material? I guess not since you use a special scattering effect.
How does this material handles the extra color buffers?

Im not sure what you mean exactly.It looks like this:

	mat = new Material(assets, "MatDefs/Sky.j3md");
	sky = new Geometry("Sky", outMesh);
	sky.setModelBound(new BoundingSphere(Float.POSITIVE_INFINITY, Vector3f.ZERO));
	sky.setMaterial(mat);
	sky.setQueueBucket(Bucket.Sky);
	sky.setCullHint(CullHint.Never);
	rootNode.attachChild(sky);

material def:

MaterialDef Sky {

MaterialParameters {
    ...
}

Technique {
    VertexShader GLSL110:   MatDefs/SkyAtmosphere.vert
    FragmentShader GLSL110: MatDefs/SkyAtmosphere.frag

    WorldParameters {
        WorldViewProjectionMatrix
        ProjectionMatrix
        WorldMatrix
        ViewMatrix
        Position
        CameraPosition
    }

    RenderState {
        FaceCull Front
        Blend AlphaAdditive
        DepthTest On
        DepthWrite On
    }
}
}

fragment shader:

...
void main (void)
{
         ...
	// simple "HDR" clamping
	gl_FragColor = 1.0 - exp(-m_fExposure * gl_FragColor);
	
	gl_FragColor.a = 1.0;
}

yes, so here you are writing only to the first color buffer. you don’t write to the glow buffer nor the water mask buffer.
You should try to write a black pixel to them.

1 Like

Yes! this works!

I replaced gl_FragColor by gl_FragData[0]. It was not necessary to write black pixels to the other buffers.
Thank you and I really hope the problem is now solved :blush:

glow map:

1 Like

cool, tell me if the perf are better when you’re done :wink:

ATM I have a fps speedup of 2.43 :slight_smile: But now comes the tricky part. I need to render the pixels below the water surface. For this I use my water mask and lay it over the screen. Then I only render the pixels of the world within this mask and all other pixels are discarded. I think the vertex animations should be disabled for this render pass because they are slow and I don’t think one can see the weaving grass through a disorted water surface. Hope this helps for performance :smiley:

I tell you the fps when all is done :slight_smile:

This is what I expect: Rendered pixels below the water surface and wihtin the water mask:

Hey nehon I have another question about the rendering stuff:

you know I’ve rendered the world to MRT. One of these targets is my water mask. The problem is that I have to render the pixels below the water surface in an additional render pass. Usually this is done in a filter in the method postQueue(). But this method is called before the frame was rendered, so my water mask is completely black. I tried to render this pass in postFrame() instead but nothing happens or the screen is black. What I am doing wrong?

this is my postQueue() implementation of my own water filter class:

@Override
protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h)
{
	...

	prePass = new Pass()
	{
	};
	prePass.init(renderManager.getRenderer(), w, h, Format.RGBA8, Format.Depth, 1, true);

	material.setTexture("Texture", prePass.getRenderedTexture()); // pixels below water surface
	material.setTexture("MaskTex", processor.getWaterMaskMap()); // the water mask rom the MRT-Rendering
}

@Override
protected void postQueue(RenderQueue queue)
{
	 renderManager.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha);
	 renderManager.getRenderer().setFrameBuffer(prePass.getRenderFrameBuffer());
	 renderManager.getRenderer().clearBuffers(true, true, true);
	 renderManager.setForcedTechnique("RenderBelowWater");
	
	 renderManager.renderViewPortQueues(viewPort, false);
	 renderManager.renderTranslucentQueue(viewPort);
	
	 renderManager.setForcedTechnique(null);
	 renderManager.getRenderer().setFrameBuffer(viewPort.getOutputFrameBuffer());
}

TBH I’m getting out of ideas here.
Not sure why you need an extra pass though to generate this map.
can’t you render it in the main pass?

The problem is I want post water shaders on arbitrary surfaces. So the only chance I see to solve this is to use a post filter. The post filter need the watersurface and the ground below the surface and the depth values for both. I use the depth to simulate the water depth. As far as I know there is no way to render the water surface and the ground in one pass.
On basis of this I need to render the world again, but this is slow. To improve this I mark the watersurface as a map. This water mask will then be used to render the world again but only the pixels that are within these mask and all other are discarded to save all other heavy calculations.

This all does work if I render the world with MRT as a post filter but I had problems with translucent objects and other things. Now the world is rendered with MRT in the FPP. This has the advantage that I have no other issues with translucent objects and so on, but now I have problems to render the second pass (pixels below water surface).

I hope you understand it and can help me :blush:

I’ve figured out why there is nothing rendered in the filter postFrame(). The culprit was flushQueue() in the RenderManager class. The problem was that the queues were cleared right after the rendering, so there is nothing left to render. But the queues will be cleared either way in RenderManager.renderViewPort() => clearQueue(vp);

I modified flushQueue() by disable queue flushing right after the rendering:

public void flushQueue(ViewPort vp)
{
	//renderViewPortQueues(vp, true);
	renderViewPortQueues(vp, false);
}

It is the same problem as in this thread. You (@nehon) said it is a design stand point but I think postFrame() is useless when all important queues are already been cleared. Maybe this modification should be also changed in the core?

yeah but if flushQueues doesn’t flush the queues, it like VERY misleading…
Maybe the issue is more one level higher and it should be changes where flushQueue is called.

Ok then maybe the flushQueue() call should be replaced by renderViewportQueues() like the following?

RenderManager:

public void renderViewPort(ViewPort vp, float tpf)
{
	...
	// flushQueue(vp);
	renderViewPortQueues(vp, false);
	...
}

edit: The postFrame() method of the Filter says:

“Override this method if you want to make a pass just after the frame has been rendered and just before the filter rendering”

If I want to render an additional pass then there is nothing left to render because the queues are already empty.

Mhhhhh that may break things when you are not using a post processor.
@Momoko_Fan what do you think?