void CAngularSpectralProperties::calculateAngularProperties( std::shared_ptr<CSpectralSample> const & t_SpectralSample, MaterialType const t_Type) { assert(t_SpectralSample != nullptr); auto aMeasuredData = t_SpectralSample->getMeasuredData(); if(m_Angle != 0) { auto aSourceData = t_SpectralSample->getSourceData(); auto aWavelengths = aMeasuredData->getWavelengths(); auto aT = aMeasuredData->properties(SampleData::T); assert(aT->size() == aWavelengths.size()); auto aRf = aMeasuredData->properties(SampleData::Rf); assert(aRf->size() == aWavelengths.size()); auto aRb = aMeasuredData->properties(SampleData::Rb); assert(aRb->size() == aWavelengths.size()); auto lowLambda = 0.3; auto highLambda = 2.5; // TODO: Only one side is measured and it is considered that front properties are equal // to back properties auto aTSolNorm = t_SpectralSample->getProperty(lowLambda, highLambda, Property::T, Side::Front); for(size_t i = 0; i < aWavelengths.size(); ++i) { auto ww = aWavelengths[i] * 1e-6; auto T = (*aT)[i].value(); auto Rf = (*aRf)[i].value(); auto Rb = (*aRb)[i].value(); auto aSurfaceType = coatingType.at(t_Type); auto aFrontFactory = CAngularPropertiesFactory(T, Rf, m_Thickness, aTSolNorm); auto aBackFactory = CAngularPropertiesFactory(T, Rb, m_Thickness, aTSolNorm); auto aFrontProperties = aFrontFactory.getAngularProperties(aSurfaceType); auto aBackProperties = aBackFactory.getAngularProperties(aSurfaceType); auto Tangle = aFrontProperties->transmittance(m_Angle, ww); auto Rfangle = aFrontProperties->reflectance(m_Angle, ww); auto Rbangle = aBackProperties->reflectance(m_Angle, ww); m_AngularData->addRecord(ww * 1e6, Tangle, Rfangle, Rbangle); } } else { m_AngularData = aMeasuredData; } }
bool Tracer::scatterRefractive(const IntersectDescr& node, Ray& ray) const { // here we throw the dice to dices whether to reflect or to refract const double probability = ::uniform_distrib_( ::rand_gen_ ); // heuristic to determine material transition // note, this assumes that only one type of refractive material exists AND // that two objects do not intersect, such that an interface within a // non-air material exists (well, its not that strict, but simpler to // explain this way) const double surface_dot = node.normal_.dot( node.incident_ ); const bool is_entry = ( surface_dot <= 0. ); // 1.52 is for crown glass const double refractive_idx_from = is_entry ? 1.0 : 1.52; const double refractive_idx_to = is_entry ? 1.52 : 1.0; // The reflectance and refract functions require the normal to point into // the direction of the first material. If this is not the case, we invert // its direction. const Vector corrected_normal = is_entry ? node.normal_ : -1. * node.normal_; const double reflect = reflectance( corrected_normal, node.incident_, refractive_idx_from, refractive_idx_to ); if( probability <= reflect ) { return scatterSpecular( node, ray ); } else { Vector refracted_dir = refract( corrected_normal, node.incident_, refractive_idx_from, refractive_idx_to ); if( refracted_dir.length() > 1e-4 ) { ray = Ray{ node.point_, refracted_dir.normalized() }; return true; } else { return false; } } return false; // should never get here, though }
a3Spectrum a3Dieletric::sample(const t3Vector3f& wi, t3Vector3f& wo, float* pdf, const a3Intersection& its) const { static a3Random random; t3Vector3f n = its.getNormal(); // 入射光 / 出射光所在折射率 float etai = 1.0f, etat = its.shape->refractiveIndex; // 光密到光疏 if(wi.dot(n) > 0) { t3Math::swap(etai, etat); // 翻转法线 保持与入射光线一个平面 n = -n; } float eta = etai / etat; // 菲涅尔反射(反射的概率) //float Fr = a3FresnelDielectric(costhetai, costhetat, etai, etat); float Fr = reflectance(n, wi, etai, etat); //float P = 0.25 + 0.5 * Fr; float r = random.randomFloat(); if(r > Fr) { bool TIR = false; wo = refract(n, wi, etai, etat, TIR); *pdf = 1.0f; eta = 1 / eta; return getColor(its) * specularTransmittance / t3Math::Abs(wo.dot(n)); } else { wo = reflect(n, wi); *pdf = 1.0f; // 镜面反射 return getColor(its) * specularReflectance / t3Math::Abs(wo.dot(n)); } }