Exemplo n.º 1
0
void Path::AdvancePath(PathRenderEngine *renderEngine, Sampler *sampler, const RayBuffer *rayBuffer,
		SampleBuffer *sampleBuffer) {
	SLGScene *scene = renderEngine->scene;

	//--------------------------------------------------------------------------
	// Select the path ray hit
	//--------------------------------------------------------------------------

	const RayHit *rayHit = NULL;
	switch (state) {
		case EYE_VERTEX:
			if (scene->volumeIntegrator) {
				rayHit = rayBuffer->GetRayHit(currentPathRayIndex);

				// Use Russian Roulette to check if I have to do participating media computation or not
				if (sample.GetLazyValue() <= scene->volumeIntegrator->GetRRProbability()) {
					Ray volumeRay(pathRay.o, pathRay.d, 0.f, rayHit->Miss() ? std::numeric_limits<float>::infinity() : rayHit->t);
					scene->volumeIntegrator->GenerateLiRays(scene, &sample, volumeRay, volumeComp);
					radiance += volumeComp->GetEmittedLight();

					if (volumeComp->GetRayCount() > 0) {
						// Do the EYE_VERTEX_VOLUME_STEP
						state = EYE_VERTEX_VOLUME_STEP;
						eyeHit = *(rayBuffer->GetRayHit(currentPathRayIndex));
						return;
					}
				}
			} else
				rayHit = rayBuffer->GetRayHit(currentPathRayIndex);
			break;
		case NEXT_VERTEX:
			rayHit = rayBuffer->GetRayHit(currentPathRayIndex);
			break;
		case EYE_VERTEX_VOLUME_STEP:
			// Add scattered light
			radiance += throughput * volumeComp->CollectResults(rayBuffer) / scene->volumeIntegrator->GetRRProbability();

			rayHit = &eyeHit;
			break;
		case TRANSPARENT_SHADOW_RAYS_STEP:
			rayHit = &eyeHit;
			break;
		case TRANSPARENT_ONLY_SHADOW_RAYS_STEP:
		case ONLY_SHADOW_RAYS:
			// Nothing
			break;
		default:
			assert(false);
			break;
	}

	//--------------------------------------------------------------------------
	// Finish direct light sampling
	//--------------------------------------------------------------------------

	if (((state == NEXT_VERTEX) ||
			(state == ONLY_SHADOW_RAYS) ||
			(state == TRANSPARENT_SHADOW_RAYS_STEP) ||
			(state == TRANSPARENT_ONLY_SHADOW_RAYS_STEP)) &&
			(tracedShadowRayCount > 0)) {
		unsigned int leftShadowRaysToTrace = 0;
		for (unsigned int i = 0; i < tracedShadowRayCount; ++i) {
			const RayHit *shadowRayHit = rayBuffer->GetRayHit(currentShadowRayIndex[i]);
			if (shadowRayHit->Miss()) {
				// Nothing was hit, light is visible
				radiance += lightColor[i] / lightPdf[i];
			} else {
				// Something was hit check if it is transparent
				const unsigned int currentShadowTriangleIndex = shadowRayHit->index;
				const unsigned int currentShadowMeshIndex = scene->dataSet->GetMeshID(currentShadowTriangleIndex);
				Material *triMat = scene->objectMaterials[currentShadowMeshIndex];

				if (triMat->IsShadowTransparent()) {
					// It is shadow transparent, I need to continue to trace the ray
					shadowRay[leftShadowRaysToTrace] = Ray(
							shadowRay[i](shadowRayHit->t),
							shadowRay[i].d,
							shadowRay[i].mint,
							shadowRay[i].maxt - shadowRayHit->t);

					lightColor[leftShadowRaysToTrace] = lightColor[i] * triMat->GetSahdowTransparency();
					lightPdf[leftShadowRaysToTrace] = lightPdf[i];
					leftShadowRaysToTrace++;
				} else {
					// Check if there is a texture with alpha
					TexMapInstance *tm = scene->objectTexMaps[currentShadowMeshIndex];

					if (tm) {
						const TextureMap *map = tm->GetTexMap();

						if (map->HasAlpha()) {
							const ExtMesh *mesh = scene->objects[currentShadowMeshIndex];
							const UV triUV = mesh->InterpolateTriUV(scene->dataSet->GetMeshTriangleID(currentShadowTriangleIndex),
									shadowRayHit->b1, shadowRayHit->b2);

							const float alpha = map->GetAlpha(triUV);

							if (alpha < 1.f) {
								// It is shadow transparent, I need to continue to trace the ray
								shadowRay[leftShadowRaysToTrace] = Ray(
										shadowRay[i](shadowRayHit->t),
										shadowRay[i].d,
										shadowRay[i].mint,
										shadowRay[i].maxt - shadowRayHit->t);

								lightColor[leftShadowRaysToTrace] = lightColor[i] * (1.f - alpha);
								lightPdf[leftShadowRaysToTrace] = lightPdf[i];
								leftShadowRaysToTrace++;
							}
						}
					}
				}
			}
		}

		if (leftShadowRaysToTrace > 0) {
			tracedShadowRayCount = leftShadowRaysToTrace;
			if ((state == ONLY_SHADOW_RAYS) || (state == TRANSPARENT_ONLY_SHADOW_RAYS_STEP))
				state = TRANSPARENT_ONLY_SHADOW_RAYS_STEP;
			else {
				eyeHit = *rayHit;
				state = TRANSPARENT_SHADOW_RAYS_STEP;
			}

			return;
		}
	}

	//--------------------------------------------------------------------------
	// Calculate next step
	//--------------------------------------------------------------------------

	depth++;

	const bool missed = rayHit ? rayHit->Miss() : false;
	if (missed ||
			(state == ONLY_SHADOW_RAYS) ||
			(state == TRANSPARENT_ONLY_SHADOW_RAYS_STEP) ||
			(depth >= renderEngine->maxPathDepth)) {
		if (missed && scene->infiniteLight && (scene->useInfiniteLightBruteForce || specularBounce)) {
			// Add the light emitted by the infinite light
			radiance += scene->infiniteLight->Le(pathRay.d) * throughput;
		}

		// Hit nothing/only shadow rays/maxdepth, terminate the path
		sampleBuffer->SplatSample(sample.screenX, sample.screenY, radiance);
		// Restart the path
		Init(renderEngine, sampler);
		return;
	}

	// Something was hit
	const unsigned int currentTriangleIndex = rayHit->index;
	const unsigned int currentMeshIndex = scene->dataSet->GetMeshID(currentTriangleIndex);

	// Get the triangle
	const ExtMesh *mesh = scene->objects[currentMeshIndex];
	const unsigned int triIndex = scene->dataSet->GetMeshTriangleID(currentTriangleIndex);

	// Get the material
	const Material *triMat = scene->objectMaterials[currentMeshIndex];

	// Check if it is a light source
	if (triMat->IsLightSource()) {
		if (specularBounce) {
			// Only TriangleLight can be directly hit
			const LightMaterial *mLight = (LightMaterial *) triMat;
			Spectrum Le = mLight->Le(mesh, triIndex, -pathRay.d);

			radiance += Le * throughput;
		}

		// Terminate the path
		sampleBuffer->SplatSample(sample.screenX, sample.screenY, radiance);
		// Restart the path
		Init(renderEngine, sampler);
		return;
	}

	//--------------------------------------------------------------------------
	// Build the shadow rays (if required)
	//--------------------------------------------------------------------------

	// Interpolate face normal
	Normal N = mesh->InterpolateTriNormal(triIndex, rayHit->b1, rayHit->b2);

	const SurfaceMaterial *triSurfMat = (SurfaceMaterial *) triMat;
	const Point hitPoint = pathRay(rayHit->t);
	const Vector wo = -pathRay.d;

	Spectrum surfaceColor;
	if (mesh->HasColors())
		surfaceColor = mesh->InterpolateTriColor(triIndex, rayHit->b1, rayHit->b2);
	else
		surfaceColor = Spectrum(1.f, 1.f, 1.f);

	// Check if I have to apply texture mapping or normal mapping
	TexMapInstance *tm = scene->objectTexMaps[currentMeshIndex];
	BumpMapInstance *bm = scene->objectBumpMaps[currentMeshIndex];
	NormalMapInstance *nm = scene->objectNormalMaps[currentMeshIndex];
	if (tm || bm || nm) {
		// Interpolate UV coordinates if required
		const UV triUV = mesh->InterpolateTriUV(triIndex, rayHit->b1, rayHit->b2);

		// Check if there is an assigned texture map
		if (tm) {
			const TextureMap *map = tm->GetTexMap();

			// Apply texture mapping
			surfaceColor *= map->GetColor(triUV);

			// Check if the texture map has an alpha channel
			if (map->HasAlpha()) {
				const float alpha = map->GetAlpha(triUV);

				if ((alpha == 0.0f) || ((alpha < 1.f) && (sample.GetLazyValue() > alpha))) {
					pathRay = Ray(pathRay(rayHit->t), pathRay.d, RAY_EPSILON, pathRay.maxt - rayHit->t);
					state = NEXT_VERTEX;
					tracedShadowRayCount = 0;
					return;
				}
			}
		}

		// Check if there is an assigned bump/normal map
		if (bm || nm) {
			if (nm) {
				// Apply normal mapping
				const Spectrum color = nm->GetTexMap()->GetColor(triUV);

				const float x = 2.f * (color.r - 0.5f);
				const float y = 2.f * (color.g - 0.5f);
				const float z = 2.f * (color.b - 0.5f);

				Vector v1, v2;
				CoordinateSystem(Vector(N), &v1, &v2);
				N = Normalize(Normal(
						v1.x * x + v2.x * y + N.x * z,
						v1.y * x + v2.y * y + N.y * z,
						v1.z * x + v2.z * y + N.z * z));
			}

			if (bm) {
				// Apply bump mapping
				const TextureMap *map = bm->GetTexMap();
				const UV &dudv = map->GetDuDv();

				const float b0 = map->GetColor(triUV).Filter();

				const UV uvdu(triUV.u + dudv.u, triUV.v);
				const float bu = map->GetColor(uvdu).Filter();

				const UV uvdv(triUV.u, triUV.v + dudv.v);
				const float bv = map->GetColor(uvdv).Filter();

				const float scale = bm->GetScale();
				const Vector bump(scale * (bu - b0), scale * (bv - b0), 1.f);

				Vector v1, v2;
				CoordinateSystem(Vector(N), &v1, &v2);
				N = Normalize(Normal(
						v1.x * bump.x + v2.x * bump.y + N.x * bump.z,
						v1.y * bump.x + v2.y * bump.y + N.y * bump.z,
						v1.z * bump.x + v2.z * bump.y + N.z * bump.z));
			}
		}
	}

	// Flip the normal if required
	Normal shadeN = (Dot(pathRay.d, N) > 0.f) ? -N : N;

	tracedShadowRayCount = 0;
	const bool skipInfiniteLight = !renderEngine->onlySampleSpecular;
	const unsigned int lightCount = scene->GetLightCount(skipInfiniteLight);
	if (triSurfMat->IsDiffuse() && (scene->GetLightCount(skipInfiniteLight) > 0)) {
		// Direct light sampling: trace shadow rays

		switch (renderEngine->lightStrategy) {
			case ALL_UNIFORM: {
				// ALL UNIFORM direct sampling light strategy
				const Spectrum lightThroughtput = throughput * surfaceColor;

				for (unsigned int j = 0; j < lightCount; ++j) {
					// Select the light to sample
					const LightSource *light = scene->GetLight(j, skipInfiniteLight);

					for (unsigned int i = 0; i < renderEngine->shadowRayCount; ++i) {
						// Select a point on the light surface
						lightColor[tracedShadowRayCount] = light->Sample_L(
								scene, hitPoint, &shadeN,
								sample.GetLazyValue(), sample.GetLazyValue(), sample.GetLazyValue(),
								&lightPdf[tracedShadowRayCount], &shadowRay[tracedShadowRayCount]);

						// Scale light pdf for ALL_UNIFORM strategy
						lightPdf[tracedShadowRayCount] *= renderEngine->shadowRayCount;

						if (lightPdf[tracedShadowRayCount] <= 0.0f)
							continue;

						const Vector lwi = shadowRay[tracedShadowRayCount].d;
						lightColor[tracedShadowRayCount] *= lightThroughtput * Dot(shadeN, lwi) *
								triSurfMat->f(wo, lwi, shadeN);

						if (!lightColor[tracedShadowRayCount].Black())
							tracedShadowRayCount++;
					}
				}
				break;
			}
			case ONE_UNIFORM: {
				// ONE UNIFORM direct sampling light strategy
				const Spectrum lightThroughtput = throughput * surfaceColor;

				for (unsigned int i = 0; i < renderEngine->shadowRayCount; ++i) {
					// Select the light to sample
					float lightStrategyPdf;
					const LightSource *light = scene->SampleAllLights(sample.GetLazyValue(),
							&lightStrategyPdf, skipInfiniteLight);

					// Select a point on the light surface
					lightColor[tracedShadowRayCount] = light->Sample_L(
							scene, hitPoint, &shadeN,
							sample.GetLazyValue(), sample.GetLazyValue(), sample.GetLazyValue(),
							&lightPdf[tracedShadowRayCount], &shadowRay[tracedShadowRayCount]);

					if (lightPdf[tracedShadowRayCount] <= 0.f)
						continue;

					const Vector lwi = shadowRay[tracedShadowRayCount].d;
					lightColor[tracedShadowRayCount] *= lightThroughtput * Dot(shadeN, lwi) *
							triSurfMat->f(wo, lwi, shadeN);

					if (!lightColor[tracedShadowRayCount].Black()) {
						lightPdf[tracedShadowRayCount] *= lightStrategyPdf * renderEngine->shadowRayCount;
						tracedShadowRayCount++;
					}
				}
				break;
			}
			default:
				assert(false);
		}
	}

	//--------------------------------------------------------------------------
	// Build the next vertex path ray
	//--------------------------------------------------------------------------

	float fPdf;
	Vector wi;
	const Spectrum f = triSurfMat->Sample_f(wo, &wi, N, shadeN,
			sample.GetLazyValue(), sample.GetLazyValue(), sample.GetLazyValue(),
			renderEngine->onlySampleSpecular, &fPdf, specularBounce) * surfaceColor;
	if ((fPdf <= 0.f) || f.Black()) {
		if (tracedShadowRayCount > 0)
			state = ONLY_SHADOW_RAYS;
		else {
			// Terminate the path
			sampleBuffer->SplatSample(sample.screenX, sample.screenY, radiance);
			// Restart the path
			Init(renderEngine, sampler);
		}

		return;
	}

	throughput *= f / fPdf;

	if (depth > renderEngine->rrDepth) {
		// Russian Roulette
		switch (renderEngine->rrStrategy) {
			case PROBABILITY: {
				if (renderEngine->rrProb >= sample.GetLazyValue())
					throughput /= renderEngine->rrProb;
				else {
					// Check if terminate the path or I have still to trace shadow rays
					if (tracedShadowRayCount > 0)
						state = ONLY_SHADOW_RAYS;
					else {
						// Terminate the path
						sampleBuffer->SplatSample(sample.screenX, sample.screenY, radiance);
						// Restart the path
						Init(renderEngine, sampler);
					}

					return;
				}
				break;
			}
			case IMPORTANCE: {
				const float prob = Max(throughput.Filter(), renderEngine->rrImportanceCap);
				if (prob >= sample.GetLazyValue())
					throughput /= prob;
				else {
					// Check if terminate the path or I have still to trace shadow rays
					if (tracedShadowRayCount > 0)
						state = ONLY_SHADOW_RAYS;
					else {
						// Terminate the path
						sampleBuffer->SplatSample(sample.screenX, sample.screenY, radiance);
						// Restart the path
						Init(renderEngine, sampler);
					}

					return;
				}
				break;
			}
			default:
				assert(false);
		}
	}

	pathRay.o = hitPoint;
	pathRay.d = wi;
	state = NEXT_VERTEX;
}
Exemplo n.º 2
0
    Color3f Li(const Scene *scene, Sampler *sampler, const Ray3f &ray) const {
        /* Find the surface that is visible in the requested direction */
        Intersection its;

        //check if the ray intersects the scene
        if (!scene->rayIntersect(ray, its)) {
            //check if a distant disk light is set
            const Emitter* distantsDisk = scene->getDistantEmitter();
            if(distantsDisk == nullptr ) return Color3f(0.0f);

            //sample the distant disk light
            Vector3f d = ray.d;
            return distantsDisk->sampleL(d);
        }

        //get the Number of lights from the scene
        const  std::vector<Emitter *> lights = scene->getEmitters();
        uint32_t nLights = lights.size();

        Color3f tp(1.0f, 1.0f, 1.0f);
        Color3f L(0.0f, 0.0f, 0.0f);
        Ray3f pathRay(ray.o, ray.d);

        bool deltaFlag = true;

        while(true) {

            if (its.mesh->isEmitter() && deltaFlag) {
                const Emitter* areaLightEM = its.mesh->getEmitter();
                const areaLight* aEM = static_cast<const areaLight *> (areaLightEM);
                L += tp * aEM->sampleL(-pathRay.d, its.shFrame.n, its);
            }

            //Light sampling
            //randomly select a lightsource
            uint32_t var = uint32_t(std::min(sampler->next1D()*nLights, float(nLights) - 1.0f));

            //init the light color
            Color3f Li(0.0f, 0.0f, 0.0f);
            Color3f Ld(1.0f, 1.0f, 1.0f);

            //create a sample for the light
            const BSDF* curBSDF = its.mesh->getBSDF();
            const Point2f lightSample = sampler->next2D();
            VisibilityTester vis;
            Vector3f wo;
            float lightpdf;
            float bsdfpdf;
            Normal3f n = its.shFrame.n;

            deltaFlag = curBSDF->isDeltaBSDF();

            //sample the light

            {
                Li = lights[var]->sampleL(its.p, Epsilon, lightSample , &wo, &lightpdf, &vis);
                lightpdf /= float(nLights);
                //check if the pdf of the sample is greater than 0 and if the color is not black
                if(lightpdf > 0 && Li.maxCoeff() != 0.0f) {
                    //calculate the cosine term wi in my case the vector to the light
                    float cosTerm = std::abs(n.dot(wo));
                    const BSDFQueryRecord queryEM = BSDFQueryRecord(its.toLocal(- pathRay.d), its.toLocal(wo), EMeasure::ESolidAngle, sampler);
                    Color3f f = curBSDF->eval(queryEM);

                    if(f.maxCoeff() > 0.0f && f.minCoeff() >= 0.0f && vis.Unoccluded(scene)) {
                        bsdfpdf = curBSDF->pdf(queryEM);
                        float weight = BalanceHeuristic(float(1), lightpdf, float(1), bsdfpdf);
                        if(curBSDF->isDeltaBSDF())  weight = 1.0f;
                        if(bsdfpdf > 0.0f) {
                            Ld = (weight * f * Li * cosTerm) / lightpdf;
                            L += tp * Ld;
                        } else {
                            //cout << "bsdfpdf = " << bsdfpdf  << endl;
                            //cout << "f = " << f  << endl;
                        }
                    }
                }
            }

            //Material part
            BSDFQueryRecord queryMats = BSDFQueryRecord(its.toLocal(-pathRay.d), Vector3f(0.0f), EMeasure::ESolidAngle, sampler);

            Color3f fi =  curBSDF->sample(queryMats, sampler->next2D());
            bsdfpdf = curBSDF->pdf(queryMats);
            lightpdf = 0.0f;
            if(fi.maxCoeff() > 0.0f && fi.minCoeff() >= 0.0f) {
                if(bsdfpdf > 0.0f) {
                    Ray3f shadowRay(its.p, its.toWorld(queryMats.wo));
                    Intersection lightIsect;

                     if (scene->rayIntersect(shadowRay, lightIsect)) {
                         if(lightIsect.mesh->isEmitter()){
                            const Emitter* areaLightEMcur = lightIsect.mesh->getEmitter();
                            const areaLight* aEMcur = static_cast<const areaLight *> (areaLightEMcur);

                            Li = aEMcur->sampleL(-shadowRay.d, lightIsect.shFrame.n, lightIsect);
                            lightpdf = aEMcur->pdf(its.p, (lightIsect.p - its.p).normalized(), lightIsect.p, Normal3f(lightIsect.shFrame.n));
                         }
                     } else {
                         const Emitter* distantsDisk = scene->getDistantEmitter();
                         if(distantsDisk != nullptr ) {
                             //check if THIS is right!
                             Li = distantsDisk->sampleL(lightIsect.toWorld(queryMats.wo));
                             lightpdf = distantsDisk->pdf(Point3f(0.0f), wo, Point3f(0.0f), Normal3f(0.0f));
                         }
                     }
                     lightpdf /= float(nLights);
                     //calculate the weights
                     float weight = BalanceHeuristic(float(1), bsdfpdf, float(1), lightpdf);


                     //check if the lightcolor is not black
                     if(Li.maxCoeff() > 0.0f  && lightpdf > 0.0f ) {
                         //wo in my case the vector to the light
                         Ld = weight * Li * fi;
                         L += tp * Ld;
                     }
                }



                 tp *= fi;
            } else {
                break;
            }

            wo = its.toWorld(queryMats.wo);
            pathRay = Ray3f(its.p, wo);

            if (!scene->rayIntersect(pathRay, its)) {
                const Emitter* distantsDisk = scene->getDistantEmitter();
                if(distantsDisk != nullptr ) {
                    //sample the distant disk light
                    Vector3f d = pathRay.d;
                    L += tp * distantsDisk->sampleL(d);
                }


                break;
            }

            float maxCoeff = tp.maxCoeff();
            float q = std::min(0.99f, maxCoeff);
            if(q < sampler->next1D()){
                break;
            }
            tp /= q;
        }

        return L;

    }
