Vignetting Shader

A place to show off your latest screenshots and for people to comment on them. Only start a new thread here if you have some nice images to show off!
Sgw32
Greenskin
Posts: 100
Joined: Mon Aug 30, 2010 9:35 am
x 11

Vignetting Shader

Post by Sgw32 »

Hello.

I was searching ogre3d forums for a vignetting shader, but found nothing.
So I just made my own compositor script and shader.

License: public domain, but I'll be glad if you will put my credits :)

Screenshots:
Image
Image

CG Shader(vignetting.cg):

Code: Select all

sampler RT : register(s0);

float4 main_ps(float2 iTexCoord : TEXCOORD0,
uniform float radius,
uniform float darkness) : COLOR
{
float4 color=tex2D(RT,iTexCoord);
float2 inTex = iTexCoord - 0.5;
float vignette  = 1 - dot(inTex, inTex);
color.rgb    *= saturate(pow(vignette, radius) + darkness);
return color;
}
Fragment program and material:

Code: Select all

fragment_program Vignetting cg
{
	source vignetting.cg
	entry_point main_ps
	default_params
	{
		param_named radius float 4
		param_named darkness float 0.7
	}
	profiles ps_2_x arbfp1
}

material Ogre/Compositor/Vignetting
{
	technique
	{
		pass
		{
			depth_check off

			vertex_program_ref Ogre/Compositor/StdQuad_Cg_vp
			{
			}

			fragment_program_ref Vignetting
			{
			}

			texture_unit RT
			{
                tex_coord_set 0
				tex_address_mode clamp
				filtering linear linear linear
			}
		}
	}
}
Compositor script:

Code: Select all

compositor vignetting
{   
technique
    {
        texture rt0 target_width target_height PF_R8G8B8

        target rt0 { input previous }

        target_output
        {
            // Start with clear output
            input none

            pass render_quad
            {
                material Ogre/Compositor/Vignetting
		input 0 rt0
            }
        }
    }
}
:)
User avatar
duststorm
Minaton
Posts: 921
Joined: Sat Jul 31, 2010 6:29 pm
Location: Belgium
x 80

Re: Vignetting Shader

Post by duststorm »

Cool!
Thanks for so generously sharing this with us.

At first I didn't know what vignetting was exactly, so I looked it up. For others who don't know: it's creating a circle with darker edges around the image, so the center is brighter than the edges. (http://en.wikipedia.org/wiki/Vignetting)

Is it frequently used in 3D applications? What would be good scenarios to use it for?
Developer @ MakeHuman.org
Sgw32
Greenskin
Posts: 100
Joined: Mon Aug 30, 2010 9:35 am
x 11

Re: Vignetting Shader

Post by Sgw32 »

It is used in most of modern games, and for example, in Marmoset program.
User avatar
duststorm
Minaton
Posts: 921
Joined: Sat Jul 31, 2010 6:29 pm
Location: Belgium
x 80

Re: Vignetting Shader

Post by duststorm »

I see. Apparently games like Mass Effect and Pure do indeed use it.
I found a kind of funny but also interesting forum thread about post effects in games that I want to share:
http://queststudios.com/smf/index.php?topic=2905.0

That research made me somewhat up to date again with recent trends in video games :)
Developer @ MakeHuman.org
User avatar
lordsme
Gremlin
Posts: 167
Joined: Sun Mar 11, 2007 1:11 pm
Location: Turin, Italy
x 10

Re: Vignetting Shader

Post by lordsme »

