Cg Shader with Diffuse+Specular+Normal+Shadow Mapping + Fog

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!
jguerra
Gnoblar
Posts: 21
Joined: Tue Sep 04, 2007 11:45 am
Location: Portugal

Cg Shader with Diffuse+Specular+Normal+Shadow Mapping + Fog

Post by jguerra »

Hello.

I've been working for a while on a generic multi functional cg shader and i've finally finished it. Well... sort of. (More on that later)

This shader includes:
- diffuse, specular and normal mapping (with scale and scroll)
- pixel lighting
- point and spot light attenuation
- spot light effect
- VSM shadows for all kinds of light (except cube mapping for point lights) - based on nullsquared example
- Linear and exponential Fog
- **NEW**Cel-Shading

Has you can see in the following code, i'm using all the 4 channels of the shadow map. I'm doing this because i need to have all the light types casting shadows. So, due to the fact that VSM uses 2 channels to store the depth and depth squared, i use the first two for Spot and Point lights and the last two for Directional lights. I don't know if there is another workaround to this (if you do, please let me know :wink:), but for now i find this solution satisfying.

######## CODE #########
-- Main Shader (newLighting.cg)

Code: Select all

#include "newUtils.cg"

void ambient_vs
(
	float4 iPosition	: POSITION,
	float2 iUV		: TEXCOORD0,
	
	uniform float3 iAmbient,
	uniform float4 iFogParams,
	uniform float4x4 iWorldViewProj,

	out float2 oUV		: TEXCOORD0,
	out float3 oAmbient	: TEXCOORD1,
	out float oFog		: TEXCOORD2,
	out float4 oPosition	: POSITION
) 
{
	oPosition = mul(iWorldViewProj, iPosition);
	oAmbient = iAmbient;
	oUV = iUV;

	oFog = 1;
	if(iFogParams.x==0)
	{
		if(iFogParams.w>0)
			oFog = smoothstep(iFogParams.y, iFogParams.z, iFogParams.z-oPosition.z);
	}
	else
		oFog = exp2(-iFogParams.x*oPosition.z);
}

void ambient_ps
(
	float2 iUV		: TEXCOORD0,
	float3 iAmbient	: TEXCOORD1,
	float iFog		: TEXCOORD2,

	uniform sampler2D dMap	: TEXUNIT0,
	uniform float3 iFogColour,
	uniform float2 iScale,
	uniform float2 iScroll,

	out float4 oColour	: COLOR
)
{
	iUV.x = (iUV.x + iScroll.x)*iScale.x;
	iUV.y = (iUV.y + iScroll.y)*iScale.y;

	float3 diffuse = tex2D(dMap, iUV).rgb;
	oColour = float4(iFog * iAmbient * diffuse + iFogColour*(1-iFog),1);
}

void diffuse_vs
(
	float4 iPosition	: POSITION,
	float4 iNormal	: NORMAL,
	float2 iUV		: TEXCOORD0,

	uniform float4x4 iWorld,
        uniform float4x4 iWorldIT,
	uniform float4x4 iWorldViewProj,
	uniform float4 iFogParams,

#if _SPOTLIGHT
	uniform float4 iSpotDir,
	out float3 oSpotDir	: TEXCOORD3,
#endif

#if _NORMAL
	out float3 oTangent	: TEXCOORD4,
	out float3 oBinormal	: TEXCOORD5,
#endif

#if _SHADOWS
	uniform float4x4 iTextViewProj,
	out float4 oShadowUV	: TEXCOORD6,
#endif

	out float2 oUV		: TEXCOORD0,
	out float4 oWorldPos	: TEXCOORD1,
	out float3 oNormal	: TEXCOORD2,
	out float oFog		: TEXCOORD7,
	out float4 oPosition	: POSITION
)
{
	oWorldPos = mul(iWorld,iPosition);
	oPosition = mul(iWorldViewProj,iPosition);
	oNormal = normalize(mul(iWorldIT, iNormal).xyz);
	oUV = iUV;

#if _SPOTLIGHT
	oSpotDir = mul(iWorld, iSpotDir).xyz;
#endif

#if _NORMAL
	oTangent = normalize(-float3(abs(iNormal.y) + abs(iNormal.z), abs(iNormal.x), 0));
	oBinormal = normalize(cross(oTangent,oNormal));
#endif

#if _SHADOWS
	oShadowUV = mul(iTextViewProj, oWorldPos);
	oShadowUV = oShadowUV / oShadowUV.w;
#endif

	oFog = 1;
	if(iFogParams.x==0)
	{
		if(iFogParams.w>0)
			oFog = smoothstep(iFogParams.y, iFogParams.z, iFogParams.z-oPosition.z);
	}
	else
		oFog = exp2(-iFogParams.x*oPosition.z);
}