Exemplo n.º 3
0
    Color3f Li(const Scene *scene, Sampler *sampler, const Ray3f &ray) const {
        /* Find the surface that is visible in the requested direction */
        Intersection its;


        //check if the ray intersects the scene
        if (!scene->rayIntersect(ray, its)) {
            return Color3f(0.0f);
        }

        Color3f tp(1.0f, 1.0f, 1.0f);
        Color3f L(0.0f, 0.0f, 0.0f);
        Ray3f pathRay(ray.o, ray.d);
        while(true) {

            //get the radiance of hitten object

            if (its.mesh->isEmitter() ) {
                const Emitter* areaLightEM = its.mesh->getEmitter();
                const areaLight* aEM = static_cast<const areaLight *> (areaLightEM);
                L += tp * aEM->sampleL(-pathRay.d, its.shFrame.n, its);
            }

            //get the asigned BSDF
            const BSDF* curBSDF = its.mesh->getBSDF();

            //transform to the local frame
            BSDFQueryRecord query = BSDFQueryRecord(its.toLocal(-pathRay.d), Vector3f(0.0f), EMeasure::ESolidAngle);

            //Normal3f n = its.shFrame.n;



            if(curBSDF->isDiffuse()) {
                std::vector<uint32_t> results;
                m_photonMap->search(its.p, m_photonRadius, results);
                Color3f Li(0.0f, 0.0f, 0.0f);
                int k = results.size();
                //cout << k << endl;

                if(k > 0) {

                    //cout << results.size() << " Photons found!" << endl;
                    //get the power from all photons
                    //for (uint32_t i : results)
                    //const Photon &photonk = (*m_photonMap)[k-1];
                    Color3f Lindir(0.0f, 0.0f, 0.0f);
                    for (int i = 0; i < k; ++i)
                    {
                        const Photon &photon = (*m_photonMap)[results[i]];
                        Vector3f wi = its.toLocal(photon.getDirection());
                        Vector3f wo = its.toLocal(its.shFrame.n);
                        BSDFQueryRecord dummy = BSDFQueryRecord(wi, wo, EMeasure::ESolidAngle);
                        Color3f f = curBSDF->eval(dummy);


                        Lindir += (tp * f) * photon.getPower() / (M_PI * m_photonRadius * m_photonRadius);


                    }

                    Li += Lindir;

                    //cout << "Li = " <<  Li.toString() << endl;
                    if(Li.maxCoeff() > 0.0f)
                        L +=  Li  / m_shootedRays;

                }
                break;
            }

            //sample the BRDF
            Color3f fi =  curBSDF->sample(query, sampler->next2D());
            //check for black brdf
            if(fi.maxCoeff() > 0.0f) {
                tp *= fi;
            } else {
                //stop
                // hit a black brdf
                break;
            }
            Vector3f wo = its.toWorld(query.wo);
            pathRay = Ray3f(its.p, wo);

            //ray escapes the scene
            if (!scene->rayIntersect(pathRay, its)) break;


            //stop critirium russian roulette
            float maxCoeff = tp.maxCoeff();
            float q = std::min(0.99f, maxCoeff);
            if(q < sampler->next1D()) break;
            tp /= q;
        }
        return L;
    }