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
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.r0.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]