void diffuse_ps
(
	float2 iUV		: TEXCOORD0,
	float4 iWorldPos	: TEXCOORD1,
	float3 iNormal	: TEXCOORD2,
	float iFog		: TEXCOORD7,

	uniform float2 iScale,
	uniform float2 iScroll,
	uniform float3 iLightDif,
	uniform float4 iLightPos,
	uniform sampler2D dMap	: TEXUNIT0,

#if _SPOTLIGHT
	float3 iSpotDir		: TEXCOORD3,
	uniform float4 iSpotParams,
#endif

#if !_DIRECTIONAL
	uniform float4 iLightAtt,
	#if _SHADOWS
		uniform float4 iDepthRange,
	#endif
#endif

#if _SPECULAR
	uniform float4 iLightSpec,
	uniform float3 iEyePos,
	uniform float iShininess,
	uniform sampler2D spMap	: TEXUNIT1,
#endif

#if _NORMAL
	uniform sampler2D nMap	: TEXUNIT2,
	float3 iTangent		        : TEXCOORD4,
	float3 iBinormal	                : TEXCOORD5,
#endif

#if _SHADOWS
	uniform float4 iInvShMapSize,
	uniform sampler2D shMap : TEXUNIT3,
	float4 iShadowUV	: TEXCOORD6,
#endif

#if _CELSHADING
	#if !_SPECULAR
		uniform float3 iEyePos,
	#endif
	uniform sampler1D dCelMap	: TEXUNIT4,
	uniform sampler1D sCelMap	: TEXUNIT5,
	uniform sampler1D eCelMap	: TEXUNIT6,
#endif

	out float4 oColour	: COLOR
)
{
	if(iFog == 0)
		discard;

	float3 lightDir = iLightPos.xyz - (iLightPos.w * iWorldPos.xyz);
	float distanceLight = length(lightDir);
	lightDir = normalize(lightDir);

	iUV.x = (iUV.x + iScroll.x)*iScale.x;
	iUV.y = (iUV.y + iScroll.y)*iScale.y;

#if _NORMAL
	float3 normalTex = (tex2D(nMap,iUV).rgb - 0.5)*2;
	iNormal = normalize(normalTex.x * iTangent - normalTex.y * iBinormal + normalTex.z * iNormal);
#endif

	float nDotL = max(dot(lightDir,iNormal),0);
	float4 difTex = tex2D(dMap,iUV);
	if(difTex.a<0.5f)
		discard;

#if _CELSHADING
	// Step functions from textures
	float edge = max(dot(iNormal,normalize(iEyePos - iWorldPos.xyz)),0);
	nDotL = tex1D(dCelMap, nDotL).x;
	edge = tex1D(eCelMap, edge).x;

	#if _SPECULAR
		float4 specTex = tex2D(spMap,iUV);
		float specular = getSpecularContribution(iLightSpec.w,iEyePos,iWorldPos,lightDir,iNormal,nDotL,iShininess);
		specular = tex1D(sCelMap, specular).x;
		float3 light = edge*(difTex.xyz * (iLightDif * nDotL) + (specular * specTex.xyz * iLightSpec.xyz)); 
	#else
		float3 light = edge*(difTex.xyz * (iLightDif * nDotL)); 
	#endif
#else
	float3 light = iLightDif * nDotL * difTex.xyz;

	#if _SPECULAR
		float4 specTex = tex2D(spMap,iUV);
		light += getSpecularContribution(iLightSpec.w,iEyePos,iWorldPos,lightDir,iNormal,nDotL,iShininess) * specTex.xyz * iLightSpec.xyz;
	#endif
#endif

#if !_DIRECTIONAL
	half lightAtt = getLightAttenuation(distanceLight,iLightAtt);
	light *= lightAtt;
#endif 

#if _SPOTLIGHT
	float spot = getSpotlightEffect(lightDir,iSpotDir,iSpotParams);
	light *= spot;
#endif

#if _SHADOWS
	#if !_DIRECTIONAL
	    	float lD = (distanceLight - iDepthRange.x) * iDepthRange.w;
		float2 moments = btex2D_rg(shMap,iShadowUV.xy,iInvShMapSize).rg;
	#else
		float lD = iShadowUV.z;
		float2 moments = btex2D_rg(shMap,iShadowUV.xy,iInvShMapSize).ba;
	#endif
		
	float p = lD<=moments.x?1:0;	
	float variance = moments.y - (moments.x*moments.x);
   	variance = max(variance, 0.001);
	float d = lD - moments.x;
	float p_max = variance / (variance + d*d);
	p_max = max(p,p_max);
	light *= clamp((p_max - 0.6) / (1 - 0.6), 0, 1);
#endif

	light *= iFog;
	oColour = float4(light, 1);
}
-- Utils (newUtils.cg)

Code: Select all

#ifndef _newUtils_cg
#define _newUtils_cg

half getLightAttenuation(float distanceLight, float4 lightAtt)
{
	half att = distanceLight / lightAtt.r;
	att *= att;
	return 1.0 - att;
}

float getSpecularContribution(float lightSpec, float3 eyePos, float4 worldPos, float3 direction, float3 normal, float nDotL, float shininess)
{
	float3 viewVector = normalize(eyePos - worldPos.xyz);
	float3 half = normalize(direction + viewVector);
	float nDotH = dot(normal, half);
#if _CELSHADING
	return pow(max(nDotH,0), lightSpec * shininess);
#else
	return lit(nDotL, nDotH, lightSpec * shininess).z;
#endif
}

float getSpotlightEffect(float3 ld0, float3 spotDir, float4 spotParams)
{
	float spot = dot(ld0, normalize(-spotDir));
	spot = saturate((spot - spotParams.y) / (spotParams.x - spotParams.y));
	return spot;
}

