Пример #1
0
// use phong shading model
Vec4d PhongMaterial::shade(
  const RayIntersection& intersection,
  const Light& light) const 
{
  // calculate diffuse part of the equation
  Vec3d lightDirection = (light.position() - intersection.position()).normalize();  
  Vec3d diffuse = this->color() * std::max(dot(intersection.normal(), lightDirection), 0.d);
  
  // calculate specular part
  Vec3d viewDirection = intersection.ray().direction();
  Vec3d reflection = reflect(lightDirection, intersection.normal());
  Vec3d lightcolor = light.spectralIntensity() / 255;
  Vec3d specular = ((mShininess + 2) / (2 * M_PI)) * SPECULAR_REFLECTION_DEGREE * pow(std::max(dot(reflection, viewDirection), 0.d), mShininess) * lightcolor;
  
  // calculcate sum -> result
  return Vec4d(diffuse + specular, 1);
}
Пример #2
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;
}
Пример #3
0
Vec4d Raytracer::shade(const RayIntersection& intersection,
                      size_t depth) const
{
  // This offset must be added to intersection points for further
  // traced rays to avoid noise in the image
  const Vec3d offset(intersection.normal() * Math::safetyEps());

  Vec4d color(0,0,0,1);
  std::shared_ptr<const Renderable> renderable = intersection.renderable();
  std::shared_ptr<const Material>   material   = renderable->material();

  for(size_t i=0;i <mScene->lights().size();++i)
  {
    const Light &light = *(mScene->lights()[i].get());

    //Shadow ray from light to hit point.
    const Vec3d L = (intersection.position() + offset) - light.position();
    const Ray shadowRay(light.position(), L);

    //Shade only if light in visible from intersection point.
    if (!mScene->anyIntersection(shadowRay,L.length()))
      color += material->shade(intersection,light);
  }

  // limit recursion depth
  if (depth >= mMaxDepth)
    return color;

  Vec3d dir = reflect(intersection.ray().direction(), intersection.normal());
  Ray reflectedRay(intersection.position() + offset, dir);
  double reflectance = material->reflectance();
  color = color * (1 - reflectance) +  reflectance * trace(reflectedRay, depth - 1) + Vec4d(0.0,0.0,0.0,1.0);
  return color;
}
Пример #4
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;
}
Пример #5
0
    Vec4d Raytracer::shade(const RayIntersection &intersection,
                           size_t depth) const {
        // This offset must be added to intersection points for further
        // traced rays to avoid noise in the image
        const Vec3d offset(intersection.normal() * Math::safetyEps());

        Vec4d color(0, 0, 0, 1);
        std::shared_ptr<const Renderable> renderable = intersection.renderable();
        std::shared_ptr<const Material> material = renderable->material();

        for (size_t i = 0; i < mScene->lights().size(); ++i) {
            const Light &light = *(mScene->lights()[i].get());

            //Shadow ray from light to hit point.
            const Vec3d L = (intersection.position() + offset) - light.position();
            const Ray shadowRay(light.position(), L);

            //Shade only if light in visible from intersection point.
            if (!mScene->anyIntersection(shadowRay, L.length()))
                color += material->shade(intersection, light);
        }
        return color;
    }
