Refraction? Demo


Click to load unity player

requires unity3d web player, click to play


This weekend I ended up reading about cg shaders and writing a little experiment; I wanted to apply a lens effect in front of a texture, by using a fragment and vertex program.
When time was up I still had some trouble with the quality of the resulting image;

Please leave a response if you have any ideas of how to make text readable behind the distortion.

Update
With some feedback and a good read from Texel in #unity3d@ freenode; I implemented a poisson disc filter to remove some of the artifacts;
here Is the before and after footage.

Update new shader program
Update added art made by Kuroto Robert
Here is the unity material with the shader program included(with poissonDisc),

// Per pixel refraction.
// Uses a normal map and vertex normals to distort the image behind
Shader "FX/Glass/RefractionMap"
{
Properties
{

	_ReflectionStartVal ("Reflection", Range (0.0,1.0)) = 0.5	

	_BumpAmt ("Glass Distortion", Range (0.01,1.0)) = 0.5

	_DiscRadius("Normal Blur Radius", Float) = 1
	_MainTexWidth ("NormalMapWidth", Float) = 512
	_MainTexHeight("NormalMapHeight", Float) = 512
	_MainTex ("Background", 2D) = "white" {}
	_BumpMap ("NormalInfo", 2D) = "bump" {}

	_MaskTexture ("FrameTexture", 2D) = "white" {}

	_Color ("Main Color", Color) = (1,1,1,1)
	_ReflectColor ("Reflection Color", Color) = (1,1,1,0.5)
	_Cube ("Reflection Cubemap", Cube) = "" { TexGen CubeReflect }
}

Category {
	// We must be transparent, so other objects are drawn before this one.
	Tags { "Queue"="Transparent" "RenderType"="Opaque" }
	SubShader
	{
		Pass
		{
			Name "BASE"
			//Blend SrcAlpha OneMinusSrcAlpha
			//Tags {"LightMode" = "Always"}

			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma fragmentoption ARB_precision_hint_fastest

			#include "UnityCG.cginc"

			struct v2f {
				float4 pos : SV_POSITION;
				float2	uv		: TEXCOORD0;
				float2	uv2		: TEXCOORD1;
				float3	I		: TEXCOORD2;
				float3	TtoW0 	: TEXCOORD3;
				float3	TtoW1	: TEXCOORD4;
				float3	TtoW2	: TEXCOORD5;
			};

			uniform float4 _MainTex_ST, _BumpMap_ST;
			uniform half _BumpAmt;
			v2f vert(appdata_tan v)
			{
				v2f o;
				o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
				o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
				o.uv2 = TRANSFORM_TEX(v.texcoord,_BumpMap);

				o.I = -WorldSpaceViewDir( v.vertex );

				TANGENT_SPACE_ROTATION;
				o.TtoW0 = mul(rotation, _Object2World[0].xyz * unity_Scale.w);
				o.TtoW1 = mul(rotation, _Object2World[1].xyz * unity_Scale.w) ;
				o.TtoW2 = mul(rotation, _Object2World[2].xyz * unity_Scale.w);

				return o;
			}

			uniform sampler2D _BumpMap;
			uniform sampler2D _MainTex;
			uniform samplerCUBE _Cube;
			uniform float4 _ReflectColor;
			uniform float4 _Color;
			uniform float _ReflectionStartVal;
			uniform float _MainTexHeight;
			uniform float _MainTexWidth;
			uniform float _DiscRadius;
			uniform float _InnerDiscRadius;
			half2 PixelSize()
			{
				return 1f / float2(_MainTexWidth,_MainTexHeight);
			}
			half4 MultiSample5(sampler2D source, half2 pixelSize, half radius, half2 uvTarget )
			{
				float acctualSize = pixelSize * radius;
				half4 resultColor = tex2D(source, uvTarget);
				resultColor += tex2D(source, uvTarget + half2(-0.707106781f, 0.707106781f) * acctualSize); //upLeft
				resultColor += tex2D(source, uvTarget + half2(0.707106781f, 0.707106781f) * acctualSize); //upRight
				resultColor += tex2D(source, uvTarget + half2(-0.707106781f, -0.707106781f) * acctualSize); //downLeft
				resultColor += tex2D(source, uvTarget + half2(0.707106781f, -0.707106781f) * acctualSize); //downRight
				return resultColor * 0.2f; // /5;
			}
			float4 frag (v2f i) : COLOR
			{
				// Sample and expand the normal map texture
				half4 normal = UnpackNormal(MultiSample5(
					_BumpMap,
					PixelSize(),
					_DiscRadius,
					i.uv2
				));

				// transform normal to world space
				half3 wn;
				wn.x = dot(i.TtoW0, normal.xyz);
				wn.y = dot(i.TtoW1, normal.xyz);
				wn.z = dot(i.TtoW2, normal.xyz);

				//create pointSpaceMatrix from world space normal and position

				// calculate reflection vector in world space
				half3 r = reflect(i.I, wn);

				half lookDirectionDotNormal = dot(normalize(i.I),normalize( wn));

				//glass distortion
				half4 texcol = tex2D(_MainTex, i.uv - normal * lookDirectionDotNormal *_BumpAmt);

				half reflectionAmnt = min(1.0f,max(0.0f, _ReflectionStartVal + lookDirectionDotNormal));

				//half4 c = UNITY_LIGHTMODEL_AMBIENT * texcol;
				//c.rgb *= 2;
				half4 c = _Color * texcol;
				half4 reflcolor = texCUBE(_Cube, r) * _ReflectColor * reflectionAmnt;
				return c + reflcolor;
			}

			ENDCG
		}

	}
	// ------------------------------------------------------------------
	// Fallback for older cards and Unity non-Pro
	SubShader {
		Blend DstColor Zero
		Pass {
			Name "BASE"
			SetTexture [_BumpMap] {	combine texture }
		}
	}

}
}

Leave a Response