float4 btex2D_rg(sampler2D shadowMap, float2 uv, float offset)
{	
    float4 c = tex2D(shadowMap, uv.xy); // center
    c += tex2D(shadowMap, uv.xy - offset); // top left
    c += tex2D(shadowMap, uv.xy + offset); // bottom right
    c += tex2D(shadowMap, float2(uv.x - offset, uv.y)); // left
    c += tex2D(shadowMap, float2(uv.x + offset, uv.y)); // right
    c += tex2D(shadowMap, float2(uv.x, uv.y + offset)); // bottom
    c += tex2D(shadowMap, float2(uv.x, uv.y - offset)); // top
    c += tex2D(shadowMap, float2(uv.x - offset, uv.y + offset)); // bottom left
    c += tex2D(shadowMap, float2(uv.x + offset, uv.y - offset)); // top right
    return c / 9;
}
#endif
-- Program

Code: Select all

vertex_program ambient_vs cg
{
    source newLighting.cg
    profiles vs_1_1 arbvp1
    entry_point ambient_vs

    default_params
    {
        param_named_auto iAmbient ambient_light_colour
        param_named_auto iWorldViewProj worldviewproj_matrix
	param_named_auto iFogParams fog_params
    }
}

fragment_program ambient_ps cg
{
    source newLighting.cg
    profiles ps_2_0 arbfp1
    entry_point ambient_ps

    default_params
    {
	param_named_auto iFogColour fog_colour
    }
}

vertex_program diffuse_directional_normal_shadow_vs cg
{
	source newLighting.cg
	profiles vs_1_1 arbvp1
	entry_point diffuse_vs

	compile_arguments -D_DIRECTIONAL=1 -D_POINT=0 -D_SPOTLIGHT=0 -D_SPECULAR=0 -D_NORMAL=1 -D_SHADOWS=1

	default_params
	{
		param_named_auto iWorld world_matrix
  	        param_named_auto iWorldIT inverse_transpose_world_matrix
		param_named_auto iWorldViewProj worldviewproj_matrix
		param_named_auto iTextViewProj texture_viewproj_matrix
		param_named_auto iFogParams fog_params
	}
}

vertex_program diffuse_point_normal_shadow_vs cg
{
	source newLighting.cg
	profiles vs_1_1 arbvp1
	entry_point diffuse_vs

	compile_arguments -D_DIRECTIONAL=0 -D_POINT=1 -D_SPOTLIGHT=0 -D_SPECULAR=0 -D_NORMAL=1 -D_SHADOWS=1
 
	default_params
	{
		param_named_auto iWorld world_matrix
  	        param_named_auto iWorldIT inverse_transpose_world_matrix
		param_named_auto iWorldViewProj worldviewproj_matrix
		param_named_auto iTextViewProj texture_viewproj_matrix
		param_named_auto iFogParams fog_params
	}
}

vertex_program diffuse_spot_normal_shadow_vs cg
{
	source newLighting.cg
	profiles vs_1_1 arbvp1
	entry_point diffuse_vs

	compile_arguments -D_DIRECTIONAL=0 -D_POINT=0 -D_SPOTLIGHT=1 -D_SPECULAR=0 -D_NORMAL=1 -D_SHADOWS=1

	default_params
	{
		param_named_auto iWorld world_matrix
  	        param_named_auto iWorldIT inverse_transpose_world_matrix
		param_named_auto iWorldViewProj worldviewproj_matrix
		param_named_auto iTextViewProj texture_viewproj_matrix
		param_named_auto iSpotDir light_direction_object_space 0
		param_named_auto iFogParams fog_params
	}
}

fragment_program diffuse_directional_specular_normal_shadow_ps cg
{
	source newLighting.cg
	profiles ps_2_x arbfp1
	entry_point diffuse_ps

	compile_arguments -D_DIRECTIONAL=1 -D_POINT=0 -D_SPOTLIGHT=0 -D_SPECULAR=1 -D_NORMAL=1 -D_SHADOWS=1

	default_params
	{
		param_named_auto iLightPos light_position 0
		param_named_auto iLightDif light_diffuse_colour 0
		param_named_auto iLightSpec light_specular_colour 0
		param_named_auto iEyePos camera_position
		param_named_auto iInvShMapSize inverse_texture_size 3
	}
}

fragment_program diffuse_point_specular_normal_shadow_ps cg
{
	source newLighting.cg
	profiles ps_2_x arbfp1
	entry_point diffuse_ps

	compile_arguments -D_DIRECTIONAL=0 -D_POINT=1 -D_SPOTLIGHT=0 -D_SPECULAR=1 -D_NORMAL=1 -D_SHADOWS=1

	default_params
	{
		param_named_auto iLightPos light_position 0
		param_named_auto iLightDif light_diffuse_colour 0
		param_named_auto iLightSpec light_specular_colour 0
		param_named_auto iLightAtt light_attenuation 0
		param_named_auto iEyePos camera_position
	        param_named_auto iDepthRange shadow_scene_depth_range 0
		param_named_auto iInvShMapSize inverse_texture_size 3
	}
}

