void UniformResamplingRecursiveMISBPTRenderer::connectLightVerticesToSensor(uint32_t threadID, uint32_t tileID, const Vec4u& viewport) const {
    auto rcpPathCount = 1.f / m_nLightPathCount;

    auto mis = [&](float v) {
        return Mis(v);
    };

    for(const auto& directImportanceSample: m_DirectImportanceSampleTilePartitionning[tileID]) {
        auto pLightVertex = &m_LightPathBuffer[directImportanceSample.m_nLightVertexIndex];

        auto totalDepth = 1 + pLightVertex->m_nDepth;
        if(!acceptPathDepth(totalDepth) || totalDepth > m_nMaxDepth) {
            continue;
        }

        auto pixel = directImportanceSample.m_Pixel;
        auto pixelID = BnZ::getPixelIndex(pixel, getFramebufferSize());

        PixelSensor sensor(getSensor(), pixel, getFramebufferSize());

        auto contrib = rcpPathCount * connectVertices(*pLightVertex,
                                       SensorVertex(&sensor, directImportanceSample.m_LensSample),
                                       getScene(), m_nLightPathCount, mis);

        if(isInvalidMeasurementEstimate(contrib)) {
            reportInvalidContrib(threadID, tileID, pixelID, [&]() {
                debugLog() << "s = " << (pLightVertex->m_nDepth + 1) << ", t = " << 1 << std::endl;
            });
        }

        accumulate(FINAL_RENDER, pixelID, Vec4f(contrib, 0.f));
        accumulate(FINAL_RENDER_DEPTH1 + totalDepth - 1u, pixelID, Vec4f(contrib, 0.f));

        auto strategyOffset = computeBPTStrategyOffset(totalDepth + 1, pLightVertex->m_nDepth + 1);
        accumulate(BPT_STRATEGY_s0_t2 + strategyOffset, pixelID, Vec4f(contrib, 0));
    }
}
void UniformResamplingRecursiveMISBPTRenderer::processSample(uint32_t threadID, uint32_t tileID, uint32_t pixelID, uint32_t sampleID,
                       uint32_t x, uint32_t y) const {
    auto mis = [&](float v) {
        return Mis(v);
    };
    ThreadRNG rng(*this, threadID);

    PixelSensor pixelSensor(getSensor(), Vec2u(x, y), getFramebufferSize());

    auto pixelSample = getPixelSample(threadID, sampleID);
    auto sensorSample = getFloat2(threadID);

    auto fImportanceScale = 1.f / getSppCount();
    BDPTPathVertex eyeVertex(getScene(), pixelSensor, sensorSample, pixelSample, m_nLightPathCount, mis);

    if(eyeVertex.m_Power == zero<Vec3f>() || !eyeVertex.m_fPathPdf) {
        return;
    }

    // Sample the light path to connect with the eye path
    auto lightPathIdx = clamp(std::size_t(getFloat(threadID) * m_nLightPathCount),
                              std::size_t(0),
                              m_nLightPathCount - 1);
    auto pLightPath = m_LightPathBuffer.getSlicePtr(lightPathIdx);

    auto maxEyePathDepth = getMaxEyePathDepth();
    auto maxLightPathDepth = getMaxLightPathDepth();


    auto extendEyePath = [&]() -> bool {
        return eyeVertex.m_nDepth < maxEyePathDepth &&
            eyeVertex.extend(eyeVertex, getScene(), getSppCount(), false, rng, mis);
    };

    // Iterate over an eye path
    do {
        // Intersection with light source
        auto totalLength = eyeVertex.m_nDepth;
        if(acceptPathDepth(totalLength) && totalLength <= m_nMaxDepth) {
            auto contrib = fImportanceScale * computeEmittedRadiance(eyeVertex, getScene(), m_LightSampler, getSppCount(), mis);

            if(isInvalidMeasurementEstimate(contrib)) {
                reportInvalidContrib(threadID, tileID, pixelID, [&]() {
                    debugLog() << "s = " << 0 << ", t = " << (eyeVertex.m_nDepth + 1) << std::endl;
                });
            }

            accumulate(FINAL_RENDER, pixelID, Vec4f(contrib, 0));
            accumulate(FINAL_RENDER_DEPTH1 + totalLength - 1u, pixelID, Vec4f(contrib, 0));

            auto strategyOffset = computeBPTStrategyOffset(totalLength + 1, 0u);
            accumulate(BPT_STRATEGY_s0_t2 + strategyOffset, pixelID, Vec4f(contrib, 0));
        }

        // Connections
        if(eyeVertex.m_Intersection) {
            // Direct illumination
            auto totalLength = eyeVertex.m_nDepth + 1;
            if(acceptPathDepth(totalLength) && totalLength <= m_nMaxDepth) {
                float lightPdf;
                auto pLight = m_LightSampler.sample(getScene(), getFloat(threadID), lightPdf);
                auto s2D = getFloat2(threadID);
                auto contrib = fImportanceScale * connectVertices(eyeVertex, EmissionVertex(pLight, lightPdf, s2D), getScene(), getSppCount(), mis);

                if(isInvalidMeasurementEstimate(contrib)) {
                    reportInvalidContrib(threadID, tileID, pixelID, [&]() {
                        debugLog() << "s = " << 1 << ", t = " << (eyeVertex.m_nDepth + 1) << std::endl;
                    });
                }

                accumulate(FINAL_RENDER, pixelID, Vec4f(contrib, 0));
                accumulate(FINAL_RENDER_DEPTH1 + totalLength - 1u, pixelID, Vec4f(contrib, 0));

                auto strategyOffset = computeBPTStrategyOffset(totalLength + 1, 1);
                accumulate(BPT_STRATEGY_s0_t2 + strategyOffset, pixelID, Vec4f(contrib, 0));
            }

            // Connection with each light vertex
            for(auto j = 0u; j < maxLightPathDepth; ++j) {
                auto pLightVertex = pLightPath + j;
                auto totalLength = eyeVertex.m_nDepth + pLightVertex->m_nDepth + 1;

                if(pLightVertex->m_fPathPdf > 0.f && acceptPathDepth(totalLength) && totalLength <= m_nMaxDepth) {
                    auto contrib = fImportanceScale * connectVertices(eyeVertex, *pLightVertex, getScene(), getSppCount(), mis);

                    if(isInvalidMeasurementEstimate(contrib)) {
                        reportInvalidContrib(threadID, tileID, pixelID, [&]() {
                            debugLog() << "s = " << (pLightVertex->m_nDepth + 1) << ", t = " << (eyeVertex.m_nDepth + 1) << std::endl;
                        });
                    }

                    accumulate(FINAL_RENDER, pixelID, Vec4f(contrib, 0));
                    accumulate(FINAL_RENDER_DEPTH1 + totalLength - 1u, pixelID, Vec4f(contrib, 0));

                    auto strategyOffset = computeBPTStrategyOffset(totalLength + 1, pLightVertex->m_nDepth + 1);
                    accumulate(BPT_STRATEGY_s0_t2 + strategyOffset, pixelID, Vec4f(contrib, 0));
                }
            }
        }
    } while(extendEyePath());
}
コード例 #3
0
void BidirPathTracing::runIteration(int iter)
{
	lightPathNum = height * width;
	cameraPathNum = lightPathNum;

	lightStateIndex.resize(lightPathNum);
	memset(&lightStateIndex[0] , 0 , lightStateIndex.size() * sizeof(int));

	lightStates.reserve(lightPathNum);
	lightStates.clear();

	cameraStates.reserve(cameraPathNum);
	cameraStates.clear();

	// generating light paths
	for (int pathIndex = 0; pathIndex < lightPathNum; pathIndex++)
	{
		BidirPathState lightState;

		bool deltaLight;
		generateLightSample(lightState);

		int s = 1;

		for (;; lightState.pathLength++ , s++)
		{
			Ray ray(lightState.origin + lightState.dir * EPS ,
				lightState.dir);
			Intersection inter;
			if (scene.intersect(ray , inter) == NULL)
				break;

			Vector3 hitPos = inter.p;

			BSDF bsdf(-ray.dir , inter , scene);
			if (!bsdf.isValid())
				break;

			lightState.pos = hitPos;
			lightState.bsdf = bsdf;

			if (lightState.pathLength > 1 || lightState.isFiniteLight)
			{
				lightState.dVCM *= mis(SQR(inter.t));
			}
			lightState.dVCM /= mis(std::abs(bsdf.cosWi()));
			lightState.dVC /= mis(std::abs(bsdf.cosWi()));
			
			if (!bsdf.isDelta)
				lightStates.push_back(lightState);

			// connect to camera
			if (!bsdf.isDelta)
			{
				if (lightState.pathLength + 1 >= minPathLength 
					&& lightState.pathLength + 1 == controlLength)
				{
					Vector3 imagePos = scene.camera.worldToRaster.tPoint(hitPos);
					if (scene.camera.checkRaster(imagePos.x , imagePos.y))
					{
						Color3 res = connectToCamera(lightState , hitPos , bsdf);

						// weight
						//Real weight = 1.f / (lightState.pathLength + 1 - lightState.specularVertexNum);

						film->addColor((int)imagePos.x , (int)imagePos.y , res);
					}
				}
			}

			if (lightState.pathLength + 2 > maxPathLength)
				break;

			if (!sampleScattering(bsdf , hitPos , lightState))
				break;
		}

		lightStateIndex[pathIndex] = (int)lightStates.size();
	}

	// generating camera paths
	for (int index = 0; index < cameraPathNum; index++)
	{
		int pathIndex = index % (height * width);

		if (pathIndex == 111 * 512 + 364)
		{
			int flag = 1;
		}

		BidirPathState cameraState;
		Vector3 screenSample = generateCameraSample(pathIndex , cameraState);

		Color3 color(0);

		for (;; cameraState.pathLength++)
		{
			Ray ray(cameraState.origin + cameraState.dir * EPS ,
				cameraState.dir);

			Intersection inter;

			if (scene.intersect(ray , inter) == NULL)
			{
				/*
				if (scene.background != NULL)
				{
					if (cameraState.pathLength >= minPathLength)
					{
						// weight
						Real weight = 1.f / (cameraState.pathLength - cameraState.specularVertexNum);

						color = color + (cameraState.throughput |
							getLightRadiance(scene.background ,
							cameraState , Vector3(0) , ray.dir)) * weight;
					}
				}
				*/
				break;
			}

			Vector3 hitPos = inter.p;

			BSDF bsdf(-ray.dir , inter , scene);
			if (!bsdf.isValid())
				break;

			cameraState.dVCM *= mis(SQR(inter.t));
			cameraState.dVCM /= mis(std::abs(bsdf.cosWi()));
			cameraState.dVC /= mis(std::abs(bsdf.cosWi()));

			if (inter.matId < 0)
			{
				AbstractLight *light = scene.lights[-inter.matId - 1];

				if (cameraState.pathLength >= minPathLength
					&& cameraState.pathLength == controlLength)
				{
					// weight
					//Real weight = 1.f / (cameraState.pathLength - cameraState.specularVertexNum);

					color = color + (cameraState.throughput |
						getLightRadiance(light , cameraState , 
						hitPos , ray.dir));
				}
				break;
			}

			if (cameraState.pathLength >= maxPathLength)
				break;
            
			// vertex connection: connect to light source
			if (!bsdf.isDelta)
			{
				if (cameraState.pathLength + 1 >= minPathLength
					&& cameraState.pathLength + 1 == controlLength)
				{
					// weight
					Real weight = 1.f / (cameraState.pathLength + 1.f - cameraState.specularVertexNum);

					color = color + (cameraState.throughput |
						getDirectIllumination(cameraState , hitPos , bsdf)) *
						weight;
				}
			}

			// vertex connection: connect to light vertices
			if (!bsdf.isDelta)
			{
				int st , ed;
				if (pathIndex == 0)
					st = 0;
				else
					st = lightStateIndex[pathIndex - 1];
				ed = lightStateIndex[pathIndex];

				for (int i = st; i < ed; i++)
				{
					BidirPathState& lightState = lightStates[i];

					if (lightState.pathLength + 1 + 
						cameraState.pathLength < minPathLength)
						continue;

					if (lightState.pathLength + 1 +
						cameraState.pathLength > maxPathLength)
						break;
					
					if (lightState.bsdf.isDelta)
						continue;

					Color3 tmp = connectVertices(lightState ,
						bsdf , hitPos , cameraState);

					// weight
					Real weight = 1.f / (lightState.pathLength + 1.f +
						cameraState.pathLength - lightState.specularVertexNum - 
						cameraState.specularVertexNum);

					if (lightState.pathLength + 1 + cameraState.pathLength ==
						controlLength)
					color = color + (cameraState.throughput |
						lightState.throughput | tmp) * weight;
				}
			}

			if (!sampleScattering(bsdf , hitPos , cameraState))
				break;
		}

		film->addColor((int)screenSample.x , (int)screenSample.y , color);
	}
}