Пример #1
0
DistributionSample
MirrorMaterial::sampleBxDF( RandomNumberGenerator & rng,
                            const RayIntersection & intersection ) const
{
    // Perfect mirror - PDF if a Dirac delta function
    DistributionSample sample;
    sample.direction = mirror( intersection.fromDirection(),
                               intersection.normal );
    sample.pdf_sample = DistributionSample::DIRAC_PDF_SAMPLE;
    return sample;
}
Пример #2
0
void InspectionShader::shade( Scene & scene, RandomNumberGenerator & rng, RayIntersection & intersection )
{
    RGBColor color( 0.0f, 0.0f, 0.0f );
    const float index_in = intersection.ray.index_of_refraction;
    const float index_out = intersection.material->index_of_refraction;
    const Vector4 from_dir = intersection.fromDirection();

    switch( property ) {
        case FresnelDialectric:
            {
                Vector4 refracted = refract( from_dir, intersection.normal, index_in, index_out );
                float fresnel = 1.0f;
                if( refracted.magnitude() > 0.0001 ) {
                    fresnel = Fresnel::Dialectric::Unpolarized( dot( from_dir, intersection.normal ),
                                                                dot( refracted, intersection.normal.negated() ),
                                                                index_in,
                                                                index_out );
                }
                color = RGBColor( fresnel, fresnel, fresnel );
            }
            break;
        case FresnelConductor:
            {
                float absorptionCoeff = 2.0; // FIXME: material specific
                float fresnel = Fresnel::Conductor::Unpolarized( dot( from_dir, intersection.normal ), index_out, absorptionCoeff );
                color = RGBColor( fresnel, fresnel, fresnel );
            }
            break;
        case Normal:
            {
                auto shifted = add( scale( intersection.normal, 0.5 ),
                                    Vector4( 0.5, 0.5, 0.5 ) );
                color = RGBColor( shifted.x, shifted.y, shifted.z );
            }
            break;
        case IndexOfRefraction:
            {
                float v = index_out / 3.0;
                color = RGBColor( v, v, v );
            }
            break;
        case TextureUVCoordinate:
            {
                color = RGBColor( intersection.u, intersection.v, 0.0 );
            }
            break;
        default:
            ;
    }

    intersection.sample.color = color;
}
Пример #3
0
DistributionSample
RefractiveMaterial::sampleBxDF( RandomNumberGenerator & rng,
                                const RayIntersection & intersection ) const
{
    // Perfect Fresnel refractor
    DistributionSample sample;

    const float index_in = intersection.ray.index_of_refraction;
    const float index_out = index_of_refraction;
    const Vector4 from_dir = intersection.fromDirection();

    // FIXME: HACK - This assumes that if we hit the surface of an object with the same
    //        index of refraction as the material we're in, then we are moving back into
    //        free space. This might not be true if there are numerical errors tracing
    //        abutting objects of the same material type, or for objects that are intersecting.
    if( index_out == index_in ) {
        sample.new_index_of_refraction = 1.0f;
    }

    Vector4 refracted = refract( from_dir, intersection.normal, index_in, index_out );
    float fresnel = 1.0f; // default to total internal reflection if refract() returns
    // a zero length vector
    if( refracted.magnitude() > 0.0001 ) {
        fresnel = Fresnel::Dialectric::Unpolarized( dot( from_dir, intersection.normal ),
                                                    dot( refracted, intersection.normal.negated() ),
                                                    index_in,
                                                    index_out );
    }

    const float draw = rng.uniform01();

    // Use RNG to choose whether to reflect or refract based on Fresnel coefficient.
    //   Random selection accounts for fresnel or 1-fresnel scale factor.
    if( fresnel == 1.0f || draw < fresnel ) {
        // Trace reflection (mirror ray scaled by fresnel or 1 for total internal reflection)
        sample.direction = mirror( from_dir, intersection.normal );
        // FIXME - How do we determine pdf_sample for total internal reflection?
        sample.pdf_sample = fresnel;
        sample.new_index_of_refraction = index_in;
    }
    else {
        // Trace refraction (refracted ray scaled by 1-fresnel)
        sample.direction = refracted;
        sample.pdf_sample = 1.0 - fresnel;
        sample.new_index_of_refraction = index_out;
    }

    return sample;
}
Пример #4
0
void BasicDiffuseSpecularShader::shade( Scene & scene, RandomNumberGenerator & rng, RayIntersection & intersection )
{
    RGBColor diffuse_contrib( 0.0, 0.0, 0.0 );
    RGBColor specular_contrib( 0.0, 0.0, 0.0 );
    RGBColor direct_contrib( 0.0, 0.0, 0.0 );
    Ray new_ray;
    RayIntersection new_intersection;
    new_intersection.min_distance = 0.01;
    Vector4 offset( 0.0, 0.0, 0.0 );
    //offset = scale( intersection.normal, 0.01 ); // NOTE - Seems to help 
    new_ray.origin = add( intersection.position, offset );
    new_ray.depth = intersection.ray.depth + 1;
    const unsigned char max_depth = 5;
    //const unsigned char max_depth = 4;
    //const unsigned char max_depth = 3;
    //const unsigned char max_depth = 2;

    Vector4 from_dir = intersection.fromDirection();

    // Asserts
    intersection.normal.assertIsUnity();
    intersection.normal.assertIsDirection();

    // Direct lighting
    //
    // Area lights
    //for( Traceable * traceable : scene.lights ) {
    //    // TODO - sample lights
    //}
    // Point lights
    for( const PointLight & light : scene.point_lights ) {
        Vector4 to_light = subtract( light.position, intersection.position );
        float dist_sq_to_light = to_light.magnitude_sq();
        Vector4 direction = to_light.normalized();
        direction.makeDirection();

        // Shoot a ray toward the light to see if we are in shadow
        Ray shadow_ray( intersection.position, direction );
        RayIntersection shadow_isect;
        shadow_isect.min_distance = 0.01;
        if( scene.intersect( shadow_ray, shadow_isect )
            && sq(shadow_isect.distance) < dist_sq_to_light ) {
            continue;
        }

        // Not in shadow
        float cos_r_n = fabs( dot( direction, intersection.normal ) ); 
        RGBColor color = light.band_power;
        color.scale(cos_r_n);
        color.scale(1.0f / to_light.magnitude_sq()); // distance falloff
        // TODO: use actual material parameters properly so we can get specular here, too
        if( intersection.material )
            direct_contrib.accum( mult( color, intersection.material->diffuse ) );
        else
            direct_contrib.accum( color );
    }

    // TODO - How best should we choose between diffuse and specular?
    // FIXME: Should I scale by the cosine for a perfect reflector?

    if( intersection.ray.depth < max_depth ) {
        const float diffuse_chance = 0.9;
        float diff_spec_select = rng.uniform01();

        if( intersection.material->perfect_reflector
            || intersection.material->perfect_refractor ) {
            auto sample = intersection.material->sampleBxDF( rng, intersection );
            new_ray.direction = sample.direction;
            new_ray.index_of_refraction = sample.new_index_of_refraction;

            if( scene.intersect( new_ray, new_intersection ) ) {
                if( new_intersection.distance != FLT_MAX ) {
                    shade( scene, rng, new_intersection );
                }
                specular_contrib.accum( new_intersection.sample.color );
            }
        }
        else if( diff_spec_select < diffuse_chance ) {
            // Diffuse
            rng.uniformSurfaceUnitHalfSphere( intersection.normal, new_ray.direction );
            new_ray.direction.makeDirection();

            if( scene.intersect( new_ray, new_intersection ) ) {
                if( new_intersection.distance != FLT_MAX )
                    shade( scene, rng, new_intersection );
                float cos_r_n = dot( new_ray.direction, intersection.normal ); 
                new_intersection.sample.color.scale( cos_r_n );
                diffuse_contrib.accum( new_intersection.sample.color );
            }
        }
        else {
            // Specular
            // TODO - sample the specular lobe, not just the mirror direction
            new_ray.direction = mirror( from_dir, intersection.normal );
            new_ray.direction.makeDirection();

            if( scene.intersect( new_ray, new_intersection ) ) {
                if( new_intersection.distance != FLT_MAX )
                    shade( scene, rng, new_intersection );
                float cos_r_n = dot( new_ray.direction, intersection.normal ); 
                new_intersection.sample.color.scale( cos_r_n );
                specular_contrib.accum( new_intersection.sample.color );
            }
        }
    }

    if( intersection.material ) {
        intersection.sample.color = mult( diffuse_contrib, intersection.material->diffuse );
        intersection.sample.color.accum( mult( specular_contrib, intersection.material->specular ) );
        intersection.sample.color.accum( intersection.material->emittance );
        intersection.sample.color.accum( direct_contrib );
    }
    else {
        intersection.sample.color = diffuse_contrib;
        intersection.sample.color.accum( direct_contrib );
    }
}