fragment_program diffuse_spot_specular_normal_shadow_ps cg
{
	source newLighting.cg
	profiles ps_2_x arbfp1
	entry_point diffuse_ps

	compile_arguments -D_DIRECTIONAL=0 -D_POINT=0 -D_SPOTLIGHT=1 -D_SPECULAR=1 -D_NORMAL=1 -D_SHADOWS=1

	default_params
	{
		param_named_auto iLightPos light_position 0
		param_named_auto iLightDif light_diffuse_colour 0
		param_named_auto iLightSpec light_specular_colour 0
		param_named_auto iLightAtt light_attenuation 0
		param_named_auto iSpotParams spotlight_params 0
		param_named_auto iEyePos camera_position
	        param_named_auto iDepthRange shadow_scene_depth_range 0
		param_named_auto iInvShMapSize inverse_texture_size 3
	}
}

fragment_program diffuse_directional_specular_celshading_shadow_ps cg
{
	source newLighting.cg
	profiles ps_2_x arbfp1
	entry_point diffuse_ps

	compile_arguments -D_DIRECTIONAL=1 -D_POINT=0 -D_SPOTLIGHT=0 -D_SPECULAR=1 -D_NORMAL=0 -D_CELSHADING=1 -D_SHADOWS=1

	default_params
	{
		param_named_auto iLightPos light_position 0
		param_named_auto iLightDif light_diffuse_colour 0
		param_named_auto iLightSpec light_specular_colour 0
		param_named_auto iEyePos camera_position
		param_named_auto iInvShMapSize inverse_texture_size 3
	}
}

fragment_program diffuse_point_specular_celshading_shadow_ps cg
{
	source newLighting.cg
	profiles ps_2_x arbfp1
	entry_point diffuse_ps

	compile_arguments -D_DIRECTIONAL=0 -D_POINT=1 -D_SPOTLIGHT=0 -D_SPECULAR=1 -D_NORMAL=0 -D_CELSHADING=1 -D_SHADOWS=1

	default_params
	{
		param_named_auto iLightPos light_position 0
		param_named_auto iLightDif light_diffuse_colour 0
		param_named_auto iLightSpec light_specular_colour 0
		param_named_auto iLightAtt light_attenuation 0
		param_named_auto iEyePos camera_position
	        param_named_auto iDepthRange shadow_scene_depth_range 0
		param_named_auto iInvShMapSize inverse_texture_size 3
	}
}

fragment_program diffuse_spot_specular_celshading_shadow_ps cg
{
	source newLighting.cg
	profiles ps_2_x arbfp1
	entry_point diffuse_ps

	compile_arguments -D_DIRECTIONAL=0 -D_POINT=0 -D_SPOTLIGHT=1 -D_SPECULAR=1 -D_NORMAL=0 -D_CELSHADING=1 -D_SHADOWS=1

	default_params
	{
		param_named_auto iLightPos light_position 0
		param_named_auto iLightDif light_diffuse_colour 0
		param_named_auto iLightSpec light_specular_colour 0
		param_named_auto iLightAtt light_attenuation 0
		param_named_auto iSpotParams spotlight_params 0
		param_named_auto iEyePos camera_position
	        param_named_auto iDepthRange shadow_scene_depth_range 0
		param_named_auto iInvShMapSize inverse_texture_size 3
	}
}
-- Material

Code: Select all

material newLighting
{
	technique
	{
		pass Ambient
		{
			ambient  1 1 1
			diffuse  0 0 0
			specular 0 0 0 0
			emissive 0 0 0

			vertex_program_ref ambient_vs
			{
			}

			fragment_program_ref ambient_ps
			{
				param_named iScale float2 1 1
				param_named iScroll float2 0 0
			}

			texture_unit
			{
				texture diffuse.png
			}
		}

		pass Directional
		{
			ambient  0 0 0
			diffuse  1 1 1
			specular 1 1 1 255

			max_lights 8
			scene_blend add
			iteration once_per_light directional

			vertex_program_ref diffuse_directional_shadow_vs
			{
			}

			fragment_program_ref diffuse_directional_specular_celshading_shadow_ps
			{
				param_named iScale float2 1 1
				param_named iScroll float2 0 0
                                param_named iShininess float 128
			}

			texture_unit
			{
				texture diffuse.png
			}

			texture_unit
			{
				texture specular.png
			}

			texture_unit
			{
				texture normal.png
			}

			texture_unit
			{
				content_type shadow
				tex_address_mode clamp
			}

			texture_unit
			{
				texture cel_diff.png 1d
				tex_address_mode clamp
				filtering point point none
			}

			texture_unit
			{
				texture cel_spec.png 1d
				tex_address_mode clamp
				filtering point point none
			}

			texture_unit
			{
				texture cel_edge.png 1d
				tex_address_mode clamp
				filtering point point none
			}
		}

		pass Point
		{
			ambient  0 0 0
			diffuse  1 1 1
			specular 1 1 1 255

			max_lights 8
			scene_blend add
			iteration once_per_light point

			vertex_program_ref diffuse_point_shadow_vs
			{
			}

			fragment_program_ref diffuse_point_specular_celshading_shadow_ps
			{
				param_named iScale float2 1 1
				param_named iScroll float2 0 0
                                param_named iShininess float 128
			}

			texture_unit
			{
				texture diffuse.png
			}

			texture_unit
			{
				texture specular.png
			}

			texture_unit
			{
				texture normal.png
			}

			texture_unit
			{
				content_type shadow
				tex_address_mode clamp
			}

			texture_unit
			{
				texture cel_diff.png 1d
				tex_address_mode clamp
				filtering point point none
			}

			texture_unit
			{
				texture cel_spec.png 1d
				tex_address_mode clamp
				filtering point point none
			}

			texture_unit
			{
				texture cel_edge.png 1d
				tex_address_mode clamp
				filtering point point none
			}
		}

		pass Spot
		{
			ambient  0 0 0
			diffuse  1 1 1
			specular 1 1 1 255

			max_lights 8
			scene_blend add
			iteration once_per_light spot

			vertex_program_ref diffuse_spot_shadow_vs
			{
			}

			fragment_program_ref diffuse_spot_specular_celshading_shadow_ps
			{
				param_named iScale float2 1 1
				param_named iScroll float2 0 0
                                param_named iShininess float 128
			}

			texture_unit
			{
				texture diffuse.png
			}

			texture_unit
			{
				texture specular.png
			}

			texture_unit
			{
				texture normal.png
			}

			texture_unit
			{
				content_type shadow
				tex_address_mode clamp
			}

			texture_unit
			{
				texture cel_diff.png 1d
				tex_address_mode clamp
				filtering point point none
			}

			texture_unit
			{
				texture cel_spec.png 1d
				tex_address_mode clamp
				filtering point point none
			}

			texture_unit
			{
				texture cel_edge.png 1d
				tex_address_mode clamp
				filtering point point none
			}
		}
	}
}
--Shadow Caster Shader (vsmCaster.cg)

