Пример #1
0
Vec3 PhotonMapRenderer::GlossyRay(const Vec3& w, float exponent, Random& rand)
{
    real r1 = 2.f*(PI*rand.F32());
    real r2 = rand.F32();
    real cosTheta = powf(1.f-r2, 1.0f/(exponent+1.0f));
    real sinTheta = sqrtf(1.0f - cosTheta*cosTheta);
    real rx = cosf(r1) * sinTheta;
    real ry = sinf(r1) * sinTheta;
    real rz = cosTheta;
    Vec3 u = ((fabs(w.x) > .1f ? Vec3(0.f, 1.f, 0.f) : Vec3(1.f, 0.f, 0.f)) ^ w).normalize(); // binormal
    Vec3 v = w ^ u; // tangent
    
    // ucosφsinθ + vsinφsinθ + wcosθ
    return (u*rx + v*ry + w*rz).normalize();
}
Пример #2
0
void PhotonMapRenderer::TracePhoton(const Ray& r, const Vec3& power, PathInfo pathInfo, Random& rand)
{
    // max refl
    if (++pathInfo.depth > pPmConf_->maxPhotonBounce)
    {
        return;
    }

    HitRecord rec;
    rec.hitLit = false;
    if (!pScene_->Intersect(r, EPSILON, REAL_MAX, rec))
        return;
    
    Vec3 x = r.o + r.d * rec.t;
    Vec3 n = rec.normal;
    Vec3 nl = n.dot(r.d) < 0.f ? n : n*-1.f; // 交点の法線, 裏面ヒット考慮
    Vec3 color = rec.color;
    Refl_t refl = rec.pOldMaterial->refl;
    
    // Ideal DIFFUSE reflection
    if (refl == DIFF || refl == LIGHT) { // 光源表面はLambert面という事にしておく
        pathInfo.diffuseDepth++;
        bool direct = pathInfo.diffuseDepth == 1;
        pPhotonMap_->store(power.e, x.e, r.d.e, direct, pathInfo.lightNo);
        
        float ave_refl = (color.x + color.y + color.z) / 3.f;
        if (rand.F32() < ave_refl)
        {
            // 法線となす角のcosに比例する分布で反射方向を決める
            Vec3 d = Ray::CosRay(nl, rand);
            
            // lambertのBRDFかけなくていいのか?
            // cos分布でレイを発している(cosが掛けてある)
            // / probability cos
            // / lambert brdf PI
            real ave_refl_inv = 1.0f / ave_refl;
            Vec3 refPower = power.mult(color) * ave_refl_inv;
            TracePhoton(Ray(x,d), refPower, pathInfo, rand);
        }
        //fprintf(stderr, "p (%f %f %f) (%f %f %f) (%f %f %f)\n", power[0], power[1], power[2], pos[0], pos[1], pos[2], dir[0], dir[1], dir[2]);
        return;
    }
    // Ideal SPECULAR reflection
    else if (refl == SPEC) {
        pathInfo.specularDepth++;
        Ray refl(x, r.d - n * 2.f * n.dot(r.d));
        TracePhoton(refl, power, pathInfo, rand);
        return;
    }
    else if (refl == PHONGMETAL) {
        pathInfo.glossyDepth++;
        
        Vec3 rdir = r.d - n * 2.f * n.dot(r.d); // reflected ray
        Vec3 d = GlossyRay(rdir, 10, rand);
        Vec3 mx = x + n*1e-4f;
        TracePhoton(Ray(mx, d), power, pathInfo, rand);
        return;
    }
    
    pathInfo.specularDepth++;
    
    // Ideal dielectric REFRACTION
    Ray reflRay(x, r.d - n * 2.f * n.dot(r.d));
    bool into = n.dot(nl) > 0.f;  // Ray from outside going in?
    real airRefrIdx = 1.f;
    real refrIdx = rec.pOldMaterial->refractiveIndex;
    real nnt = into ? airRefrIdx/refrIdx : refrIdx/airRefrIdx;
    real ddn = r.d.dot(nl);   // レイと法線のcos
    real cos2t;
    
    // Total internal reflection
    if ((cos2t = 1.f - nnt * nnt * (1.f - ddn * ddn)) < 0.f) {
        TracePhoton(reflRay, power, pathInfo, rand);
        return;
    }
    
    // 屈折方向
    Vec3 tdir = (r.d * nnt - n * ((into ? 1.f : -1.f) * (ddn * nnt + sqrtf(cos2t)))).normalize();
    real a = refrIdx - airRefrIdx;
    real b = refrIdx + airRefrIdx;
    real R0 = a * a / (b * b);
    real c = 1.f - (into ? -ddn : tdir.dot(n));
    real Re = R0 + (1.f - R0)*c*c*c*c*c;
    real P = Re;
    if (rand.F32() < P)
        TracePhoton(reflRay, power, pathInfo, rand);       // 反射
    else
        TracePhoton(Ray(x, tdir), power.mult(color), pathInfo, rand);  // 屈折

    return;
}
Пример #3
0
Vec3 PhotonMapRenderer::Irradiance(const Ray &r, PathInfo pathInfo, Random& rand)
{
    // max refl
    if (++pathInfo.depth > pPmRenConf_->maxRayBounce)
    {
        return Vec3();
    }

    HitRecord rec;
    rec.hitLit = true;
    if (!pScene_->Intersect(r, EPSILON, REAL_MAX, rec)) return pConf_->bgColor;
    //const Shape& obj = *g_shapes[id];       // the hit object
    Vec3 x = r.o + r.d * rec.t;
    Vec3 n = rec.normal;
    Vec3 nl = n.dot(r.d) < 0.f ? n : n * -1.f;   // 交点の法線
    Vec3 color = rec.color;
    Refl_t refl = rec.pOldMaterial->refl;
    
    // 0.5にしたらカラーが反射率になってるから暗くなるだけ。IDEALでない反射は扱えない。カラーと混ぜるとかもない。
    // Ideal DIFFUSE reflection
    if (refl == DIFF) {
        pathInfo.diffuseDepth++;
        Vec3 irrad;
        //fprintf(stderr, "irrad %f %f %f\r", irrad[0], irrad[1], irrad[2]);
        if (pPmRenConf_->finalGethering && pathInfo.diffuseDepth <= 1) {
            for (u32 i=0; i<pPmRenConf_->nFinalGetheringRays; i++) {
                real r1 = 2.f*(PI*rand.F32());
                real r2 = rand.F32(); // => 1-cos^2θ = 1-sqrt(1-r_2)^2 = r_2
                real r2s = sqrtf(r2);    // => sinθ = sqrt(1-cos^2θ) = sqrt(r_2)
                Vec3 w = nl; // normal
                Vec3 u = ((fabs(w.x) > .1f ? Vec3(0.f, 1.f, 0.f) : Vec3(1.f, 0.f, 0.f)) ^ w).normalize(); // binormal
                Vec3 v = w ^ u; // tangent
                
                // ucosφsinθ + vsinφsinθ + wcosθ
                Vec3 d = (u*cosf(r1)*r2s + v*sinf(r1)*r2s + w*sqrtf(1-r2)).normalize();
                PathInfo pathInfo2(pathInfo);
                irrad += Irradiance(Ray(x, d), pathInfo2, rand);// * nl.dot(d) / nl.dot(d);
                // 入射方向と法線のcosθ掛けるのとimportance samplingしたので確率密度関数cosθで割るのとで
                // 相殺するような。
            }
            irrad /= (float)pPmRenConf_->nFinalGetheringRays;
        } else {
            pPhotonMap_->irradiance_estimate(irrad.e, x.e, nl, pPmConf_->estimateDist, pPmConf_->nEstimatePhotons);
        }
        return Vec3(irrad.x * color.x, irrad.y * color.y, irrad.z * color.z);
    }
    else if (refl == SPEC) {
        // Ideal SPECULAR reflection
        return Irradiance(Ray(x,r.d-n*2.f*n.dot(r.d)), pathInfo, rand);
    }
    else if (refl == PHONGMETAL) {
        // Imperfect SPECULAR reflection
        
        // 指数的に追跡回数が増えるのを防ぐ
        if (pathInfo.glossyDepth >= pPmRenConf_->nMaxGlossyBounce) {
            // Ideal SPECULAR reflectionで近似
            return Irradiance(Ray(x,r.d-n*2.f*n.dot(r.d)), pathInfo, rand);
        }
        pathInfo.glossyDepth++;
        
        Vec3 irrad;
        const u32 nSamples = pPmRenConf_->nGlossyRays;
        for (u32 i = 0; i < nSamples; i++) {
            
            Vec3 rdir = r.d - n * 2.f * n.dot(r.d); // reflected ray
            rdir = GlossyRay(rdir, 10, rand);
            Vec3 mx = x + n*1e-4f; // 自己ヒットしないようにちょっと浮かす
            irrad += Irradiance(Ray(mx, rdir), pathInfo, rand);
        }
        return irrad / (float)nSamples;
    }
    else if (refl == REFR) {
    
        // Ideal dielectric REFRACTION
        Vec3 rdir = r.d - n * 2.f * n.dot(r.d);
        //Vec3 mx = x + rdir * EPSILON; // 自己ヒット抑止にレイ始点をちょっと進めてみる
        Ray reflRay(x, rdir);
        bool into = n.dot(nl) > 0.f; // Ray from outside going in?
        real airRefrIdx = 1.f;
        real refrIdx = rec.pOldMaterial->refractiveIndex;
        real nnt = into ? airRefrIdx/refrIdx : refrIdx/airRefrIdx;
        real ddn = r.d.dot(nl); // レイと法線のcos
        real cos2t;
        
        // Total internal reflection
        if ((cos2t = 1.f-nnt * nnt * (1.f - ddn * ddn)) < 0.f)
            return Irradiance(reflRay, pathInfo, rand);
        
        // 屈折方向
        Vec3 tdir = (r.d * nnt - n * ((into ? 1.f : -1.f) * (ddn * nnt + sqrtf(cos2t)))).normalize();
        //mx = x + rdir * EPSILON; // 自己ヒット抑止にレイ始点をちょっと進めてみる
        
        real a = refrIdx - airRefrIdx;
        real b = refrIdx + airRefrIdx;
        real R0 = a * a / (b * b);
        real c = 1.f - (into ? -ddn : tdir.dot(n));
        real Re = R0 + (1.f - R0)*c*c*c*c*c;
        // レイの運ぶ放射輝度は屈折率の異なる物体間を移動するとき、屈折率の比の2乗の分だけ変化する
        // 屈折率が単位立体角あたりの値だから
        real nnt2 = nnt * nnt;
        real Tr = (1.f - Re) * nnt2;
        // 反射屈折両方トレース
        return Irradiance(reflRay, pathInfo, rand) * Re
             + Irradiance(Ray(x,tdir), pathInfo, rand).mult(color) * Tr;
    }
    
    // refl == LIGHT
    return ((AreaLightShape*)rec.pShape)->SelfIrradiance();
}