Artefacts when rendering with renderManager.renderViewPort(vp)

Hi,

I experience artefacts when rendering to texture with renderManager.renderViewPort(vp), like this:

    public void paint(Spatial cloud)
{
    // Cloud and misc. parameters
    float radius=1000.0f;
    Vector3f sunLightDirection=visual.getSunLight().getDirection();
    Vector3f viewDir=cloud.getWorldTranslation().negate().normalize();
    Vector3f viewUp=sunLightDirection.cross(viewDir).normalize();
    
    // Setup renderer as seen from the sun
    // --------------------------------------------------------------------------
    int sunCamWidth=256;
    int sunCamHeight=256;
       
    // Create framebuffer
    sunTex=new Texture2D(sunCamWidth, sunCamHeight, Image.Format.RGBA8);
    sunDepthTex=new Texture2D(sunCamWidth, sunCamHeight, Image.Format.Depth);
    sunFB=new FrameBuffer(sunCamWidth, sunCamHeight, 1);
    sunFB.setColorTexture(sunTex);
    sunFB.setDepthTexture(sunDepthTex);
        
    // Create camera
    sunCam=new Camera(sunCamWidth, sunCamHeight);
    sunCam.setFrustum(VisualSystem.CLIP_NEAR,VisualSystem.CLIP_FAR,-radius,radius,radius,-radius) ;
    sunCam.setParallelProjection(true);
    sunCam.setLocation(sunLightDirection.mult(-VisualSystem.CLIP_NEAR-radius));
    sunCam.lookAt(sunLightDirection, viewUp);
    sunCam.update();

    // Create view port
    sunVP=new ViewPort("CLOUDPAINTER_SUN_VIEWPORT", sunCam);
    sunVP.setOutputFrameBuffer(sunFB);
    sunVP.attachScene(cloud);

    // Render cloud as seen from the sun
    // --------------------------------------------------------------------------
    cloud.updateGeometricState();
    visual.getRenderManager().renderViewPort(sunVP, 0.0f);
}

The spatial is simply a blue sphere. The artefacts look like this:

I assume that this is a GPU related problem, since I it is a NVIDIA GeForce 9400M made in 2009. Has anyone experienced similar problems and/or knows a workaround?

Try

sunVP.setClearFlags(true, true, true);

on the viewport.

Also, are you using jME 3.0 or 3.1?

Unfortunately setting the clear flags does not fully resolve the issue. I figured that I have to do the first render-to-texture at frame #2 or after (of the main application) like this:

boolean first=true;
boolean isPainted=false;

public void update(float tpf) {
    if (!first && !isPainted) {
        paint(cloud);
        isPainted=true;
    }
    first=false;
}

I have had the same issue when precomputing look up tables for the atmospheric scattering shader. Still it is quite annoying. It probably has to do with some initialization that is not complete when the first frame gets rendered, or it is my hardware.

Oh, and I’m using 3.0.

I have this issue too for PBR.
The TestPBRLighting does this exact same workaround , to be able to off render the env map into a cube map.
Rendering it in the simpleInit just doesn not work, and I have to wait for frame 2 in order for it to work.
I didn’t dig too much into it.
@Momoko_Fan, any idea?

Would help to have a more standalone test case, but anyways, I found at least one bug:

DrawBuffer(COLOR_ATTACHMENT0)
CheckFramebufferStatus(FRAMEBUFFER) = FRAMEBUFFER_COMPLETE
Viewport(0, 0, 512, 512)
Viewport(0, 0, 640, 480)

For some reason glViewport is called twice, and the second call with bad values…

I’ve put together a simple test case. The interesting thing is that it also works to render in simpleInitApp(), as long as the clear flags are set. So I cannot reproduce the artefacts here (unless you disable the clear flags). For some reason I still get artefacts in my application. Maybe Nehon has more “luck” with reproducing the artefacts, but I think he’s got plenty of other things to do. I will report if I’m still struggling with it, for now I just have to wait for frame #2.

If anybody is interested in the test case, here it is:

import com.jme3.app.*;
import com.jme3.material.*;
import com.jme3.math.*;
import com.jme3.renderer.*;
import com.jme3.scene.*;
import com.jme3.scene.shape.*;
import com.jme3.texture.*;



// =============================================================================
   public class ArtefactTestCase extends SimpleApplication
