NoisyTreshold Post Processing Filter

Hey again, yet another one.

As you may have read in @mcbeth his topic on a certain kind of toon shader, here is what I got =] Mostly useful for graphical novel kind of games with a dark kind of feel, at least, that is what it was designed for. Just before I wanted to post it I remembered the black and white shader seconds at the start of Half Life 2 and thought, why the hell not, I got as near as possible for that one anyway. So I included the possibility to decide on the threshold in and out colors, the mixing strengths of both and another feature useful to create an even more drawn feeling. I added the possibility to update the screen noise only after each x.xx seconds, so at 0.25 you only get 4 noise updates max per second. That way you won’t go crazy by what looks like a ginormous cloud of flies all over the place.

Best effect are probably obtained by good drawn-like textures, posterization filter and the cartoon edge filter of course.



As a small note on the side, I reused my ‘random’ function once more, if you know any faster kind of ‘random’ for the gpu, please tell me. I believe there are a number of pointless additions that could be removed somehow but I had to add them to get rid of strange mistakes.



Oh, and @mcbeth I decided to go with another name anyway as this is a bit more multi-purpose and only part in the pipeline for the graphic novel look. Might get confusing if I give it a name that sounds like it’s the all mighty cartoon filter. I’ll post my settings for that look on your topic in a minute after this post :wink:



Edit: And of course, thanks to @mcbeth for the idea to write this!



Impression of a possible look during development:





NoisyTreshold.java

[java]package shaders;



import com.jme3.asset.AssetManager;

import com.jme3.material.Material;

import com.jme3.math.ColorRGBA;

import com.jme3.post.Filter;

import com.jme3.renderer.RenderManager;

import com.jme3.renderer.Renderer;

import com.jme3.renderer.ViewPort;



