 	return &aovs[idx];
 }
 
+inline __device__ float3 computeViewSpace(
+	int ix, int iy,
+	float centerDepth,
+	int width, int height,
+	const aten::mat4* mtxC2V)
+{
+	// NOTE
+	// Pview = (Xview, Yview, Zview, 1)
+	// mtxV2C = W 0 0  0
+	//          0 H 0  0
+	//          0 0 A  B
+	//          0 0 -1 0
+	// mtxV2C * Pview = (Xclip, Yclip, Zclip, Wclip) = (Xclip, Yclip, Zclip, Zview)
+	//  Wclip = Zview = depth
+	// Xscr = Xclip / Wclip = Xclip / Zview = Xclip / depth
+	// Yscr = Yclip / Wclip = Yclip / Zview = Yclip / depth
+	//
+	// Xscr * depth = Xclip
+	// Xview = mtxC2V * Xclip
+
+	float2 uv = make_float2(ix + 0.5, iy + 0.5);
+	uv /= make_float2(width - 1, height - 1);	// [0, 1]
+	uv = uv * 2.0f - 1.0f;	// [0, 1] -> [-1, 1]
+
+	aten::vec4 pos(uv.x, uv.y, 0, 0);
+
+	// Screen-space -> Clip-space.
+	pos.x *= centerDepth;
+	pos.y *= centerDepth;
+
+	// Clip-space -> View-space
+	pos = mtxC2V->apply(pos);
+	pos.z = -centerDepth;
+	pos.w = 1.0;
+
+	return make_float3(pos.x, pos.y, pos.z);
+}
+
+#define IS_IN_BOUND(x, a, b)	((a) <= (x) && (x) < (b))
+
 __global__ void varianceEstimation(
 	cudaSurfaceObject_t dst,
 	idaten::SVGFPathTracing::AOV* aovs,
+	aten::mat4 mtxC2V,
 	int width, int height)
 {
 	int ix = blockIdx.x * blockDim.x + threadIdx.x;

		{
			for (int u = -radius; u <= radius; u++)
			{
				auto sampleaov = sampleAov(aovs, ix + u, iy + v, width, height);
				
				auto moment = sampleaov->moments;
				moment /= moment.w;

				auto sampleNml = sampleaov->normal;

				float sampleDepth = sampleaov->depth;
				int sampleMeshId = sampleaov->meshid;

				float n = 1 - dot(sampleNml, centerNormal);
				float Wn = exp(-0.5f * n * n / (sigmaN * sigmaN));

				float d = 1 - min(centerDepth, sampleDepth) / max(centerDepth, sampleDepth);
				float Wd = exp(-0.5f * d * d / (sigmaD * sigmaD));

				float Ws = exp(-0.5f * (u * u + v * v) / (sigmaS * sigmaS));

				float Wm = centerMeshId == sampleMeshId ? 1.0f : 0.0f;

				float W = Ws * Wn * Wd * Wm;
				sum += moment * W;
				weight += W;
			}
		}


		static const int radius = 3;
		static const float sigmaN = 0.005f;
		static const float sigmaD = 0.005f;
		static const float sigmaS = 0.965f;

		auto centerNormal = aovs[idx].normal;

