Ejemplo n.º 1
0
// Preprocess
void InstantRadiosity::PreProcess()
{
	m_pVirtualLightSources = new list<VirtualLightSource>[m_nLightPathSet];

	for( int k = 0 ; k < m_nLightPathSet ; ++k )
	{
		for( int i = 0 ; i < m_nLightPaths ; ++i )
		{
			// pick a light first
			float light_pick_pdf;
			const Light* light = scene.SampleLight( sort_canonical() , &light_pick_pdf );

			// sample a ray from the light source
			float	light_emission_pdf = 0.0f;
			float	light_pdfa = 0.0f;
			Ray		ray;
			float   cosAtLight = 1.0f;
			Spectrum le = light->sample_l( LightSample(true) , ray , &light_emission_pdf , &light_pdfa , &cosAtLight );

			Spectrum throughput = le * cosAtLight / ( light_pick_pdf * light_emission_pdf );

			int current_depth = 0;
			Intersection intersect;
			while( true )
			{
				if (false == scene.GetIntersect(ray, &intersect))
					break;

				VirtualLightSource ls;
				ls.power = throughput;
				ls.intersect = intersect;
				ls.wi = -ray.m_Dir;
				ls.depth = ++current_depth;
				m_pVirtualLightSources[k].push_back( ls );

				float bsdf_pdf;
				Vector wo;
				Bsdf* bsdf = intersect.primitive->GetMaterial()->GetBsdf(&intersect);
				Spectrum bsdf_value = bsdf->sample_f(ls.wi, wo, BsdfSample(true), &bsdf_pdf, BXDF_ALL);

				if( bsdf_pdf == 0.0f )
					break;

				// apply russian roulette
				float continueProperbility = min( 1.0f , throughput.GetIntensity() );
				if( sort_canonical() > continueProperbility )
					break;
				throughput /= continueProperbility;

				// update throughput
				throughput *= bsdf_value * ( AbsDot(wo, intersect.normal) / bsdf_pdf );

				// update next ray
				ray = Ray(intersect.intersect, wo, 0, 0.001f);
			}
		}
	}
}
Ejemplo n.º 2
0
// return the radiance of a specific direction
// note : there are one factor makes the method biased.
//		there is a limitation on the number of vertexes in the path
Spectrum PathTracing::Li( const Ray& ray , const PixelSample& ps ) const
{
	Spectrum	L = 0.0f;
	Spectrum	throughput = 1.0f;

	int			bounces = 0;
	Ray	r = ray;
	while(true)
	{
		Intersection inter;

		// get the intersection between the ray and the scene
		// if it's a light , accumulate the radiance and break
		if( false == scene.GetIntersect( r , &inter ) )
		{
			if( bounces == 0 )
				return scene.Le( r );
			break;
		}

		if( bounces == 0 ) L+=inter.Le(-r.m_Dir);

		// make sure there is intersected primitive
		Sort_Assert( inter.primitive != 0 );

		// evaluate the light
		Bsdf*			bsdf = inter.primitive->GetMaterial()->GetBsdf(&inter);
		float			light_pdf = 0.0f;
		LightSample		light_sample = (bounces==0)?ps.light_sample[0]:LightSample(true);
		BsdfSample		bsdf_sample = (bounces==0)?ps.bsdf_sample[0]:BsdfSample(true);
		const Light*	light = scene.SampleLight( light_sample.t , &light_pdf );
		if( light_pdf > 0.0f )
			L += throughput * EvaluateDirect(	r  , scene , light , inter , light_sample , 
												bsdf_sample , BXDF_TYPE(BXDF_ALL) ) / light_pdf;

		// sample the next direction using bsdf
		float		path_pdf;
		Vector		wi;
		BXDF_TYPE	bxdf_type;
		Spectrum f;
		BsdfSample	_bsdf_sample = (bounces==0)?ps.bsdf_sample[1]:BsdfSample(true);
		f = bsdf->sample_f( -r.m_Dir , wi , _bsdf_sample , &path_pdf , BXDF_ALL , &bxdf_type );
		if( f.IsBlack() || path_pdf == 0.0f )
			break;

		// update path weight
		throughput *= f * AbsDot( wi , inter.normal ) / path_pdf;

		if( throughput.GetIntensity() == 0.0f )
			break;
		if( bounces > 4 )
		{
			float continueProperbility = min( 0.5f , throughput.GetIntensity() );
			if( sort_canonical() > continueProperbility )
				break;
			throughput /= continueProperbility;
		}

		r.m_Ori = inter.intersect;
		r.m_Dir = wi;
		r.m_fMin = 0.001f;

		++bounces;

		// note :	the following code makes the method biased
		//			'path_per_pixel' could be set very large to reduce the side-effect.
		if( bounces >= max_recursive_depth )
			break;
	}

	return L;
}