Пример #6
0
bool
Scene::closestIntersection(const Ray &ray,RayIntersection& intersection, double maxLambda) const
{ 
  double closestLambda = maxLambda;
  RayIntersection tmpIntersection;
  RayIntersection closestIntersection;
  bool hit(false);
  for (size_t i=0;i<mRenderables.size();++i)
  {
    std::shared_ptr<Renderable> r = mRenderables[i];
    if(r->closestIntersection(ray,closestLambda,tmpIntersection))
    {
      if(tmpIntersection.lambda() < closestLambda)
      {
        hit=true;
        closestLambda = tmpIntersection.lambda();
        closestIntersection = tmpIntersection;
      }
    }
  }
  intersection=closestIntersection;
  return hit;
}
Пример #7
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;
}
Пример #8
0
Vec4d CheckerMaterial::shade(const RayIntersection& intersection, 
           const Light& light) const
{
  const Vec3d &uvw = intersection.uvw();

  const bool left  = (fmod(fabs(uvw[0]), 1/mTiles[0])
    < (1/mTiles[0] / double(2)))
    ^ (uvw[0] < double(0));
  const bool lower = (fmod(fabs(uvw[1]), 1/mTiles[1])
    < (1/mTiles[1] / double(2)))
    ^ (uvw[1] < double(0));

  if(left ^ lower)
    return mMaterial1->shade(intersection, light);
  else
    return mMaterial2->shade(intersection, light);
}
Пример #9
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 );
    }
}
Пример #10
0
Spectrum Path::computeLi( const vec2f &pFilm, const SceneData &i_scene, const Camera &i_camera, const Sampler &i_sampler, int i_depth )
{
    Camera::CameraSample cameraSample;
    cameraSample.pixelSample = pFilm + i_sampler.sample2D();
    cameraSample.lensSample = i_sampler.sample2D();
    
    Ray ray;
    float weight = i_camera.generateRay( cameraSample, &ray );
    
    // Radiance
    Spectrum L = Spectrum( 0.0f );
    
    // Importance
    Spectrum beta = Spectrum( 1.0 );
    
    for ( int bounces = 0;; bounces++ ) {
        
        RayIntersection intersection;
        bool foundIntersection = i_scene.intersect( ray, intersection );
        
        float maxDepth = 5;
        if ( !foundIntersection || bounces >= maxDepth ) {
            break;
        }
        
        Spectrum Le = intersection.Le();
        if ( Le.isBlack() )
        {
            // Direct illumination sampling

            Spectrum Ld = beta * uniformSampleOneLight( intersection, i_sampler, i_scene );
            L += Ld;
            
            // BSDF Sampling
            const shading::BSDF &bsdf = intersection.getBSDF();
            const vec3f &surfacePosition = intersection.getSurfacePoint().pos;
            
            vec3f woLocal = -intersection.worldToSurface( -intersection.dir );
            vec3f wiLocal;
            float pdf = 1.0;
            
            const vec2f &bsdfSample = i_sampler.sample2D();
            Spectrum f = bsdf.sampleF( woLocal, &wiLocal, bsdfSample, &pdf );
            
            // No point of continuing if no color
            if ( f.isBlack() || pdf == 0.0 ) {
                break;
            }
            
            // Transform to world space
            vec3f wiWorld = intersection.surfaceToWorld( wiLocal );
            
            // Generate new ray
            ray = Ray( surfacePosition, wiWorld );
            
            beta *= ( f * absDot( wiWorld, intersection.getSurfacePoint().normal ) ) / pdf;
            
            // Russian Roulette
            if ( beta.y() < 1.0f && bounces > 3 ) {
                
                float q = std::max( .05f, 1 - beta.maxComponentValue() );
                
                if ( i_sampler.sample1D() > q ) {
                    beta /= ( 1.0 - q );
                }
                else {
                    break;
                }
            }
        }
        else {
            L += beta * intersection.Le() / 50.0;
            break;
        }
    }
    
    return weight * L;
}
Пример #11
0
Spectrum Path::estimateDirectLighting( const RayIntersection i_intersection, RenderablePtr i_light, const Sampler &i_sampler, const SceneData &i_scene )
{
    // Direct contribution
    Spectrum Ld = Spectrum::black();
    
    float lightPdf = 0.0f;
    float surfacePdf = 0.0f;
    
    vec3f wiWorld;
    
    const vec3f &woWorld = -i_intersection.dir;
    const vec3f &woLocal = i_intersection.worldToSurface( woWorld );
    const vec3f &normal = i_intersection.getSurfacePoint().normal;
    const shading::BSDF &bsdf = i_intersection.getBSDF();
    
    /* ==================== */
    /*     Sample Light     */
    /* ==================== */
    {
        VisibilityTester visibilityTester;
        const vec3f &uLight = i_sampler.sample3D();
        
        Spectrum Li = i_light->sampleIncidenceRadiance( i_intersection, uLight, &wiWorld, &lightPdf, &visibilityTester );
        
        // Convert to local (surface) coords
        const vec3f &wiLocal = i_intersection.worldToSurface( wiWorld );
        
        // Sample light
        if ( !Li.isBlack() && lightPdf > 0.0f ) {
            
            const Spectrum &f = bsdf.computeF( woLocal, wiLocal ) * absDot( wiWorld, normal );
            surfacePdf = bsdf.pdf( woLocal, wiLocal );
            
            if ( !f.isBlack() ) {
                
                // Ray is in shadow
                if ( visibilityTester.isOccluded( i_scene ) ) {
                    Li = Spectrum::black();
                }
                
                if ( !Li.isBlack() ) {
                    
                    // Weight with MIS
                    float misWeight = powerHeuristic( lightPdf, surfacePdf );
                    Ld += ( Li * f * misWeight ) / lightPdf;
                }
            }
        }
    }
    
    /* ==================== */
    /*     Sample BSDF      */
    /* ==================== */
    {
        const vec2f &uSurface = i_sampler.sample2D();
        vec3f wiLocal;
        
        const Spectrum &f = bsdf.sampleF( woLocal, &wiLocal, uSurface, &surfacePdf ) * absDot( wiWorld, normal );
        
        if ( !f.isBlack() && surfacePdf > 0.0f ) {
            
            // TODO computer light PDF
            lightPdf = 0.0;
            
            // No contribution, return
            if ( lightPdf == 0.0 ) {
                return Ld;
            }

            // Convert to local (surface) coords
            vec3f wiWorld = i_intersection.surfaceToWorld( wiLocal );
            
            const Ray bsdfRay = Ray( i_intersection.getSurfacePoint().pos, wiWorld );
            RayIntersection lightIntersection;
            
            bool foundIntersection = i_scene.intersect( bsdfRay, lightIntersection );
            Spectrum Li = Spectrum::black();
            
            if ( foundIntersection ) {
                
                if ( lightIntersection.m_shapeId == i_light->getIdentifier() ) {
                    Li = i_light->computeRadiance( lightIntersection.getSurfacePoint(), wiWorld );
                }
            }
            
            if ( !Li.isBlack() ) {
                
                // Weight with MIS
                float misWeight = powerHeuristic( lightPdf, surfacePdf );
                Ld += ( Li * f * misWeight ) / surfacePdf;
            }
        }
    }
    
    return Ld;
}