// generate sample in two dimension void RegularSampler::Generate2D( float* sample , unsigned num , bool accept_uniform ) const { Sort_Assert( sample != 0 ); unsigned n = (unsigned)sqrt((float)num); Sort_Assert( n * n == num ); unsigned dn = 2 * n; for( unsigned i = 0 ; i < n ; ++i ) { unsigned offset = dn * i; for( unsigned j = 0 ; j < dn ; j+=2 ) { // fall back to random sampling if uniform sampling is not accepted. // For certain cases, like sampling brdf and light, uniform sampling is not acceptable if( !accept_uniform ) { sample[offset+j] = sort_canonical(); sample[offset+j+1] = sort_canonical(); continue; } sample[offset+j] = ( (float)j/2 + 0.5f ) / (float)n ; sample[offset+j+1] = ( (float)i + 0.5f ) / (float)n ; } } }
// generate sample in one dimension void RandomSampler::Generate1D( float* sample , unsigned num , bool accept_uniform ) const { Sort_Assert( sample != 0 ); for( unsigned i = 0 ; i < num ; ++i ) sample[i] = sort_canonical(); }
// generate sample in one dimension void StratifiedSampler::Generate1D( float* sample , unsigned num , bool accept_uniform ) const { Sort_Assert( sample != 0 ); for( unsigned i = 0 ; i < num ; ++i ) sample[i] = ( (float)i + sort_canonical() ) / (float)num ; }
// sample a ray from light Spectrum SpotLight::sample_l( const LightSample& ls , Ray& r , float* pdfW , float* pdfA , float* cosAtLight ) const { // udpate ray r.m_fMin = 0.0f; r.m_fMax = FLT_MAX; r.m_Ori = light_pos; // sample a light direction const Vector local_dir = UniformSampleCone( ls.u , ls.v , cos_total_range ); r.m_Dir = light2world.matrix( local_dir ); // product of pdf of sampling a point w.r.t surface area and a direction w.r.t direction if( pdfW ) { *pdfW = UniformConePdf( cos_total_range ); Sort_Assert( *pdfW != 0.0f ); } // pdf w.r.t surface area if( pdfA ) *pdfA = 1.0f; if( cosAtLight ) *cosAtLight = 1.0f; const float falloff = SatDot( r.m_Dir , light_dir ); if( falloff <= cos_total_range ) return 0.0f; if( falloff >= cos_falloff_start ) return intensity; const float d = ( falloff - cos_total_range ) / ( cos_falloff_start - cos_total_range ); if( d == 0.0f ) return 0.0f; return intensity * d * d; }
// generate sample in two dimension void StratifiedSampler::Generate2D( float* sample , unsigned num , bool accept_uniform ) const { Sort_Assert( sample != 0 ); unsigned n = (unsigned)sqrt((float)num); Sort_Assert( n * n == num ); unsigned dn = 2 * n; for( unsigned i = 0 ; i < n ; ++i ) { unsigned offset = dn * i; for( unsigned j = 0 ; j < dn ; j+=2 ) { sample[offset+j] = ( (float)j/2 + sort_canonical() ) / (float)n ; sample[offset+j+1] = ( (float)i + sort_canonical() ) / (float)n ; } } }
// generate sample in two dimension void RandomSampler::Generate2D( float* sample , unsigned num , bool accept_uniform ) const { Sort_Assert( sample != 0 ); int count = 2 * num; for( int i = 0 ; i < count ; i += 2 ) { sample[i] = sort_canonical(); sample[i+1] = sort_canonical(); } }
// generate sample in one dimension void RegularSampler::Generate1D( float* sample , unsigned num , bool accept_uniform ) const { Sort_Assert( sample != 0 ); for( unsigned i = 0 ; i < num ; ++i ) { // fall back to random sampling if uniform sampling is not accepted. // For certain cases, like sampling brdf and light, uniform sampling is not acceptable if( !accept_uniform ) sample[i] = sort_canonical(); else sample[i] = ( (float)i + 0.5f ) / (float)num ; } }
// 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; }
void OrthoCamera::SetCameraHeight( float h ) { Sort_Assert( h > 0.0f ); m_camHeight = h; }
// set the camera range void OrthoCamera::SetCameraWidth( float w ) { Sort_Assert( w > 0.0f ); m_camWidth = w; }