/**

  • A Post Processing filter that tresholds your final render with some grain
  • around the edges. Seemed useful for graphical novel styles. Use in combination
  • with posterization and cartoon edges for an impression of the idea.

    *
  • Added possibility to turn noise updates dependent on time to get rid of
  • strange effects. Full speed updating gave a bad effect so there also is an
  • update time available. If you put it to 0.25, every quarter of a second a new
  • noise map will be used. Gives the impression of numerous drawings per second
  • instead of crazy noise.

    *
  • @author: Roy Straver a.k.a. Baal Garnaal

    /

    public class NoisyTresholdFilter extends Filter{

    float time = 42.98375f; // Random value to get rid of first frame erroneous visuals

    float treshold = 0.4f;

    float noiseWidth = 8.0f;

    float noiseUpdateTime = 1/4.0f;

    float timeSinceLastUpdate = 0.0f;

    boolean updateNoise = false;



    float inMix = 0;

    float outMix = 1;

    ColorRGBA inColor = ColorRGBA.White.clone();

    ColorRGBA outColor = ColorRGBA.Black.clone();



    public NoisyTresholdFilter() {

    super("NoisyTresholdFilter");

    }



    public NoisyTresholdFilter(float treshold, float noiseWidth) {

    this();

    this.treshold = treshold;

    this.noiseWidth = noiseWidth;

    }



    public NoisyTresholdFilter(float treshold, float noiseWidth, boolean updateNoise) {

    this(treshold, noiseWidth);

    this.updateNoise = updateNoise;

    }



    @Override

    public boolean isRequiresDepthTexture() {

    return false;

    }



    @Override

    public void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {

    material = new Material(manager, "/MatDefs/Post/NoisyTreshold.j3md");

    material.setFloat("Time", time);

    material.setFloat("Treshold", 1-treshold);

    material.setFloat("NoiseWidth", noiseWidth);

    material.setFloat("InMix", inMix);

    material.setFloat("OutMix", outMix);

    material.setColor("InColor", inColor);

    material.setColor("OutColor", outColor);

    }



    @Override

    public Material getMaterial() {

    return material;

    }



    @Override

    public void preRender(RenderManager renderManager, ViewPort viewPort) {

    }



    @Override

    public void cleanUpFilter(Renderer r) {

    }



    @Override

    public void preFrame(float tpf) {

    time += tpf;

    timeSinceLastUpdate += tpf;

    if (material != null && updateNoise){

    if (timeSinceLastUpdate > noiseUpdateTime){

    material.setFloat("Time", time);

    timeSinceLastUpdate = 0.0f;

    }

    }

    }



    /

  • Sets treshold level for black parts

    /

    public void setTreshold(float treshold){

    this.treshold = treshold;

    if (material != null)

    material.setFloat("Treshold", 1-treshold);

    }



    /

  • Sets width of noise band on treshold edges
  • Please note this is not really the amount of pixels wide on your screen,
  • it’s a multiplier for relative coordinatess.

    /

    public void setNoiseWidth(float noiseWidth){

    this.noiseWidth = noiseWidth;

    if (material != null)

    material.setFloat(“NoiseWidth”, noiseWidth);

    }



    /

  • Sets time a noise pattern is used before replacing it, set to 0 for every frame

    /

    public void setNoiseUpdateTime(float noiseUpdateTime){

    this.noiseUpdateTime = noiseUpdateTime;

    }



    /

  • Sets noise updates over time on or off

    /

    public void setUpdateNoise(boolean updateNoise){

    this.updateNoise = updateNoise;

    }



    /

  • Sets mixing strength of color for pixels that are ‘in’ the treshold
  • 1 is inColor only, 0 is do not touch

    /

    public void setInMix(float inMix){

    this.inMix = inMix;

    if (material != null)

    material.setFloat("InMix", inMix);

    }



    /

  • Sets mixing strength of color for pixels that are ‘out’ the treshold
  • 1 is outColor only, 0 is do not touch

    /

    public void setOutMix(float outMix){

    this.outMix = outMix;

    if (material != null)

    material.setFloat("OutMix", outMix);

    }



    /

  • Sets color for pixels that are ‘in’ the treshold

    /

    public void setInColor(ColorRGBA inColor){

    this.inColor = inColor;

    if (material != null)

    material.setColor(“InColor”, inColor);

    }



    /

  • Sets color for pixels that are ‘out’ the treshold

    /

    public void setOutColor(ColorRGBA outColor){

    this.outColor = outColor;

    if (material != null)

    material.setColor(“OutColor”, outColor);

    }



    /

  • Returns treshold level for black parts

    /

    public float getTreshold(){

    return treshold;

    }



    /

  • Returns width of noise along treshold edges

    /

    public float getNoiseWidth(){

    return noiseWidth;

    }



    /

  • Returns number of noise updates per second

    /

    public float getNoiseUpdateTime(){

    return noiseUpdateTime;

    }



    /

  • Returns true if noise updates during frames or is steady

    /

    public boolean getUpdateNoise(){

    return updateNoise;

    }



    /

  • Returns mixing strength of color for pixels that are ‘in’ the treshold
  • 1 is inColor only, 0 is do not touch

    /

    public float getInMix() {

    return inMix;

    }



    /

  • Returns mixing strength of color for pixels that are ‘out’ the treshold
  • 1 is outColor only, 0 is do not touch

    /

    public float getOutMix() {

    return outMix;

    }



    /

  • Returns color for pixels that are ‘in’ the treshold

    /

    public ColorRGBA getInColor() {

    return inColor;

    }



    /

  • Returns color for pixels that are ‘out’ the treshold

    /

    public ColorRGBA getOutColor() {

    return outColor;

    }

    }[/java]



    NoisyTreshold.j3md

    [java]MaterialDef NoisyTreshold {



    MaterialParameters {

    Int NumSamples

    Int NumSamplesDepth

    Texture2D Texture

    Float Time

    Float Treshold

    Float NoiseWidth

    Float InMix

    Float OutMix

    Vector4 InColor

    Vector4 OutColor

    }



    Technique {

    VertexShader GLSL150: Common/MatDefs/Post/Post15.vert

    FragmentShader GLSL150: MatDefs/Post/NoisyTreshold15.frag



    WorldParameters {

    WorldViewProjectionMatrix

    }

    }



    Technique {

    VertexShader GLSL100: Common/MatDefs/Post/Post.vert

    FragmentShader GLSL100: MatDefs/Post/NoisyTreshold.frag



    WorldParameters {

    WorldViewProjectionMatrix

    }

    }



    Technique FixedFunc {

    }

    }[/java]



    NoisyTreshold15.frag

    [java]#import “Common/ShaderLib/MultiSample.glsllib”



    uniform COLORTEXTURE m_Texture;

    in vec2 texCoord;



    uniform float m_Time;

    uniform float m_Treshold;

    uniform float m_NoiseWidth;



    uniform float m_InMix;

    uniform float m_OutMix;



    uniform vec4 m_InColor;

    uniform vec4 m_OutColor;



    void main() {

    vec4 texVal = getColor(m_Texture, texCoord);

    float lum = texVal.r
    0.2126 + texVal.g0.7152 + texVal.b0.0722;



    float grain = (texCoord.x+4) * (texCoord.y+4) * m_Time;

    grain = mod((mod(grain, 13) + 1) * (mod(grain, 123) + 1), 0.01) * m_NoiseWidth;



    lum = floor(lum+m_Treshold+grain);

    texVal = mix(texVal, m_InColor, m_InMix) * lum + mix(texVal, m_OutColor, m_OutMix) * (1-lum);



    gl_FragColor = texVal;

    }[/java]



    NoisyTreshold.frag

    [java]uniform sampler2D m_Texture;

    in vec2 texCoord;



    uniform float m_Time;

    uniform float m_Treshold;

    uniform float m_NoiseWidth;



    uniform float m_InMix;

    uniform float m_OutMix;



    uniform vec4 m_InColor;

    uniform vec4 m_OutColor;



    void main() {

    vec4 texVal = texture2D(m_Texture, texCoord);

    float lum = texVal.r0.2126 + texVal.g0.7152 + texVal.b*0.0722;



    float grain = (texCoord.x+4) * (texCoord.y+4) * m_Time;

    grain = mod((mod(grain, 13) + 1) * (mod(grain, 123) + 1), 0.01) * m_NoiseWidth;



    lum = floor(lum+m_Treshold+grain);

    texVal = mix(texVal, m_InColor, m_InMix) * lum + mix(texVal, m_OutColor, m_OutMix) * (1-lum);



    gl_FragColor = texVal;

    }[/java]
1 Like

will dig into this asap thanks, I’m a bit indisposed atm …thanks again

okay I am try to get this to work but the asset manager is messing with me, have no idea why it keeps saying it cant find the mat def its setup correctly as far as I can see even tried dumping it into the jme3 def folder still crashes…really weird… I’ll try to figure out what going on

You do put it in as a post processing filter? :wink:



Also, watch line 17 and 18 of the j3md:

[java]VertexShader GLSL150: Common/MatDefs/Post/Post15.vert

FragmentShader GLSL150: MatDefs/Post/NoisyTreshold15.frag[/java]

yeah had to settled a few path issues thought I got them all but I missed or misinterpreted a few

ok I gone over it some, I full of flu at the moment so forgive me, I’ve tested it thoroughly and couldn’t get the results I wanted, no worries though I learn alot from that and your film grain filter to work up the effect I was going for, my idea was to project the noise base on the normals and lighting yours seem to saturate the scene based on set parameter, still though your great work made mine possible



second thought I think this might be better as a material than a PPF to allow u to play with the “tweakables” on a node by node basic…if necessary…or am I misunderstanding how filters work



this what I was able to produce…and how would you get a screen shot out of jme the normal windows function gives only black

click link to enlarge

http://i.imgur.com/zDlcy.jpg

http://i.imgur.com/uiHPE.jpg

http://i.imgur.com/IV8X6.jpg