I made the same shader for my framework,
but added chromatic aberration and saturation loss (http://en.wikipedia.org/wiki/Vignetting).
Code is almost the same of Sgw32, but I'd like to share it (not optimized yet).

Cg shader (need functions to convert between HSV and RGB):

Code: Select all


float4 EPF_Vignetting_PS(
	in float2 iTexCoord : TEXCOORD0
	, uniform sampler2D RT : TEXUNIT0
	, uniform float EPF_Radius
	, uniform float EPF_Darkness
	, uniform float EPF_ChromaticAberration
	, uniform float EPF_SaturationLoss
	
) : COLOR
{
    float3 base = tex2D(RT, iTexCoord).rgb;

	float2 inTex = iTexCoord - float2(0.5, 0.5);
	float dot_tex = dot(inTex, inTex);
	float vignette = 1 - dot_tex;

	vignette = saturate(pow(vignette, EPF_Radius) + EPF_Darkness);
	
	// chromatic aberration
	// compute green and blue sampling offset
	float2 sign_tc = sign(inTex);
	float vignette_inv =  1 - vignette;
	float2 g_tc = iTexCoord - EPF_ChromaticAberration * inTex * vignette_inv;
	float2 b_tc = iTexCoord - EPF_ChromaticAberration * 2.0f * inTex * vignette_inv;
	// sample again green and blue
	float base_g = tex2D(RT, g_tc).g;
	float base_b = tex2D(RT, b_tc).b;
	
	// compose result color
	float3 result = float3(base.r, base_g, base_b);
	
	// apply vignette as color multiplication
	result *= vignette;
	
	// correct saturation
	// convert to hsv
	float3 result_hsv = ES_RGBtoHSV(result);
	result_hsv.y -= EPF_SaturationLoss * vignette_inv;
	result_hsv.y = saturate(result_hsv.y);
	result = ES_HSVtoRGB(result_hsv);
	
	return float4(result, 1.0);
}
Material:

Code: Select all

fragment_program EPF_Vignetting_PS cg
{
	source Vignetting.cg
	entry_point EPF_Vignetting_PS
	
	// needs ps_3_0, otherwise different tex2D instructions
	// with different texcoords will return the same color value!
	// Seems that ps_2_0 and ps_2_x doesn't support multiple texture sampling 
	// with different tex coords computed at pixel/fragment level.
	// Perhaps computing tex coord shift in the vertex shader and interpolating 
	// would hopefully work...
	profiles ps_3_0 arbfp1
	
}

material EPF_Vignetting
{
	technique
	{

		pass
		{
			cull_hardware none
			cull_software none
			depth_check off
			fog_override true
			
			vertex_program_ref EPF_StdQuad_VS
			{
			}

			fragment_program_ref EPF_Vignetting_PS
			{
			}

			texture_unit RT
			{
				tex_coord_set 0
				tex_address_mode clamp
				filtering linear linear linear
			}
		}
	}
}
And compositor:

Code: Select all

// Vignetting effect
compositor EPFC_Vignetting
{
    technique
    {
        // Temporary textures
        texture rt0 target_width target_height PF_A8R8G8B8

        target rt0
        {
            // Render output from previous compositor (or original scene)
            input previous
        }

        target_output
        {
            // Start with clear output
            input none
            // Draw a fullscreen quad with the black and white image
            pass render_quad
            {
                // Renders a fullscreen quad with a material
                material EPF_Vignetting
                input 0 rt0

				identifier 999
            }
        }
    }
}
Leave feedback and enjoy!
My Portfolio
http://davidedigiannantonio.weebly.com

MESH - Mise-en-scene Helper
http://www.mesh-project.org/

ASALab @ Virtual Reality & Multimedia Park
http://www.vrmmp.it
Sgw32
Greenskin
Posts: 100
Joined: Mon Aug 30, 2010 9:35 am
x 11

Re: Vignetting Shader

Post by Sgw32 »

Thanks for sharing!

I have many other interesting screen-space effects, written on CG with ogre compositor.
For example:

Drug effects(2 effects)
Plasma Old-school CG Shader(and compositor)
Plasma with world influence(scene is coloured into plasma)
2.5d tunnel(old school effect)
Adjustable Gamma Correction(rgb components & saturation)
Lens(on screen effect something like you look through a lens)
Run3 Glass(Ok, I can share it too. An effect for changing screen coordinates to simulate a rough glass)

Some of them:
Plasma
Image
Run3 Glass(not a cube map :D you can see a little texcoord shift of things behind the glass)
Image
Tunnel
Image
2 Drug effects turned on at one time
Image

I can post any of these effects :)

P.S Can I rename the subject of thread to "Various compositor effects"?
User avatar
duststorm
Minaton
Posts: 921
Joined: Sat Jul 31, 2010 6:29 pm
Location: Belgium
x 80

Re: Vignetting Shader

Post by duststorm »

Those are some cool effects! :)
Are they moving? (for example the drug effect or the plasma)

