Sketch pass gamestate

I having the hardest time getting this to work as a game state, can any one take a look and tell me what I'm not doing right, been through the examples and forum stuff already, I keep getting an NPE that seems related to accessing the camera but nothing have tried work


Exception in thread "main" java.lang.NullPointerException
   at game.SketchPassState.<init>(SketchPassState.java:30)
   at game.Hkmain4.main(Hkmain4.java:28)



the pass

public class SketchPassState extends GameState
{
    private Renderer renderer = DisplaySystem.getDisplaySystem().getRenderer();
 
    private SketchOverRenderPass sketchPass = null;
    private BasicPassManager pManager = null;

    private Camera cam;
 
    public SketchPassState(String name)
    {
        setName(name);
        TestGamestate5 gameState5 = ((TestGamestate5)GameStateManager.getInstance().getChild("gameState5"));
       
        //Setup camera
       [b] cam.setFrustumPerspective(55.0f, (float) DisplaySystem.getDisplaySystem().getWidth() / (float) DisplaySystem.getDisplaySystem().getHeight(), 1, 3000);[/b]
                      
        sketchPass = new SketchOverRenderPass(cam, 2);
        pManager = new BasicPassManager();
            
        Node rootNode = gameState5.getRootNode();
        sketchPass.add(rootNode);
        sketchPass.setEnabled(true);
       
        RenderPass rPass = new RenderPass();
        rPass.add(gameState5.getRootNode());
       
        pManager.add(rPass);
        pManager.add(sketchPass);
      
    }
 
    @Override
    public void render(float tpf)
    {
        renderer.clearBuffers();
        pManager.renderPasses(renderer);
       
    }
 
    @Override
    public void update(float tpf)
    {
        pManager.updatePasses(tpf);
    }
 
    @Override
    public void cleanup()
    {
 
    }
}



main class


public class Hkmain4 {
 
    private static StandardGame game;
 