Code: Select all

void shadow_caster_vs
(
	float4 iPosition	: POSITION,
	float2 iUV		: TEXCOORD0,


	uniform float4x4 iWorldView,
	uniform float4x4 iWorldViewProj,

	out float4 oPosition	: POSITION,
	out float2 oUV		: TEXCOORD0,
	out float4 oDepth	: TEXCOORD1,
	out float4 oDepthDir	: TEXCOORD2

)

{

	oDepth = mul(iWorldView, iPosition);
	oDepthDir = mul(iWorldViewProj, iPosition);

	oPosition = oDepthDir;

	oUV = iUV;

}



void shadow_caster_ps
(
	float2 iUV		: TEXCOORD0,
	float4 iDepth		: TEXCOORD1,
	float4 iDepthDir	: TEXCOORD2,

	uniform sampler2D dTex	: TEXUNIT0,

	uniform float4 iDepthRange,
	uniform float iAlphaReject,

	out float4 oColour	: COLOR
)

{
	if(tex2D(dTex,iUV).a < iAlphaReject)
		discard;	

	float d = (length(iDepth.xyz) - iDepthRange.x) * iDepthRange.w;

	oColour = float4(d, d * d, iDepthDir.z, iDepthDir.z*iDepthDir.z);

}
-- Shadow Caster Program

Code: Select all

vertex_program shadow_caster_vs cg
{
    source vsmCaster.cg
    profiles vs_1_1 arbvp1
    entry_point shadow_caster_vs

    default_params
    {
        param_named_auto iWorldView worldview_matrix
	param_named_auto iWorldViewProj worldviewproj_matrix
    }
}

fragment_program shadow_caster_ps cg
{
    source vsmCaster.cg
    profiles ps_2_0 arbfp1
    entry_point shadow_caster_ps

    default_params
    {
        param_named_auto iDepthRange scene_depth_range
    }
}
-- Shadow Caster Material

Code: Select all

material shadowCaster
{	
	technique
	{
		pass
		{
			vertex_program_ref shadow_caster_vs
			{
			}

			fragment_program_ref shadow_caster_ps
			{
				param_named iAlphaReject float 0.5
			}

			texture_unit
			{
				texture diffuse.png
			}
        	}
	}
}
############### SCREENSHOTS ############
Directional light with linear fog:
Image
Point light:
Image
Spot light:
Image
Several spot lights:
Image
Cel-Shading:
Image

############### ISSUES ###############
- Point + Spot lights
For some reason if i have a spot light between the lighted area and a point light, the lighting done by the point light is ignored has shown in the images below.

Point light:
Image

Spot light:
Image

Another issue is the light limit that is visible in the point light screenshot shouldn't be there. The range is big enough to light the whole scenario.
This is because of the way the depth is calculated. Specifically, this line:

Code: Select all

float d = (length(iDepth.xyz) - iDepthRange.x) * iDepthRange.w

I don't know how to avoid this. Any help would be appreciated.

- I have to use FocusedShadowCamera or the shadowing doesn't work correctly. Don't know why this is....

Bare in mind that this isn't the most efficient way to achieve the result you might want for a specific scenario. But i think it does a good job in illustrating all the available options.
Any suggestions to improve/optimize the code or to correct any problem you might find is highly appreciated.

If you would like a more detail explanation of the code, i'll be glad to had some comments.

