Materials (BRDF and its sampling)


This part contains our implemented materials. It consists of implementing BRDF and its sampling for each of them. Note that we have implemented the importance sampling technique which greatly reduces number of samples requiered for rendering less noisy images.

Source code (core part):

class PhongMaterial : public Material

{

private:

       double ks, kd, spec_n;

       bool lastType;

       SphereSampler ss;

       Vec3f refFdiffuse;

 

public:

   

    PhongMaterial(double _kd, double _ks, double _spec_n, Vec3f reflektance, Shader * _shader)

    : Material(reflektance, _shader),ks(_ks),kd(_kd), spec_n(_spec_n)

    {

             lastType = false;

             refFdiffuse = reflektance * INV_PI;

    }; 

      

       ~PhongMaterial()

       {

 

       };

   

    bool ReflectRay (Ray &inRay, Ray &outRay, double *weight)

       {

             // set reflection as diffuse

             lastType = false;

 

        // get shading normal

        Vec3f normal = inRay.hit->GetNormal(inRay);

       

        // turn normal to front

        if (Dot(normal,inRay.dir) > 0)

            normal = -normal;

 

             // initiate outgoing ray

             outRay.hit = NULL;

        outRay.t = Infinity;

        outRay.u = outRay.v = 0.0;

             outRay.org = inRay.org + inRay.t * inRay.dir;

 

             double val, fi, psi;

 

             val = frand();

             fi = frand();

             psi = frand();

 

             // this ray is diffuse reflection

             if (val < kd)

             {

                    // random vector sampled with pdf(x) = 1/PI * cos(x)

                    // no need to return weigh with of cos, already included in sampling techniques

                    ss.ImportanceSampleHemisphere(outRay.dir, weight, normal);

 

                    //ss.UniformSampleHemisphere(outRay.dir, weight, normal);

                    //*weight *= Dot(normal, outRay.dir) * kd;

             }

             // this is specular reflection

             else if (val < kd + ks)

             {

                    // random vector sampled with pdf(x) = cos (alpha) (n + 1) / (2 * PI), where alpha is angle from reflected ray to ideal mirror reflection

                    outRay.dir = Vec3f(sqrt(1-pow(fi, 2/(spec_n+1)))*cos(2*M_PI*psi), sqrt(1-pow(fi, 2/(spec_n+1)))*sin(2*M_PI*psi), pow(fi, 2/(spec_n+1)));

 

                    // compute reflection vector

                    Vec3f reflect = inRay.dir - 2*Dot(normal,inRay.dir)*normal;

 

                    outRay.dir = RotateByAngle(Vec3f(0,0,1), reflect, outRay.dir);

                    *weight =  ks;

 

                    // reflection is specular              

                    lastType = true;

             }

             else

             {

                    // nothing reflected, contribution is 0

                    *weight = 0;

                    *weight = 1 - ks - kd;

             }

 

             return lastType;

       }

 

       virtual Vec3f f(Vec3f& /*outDir*/, Vec3f& /*inDir*/) const

       {           

             // if last one was specular

             if (lastType)

             {

                    return 1.;

             }

             else

             {

                    return refFdiffuse;

             }

       };

};

 

class LambertianMaterial : public Material

{

private:

             SphereSampler ss;

             Vec3f retF;

 

public:

   

    LambertianMaterial(Vec3f reflektance, Shader * _shader)

    : Material(reflektance, _shader)

    {

             retF = reflektance * INV_PI;

       }; 

      

       ~LambertianMaterial()

       {

 

       };

   

    bool ReflectRay (Ray &inRay, Ray &outRay, double *weight)

       {

             double fi, psi;

 

        // get shading normal

        Vec3f normal = inRay.hit->GetNormal(inRay);

       

        // turn normal to front

        if (Dot(normal,inRay.dir) > 0)

            normal = -normal;

 

             // initiate outgoing ray

             outRay.hit = NULL;

        outRay.t = Infinity;

        outRay.u = outRay.v = 0.0;

             outRay.org = inRay.org + inRay.t * inRay.dir;

 

             // init random numbers

             fi = frand();

             psi = frand();

 

             // random vector sampled with pdf(x) = 1/PI * cos(x)

             // no need to return weigh with of cos, already included in sampling techniques

             ss.ImportanceSampleHemisphere(outRay.dir, weight, normal);

 

             // not specular

             return false;

       }

 

       virtual Vec3f f(Vec3f& /*outDir*/, Vec3f& /*inDir*/) const

       {           

             // preprocessed reflektance / M_PI;

             return retF;

       };

};

 

class MirrorMaterial : public Material

{

private:

 

public:

   

    MirrorMaterial(Shader * _shader)

    : Material(Vec3f(1.), _shader)

    {

 

       }; 

      

       ~MirrorMaterial()

       {

 

       };

   

    bool ReflectRay (Ray &inRay, Ray &outRay, double *weight)

       {

        // get shading normal

        Vec3f normal = inRay.hit->GetNormal(inRay);

       

        // turn normal to front

        if (Dot(normal,inRay.dir) > 0)

            normal = -normal;

 

             // initiate outgoing ray

             outRay.hit = NULL;

        outRay.t = Infinity;

        outRay.u = outRay.v = 0.0;

             outRay.org = inRay.org + inRay.t * inRay.dir;

             outRay.dir = inRay.dir - 2*Dot(normal,inRay.dir)*normal;

            

             *weight = 1.;

             return true;

       }

 

       virtual Vec3f f(Vec3f& /*outDir*/, Vec3f& /*inDir*/) const

       {           

             return 1.;

       };

 

       //virtual Vec3f GetColor(double u, double v, Vec3f &hitPoint, Primitive *prim)

       //{

       //     return Vec3f(1.);

       //}

 

};

 

class CombinedMaterial : public Material

{

private:

             SphereSampler ss;

             Vec3f retF;

             double specularity;

             bool lastSpecular;

 

public:

   

    CombinedMaterial(Vec3f reflektance, double specularity, Shader * _shader)

    : Material(reflektance, _shader), specularity(specularity)

    {

             retF = reflektance * INV_PI;

       }; 

      

       ~CombinedMaterial()

       {

 

       };

   

    bool ReflectRay (Ray &inRay, Ray &outRay, double *weight)

       {

             lastSpecular = false;

             double fi, psi, pom;

 

        // get shading normal

        Vec3f normal = inRay.hit->GetNormal(inRay);

       

        // turn normal to front

        if (Dot(normal,inRay.dir) > 0)

            normal = -normal;

 

             // initiate outgoing ray

             outRay.hit = NULL;

        outRay.t = Infinity;

        outRay.u = outRay.v = 0.0;

             outRay.org = inRay.org + inRay.t * inRay.dir;

 

             // init random numbers

             fi = frand();

             psi = frand();

             pom = frand();

 

             if (pom < specularity)

             {

                    outRay.dir = inRay.dir - 2*Dot(normal,inRay.dir)*normal;

                    *weight = 1.;

                    lastSpecular = true;

             }

             else

             {

                    // random vector sampled with pdf(x) = 1/PI * cos(x)

                    // no need to return weigh with of cos, already included in sampling techniques

                    ss.ImportanceSampleHemisphere(outRay.dir, weight, normal);

             }

 

             return lastSpecular;

       }

 

       virtual Vec3f f(Vec3f& /*outDir*/, Vec3f& /*inDir*/) const

       {           

             if (lastSpecular)

             {

                    return 1.;

             }

             else

             {

                    // preprocessed reflektance / M_PI;

                    return retF;

             }

       };

};

References: