#include #include #include #include using namespace std; #include "pbrt_wrapper.cpp" #ifndef FLT_EPSILON #define FLT_EPSILON 1.192092896e-07F #endif #ifndef FLT_MAX #define FLT_MAX 3.402823466e+38F /* max value */ #endif float RandomFloat() { return (float)rand()/(float)RAND_MAX; } // L_r(1): specular reflection on the first hit: // when cos(wo)>0, i.e., entering, it is the contaminant-air interface // when cos(wo)<0, i.e., outgoing, it is the contaminant-glass interface // class DustyGlassSpecularReflectionDust { public: // DustyGlassSpecularReflectionDust Public Methods DustyGlassSpecularReflectionDust(float r_glass, float r_dust, float ior_air, float ior_dust, float ior_glass): R_glass(r_glass), R_dust(r_dust), fresnel_air_dust(ior_air, ior_dust), fresnel_dust_glass(ior_dust, ior_glass){} float Sample_f(const Vector &wo, Vector *wi, float u1, float u2, float *pdf) const; private: // DustyGlassSpecularReflectionDust Private Data float R_glass, R_dust; FresnelDielectric fresnel_air_dust; FresnelDielectric fresnel_dust_glass; }; // L_r(2): attenuated specular reflection (on the second hit) // when cos(wo)>0, light path is air-->contaminant-->glass-->contaminant-->air // when cos(wo)<0, light path is glass-->contaminant-->air-->contaminant-->glass // // so it involves two refractions, one reflection, and two attenuations. // class DustyGlassSpecularReflection { public: // DustyGlassSpecularReflection Public Methods DustyGlassSpecularReflection(float r_glass, float t_glass, float r_dust,float t_dust, float ior_air, float ior_dust, float ior_glass, float tau_dust): R_glass(r_glass), T_glass(t_glass), R_dust(r_dust), T_dust(t_dust), fresnel_air_dust(ior_air, ior_dust), fresnel_dust_glass(ior_dust, ior_glass), Tau(tau_dust){} float Sample_f(const Vector &wo, Vector *wi, float u1, float u2, float *pdf) const; private: // DustyGlassSpecularReflection Private Data float R_glass, T_glass, R_dust, T_dust; FresnelDielectric fresnel_air_dust; FresnelDielectric fresnel_dust_glass; float Tau; }; // L_t(1): attenuated transmission class DustyGlassSpecularTransmission { public: // DustyGlassSpecularTransmission Public Methods DustyGlassSpecularTransmission(float t_glass, float t_dust, float ior_air, float ior_dust, float ior_glass, float tau_dust) : T_glass(t_glass), T_dust(t_dust), fresnel_air_dust(ior_air, ior_dust), fresnel_dust_glass(ior_dust, ior_glass), Tau(tau_dust){} float Sample_f(const Vector &wo, Vector *wi, float u1, float u2, float *pdf) const; private: // DustyGlassSpecularTransmission Private Data float T_glass, T_dust; FresnelDielectric fresnel_air_dust; FresnelDielectric fresnel_dust_glass; float Tau; }; // L_r(3)+L_r(4): scattering components in reflection class DustyGlassDiffuseReflection { public: // DustyGlassDiffuseReflection Public Methods DustyGlassDiffuseReflection(float r_glass, float t_glass, float r_dust, float t_dust, float ior_air, float ior_dust, float ior_glass, float rho_dust, float tau_dust, float g_dust, int b_hk93) : R_glass(r_glass), T_glass(t_glass), R_dust(t_dust), T_dust(t_dust), fresnel_air_dust(ior_air, ior_dust), fresnel_dust_glass(ior_dust, ior_glass), rho(rho_dust), tau(tau_dust), g(g_dust), bHK93(b_hk93){ } float f(const Vector &, const Vector &) const; private: // DustyGlassDiffuseReflection Private Data float R_glass, T_glass, R_dust, T_dust; FresnelDielectric fresnel_air_dust; FresnelDielectric fresnel_dust_glass; float rho, tau, g; int bHK93; }; // L_t(2): scattering component in transmission class DustyGlassDiffuseTransmission { public: // DustyGlassDiffuseTransmission Public Methods DustyGlassDiffuseTransmission(float t_glass, float t_dust, float ior_air, float ior_dust, float ior_glass, float rho_dust, float tau_dust, float g_dust) : T_glass(t_glass), T_dust(t_dust), fresnel_air_dust(ior_air, ior_dust), fresnel_dust_glass(ior_dust, ior_glass), rho(rho_dust), tau(tau_dust), g(g_dust){ } float f(const Vector &, const Vector &) const; private: // DustyGlassDiffuseTransmission Private Data float T_glass, T_dust; FresnelDielectric fresnel_air_dust; FresnelDielectric fresnel_dust_glass; float rho, tau, g; }; // L_r(1) float DustyGlassSpecularReflectionDust::Sample_f(const Vector &wo, Vector *wi, float u1, float u2, float *pdf) const { bool entering = CosTheta(wo) > 0.f; if(entering) // mirror reflection on the air-contaminant interface { // if no interface between air and contaminant, this term is zero if(fresnel_air_dust.eta_i == fresnel_air_dust.eta_t) { return (0.f); } *wi = Vector(-wo.x, -wo.y, wo.z); *pdf = 1.f; float cosThetai = fabsf(CosTheta(*wi)); if(cosThetai 0.f; if(entering) { // if no interface between glass and contaminant, this term is zero if(fresnel_dust_glass.eta_i == fresnel_dust_glass.eta_t) { return (0.f); } if(T_dust==0 || R_glass==0) { return (0.f); } float weight(1.f), F; float ei = fresnel_air_dust.eta_i, et = fresnel_air_dust.eta_t; float sini2 = SinTheta2(wo); float eta = ei / et; float sint2 = eta * eta * sini2; if (sint2 > 1.) return 0.f; float cost = sqrtf(std::max(0.f, 1.f - sint2)); F = fresnel_air_dust.Evaluate(CosTheta(wo)); float TT = T_dust * ((1.f)-F); weight *= TT*TT; // Fresnel (the two Fresnel transmissions should be the same) float sintOverSini = eta; Vector wo1 = Vector(sintOverSini * -wo.x, sintOverSini * -wo.y, -cost); float cosThetaO1 = fabsf(CosTheta(wo1)); if(cosThetaO1 1.) return 0.f; float cost = sqrtf(std::max(0.f, 1.f - sint2)); float sintOverSini = eta; Vector wo1(sintOverSini * -wo.x, sintOverSini * -wo.y, cost); // Fresnel F = fresnel_dust_glass.Evaluate(CosTheta(wo)); float TT = T_glass * ((1.f)-F); weight *= TT * TT; // The two Fresnel transmissions are the same. float cosThetaO1 = fabsf(CosTheta(wo1)); if(cosThetaO1 0.f; if(entering) { float weight(1.f), F; float ei = fresnel_air_dust.eta_i, et = fresnel_air_dust.eta_t; float sini2 = SinTheta2(wo); float eta = ei / et; float sint2 = eta * eta * sini2; if (sint2 > 1.) return 0.f; F = fresnel_air_dust.Evaluate(CosTheta(wo)); weight *= T_dust * ((1.f)-F); // Fresnel float cost = sqrtf(std::max(0.f, 1.f - sint2)); float sintOverSini = eta; Vector wo1 = Vector(sintOverSini * -wo.x, sintOverSini * -wo.y, -cost); float cosThetao1 = fabsf(CosTheta(wo1)); if(cosThetao1 1.) return 0.f; cost = sqrtf(std::max(0.f, 1.f-sint2)); sintOverSini = eta; *wi = Vector(sintOverSini * -wo1.x, sintOverSini * -wo1.y, -cost); *pdf = 1.f; float cosThetai = fabsf(CosTheta(*wi)); if(cosThetai 1.) return 0.f; F = fresnel_dust_glass.Evaluate(CosTheta(wo)); weight *= T_glass * ((1.f)-F); // Fresnel float cost = sqrtf(std::max(0.f, 1.f - sint2)); float sintOverSini = eta; Vector wo1 = Vector(sintOverSini * -wo.x, sintOverSini * -wo.y, cost); float cosThetao1 = fabsf(CosTheta(wo1)); if(cosThetao1 1.) return 0.f; cost = sqrtf(std::max(0.f, 1.f-sint2)); sintOverSini = eta; *wi = Vector(sintOverSini * -wo1.x, sintOverSini * -wo1.y, cost); *pdf = 1.f; float cosThetai = fabsf(CosTheta(*wi)); if(cosThetai 0.f; if (entering) { if(T_dust==0) return (0.f); float weight(1.f), F; float ei = fresnel_air_dust.eta_i, et = fresnel_air_dust.eta_t; float sini2 = SinTheta2(wo); float eta = ei / et; float sint2 = eta * eta * sini2; if (sint2 > 1.) return 0.f; float cost = sqrtf(std::max(0.f, 1.f - sint2)); F = fresnel_air_dust.Evaluate(CosTheta(wo)); weight *= T_dust * ((1.f)-F); // Fresnel float sintOverSini = eta; Vector wo1 = Vector(sintOverSini * -wo.x, sintOverSini * -wo.y, -cost); sini2 = SinTheta2(wi); sint2 = eta * eta * sini2; if (sint2 > 1.) return 0.f; cost = sqrtf(max(0.f, 1.f-sint2)); F = fresnel_air_dust.Evaluate(CosTheta(wi)); weight *= T_dust * (float(1.f)-F); // Fresnel 1 sintOverSini = eta; Vector wi1 = Vector(sintOverSini * -wi.x, sintOverSini * -wi.y, -cost); // now, actual dust attenuation and scattering computation // first change to the contaminant-glass interface wo1 = -wo1; wi1 = -wi1; float cosThetaO = fabsf(CosTheta(wo1)); if(cosThetaO 1.) return 0.f; float sint2o = SinTheta2(wo); float sini2o = eta * eta * sint2o; if (sini2o > 1.) return 0.f; float cosi = sqrtf(std::max(0.f, 1.f - sini2)); float siniOverSint = eta; Vector wio(siniOverSint * -wi.x, siniOverSint * -wi.y, cosi); F = fresnel_dust_glass.Evaluate(CosTheta(wi)); weight *= T_glass*((1.)-F); float cosio = sqrtf(std::max(0.f, 1.f - sini2o)); float sinioOverSint = eta; Vector woi(sinioOverSint * -wo.x, sinioOverSint * -wo.y, cosio); F = fresnel_dust_glass.Evaluate(CosTheta(wo)); weight *= T_glass*((1.)-F); // Lr3: dust attenuation and scattering computation woi = -woi; wio = -wio; float cosThetaO = fabsf(CosTheta(woi)); if(cosThetaO 0.f; if (entering) { float weight(1.f), F; // get the wi inside the dust float ei = fresnel_dust_glass.eta_i, et = fresnel_dust_glass.eta_t; float sint2 = SinTheta2(wi); float eta = et / ei; float sini2 = eta * eta * sint2; if (sini2 > 1.) return 0.f; float cosi = sqrtf(std::max(0.f, 1.f - sini2)); float siniOverSint = eta; Vector wio(siniOverSint * -wi.x, siniOverSint * -wi.y, cosi); F = fresnel_dust_glass.Evaluate(CosTheta(wi)); weight *= T_glass * ((1.f)-F); // Fresnel // get the wo inside the dust ei = fresnel_air_dust.eta_i, et = fresnel_air_dust.eta_t; sini2 = SinTheta2(wo); eta = ei / et; sint2 = eta * eta * sini2; if (sint2 > 1.) return 0.f; float cost = sqrtf(std::max(0.f, 1.f - sint2)); float sintOverSini = eta; Vector wo1 = Vector(sintOverSini * -wo.x, sintOverSini * -wo.y, -cost); F = fresnel_air_dust.Evaluate(CosTheta(wo)); weight *= T_dust * ((1.f)-F); // Fresnel // now, actual dust attenuation and scattering computation wo1 = -wo1; float p = PhaseHG(wio,wo1,g); float fd = rho*p; float A1, A2, A; float cosThetaO = fabsf(CosTheta(wo1)); if(cosThetaO 1.) return 0.f; float cost = sqrtf(std::max(0.f, 1.f - sint2)); float sintOverSini = eta; Vector woi(sintOverSini * -wo.x, sintOverSini * -wo.y, cost); F = fresnel_dust_glass.Evaluate(CosTheta(wo)); weight *= T_glass * ((1.f)-F); // Fresnel // get the wi inside the dust ei = fresnel_air_dust.eta_i; et = fresnel_air_dust.eta_t; sini2 = SinTheta2(wi); eta = ei / et; sint2 = eta * eta * sini2; if (sint2 > 1.) return 0.f; cost = sqrtf(std::max(0.f, 1.f-sint2)); sintOverSini = eta; Vector wi1 = Vector(sintOverSini * -wi.x, sintOverSini * -wi.y, -cost); F = fresnel_air_dust.Evaluate(CosTheta(wi)); weight *= T_dust * ((1.f)-F); // Fresnel 1 // now actual dust attenuation and scattering computation woi = -woi; float p = PhaseHG(woi,wi1,g); float fd = rho*p; float A1, A2, A; float cosThetaI = fabsf(CosTheta(wi1)); if(cosThetaI 0) return m_Lr345->f(wo,wi); else return m_Lt2->f(wo,wi); } float DustyGlassOil::SpecularReflection(const Vector &wo, Vector *wi) { Vector wii; float pdf; // This function will be called as (wi, *wo). So we first use this to get // the outgoing direction (wo). But then when computing the BRDF, we should // switch back because our model is not symmetric. float f = m_Lr1->Sample_f(wo, wi, RandomFloat(), RandomFloat(), &pdf); if(f==0) { f = m_Lr2->Sample_f(wo, wi, RandomFloat(), RandomFloat(), &pdf); } f = m_Lr1->Sample_f(*wi, &wii, RandomFloat(), RandomFloat(), &pdf); f += m_Lr2->Sample_f(*wi, &wii, RandomFloat(), RandomFloat(), &pdf); return f; } float DustyGlassOil::SpecularTransmission(const Vector &wo, Vector *wi) { Vector wii; float pdf; float f = m_Lt1->Sample_f(wo, wi, RandomFloat(), RandomFloat(), &pdf); if(f!=0) f = m_Lt1->Sample_f(*wi, &wii, RandomFloat(), RandomFloat(), &pdf); return f; } void printHelp() { cout << "Tool for evaluation of the BRDF/BTDF model " << endl; cout << "for dirty glass (glass covered with a layer of scattering media) "<< endl; cout << "The illumination is collimated light (from top or from bottom)" << endl; cout << "" << endl; cout << "Usage: evaluator.exe dust_tau dust_g dust_albedo dust_ior theta_i ngrids outputfile [bHK93=0]" << endl; cout << "" << endl; cout << "dust_tau\t optical thickness of the contaminant. "<< endl; cout << " \t typical in (0,0.4) for good approximation" << endl; cout << "dust_g\t\t scattering parameter of the contaminant. in (-1,1)" << endl; cout << "dust_albedo\t albedo of single scattering. in (0,1). " << endl; cout << " \t typical less than 0.5 for good approximation" << endl; cout << "dust_ior\t refraction index of the contaminant." << endl; cout << "theta_i(wi)\t direction of the illumination. in (0,pi). " << endl; cout << " \t if less than pi/2, air2glass; otherwise glass2air " << endl; cout << "ngrids\t\t sampling points. wo will be span in (0,pi/2) and (pi/2, pi) " << endl; cout << " \t\t into ngrids" << endl; cout << "" << endl; cout << "Example: " << endl; cout << "\tevaluator.exe 0.4 0.7 0.5 1.0 0 200 result.txt" << endl; cout << "" << endl; cout << "Format of the output: " << endl; cout << "" << endl; cout << "There are 4 parts in the output file." << endl; cout << "The values are reflectance or transmittance" << endl; cout << "(i.e. physically corresponds to radiance (W/m2/sr)" << endl; cout << "So they are BRDF*cos(theta_i) or BTDF*cos(theta_i) " << endl; cout << "" << endl; cout << " Specular Reflectance (angle, value)" << endl; cout << " Diffuse Reflectance (angles, values)" << endl; cout << " Specular Transmission (angle, value)" << endl; cout << " Diffuse Transmission (angles values)" << endl; cout << "" << endl; cout << "Jinwei GU (jwgu@cs.columbia.edu). 2007/6/5" << endl; } int main(int argc, char* argv[]) { float Kr_glass = float(1.f); float Kt_glass = float(1.f); float Kr_dust = float(1.f); float Kt_dust = float(1.f); float index_glass = 1.5f; float index_air = 1.f; if(argc<8) { printHelp(); return 0; } srand(time(0)); float tau_dust = Clamp(atof(argv[1]), 0.f, FLT_MAX); float g_dust = Clamp(atof(argv[2]), -1.f, 1.f); float albedo_dust = Clamp(atof(argv[3]), 0.f, 1.f); float rho_dust = float(albedo_dust); float index_dust = Clamp(atof(argv[4]), 0.f, FLT_MAX); float theta_i = Clamp(atof(argv[5]), 0.f, M_PI); int ngrids = (int)Clamp(atoi(argv[6]), 1, INT_MAX); string outputfile = string(argv[7]); FILE* fp = fopen(outputfile.c_str(), "wt"); if(fp==NULL) { cout << "***Error: can not open file " << outputfile << endl; return 0; } int bHK93 = 0; if(argc>8) bHK93 = atoi(argv[8]); DustyGlassOil* dustyglass_oil = new DustyGlassOil(Kr_glass, Kt_glass, index_glass, index_air, index_dust, Kr_dust, Kt_dust, rho_dust, tau_dust, g_dust, bHK93); dustyglass_oil->GetBSDF(); float sini = sin(theta_i); float cosi = cos(theta_i); bool entering = cosi > 0.f; Vector wi = Vector(sini,0,cosi); Vector wo; float f; // Part 1: compute the specular reflectance f = dustyglass_oil->SpecularReflection(wi, &wo); f = f*fabs(cosi); fprintf(fp, "SpecularReflectance\n"); fprintf(fp, "wo %f %f %f\n", wo[0], wo[1], wo[2]); fprintf(fp, "R %f\n\n", f); // Part 2: compute the specular transmittance f = dustyglass_oil->SpecularTransmission(wi, &wo); f = f*fabs(cosi); fprintf(fp, "SpecularTransmittance\n"); fprintf(fp, "wo %f %f %f\n", wo[0], wo[1], wo[2]); fprintf(fp, "T %f\n\n", f); // Part 3: compute the diffuse reflecance fprintf(fp, "DiffuseReflectance\n"); for(int i=0; imy_f(wo, wi); f = f*fabs(cosi); fprintf(fp, "%f\t%f\n", thetao, f); } fprintf(fp, "\n"); // Part 4: compute the diffuse transmittance fprintf(fp, "DiffuseTransmittance\n"); for(int i=0; imy_f(wo, wi); f = f*fabs(cosi); fprintf(fp, "%f\t%f\n", thetao, f); } fprintf(fp, "\n"); dustyglass_oil->ReleaseBSDF(); delete dustyglass_oil; dustyglass_oil = NULL; fclose(fp); fp = NULL; }