**EDIT** Added support to cel-shading. Has you can see on the .program i disabled normal mapping when using cel-shading because the effect is just ugly and weird. But you can try it out. You just have to enable the compile flag _NORMAL. Also in the .material i added three 1D textures that basically define the way the shading looks like (you can get these images from the Ogre Cel-Shading sample).
Also the shininess value was moved to be a parameter instead of being hard-coded.

22/09 Added support for alpha-rejected transparency in shadows. For this to work you'll have to set the shadow caster material in the techniques of the passes that use alpha rejection. You will also have to change the texture of the shadow caster material to the diffuse texture of the corresponding model.
Note: I've been testing this quite extensively and found several small issues. When i'm finished, i'll post the final shader.

Thank you.
JGuerra

PS: If you'd rather have the code in attachments let me know.
Last edited by jguerra on Tue Sep 22, 2009 4:07 pm, edited 7 times in total.
User avatar
DominuZ
Gnoblar
Posts: 14
Joined: Tue Oct 09, 2007 3:31 am
Location: London
Contact:

Re: Cg Shader with Diffuse+Specular+Normal+Shadow Mapping + Fog

Post by DominuZ »

Very good jguerra, It will realy be a lot useful.
Last edited by DominuZ on Wed Sep 09, 2009 12:26 am, edited 1 time in total.
There is no Limit for those who don't understand Calculus.
User avatar
Xplodwild
Goblin
Posts: 231
Joined: Thu Feb 12, 2009 3:49 pm
Location: France
x 13
Contact:

Re: Cg Shader with Diffuse+Specular+Normal+Shadow Mapping + Fog

Post by Xplodwild »

I don't know much about shaders, but this is really interesting. I've ran different NM shaders, but no one worked the same way on ATi cards and NVidia cards (most of the time they didn't work on ATi cards). I'll try it during the next days on both, and if it works, I'll be glad to include it definetly in my game.
jguerra
Gnoblar
Posts: 21
Joined: Tue Sep 04, 2007 11:45 am
Location: Portugal

Re: Cg Shader with Diffuse+Specular+Normal+Shadow Mapping + Fog

Post by jguerra »

Thank you both for the feedback. :)

I've only tested this on a Nvidia GForce 8600M. When you test it let me know what were the results.
If there is any problem i can easily get my hands on an ATI card to try and correct them.
koso
Kobold
Posts: 26
Joined: Mon May 18, 2009 6:30 pm

Re: Cg Shader with Diffuse+Specular+Normal+Shadow Mapping + Fog

Post by koso »

i tryed your shader and results were GREAT.I really like it.i've been searching for shader like yours, looong time.I must try your shader more depth but it seems like very good.
GREAT JOB :wink: :D
koso
User avatar
suny2000
Halfling
Posts: 72
Joined: Sun Sep 06, 2009 12:36 pm
x 12
Contact:

Re: Cg Shader with Diffuse+Specular+Normal+Shadow Mapping + Fog

Post by suny2000 »

Thanks a lot for your work!

I have a question: how could I modify the shaders to project shadows using the alpha of certain objects?
The idea is to display trees and I need to project shadows from the leaves.
I reckon the idea would be to use alphatested textures for this, but what I don't know is a way to use one shadow_caster shader for most of the objects, and one shadow_caster_with_alpha for all the objects using alpha.
Does anyone knows how to do this?

S.
http://bulostudio.com: website and devlog of a small indie studio working on SHMUP CREATOR
https://twitter.com/bulostudio : follow me on twitter!
jguerra
Gnoblar
Posts: 21
Joined: Tue Sep 04, 2007 11:45 am
Location: Portugal

Re: Cg Shader with Diffuse+Specular+Normal+Shadow Mapping + Fog

Post by jguerra »

That's pretty easy to accomplish. And i meant to do that but forgot.... :oops:
Thanks for reminding me. I will add it tomorrow.

In the shadow caster you just have to test the alpha channel of the caster's texture.
Define a threshold and check if the value is below.
If it is just call 'discard'.
User avatar
Sundown
Gnoblar
Posts: 24
Joined: Fri Jun 15, 2007 3:32 pm

Re: Cg Shader with Diffuse+Specular+Normal+Shadow Mapping + Fog

Post by Sundown »

This is exactly what I've been looking for - excellent work!

I'm experiencing a few problems though - I've got the diffuse, specular and normal maps working, but I'm having problems getting the shadows to display properly (they dissapear/glitch depending on the camera's position/angle).
I have to use FocusedShadowCamera or the shadowing doesn't work correctly. Don't know why this is....
I'm using a focused shadow camera like this, called inside CreateScene():

Code: Select all

ShadowCameraSetupPtr mCurrentShadowCameraSetup = ShadowCameraSetupPtr(new FocusedShadowCameraSetup());
	mSceneMgr->setShadowCameraSetup(mCurrentShadowCameraSetup);
Is that all that's needed? Doesn't seem to make a difference if active or not...
jguerra
Gnoblar
Posts: 21
Joined: Tue Sep 04, 2007 11:45 am
Location: Portugal

Re: Cg Shader with Diffuse+Specular+Normal+Shadow Mapping + Fog

Post by jguerra »

