Jump to content

decaying the shadow with distance


kensonuken

Recommended Posts

http://img218.imageshack.us/img218/4839/at...edshadowqx5.png

Inspired by this http://www.studioinverse.com/3db-site/html...ow.php#occluder

but want to get a very simple approach...

I tried to decaying the shadow with distance with the following code...

it works fine but its getting transparent in the beginning stage of shadow start...

len = lenght(L);
float start_shadow = 5;
float end_shadow = 40;
if( len > end_shadow )
	shadowatten = 0; /* no more shadow after 40 */
else if( len < start_shadow )
	shadowatten = 1; /* full shadowing before 5 */
else
{
	/* simple linear interpolation. You can add the decay here too. */
	shadowatten = 1 - (len - start_shadow) / (end_shadow-start_shadow);
}

Edited by Jason
please use [code] [/code] tags
Link to comment
Share on other sites

lerp of shadowatten ?

is it this?

len = lenght(L);
float start_shadow = 5;
float end_shadow = 40;
if( len > end_shadow )
	shadowatten = 0; /* no more shadow after 40 */
else if( len < start_shadow )
	shadowatten = 1; /* full shadowing before 5 */
else
{
	/* simple linear interpolation. You can add the decay here too. */
	shadowatten = 1 - (len - start_shadow) / (end_shadow-start_shadow);
shadowat = clamp ( shadowatten, 0, 1);
}

Edited by kensonuken
Added [code][/code] tags
Link to comment
Share on other sites

hi jason is there anyway that I can use this shader?

// light shader that explores a strategy for soft shadows
// Bertrand Bry-Marfaing
// www.3db-site.com
// Mai 2008

