 	}
 }
 
-template <bool isFirstBounce>
+template <bool isFirstBounce, int ShadowRayNum>
 __global__ void shade(
 	idaten::SVGFPathTracing::AOV* aovs,
 	aten::mat4 mtxW2C,


		auto& curaov = getCurAovs();

		if (bounce == 0) {
			shade<true> << <blockPerGrid, threadPerBlock >> > (
				curaov.ptr(), mtxW2C,
				width, height,
				m_paths.ptr(),

	// Explicit conection to light.
	if (!mtrl.attrib.isSingular)
	{
		for (int i = 0; i < ShadowRayNum; i++) {
			real lightSelectPdf = 1;
			aten::LightSampleResult sampleres;

			// TODO
			// Importance sampling.
			int lightidx = aten::cmpMin<int>(path.sampler.nextSample() * lightnum, lightnum - 1);
			lightSelectPdf = 1.0f / lightnum;

			auto light = ctxt.lights[lightidx];

			sampleLight(&sampleres, &ctxt, &light, rec.p, orienting_normal, &path.sampler);

			const auto& posLight = sampleres.pos;
			const auto& nmlLight = sampleres.nml;
			real pdfLight = sampleres.pdf;

			auto lightobj = sampleres.obj;

			auto dirToLight = normalize(sampleres.dir);
			auto distToLight = length(posLight - rec.p);

			real distHitObjToRayOrg = AT_MATH_INF;

			// Ray aim to the area light.
			// So, if ray doesn't hit anything in intersectCloserBVH, ray hit the area light.
			auto hitobj = lightobj;

			aten::Intersection isectTmp;

			auto shadowRayOrg = rec.p + AT_MATH_EPSILON * orienting_normal;
			auto tmp = rec.p + dirToLight - shadowRayOrg;
			auto shadowRayDir = normalize(tmp);
			aten::ray shadowRay(shadowRayOrg, shadowRayDir);

			bool isHit = intersectCloserBVH(&ctxt, shadowRay, &isectTmp, distToLight - AT_MATH_EPSILON);

			if (isHit) {
				hitobj = (void*)&ctxt.shapes[isectTmp.objid];
			}

			isHit = AT_NAME::scene::hitLight(
				isHit,
				light.attrib,
				lightobj,
				distToLight,
				distHitObjToRayOrg,
				isectTmp.t,
				hitobj);

			if (isHit) {
				auto cosShadow = dot(orienting_normal, dirToLight);

				real pdfb = samplePDF(&ctxt, &mtrl, orienting_normal, ray.dir, dirToLight, rec.u, rec.v);
				auto bsdf = sampleBSDF(&ctxt, &mtrl, orienting_normal, ray.dir, dirToLight, rec.u, rec.v);

				bsdf *= path.throughput;

				// Get light color.
				auto emit = sampleres.finalColor;

				if (light.attrib.isSingular || light.attrib.isInfinite) {
					if (pdfLight > real(0) && cosShadow >= 0) {
						// TODO
						// WIg^[̈ɂ.
						// singular light ̏ꍇ́AfinalColor ɋ̏Z܂܂Ă.
						// inifinite light ̏ꍇ́AɂȂApdfLightɊ܂܂鋗ƑłH.
						// ił̂ŁApdfLightɂ͋͊܂łȂj.
						auto misW = pdfLight / (pdfb + pdfLight);
						path.contrib += (misW * bsdf * emit * cosShadow / pdfLight) / lightSelectPdf / (float)ShadowRayNum;
					}
				}
				else {
					auto cosLight = dot(nmlLight, -dirToLight);

					if (cosShadow >= 0 && cosLight >= 0) {
						auto dist2 = aten::squared_length(sampleres.dir);
						auto G = cosShadow * cosLight / dist2;

						if (pdfb > real(0) && pdfLight > real(0)) {
							// Convert pdf from steradian to area.
							// http://www.slideshare.net/h013/edubpt-v100
							// p31 - p35
							pdfb = pdfb * cosLight / dist2;

							auto misW = pdfLight / (pdfb + pdfLight);

							path.contrib += (misW * (bsdf * emit * G) / pdfLight) / lightSelectPdf / (float)ShadowRayNum;
						}
					}
				}
			}