I also think the window effect is quite cool. Apart from changing screen coordinates, do you also add some reflection map to it?
And/or light attenuation?
Developer @ MakeHuman.org
Sgw32
Greenskin
Posts: 100
Joined: Mon Aug 30, 2010 9:35 am
x 11

Re: Vignetting Shader

Post by Sgw32 »

All effects are dynamic! Some of them are moving in time, some of them are moving when player/camera moves :D
Glass compositor just scans scene for "glass" scheme materials, renders the scheme, and applies texture shift. Also I added a cubemap reflections on the glass object. To put it simply, you must have a non-black things behind the glass, because shader responses on every color except (0,0,0) in rgb. So any other material glass effects can be applied. The biggest problem it solves is a texture shift - because material cannot affect the things behind it(it can use cubemap though).
User avatar
duststorm
Minaton
Posts: 921
Joined: Sat Jul 31, 2010 6:29 pm
Location: Belgium
x 80

Re: Vignetting Shader

Post by duststorm »

So the glass effect is rendered as a second pass, where everything is masked except things shown through the glass, like some occluder?
I would be very interested if you would show how you implemented it.
Developer @ MakeHuman.org
User avatar
razi
Greenskin
Posts: 130
Joined: Tue Oct 14, 2008 5:54 pm
Location: Slovakia
x 17

Re: Vignetting Shader

Post by razi »

I dont quite understand the non black rule, i use for similiar effect writing normals(of desired distortion) to texture in mrt(or new pass) and then shifting it according to these,
also, depth must be considered as well or you could shift uv on things that are in front of glass.
Sgw32
Greenskin
Posts: 100
Joined: Mon Aug 30, 2010 9:35 am
x 11

Re: Vignetting Shader

Post by Sgw32 »

The glass is sometimes very similar to Glow shader on wiki:
http://www.ogre3d.org/tikiwiki/Glow&highlight=Glow