@suny2000
It seems that adding a texture to a shadow caster is more tricky than i thought.... I've managed getting it to work with a simple material, by doing exactly what i told in the previous post. But it seems that the shadow caster doesn't know which texture_unit to use in a more complex material.... I'll try to figure this out in the next couple of days...

@Sundown
What kind of lights are you using?
And what kind of scenario? Are you using a terrain? If you do, you have to take into account LOD because of Z-Fighting. If that is the problem, just add this line to the begining of the vertex shaders.

Code: Select all

iPosition.y = iPosition.y + (delta.x * morphFactor);
where delta is

Code: Select all

float delta  	: BLENDWEIGHT
and morphFactor is a constant


I'm still learning all the ropes that hang around shaders and materials... Figuring things out as i go. So if someone wants to lend a hand, i'll be more than glad. :)
User avatar
Xplodwild
Goblin
Posts: 231
Joined: Thu Feb 12, 2009 3:49 pm
Location: France
x 13
Contact:

Re: Cg Shader with Diffuse+Specular+Normal+Shadow Mapping + Fog

Post by Xplodwild »

I've started using this shader since a few hours, and it seems to work well, except lighting stays in the same direction regardless the rotation of the object (so shaded parts stays darker, even when they are in front of sun). What's the problem?
jguerra
Gnoblar
Posts: 21
Joined: Tue Sep 04, 2007 11:45 am
Location: Portugal

Re: Cg Shader with Diffuse+Specular+Normal+Shadow Mapping + Fog

Post by jguerra »

You're absolutely right!!! :shock:

I didn't realize that... In my test app i didn't have any rotated objects.

I've edited the first post. It's corrected now.
Tuftux
Gnoblar
Posts: 20
Joined: Mon Aug 04, 2008 9:19 pm

Re: Cg Shader with Diffuse+Specular+Normal+Shadow Mapping + Fog

Post by Tuftux »

Hey guy !
What a nice shader :D And working on ATi, wow !
But I've just noticed that specular don't move with camera orientation :( Can you fix this ?
jguerra
Gnoblar
Posts: 21
Joined: Tue Sep 04, 2007 11:45 am
Location: Portugal

Re: Cg Shader with Diffuse+Specular+Normal+Shadow Mapping + Fog

Post by jguerra »

Hello Tuftux.
Thank you for trying the shader and for pointing out that error.

I've corrected the problem (edited in 1st post).
The problem was that i was using camera_position_object_space instead of just camera_position and was adding it to the worldPos instead of subtracting it.
rubasurex
Gnoblar
Posts: 15
Joined: Mon Aug 25, 2008 4:08 pm

Re: Cg Shader with Diffuse+Specular+Normal+Shadow Mapping + Fog

Post by rubasurex »

Nice work! Looks really good. Don't suppose you have a demo (with source) to see it in action?

What is the performance like? Got any figures?
jguerra
Gnoblar
Posts: 21
Joined: Tue Sep 04, 2007 11:45 am
Location: Portugal

Re: Cg Shader with Diffuse+Specular+Normal+Shadow Mapping + Fog

Post by jguerra »

No, i don't have a demo available. But it's quite easy to try it out in any application. Just add those files to the resources and use the material on your objects.

I also don't have any precise fps readings.
But with the scenario you see in the screenshots (25 ogre heads in a plane - around 300.000 triangles) with 2 lights casting shadows in a NVidia GForce 8600M using OpenGL in Gentoo Linux, i had something near 60fps.
User avatar
Mattan Furst
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 260
Joined: Tue Jan 01, 2008 11:28 am
Location: Israel
x 32

Re: Cg Shader with Diffuse+Specular+Normal+Shadow Mapping + Fog

Post by Mattan Furst »

Here is a link you might be interested in: Real Time Shader System Component

It talk's about a new shader generator system which can replace and extend the fixed pipeline. The system can take any material technique (which doesn't already have a shader) and replace it with a technique which is rendered with a shader which emulates the fixed pipeline functions.

All the fixed pipe-line features are already implemented i.e: ambient+diffuse+specular calculations, texture passes, per vertex dynamic lights, fog, environment mapping, etc...
As well as some extensions such as: per pixel dynamic lights and (single pass) texture shadow, with more extensions to come.
it's turtles all the way down
jguerra
Gnoblar
Posts: 21
Joined: Tue Sep 04, 2007 11:45 am
Location: Portugal

Re: Cg Shader with Diffuse+Specular+Normal+Shadow Mapping + Fog

Post by jguerra »

Hello all.

I've added cel-shading support to the shader. If you don't want specular mapping with cel-shading but still want the specular light to have an effect. Instead of disabling the compile flag _SPECULAR (because this will remove ALL specular lighting) you'll have to remove this line:

Code: Select all

float4 specTex = tex2D(spMap,iUV);
And all the occurrences of 'specTex' and 'spMap';

@Mattan Furst
That looks like it might be really useful. I'm going to stay tuned for that. Thanks for posting it.
dcardwell
Gnoblar
Posts: 3
Joined: Fri Aug 28, 2009 3:00 am

Re: Cg Shader with Diffuse+Specular+Normal+Shadow Mapping + Fog

Post by dcardwell »