    public static void main(String[] args) throws Exception {
        game = new StandardGame("HKShooter Testgame");
        GameSettingsPanel.prompt(game.getSettings());
        game.getSettings().setFramerate(85);
        game.start();
       
        FPSGameState fps = new FPSGameState();
        GameStateManager.getInstance().attachChild(fps);
        fps.setActive(true);
            
        TestGamestate5 state = new TestGamestate5(game.getCamera());
        GameStateManager.getInstance().attachChild(state);
        state.setActive(true);
       
       [b] SketchPassState sketchPassState = new SketchPassState("sketchPassState");[/b]
        GameStateManager.getInstance().attachChild(sketchPassState);
        sketchPassState.setActive(true);
     
        
       
    }



it looks like cam isn't instantiated…  you remembered to assign renderer, but you forgot:


cam = renderer.getCamera();

sbook said:

it looks like cam isn't instantiated...  you remembered to assign renderer, but you forgot:

cam = renderer.getCamera();




I tried what u suggested and few other things but still no go :(, but the NPE is different now, I really ned a bit of help on this

Exception in thread "main" java.lang.NullPointerException
   at com.jme.renderer.lwjgl.LWJGLTextureRenderer.<init>(LWJGLTextureRenderer.java:117)
   at com.jme.renderer.lwjgl.LWJGLTextureRenderer.<init>(LWJGLTextureRenderer.java:107)
   at com.jme.system.lwjgl.LWJGLDisplaySystem.createTextureRenderer(LWJGLDisplaySystem.java:328)
   at pass.SketchOverRenderPass.<init>(SketchOverRenderPass.java:115)
   at game.SketchPassState.<init>(SketchPassState.java:36)
   at game.Hkmain4.main(Hkmain4.java:28)



the pass state

public class SketchPassState extends GameState
{
    private Renderer renderer = DisplaySystem.getDisplaySystem().getRenderer();
 
    private SketchOverRenderPass sketchPass = null;
    private BasicPassManager pManager = null;

    private Camera cam;
 
    public SketchPassState(String name, Camera camera)
    {
        setName(name);
      
        //Setup camera
        this.cam = camera;
        cam = renderer.getCamera();
        //cam = renderer.createCamera(DisplaySystem.getDisplaySystem().getWidth(), DisplaySystem.getDisplaySystem().getHeight());
        cam.setFrustumPerspective(55.0f, (float) DisplaySystem.getDisplaySystem().getWidth() / (float) DisplaySystem.getDisplaySystem().getHeight(), 1, 3000);
       
        //setup pass
        TestGamestate5 gameState5 = ((TestGamestate5)GameStateManager.getInstance().getChild("gameState5"));
        sketchPass = new SketchOverRenderPass(cam, 2);
        pManager = new BasicPassManager();
            
        Node rootNode = gameState5.getRootNode();
        sketchPass.add(rootNode);
        sketchPass.setEnabled(true);
       
        RenderPass rPass = new RenderPass();
        rPass.add(gameState5.getRootNode());
       
        pManager.add(rPass);
        pManager.add(sketchPass);
      
    }
 
    @Override
    public void render(float tpf)
    {
        renderer.clearBuffers();
        pManager.renderPasses(renderer);
       
    }
 
    @Override
    public void update(float tpf)
    {
        pManager.updatePasses(tpf);
    }
 
    @Override
    public void cleanup()
    {
 
    }
}


execution stuff

SketchPassState sketchPassState = new SketchPassState("sketchPassState",game.getCamera());
        GameStateManager.getInstance().attachChild(sketchPassState);
        sketchPassState.setActive(true);



Can you specify which line is throwing the NPE in the pass state?  We don't have the same line numbers as you!

sbook said:

Can you specify which line is throwing the NPE in the pass state?  We don't have the same line numbers as you!


in the pass

sketchPass = new SketchOverRenderPass(cam, 2);



and in main

SketchPassState sketchPassState = new SketchPassState("sketchPassState",game.getCamera());


Weird, if you trace it you end up here at LWJGLTextureRenderer:117

supportsMultiSample = GLContext.getCapabilities().GL_EXT_framebuffer_multisample;




I thought that you had got the shader working already in the other thread so its clearly not that your GPU doesn't support multisampling..  Have you tried injecting the pass gamestate creation in the OpenGL thread?
sbook said:

Weird, if you trace it you end up here at LWJGLTextureRenderer:117

supportsMultiSample = GLContext.getCapabilities().GL_EXT_framebuffer_multisample;




I thought that you had got the shader working already in the other thread so its clearly not that your GPU doesn't support multisampling..  Have you tried injecting the pass gamestate creation in the OpenGL thread?


my card has the required support this code below works perfectly, its when I try to incorporate it as  a gamestate in my Standard game app I get these issues :?

test

package test;

import java.awt.Color;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.FloatBuffer;
import java.util.logging.Logger;

import javax.print.attribute.standard.Finishings;

import pass.SketchOverRenderPass;

import jmetest.flagrushtut.Lesson2;

import com.jme.app.BaseGame;
import com.jme.bounding.BoundingBox;
import com.jme.image.Texture;
import com.jme.input.FirstPersonHandler;
import com.jme.input.Input;
import com.jme.input.InputHandler;
import com.jme.input.InputSystem;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.light.DirectionalLight;
import com.jme.light.PointLight;
import com.jme.math.Vector3f;
import com.jme.renderer.Camera;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.renderer.pass.BasicPassManager;
import com.jme.renderer.pass.OutlinePass;
import com.jme.renderer.pass.RenderPass;
import com.jme.scene.Node;
import com.jme.scene.Spatial;
import com.jme.scene.Text;
import com.jme.scene.shape.RoundedBox;
import com.jme.scene.shape.Sphere;
import com.jme.scene.state.BlendState;
import com.jme.scene.state.LightState;
import com.jme.scene.state.MaterialState;
import com.jme.scene.state.RenderState;
import com.jme.scene.state.TextureState;
import com.jme.scene.state.ZBufferState;
import com.jme.system.DisplaySystem;
import com.jme.util.TextureManager;
import com.jme.util.Timer;

import com.jmex.terrain.TerrainBlock;
import com.jmex.terrain.util.MidPointHeightMap;


public class Main extends BaseGame {
   private Logger log = Logger.getLogger(this.getClass().getName());
   
   private int width = 800,
            height = 500;
   
   private Timer timer = Timer.getTimer();
   private Renderer rend;
   private Camera cam;
   private Node scene;
   private FirstPersonHandler fpHandler;
   private KeyBindingManager kbm = KeyBindingManager.getKeyBindingManager();
   private BasicPassManager pm = new BasicPassManager();
   private SketchOverRenderPass srp;
   
   private TerrainBlock tb;
   
   @Override
   protected void cleanup() {
      // end game

   }

   @Override
   protected void initSystem() {
      // init window, camera, input system, etc.
      display = DisplaySystem.getDisplaySystem();
      display.createWindow(width, height, 32, 60, false);
      rend = display.getRenderer();
      cam = rend.createCamera(width, height);
      cam.setFrustumPerspective(45.0f, (float)width / (float)height, 1, 3000);
      Vector3f loc = new Vector3f(200.0f, 200.0f, 200.0f);
      Vector3f left = new Vector3f(-0.5f, 0.0f, 0.5f);
      Vector3f up = new Vector3f(0.0f, 1.0f, 0.0f);
      Vector3f dir = new Vector3f(-0.5f, 0.0f, -0.5f);
      // Move our camera to a correct place and orientation.
      cam.setFrame(loc, left, up, dir);
      /** Signal that we've changed our camera's location/frustum. */
      cam.update();
      scene = new Node("scene");
      ZBufferState buf = display.getRenderer().createZBufferState();
       buf.setEnabled(true);
       buf.setFunction(ZBufferState.TestFunction.LessThanOrEqualTo);
       scene.setRenderState(buf);
      rend.setCamera(cam);
      rend.setBackgroundColor(ColorRGBA.yellow);
      BlendState as = rend.createBlendState();
      
      srp = new SketchOverRenderPass(cam, 2);
      srp.setEnabled(true);
      srp.add(scene);
      
      RenderPass rp = new RenderPass();
      rp.setEnabled(true);
      rp.add(scene);
      
      //pm.add(olp);
      pm.add(rp);
      pm.add(srp);
      //pm.updatePasses(0);
      
      fpHandler = new FirstPersonHandler(cam, 400, 1);
      fpHandler.getKeyboardLookHandler().setEnabled(true);
      fpHandler.getMouseLookHandler().setEnabled(true);
      
      kbm.set("exit", KeyInput.KEY_ESCAPE);
      kbm.set("o", KeyInput.KEY_O);
   }

   @Override
   protected void initGame() {
      // all game or scene data is set up
      buildLighting();
      buildTerrain();
      scene.attachChild(tb);
      scene.updateGeometricState(0f, true);
      scene.updateRenderState();
      
      
      Sphere s = new Sphere("sphere", 30, 30, 20);
      s.setLocalTranslation(new Vector3f(100, 200, 100));
      s.setModelBound(new BoundingBox());
      MaterialState color = rend.createMaterialState();
      color.setColorMaterial(MaterialState.ColorMaterial.None);
      color.setAmbient(ColorRGBA.red);

      color.setMaterialFace(MaterialState.MaterialFace.Front);
      color.setEnabled(true);
      s.setRenderState(color);
      s.updateRenderState();
      s.updateModelBound();
      s.updateGeometricState(0, true);
      
      scene.attachChild(s);
      scene.updateGeometricState(0.0f, true);
      scene.updateRenderState();
   }
   
   @Override
   protected void reinit() {
      // system setting are changed (e.g. change in resolution)
      
   }

   @Override
   protected void render(float interpolation) {
      // render the sali-boy
      interpolation = timer.getTimePerFrame();
      rend.clearBuffers();
      pm.renderPasses(rend);
   }

   @Override
   protected void update(float interpolation) {
      //  main frame to frame update method
      timer.update();
      interpolation = timer.getTimePerFrame();
      pm.updatePasses(interpolation);
      fpHandler.update(interpolation);
      if(kbm.isValidCommand("exit"))
         finished = true;
      if(kbm.isValidCommand("o")) {
         rend.takeScreenShot("screenshot1`");
      }
   }
   
   public static void main(String [] args) {
      BaseGame game = new Main();
      game.start();
   }
   
   private void buildTerrain() {
      MidPointHeightMap heightMap = new MidPointHeightMap(64, 0.5f);
      Vector3f terrainScale = new Vector3f(20, 1, 20);
      tb = new TerrainBlock("Terrain", heightMap.getSize(), terrainScale, heightMap.getHeightMap(), new Vector3f(0, 0, 0));
      tb.setModelBound(new BoundingBox());
      tb.updateModelBound();
      
      TextureState ts = rend.createTextureState();
      ts.setEnabled(true);
      ts.setTexture(TextureManager.loadTexture("/data/textures/scene/highest.jpg",
              Texture.MinificationFilter.Trilinear,
                Texture.MagnificationFilter.Bilinear));
      tb.setRenderState(ts);
      tb.updateRenderState();
   }
   
   private void buildLighting() {
      PointLight light = new PointLight();
      
      light.setLocation(new Vector3f(0, 10000, 0));
      light.setAmbient(ColorRGBA.white);
      light.setDiffuse(ColorRGBA.white);
      light.setEnabled(true);

 
       /** Attach the light to a lightState and the lightState to rootNode. */
       LightState lightState = display.getRenderer().createLightState();
       lightState.attach(light);
       lightState.setGlobalAmbient(ColorRGBA.white);
       lightState.setEnabled(true);
       scene.setRenderState(lightState);

   }
}



pass


package pass;

import com.jme.image.Texture;
import com.jme.image.Texture2D;
import com.jme.renderer.Camera;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.renderer.TextureRenderer;
import com.jme.renderer.pass.Pass;

import com.jme.scene.Spatial;
import com.jme.scene.Spatial.TextureCombineMode;
import com.jme.scene.shape.Quad;
import com.jme.scene.state.BlendState;
import com.jme.scene.state.GLSLShaderObjectsState;
import com.jme.scene.state.LightState;
import com.jme.scene.state.MaterialState;
import com.jme.scene.state.RenderState;
import com.jme.scene.state.TextureState;
import com.jme.system.DisplaySystem;
import com.jmex.effects.glsl.SketchRenderPass;

/**
 * GLSL sketch effect pass.
 * - Render supplied source to a texture
 * - Render normals and depth to texture
 * - Apply sobel filter to find changes is normal and depth
 * - (Blur if wanted, slow)
 * - Overwrite or blend with first pass
 *
 * @author Rikard Herlitz (MrCoder)
 */
public class SketchOverRenderPass extends Pass {
    private static final long serialVersionUID = 1L;
    
    private TextureRenderer tRendererDepth;
   private Texture2D textureDepth;

   private Quad fullScreenQuad;

   private GLSLShaderObjectsState sobelShader;
   private GLSLShaderObjectsState normShader;

   private float normalMult = 10.5f;
   private float depthMult = 1250.0f;
   private float off = 0.0001f;
   private boolean supported = true;

   protected RenderState[] preStates = new RenderState[RenderState.StateType.values().length];

   /**
    * Reset sketch parameters to default
    */
   public void resetParameters() {
      normalMult = 22.5f;
      depthMult = 1850.0f;
      off = 0.0009f;
   }

   /**
    * Release pbuffers in TextureRenderer's. Preferably called from user cleanup method.
    */
   public void cleanup() {
      tRendererDepth.cleanup();
   }
   
   public boolean isSupported() {
      return supported;
   }

   public SketchOverRenderPass(Camera cam, int renderScale) {
     //Test for glsl support
        if(!GLSLShaderObjectsState.isSupported()) {
            supported = false;
            return;
        }       
       
       DisplaySystem display = DisplaySystem.getDisplaySystem();

      resetParameters();

      //Create texture renderers and rendertextures for depth (only needed for some nvidia cards, like mine)
        tRendererDepth = display.createTextureRenderer(
                            display.getWidth() / renderScale,
                            display.getHeight() / renderScale,
                            TextureRenderer.Target.Texture2D);
        tRendererDepth.setBackgroundColor(new ColorRGBA(0.0f, 0.0f, 0.0f, 1.0f));
        tRendererDepth.setCamera(cam);

        textureDepth = new Texture2D();
        textureDepth.setWrap(Texture.WrapMode.Clamp);
        textureDepth.setMagnificationFilter(Texture.MagnificationFilter.Bilinear);
        tRendererDepth.setupTexture(textureDepth);

        //Create extract normals and depth shader
        normShader = display.getRenderer().createGLSLShaderObjectsState();
        normShader.load(SketchRenderPass.class.getClassLoader().getResource("data/shader/pass/sketch_norm.vert"),
                SketchRenderPass.class.getClassLoader().getResource("data/shader/pass/sketch_norm.frag"));
        normShader.setEnabled(true);
        normShader.setUniform("nearClip", cam.getFrustumNear());
        normShader.setUniform("diffClip", cam.getFrustumFar() - cam.getFrustumNear());

        //Create sobel shader
        sobelShader = display.getRenderer().createGLSLShaderObjectsState();
        sobelShader.load(SketchRenderPass.class.getClassLoader().getResource("data/shader/pass/sketchover_sobel.vert"),
                SketchRenderPass.class.getClassLoader().getResource("data/shader/pass/sketchover_sobel.frag"));
        sobelShader.setEnabled(true);

      //Create fullscreen quad
      fullScreenQuad = new Quad("FullScreenQuad", display.getWidth(), display.getHeight());
      fullScreenQuad.getLocalRotation().set(0, 0, 0, 1);
      fullScreenQuad.getLocalTranslation().set(display.getWidth() / 2, display.getHeight() / 2, 0);
      fullScreenQuad.getLocalScale().set(1, 1, 1);
      fullScreenQuad.setRenderQueueMode(Renderer.QUEUE_ORTHO);

      fullScreenQuad.setCullHint(Spatial.CullHint.Never);
        fullScreenQuad.setTextureCombineMode(TextureCombineMode.Replace);
        fullScreenQuad.setLightCombineMode(Spatial.LightCombineMode.Off);
        
      TextureState ts = display.getRenderer().createTextureState();
      ts.setEnabled(true);
      fullScreenQuad.setRenderState(ts);
      
      BlendState as = display.getRenderer().createBlendState();
      as.setBlendEnabled(true);
      as.setSourceFunction(BlendState.SourceFunction.SourceAlpha);
      as.setEnabled(true);
      fullScreenQuad.setRenderState(as);

      fullScreenQuad.updateRenderState();
      fullScreenQuad.updateGeometricState(0.0f, true);

      //setup shader for extracting normals and depth
      noTexture = display.getRenderer().createTextureState();
      noTexture.setEnabled(false);
      noLights = display.getRenderer().createLightState();
      noLights.setEnabled(false);
      noMaterials = display.getRenderer().createMaterialState();
      noMaterials.setEnabled(false);
   }

   protected static TextureState noTexture;
   protected static LightState noLights;
   protected static MaterialState noMaterials;

   public void doRender(Renderer r) {
      if(spatials.size() != 1) return;

      //Render scene to normals and depth
      saveEnforcedStates();
        context.enforceState(noTexture);
        context.enforceState(noLights);
        context.enforceState(noMaterials);
        context.enforceState(normShader);
      tRendererDepth.render(spatials.get(0), textureDepth);
      replaceEnforcedStates();

      TextureState ts = (TextureState) fullScreenQuad.getRenderState(RenderState.StateType.Texture);

      //Apply sobel as final render
      sobelShader.clearUniforms();
      sobelShader.setUniform("depth", 0);
      sobelShader.setUniform("normalMult", getNormalMult());
      sobelShader.setUniform("depthMult", getDepthMult());
      sobelShader.setUniform("off", getOff());

      ts.setTexture(textureDepth, 0);
      fullScreenQuad.setRenderState(sobelShader);
      fullScreenQuad.updateRenderState();
      r.draw(fullScreenQuad);
   }

   /**
     * saves any states enforced by the user for replacement at the end of the
     * pass.
     */
    protected void saveEnforcedStates() {
        for(int x = RenderState.StateType.values().length; --x >= 0;) {
            preStates[x] = context.enforcedStateList[x];
        }
    }

    /**
     * replaces any states enforced by the user at the end of the pass.
     */
    protected void replaceEnforcedStates() {
        for(int x = RenderState.StateType.values().length; --x >= 0;) {
            context.enforcedStateList[x] = preStates[x];
        }
    }

    public float getNormalMult() {
        return normalMult;
    }

    public void setNormalMult(float normalMult) {
        this.normalMult = normalMult;
    }

    public float getDepthMult() {
        return depthMult;
    }

    public void setDepthMult(float depthMult) {
        this.depthMult = depthMult;
    }

    public float getOff() {
        return off;
    }

    public void setOff(float off) {
        this.off = off;
    }
}






Yeah, it runs for me too… I think its that you need to inject the creation of the SketchOverRenderPass into the opengl thread:


try {
         GameTaskQueueManager.getManager().update(new Callable<Object>() {
            public Object call() throws Exception {
               sketchPass = new SketchOverRenderPass(cam, 2);
            }
         }).get();


didn’t work :frowning: , I am following coredump’s tut here maybe he can shed some light on the situation

I tried your project now and its as sbook pointed out.



The Problem is, that SketchPassState (or rather SketchOverRenderPass) needs to be instantiated inside the OpenGL thread. Because when its created, it acceses GLContext.getCapabilities(), and the GLContext is only available inside the already running OpenGL thread which StandardGame spawned.

That caused the NPE you saw.



    public static void main(String[] args) throws Exception {
        game = new StandardGame("HKShooter Testgame");
        GameSettingsPanel.prompt(game.getSettings());
        game.getSettings().setFramerate(85);
        
        game.start();
        
        FPSGameState fps = new FPSGameState();
        GameStateManager.getInstance().attachChild(fps);
        fps.setActive(true);
            
        TestGamestate5 state = new TestGamestate5(game.getCamera());
        GameStateManager.getInstance().attachChild(state);
        state.setActive(true);
        
        SketchPassState sketchPassState = GameTaskQueueManager.getManager().update(new Callable<SketchPassState>() {
           public SketchPassState call() throws Exception {
              return new SketchPassState("sketchPassState",game.getCamera());
           }
      }).get();
        GameStateManager.getInstance().attachChild(sketchPassState);
        sketchPassState.setActive(true);
    }  

thank you core and thank u sbook, u were right, I was trying use the queue from inside the pass state  :// anyway thanks all :slight_smile:





edit Core-dump could u post a screenshot of the test as seen on your computer is it like the screenshot below if it is I still have work to do :frowning: but atleast there's progress

that character looks very cool, nice work!

pretty much the same

yeah, I had to comment out

//cam = renderer.createCamera(DisplaySystem.getDisplaySystem().getWidth(), DisplaySystem.getDisplaySystem().getHeight());

in sketch pass state



@ sbook thank you :smiley:


a screenie still …and yes the skybox is not suppose to have an outline XD just happy to get it working and now have use texture that "agree" with the sketch pass