depth must be considered as well or you could shift uv on things that are in front of glass.
This shader is much easier, and doesn't use depth, because the shifts are too little, and I mustn't know normals and depth of a surface.
With big texture shifts, it doesn't look good.
The main problem of the shader is that sometimes shifts are getting screen tex-coords out of the glass surface, and it looks like glass mesh is not a primitive, such as a scaled box(it's rough on corners)! But again, with little shifts it looks ok.

Take a look:

C++ code

Code: Select all

if (StringConverter::parseBool(cf.getSetting("enableGlass","","true")))
{
	LogManager::getSingleton().logMessage("Glass is now enabled!");
	Camera* mCamera = global::getSingleton().getCamera();
		CompositorManager::getSingleton().addCompositor(mCamera->getViewport(), "Run3Glass");
		CompositorManager::getSingleton().setCompositorEnabled(mCamera->getViewport(), "Run3Glass", true);
		if (gml!=0)
		{
		gml = new GlowMaterialListener();
		Ogre::MaterialManager::getSingleton().addListener(gml);
		}
	}
By the way, my GlowMaterialListener is from ogre wiki, and controls both glow and glass.

Code: Select all

#ifndef GLOWMATERIALLISTENER_H__
#define GLOWMATERIALLISTENER_H__

#include <Ogre.h>
#include <OgreMaterialManager.h>

class GlowMaterialListener : public Ogre::MaterialManager::Listener
{
protected:
	Ogre::MaterialPtr mBlackMat;
public:
	GlowMaterialListener()
	{
		mBlackMat = Ogre::MaterialManager::getSingleton().create("mGlowBlack", "Internal");
		mBlackMat->getTechnique(0)->getPass(0)->setDiffuse(0,0,0,0);
		mBlackMat->getTechnique(0)->getPass(0)->setSpecular(0,0,0,0);
		mBlackMat->getTechnique(0)->getPass(0)->setAmbient(0,0,0);
		mBlackMat->getTechnique(0)->getPass(0)->setSelfIllumination(0,0,0);
	}

	Ogre::Technique *handleSchemeNotFound(unsigned short, const Ogre::String& schemeName, Ogre::Material*mat, unsigned short, const Ogre::Renderable*)
	{
		/*if (schemeName == "Scheme/Glow")
		{
			LogManager::getSingleton().logMessage(">> adding glow to material: "+mat->getName());
			return mBlackMat->getTechnique(0);
		}*/
		if (schemeName == "glow")
		{
			
			return mBlackMat->getTechnique(0);
		}
		if (schemeName == "GlassObj")
		{
			return mBlackMat->getTechnique(0);
		}
		return NULL;
	}
};

#endif //GLOWMATERIALLISTENER_H__
glassFilter.cg

Code: Select all

float4 GlassFilterFP
	(
		float2 uv: TEXCOORD0,

		uniform sampler2D scene: register(s0),
		uniform sampler2D glass: register(s1),
		uniform sampler2D n: register(s2)
	) : COLOR
{
	float4 colour = tex2D(glass,uv);
	
	if(colour.xyz!=float3(0))
{
float4 normal = 2 * (tex2D(n,uv) - 0.5);
	//return tex2D(scene, uv + float2(sin(uv[0]*6.28f*2)/50+0.02f,sin(uv[1]*6.28f*2)/50+0.02f));
return tex2D(scene, uv + normal.xy * 0.01);
}
else
{
	return tex2D(scene, uv);
}
}
Fragment and Material scripts(uses texture from ogre media,can be changed to anything else more interesting):

Code: Select all

fragment_program GlassFilter_fp cg
{
	source glassFilter.cg
	entry_point GlassFilterFP
	profiles ps_2_x arbfp1
}



material Run3/GlassFilter
{
	technique
	{
		pass
		{
			cull_hardware none
			cull_software none
			depth_func always_pass

			fragment_program_ref GlassFilter_fp
			{
			}

			texture_unit scene
			{
					tex_coord_set 0
					tex_address_mode clamp
					filtering trilinear
			}

			texture_unit map
			{
					tex_coord_set 0
					tex_address_mode clamp
					filtering trilinear
			}

 			texture_unit glassMap
                        {
tex_coord_set 1
					tex_address_mode clamp
					filtering trilinear
                                texture WaterNormal1.tga
                        }
			
		}
	}
}


Glass Compositor:

Code: Select all

compositor Run3Glass
{
	technique
	{
		texture rt0 target_width target_height PF_A8R8G8B8
		texture glassMap target_width target_height PF_A8R8G8B8
		

		//Fetch scene contents.
		target rt0
		{
			input previous
		}

		//Get scene rendered with 'GlassObj' scheme
		target glassMap
		{
			input none
			material_scheme GlassObj

			pass clear
			{
			}

			pass render_scene
			{
			}
		}

		
		target_output
		{
			input none

			pass clear
			{
			}

			pass render_quad
			{
				material Run3/GlassFilter
				input 0 rt0
				input 1 glassMap
			}
		}
	}
}
Example glass material:
(cubemap must be changed)

Code: Select all

material EXAMPLE
{
	technique
	{
scheme GlassObj
		pass
		{
			lighting off
			scene_blend alpha_blend
			depth_write off
			texture_unit
			{
				cubic_texture glass01.png combinedUVW
				tex_address_mode clamp
				env_map cubic_reflection
			}
		}

	}

}
User avatar
razi
Greenskin
Posts: 130
Joined: Tue Oct 14, 2008 5:54 pm
Location: Slovakia
x 17

Re: Vignetting Shader

Post by razi »

Well the uv errors are exactly why iI think depth is needed, with thin small objects in front it might get distracting even though the shifts are small. And when they are too small it defeats the purpose of having it. And your shifting according to random texture in screenspace isnt working in many cases, imagine using it for decorated windows(like in church etc) or for water.

Here lets call it "water shield" or whatever, the part getting in front of it would have few ugly shifted edges in your case.
Image

Of course Im just making point, not disregarding your work, keep it up. :)
Sgw32
Greenskin
Posts: 100
Joined: Mon Aug 30, 2010 9:35 am
x 11

Re: Vignetting Shader

Post by Sgw32 »

This image looks very nice, is it your work?
User avatar
razi
Greenskin
Posts: 130
Joined: Tue Oct 14, 2008 5:54 pm
Location: Slovakia
x 17

Re: Vignetting Shader

Post by razi »

Yes, that is quickly assembled scene to show my point. It uses principles that I said earlier.