I tried to implement this and once I got it working I noticed there weren't any shadows. I found that the "shadow_caster_vs" and "shadow_caster_ps" programs are not referenced in the current material file. Do I need to add something into the material file to get shadows working? If so, what do I need to add?
jguerra
Gnoblar
Posts: 21
Joined: Tue Sep 04, 2007 11:45 am
Location: Portugal

Re: Cg Shader with Diffuse+Specular+Normal+Shadow Mapping + Fog

Post by jguerra »

You just need to create a material script like this one:

Code: Select all

material vsmCaster
{	
    technique
    {
        pass
        {
            vertex_program_ref shadow_caster_vs
            {
            }
            fragment_program_ref shadow_caster_ps
            {
            }
        }
    }
}
And call setShadowTextureCasterMaterial on the Scene Manager.
User avatar
suny2000
Halfling
Posts: 72
Joined: Sun Sep 06, 2009 12:36 pm
x 12
Contact:

Re: Cg Shader with Diffuse+Specular+Normal+Shadow Mapping + Fog

Post by suny2000 »

Hi Jguerra,

I found some informations about shadows from transparent objects:
http://www.ogre3d.org/forums/viewtopic. ... 7&start=25

Seems that there is some functions permiting to do this on Ogre3D since a few months ago.
Hope that helps.

S.
http://bulostudio.com: website and devlog of a small indie studio working on SHMUP CREATOR
https://twitter.com/bulostudio : follow me on twitter!
User avatar
PJani
Gremlin
Posts: 171
Joined: Wed Dec 24, 2008 7:21 pm

Re: Cg Shader with Diffuse+Specular+Normal+Shadow Mapping + Fog

Post by PJani »

had any one tested this on ati card? Before i start loosing my nerves... :D

Looks great, beautiful. keep doing, good work... :!:
| Intel Dual Core 1.8Ghz, ATI Radeon Mobility X1600 256MB, 2GB RAM |
| AMD64 3000+ 1.8Ghz, 2GB RAM, GF6600 GT 128MB |
| Ogre 1.6.4 | VS C++ EE | OgreNewt + Newton 2.xx |
| Win XP || Ubuntu 9.04 | C/C++, Python, VB6, Delphi |
User avatar
waynhim
Kobold
Posts: 25
Joined: Wed Mar 18, 2009 3:12 pm

Re: Cg Shader with Diffuse+Specular+Normal+Shadow Mapping + Fog

Post by waynhim »

I'm having problems with the shadow casting at the moment, by outputing values as colours I've managed to narrow the problem down the the iTextViewProj. No matter what I multiply this matrix with it always returns a value of (0,0,0,0) or so I think, it's hard to pin it down by changing the colours though. Any ideas why this might be happening. I've checked against the code on here in case I'd made any accidental slip-ups with the code in removing the fog (my current project doesn't require fog) and found that the value is still in the program file in the same way, so that's not the problem.
jguerra
Gnoblar
Posts: 21
Joined: Tue Sep 04, 2007 11:45 am
Location: Portugal

Re: Cg Shader with Diffuse+Specular+Normal+Shadow Mapping + Fog

Post by jguerra »

@suny2000
I've been able to finally add the alpha rejection to the shadow casting. I've updated the first post. Try it out. :)

@PJani
I haven't tested this on ATI cards, but Tuftux and Xplodwild seem to have it working correctly on ATI cards.

@waynhim
What kind of lights are you using? If you're using directional, try spotlights. And let me know what happens.
I've recently moved this shader from my test application to my project and i'm having some problems with the shadow casting of the directional lights.
If you can give me more information about how you're using the shaders maybe i can help you (and you help me). I have no idea what's happening by reading you're post.


I would also like to thank you all for trying this out and help me test it. Keep me posted (with the good and the bad). :D
User avatar
suny2000
Halfling
Posts: 72
Joined: Sun Sep 06, 2009 12:36 pm
x 12
Contact:

Re: Cg Shader with Diffuse+Specular+Normal+Shadow Mapping + Fog

Post by suny2000 »

Thanks a lot !
The alpha rejection works perfectly.

S.
http://bulostudio.com: website and devlog of a small indie studio working on SHMUP CREATOR
https://twitter.com/bulostudio : follow me on twitter!
Akinz
Gnoblar
Posts: 12
Joined: Thu Oct 23, 2008 12:59 am
Contact:

Re: Cg Shader with Diffuse+Specular+Normal+Shadow Mapping + Fog

Post by Akinz »

Hey jguerra,

I'm new to using shaders and I'm trying to plug yours into my project.

First, I noticed that your vertex/fragment program names in the newLighting material file from the original post don't match up with the names in the program file. Maybe you changed them in one file but not the other? The vertex programs with names like "diffuse_directional_shadow_vs" need to be renamed to "diffuse_directional_normal_shadow_vs", etc.

Second, a few images are referenced (diffuse.png, specular.png, normal.png, etc.) but these are not included? Am I supposed to create my own images for these files?

Sorry if these questions are dumb! Thanks for any help!

EDIT: I was also wondering if you could give me some help making a basic material file that uses the shader. I set the shadowCaster material in my Ogre SceneManager, but I don't see anything changed (maybe because I'm missing the images), do I also need to add another material to my game objects to get it to show? What would be an example of a material file to use on one of the monsters/buildings in my game?
Stormsong Games Developer
Post Reply