// =============================================================================
{

   private FrameBuffer sunFB;
   private Camera sunCam;
   private ViewPort sunVP;
   
// Material of the fullscreen quad   
   private Material qMat;
   

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

   
   
// =============================================================================
   public void paint()
// =============================================================================   
{
   // Generate a blue sphere (the cloud)
   // --------------------------------------------------------------------------
   float radius=1.0f;
   Material sMat=new Material(assetManager, 
    "Common/MatDefs/Misc/Unshaded.j3md");
   sMat.setColor("Color", ColorRGBA.Blue);

   Sphere sMesh=new Sphere(18, 18, radius);
   Geometry sGeom=new Geometry();
   sGeom.setMesh(sMesh);
   sGeom.setMaterial(sMat);
   
   // Setup renderer as seen from the sun
   // --------------------------------------------------------------------------
   int sunCamWidth=256;
   int sunCamHeight=256;
      
   // Create framebuffer
   Texture2D sunTex=new Texture2D(sunCamWidth, sunCamHeight, 
    Image.Format.RGBA8);
   Texture2D sunDepthTex=new Texture2D(sunCamWidth, sunCamHeight, 
    Image.Format.Depth);
   sunFB=new FrameBuffer(sunCamWidth, sunCamHeight, 1);
   sunFB.setColorTexture(sunTex);
   sunFB.setDepthTexture(sunDepthTex);
      
   // Create camera
   sunCam=new Camera(sunCamWidth, sunCamHeight);
   sunCam.setFrustum(1.0f, 1.0f+2.0f*radius,-radius,radius,radius,-radius);
   sunCam.setParallelProjection(true);
   sunCam.setLocation(Vector3f.UNIT_X.mult(-1.0f-radius));
   sunCam.lookAt(Vector3f.ZERO, Vector3f.UNIT_Z);
   sunCam.update();

   // Create view port
   sunVP=new ViewPort("CLOUDPAINTER_SUN_VIEWPORT", sunCam);
   sunVP.setOutputFrameBuffer(sunFB);
   sunVP.setBackgroundColor(ColorRGBA.BlackNoAlpha);
   sunVP.setClearFlags(true, true, true);

   // Render cloud as seen from the sun
   // --------------------------------------------------------------------------
   sunVP.attachScene(sGeom);
   sGeom.updateGeometricState();
   renderManager.renderViewPort(sunVP, 0.0f);
} // paint =====================================================================
   
   
   
// =============================================================================      
   @Override
   public void simpleInitApp()
// =============================================================================      
{
   paint();
   
   qMat=new Material(assetManager,
    "Common/MatDefs/Misc/Unshaded.j3md");
   qMat.setTexture("ColorMap", sunFB.getColorBuffer().getTexture());
   
   Geometry qGeom=new Geometry();
   qGeom.setMesh(new Quad(settings.getWidth(), settings.getHeight()));
   qGeom.setMaterial(qMat);
   
   guiNode.attachChild(qGeom);
} // simpleInitApp =============================================================
   
   

// =============================================================================      
   @Override
   public void simpleUpdate(float tpf)
// =============================================================================      
{
//   paint();
//   qMat.setTexture("ColorMap", sunFB.getColorBuffer().getTexture());
   
} // simpleUpdate ==============================================================

   
   
}
1 Like

When the framebuffer isn’t cleared, the data isn’t initialized to anything so you see those artifacts. I can also reproduce the issue when I disable clearing.

Try running your app with graphics debug and see if there’s anything in the log:

AppSettings settings = new AppSettings(true);
settings.putBoolean("GraphicsDebug", true);
app.setSettings(settings);

I had this issue too for my gui application, and i found that if you do an update in the simpleinitapp the problem disappear. From that i went into the code and copied everything in the update directly into the simpleinitapp, then remove things to keep only the core of the solution.

I don’t have my code here right now (but i can have it tomorrow) but
1 - you can find the solution with the process i described.
2 - i think that the solution was with stateManager.postRender(); (and maybe even inside that).

I thought i did something wrong and it’s why i didn’t communicate about this, sorry.
also sorry for not being able to give you the code right now but i just don’t have it with me and i don’t have a jme environment here.

1 Like

When the framebuffer isn’t cleared, the data isn’t initialized to anything so you see those artifacts.

That makes sense now. I thought that there would be 0.0 everywhere but that assumption was wrong. Also, I don’t do any update in simpleinitapp like @bubuche, it actually doesn’t matter if you do the update or not (at least not for me).

I used then the clear flag and still has the problem.

The fix is that:

private void fixFirstRender()
{
  application.getRenderManager().render(0, false);
}

so it’s simpler than i remembered.

And it’s a real bug, as color was wrong (rgb turned into bgr, pure green everywhere … ), so wrong that i actually got a perfect gradient green-to-black with a background color like (0,0.001, 0). I will maybe create a test case tomorrow.

1 Like