light
softShadowSpot(	float intensity = 1;
				color lightColor = 1;
				float coneAngle = 35; // in degrees
				float penumbraAngle = 5; // outside the coneAngle
				string shadowMap = "";
				float samples = 64;
				float shadowBias = 0.01;
				float minRadius = 0.001;
				float maxRadius = 0.1;
				float biasConeSlope = 2;
				float shadowDecay = 0; // shadow decreases with occluder distance
				float shadDecayDistMin = 10; 
				float shadDecayDistMax = 25;)
{

	uniform float illumAngle = radians( coneAngle/2 + penumbraAngle );
	uniform float cosoutside = cos( illumAngle );
	uniform float cosinside = cos( radians( coneAngle/2 )  );
	uniform vector lightDir = vector "shader" ( 0,0,1 );


	/*
	_______ generate a series of random coordinates ______
			(implementation of Hammersley point set)
	*/
	uniform float sampleCoordX[ samples ];
	uniform float sampleCoordY[ samples ];
	// note: init of variable size array (although uniform variable in this case) does not compile with prman.
	uniform float iter = 0;

	// find the num of decimals
	uniform float numOfDigits = ceil( log( samples, 2 ) );
	uniform float revBinValues[ numOfDigits ];

	for( iter = 0; iter < samples; iter += 1 )
	{

		// generate binary fractions and their reversed
		uniform float digit = 0;
		uniform float remainder = iter;
		for( digit = (numOfDigits - 1); digit >= 0; digit -= 1 )
		{
			uniform float power = pow( 2, digit );
			if ( remainder >= power  )
			{
				revBinValues[ digit ] = 1;
				remainder -= power;
			}
			else
				revBinValues[ digit ] = 0;

		}

		// convert back to floats
		uniform float x = 0;
		uniform float y = 0;
		uniform float index = 0;
		for( index = 1; index <=  numOfDigits; index += 1 )
		{
			x += ( pow( 2, -index ) * revBinValues[ numOfDigits-index ] );
			y += ( pow( 2, -index ) * revBinValues[ index-1 ] );
		}

		// scale x to compensate for the non-power-of-two sample numbers
		x *= pow( 2, numOfDigits ) / samples ;

		// store coordinates
		sampleCoordX[ iter ] = x;
		sampleCoordY[ iter ] = y;
	}
	// ___________________________________




	/* 
		Function that interprets the previously generated x,y coordinates
		as angle and radius, and retruns the new coordinates.

		Output samples may be denser around 0,0 (for averaging occluder depth)
		or evenly spread (for shadowing sampling )
	*/
	float randomNumber = float random();
	void HammersleyToRadial( float shadowSampling; output float sampleCoordX; output float sampleCoordY )
	{

		;
		// if these samples are for light shadowing sampling
		if ( shadowSampling == 1 ){
			// samples should be evenly distributed
			sampleCoordY = sqrt( sampleCoordY );

			// vary the samples positions per shaded point
			extern float randomNumber;
			sampleCoordX = mod( sampleCoordX + randomNumber, 1 );
		} 

		float angleOfSample = sampleCoordX * 2 * PI;
		sampleCoordX = cos( angleOfSample ) * sampleCoordY; // cos = adj / hypot
		sampleCoordY = sqrt( pow( sampleCoordY, 2 ) - pow( sampleCoordX, 2 ) ); // a2 + b2 = c2 
		if( angleOfSample > PI )
			sampleCoordY *= -1;
	}
	// ___________________________________




	/*
		Function that samples the shadow map,
		returns sampled depth and normalised raster distance of sample
	*/
	float sampleShadowMap( float pShadS; float pShadT; float sampleX; float sampleY; float radius; float uniformSampling; output float distFromPs )
	{
		extern string shadowMap;

		// sample coord
		float ss = sampleX;
		float tt = sampleY;
		HammersleyToRadial( uniformSampling, ss, tt );
		ss *= radius;
		tt *= radius;
		ss += pShadS;
		tt += pShadT;

		// find distance from Ps coord
		distFromPs = distance( point( pShadS, pShadT, 0), point( ss, tt, 0 ) );

		// sample map without filtering
		return texture( shadowMap, ss, tt, "width", 0.00001 , "samples", 1 ); // this will generate warnings at compilation time with 3Delight
	}
	// ___________________________________





	illuminate( point "shader" ( 0,0,0 ), lightDir, illumAngle )
	{
		Cl = 0;
		float cosangle = normalize( L ).lightDir;
		float atten = smoothstep( cosoutside, cosinside, cosangle );
		float shadowValue = 0;


		if ( shadowMap != "" )
		{
			/*
			_____ Compute soft shadow _____

			*/


			// get the s and t coord of Ps on shadowmap
			float pShadS, pShadT;
			uniform matrix shadProjSpace;
			textureinfo( shadowMap, "projectionmatrix", shadProjSpace );
			point shadProjP = transform( shadProjSpace, Ps );
			pShadS = ( 1 + xcomp( shadProjP ) ) * 0.5;
			pShadT = ( 1 - ycomp( shadProjP ) ) * 0.5; 



			// get Ps distance from shadow plane
			uniform matrix shadCamSpace;
			textureinfo(  shadowMap, "viewingmatrix", shadCamSpace );
			point shadCamP = transform( shadCamSpace, Ps );
			float PsDepth = zcomp( shadCamP );



			// get the average occluder depth in shadowmap around Ps
			float avrgedDepth = 0;
			float totalWeight = 0;
			float iterator = 0;
			for ( iterator = 0; iterator < samples; iterator += 1 )
			{
				float sampleDepth, distFromPs;
				sampleDepth = sampleShadowMap( pShadS, pShadT, sampleCoordX[ iterator ], sampleCoordY[ iterator ], maxRadius, 0, distFromPs );

				// weight according to raster distance from Ps coord
				if ( (sampleDepth+shadowBias) < PsDepth )
				{
					float sampleWeight = 1 - 0.9 * ( distFromPs / maxRadius );
					totalWeight += sampleWeight;
					avrgedDepth += ( sampleDepth * sampleWeight ); 
				}
			}
			if ( totalWeight > 0 ) avrgedDepth /= totalWeight;
			// _________________________________________




			if( avrgedDepth > 0 ) // there is an occluder
			{

				// compute the radius of the filter
				float filterRadius = minRadius + (( maxRadius-minRadius ) * ( 1 - ( avrgedDepth / PsDepth )));


				// sample the shadow map with varying filter width
				avrgedDepth = 0;
				totalWeight = 0;

				// get the shadow occlusion of Ps
				for ( iterator = 0; iterator < samples; iterator += 1 )
				{

					float sampleDepth, distFromPs;
					sampleDepth = sampleShadowMap( pShadS, pShadT, sampleCoordX[ iterator ], sampleCoordY[ iterator ], filterRadius, 1, distFromPs );

					// add bias cone
					sampleDepth += shadowBias + ( distFromPs * biasConeSlope ); 

					if ( sampleDepth < PsDepth )
					{ 
						shadowValue += 1;

						// if shadow decay
						if( shadowDecay > 0 )
						{
							// store the occluder depth of the new sampling disc
							float sampleWeight = 1 - 0.9 * ( distFromPs / filterRadius );
							totalWeight += sampleWeight;
							avrgedDepth += ( sampleDepth * sampleWeight ); 
						}
					}
				}
				shadowValue /= samples;
				// __________________________________________





				// decrease light attenuation as Ps moves further from occluder
				if ( shadowDecay > 0 )
				{
					if ( totalWeight > 0 ) avrgedDepth /= totalWeight;
					float distFromOccluder = PsDepth - avrgedDepth;
					shadowValue *= 1 - ( smoothstep( shadDecayDistMin, shadDecayDistMax, distFromOccluder ) * shadowDecay );
				}
				// __________________________________________


			}	

			atten *= ( 1 - shadowValue );
		}

		Cl = intensity * lightColor * atten;
	}
}

Edited by kensonuken
Link to comment
Share on other sites

  • 4 months later...

hey kensonuken,

have you had much progress on this? I'd be interested in seeing something like this if you've had a chance to develop it some more. hopefully it becomes efficient enough and lacking in artifacts.. :) i suppose those are the challenges.. just curious as it'd be cool to see some alternatives to area lights..

cheers,

dave

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...