void PhotonMap::ShootCausticsPhoton(const Vector &dir, const Vector &pi, const Color &color, Shape *shape, int depth) { if ( depth >= confPhotonCausticsMaximumDepth ) return; if ( depth != 0 && shape->mMaterial->MatchesBSDFFlags(BSDF_DIFFUSE) ) { // Diffuse material, add photon Photon *photon = new Photon(color, dir); AddPhoton(causticsMap, pi, photon); } else if ( shape->mMaterial->MatchesBSDFFlags(BSDF_SPECULAR) ) { // Specular material, continue build photon Vector N = shape->GetNormal(pi); for ( uint32_t i = 0; i < shape->mMaterial->BSDFs.size(); i++ ) { BSDF *bsdf = shape->mMaterial->BSDFs[i]; if ( !bsdf->MatchesFlags(BSDFType(BSDF_SPECULAR)) ) continue; Vector newDir; Color matColor; Vector *vos = NULL; int voNum = 0; if ( bsdf->G(-dir, vos, voNum, N, matColor, 1.f) ) { _ASSERT(voNum > 0); newDir = vos[0]; delete [] vos; vos = NULL; matColor *= shape->GetColor(pi); if ( matColor.IsBlack() ) continue; float dist = MAXDISTANCE; Shape *newShape; Vector norm = N.Dot(dir) > 0 ? -N : N; if ( bsdf->MatchesFlags(BSDF_TRANSMISSION) ) norm = -norm; if ( scene->FindNearest(Ray(pi + norm * EPSILON, newDir), dist, newShape) == IR_MISS ) continue; ShootCausticsPhoton(newDir, pi + newDir * dist, color * matColor, newShape, depth + 1); } } } }