diff --git a/applications/reconstruct/src/ilw/ilw.cu b/applications/reconstruct/src/ilw/ilw.cu
index c1222ca7956ad5f1fa1f80fa06a114ba16cb3281..48462f300981ad29c11c5047c0ef6f6a37a33c82 100644
--- a/applications/reconstruct/src/ilw/ilw.cu
+++ b/applications/reconstruct/src/ilw/ilw.cu
@@ -8,10 +8,10 @@ using ftl::rgbd::Camera;
 #define T_PER_BLOCK 8
 #define FULL_MASK 0xffffffff
 
-__device__ inline float warpMax(float e) {
+__device__ inline float warpMin(float e) {
 	for (int i = WARP_SIZE/2; i > 0; i /= 2) {
 		const float other = __shfl_xor_sync(FULL_MASK, e, i, WARP_SIZE);
-		e = max(e, other);
+		e = min(e, other);
 	}
 	return e;
 }
@@ -39,8 +39,8 @@ __global__ void correspondence_energy_vector_kernel(
     const float3 camPos2 = pose2 * world1;
     const uint2 screen2 = cam2.camToScreen<uint2>(camPos2);
     
-    float bestconf = 0.0f;
-    float nextbest = 0.0f;
+    float bestcost = 1.1f;
+    float nextbest = 1.0f;
     float3 bestpoint;
 
     // Project to p2 using cam2
@@ -54,29 +54,28 @@ __global__ void correspondence_energy_vector_kernel(
 		if (world2.x == MINF) continue;
 
         // Determine degree of correspondence
-        const float l = length(world1 - world2);
-        const float confidence = ftl::cuda::spatialWeighting(l, 0.04f);
+        const float cost = 1.0f - ftl::cuda::spatialWeighting(world1, world2, 0.04f);
 
-        if (confidence > bestconf) {
+        if (cost < bestcost) {
             bestpoint = world2;
-            nextbest = bestconf;
-            bestconf = confidence;
+            nextbest = bestcost;
+            bestcost = cost;
         }
     }
 
-    const float maxconf = warpMax(bestconf);
-    bool best = maxconf == bestconf;
-    bestconf = (best) ? 0.0f : bestconf;
-    const float conf = maxconf - warpMax(bestconf);
+    const float mincost = warpMin(bestcost);
+    bool best = mincost == bestcost;
+    bestcost = (best) ? nextbest : bestcost;
+    const float confidence = mincost / warpMin(bestcost);
 
-    if (best && maxconf > 0.0f) {
+    if (best && mincost < 1.0f) {
         vout(x,y) = vout.tex2D(x, y) + make_float4(
             (bestpoint.x - world1.x),
             (bestpoint.y - world1.y),
             (bestpoint.z - world1.z),
-            maxconf);
-        eout(x,y) = conf * 5.0f; //maxconf * 5.0f; //(maxconf - warpMax(nextbest));
-    } else if (maxconf == 0.0f && lane == 0) {
+            mincost);
+        eout(x,y) = mincost * 5.0f; //confidence * 5.0f;
+    } else if (mincost >= 1.0f && lane == 0) {
         vout(x,y) = make_float4(0.0f);
         eout(x,y) = 0.0f;
     }
diff --git a/components/renderers/cpp/include/ftl/cuda/weighting.hpp b/components/renderers/cpp/include/ftl/cuda/weighting.hpp
index 9498d0508605087306db2658b2a1ae1943cde536..15d3dbcec387f97d8ffe60690bdb5c1fda2c098c 100644
--- a/components/renderers/cpp/include/ftl/cuda/weighting.hpp
+++ b/components/renderers/cpp/include/ftl/cuda/weighting.hpp
@@ -4,19 +4,41 @@
 namespace ftl {
 namespace cuda {
 
+__device__ inline float weighting(float r, float h) {
+	if (r >= h) return 0.0f;
+	float rh = r / h;
+	rh = 1.0f - rh*rh;
+	return rh*rh*rh*rh;
+}
+
 /*
  * Guennebaud, G.; Gross, M. Algebraic point set surfaces. ACMTransactions on Graphics Vol. 26, No. 3, Article No. 23, 2007.
  * Used in: FusionMLS: Highly dynamic 3D reconstruction with consumer-grade RGB-D cameras
  *     r = distance between points
  *     h = smoothing parameter in meters (default 4cm)
  */
-__device__ inline float spatialWeighting(float r, float h) {
+__device__ inline float spatialWeighting(const float3 &a, const float3 &b, float h) {
+	const float r = length(a-b);
 	if (r >= h) return 0.0f;
 	float rh = r / h;
 	rh = 1.0f - rh*rh;
 	return rh*rh*rh*rh;
 }
 
+/*
+ * Colour weighting as suggested in:
+ * C. Kuster et al. Spatio-Temporal Geometry Fusion for Multiple Hybrid Cameras using Moving Least Squares Surfaces. 2014.
+ * c = colour distance
+ */
+ __device__ inline float colourWeighting(uchar4 a, uchar4 b, float h) {
+	const float3 delta = make_float3((float)a.x - (float)b.x, (float)a.y - (float)b.y, (float)a.z - (float)b.z);
+	const float c = length(delta);
+	if (c >= h) return 0.0f;
+	float ch = c / h;
+	ch = 1.0f - ch*ch;
+	return ch*ch*ch*ch;
+}
+
 }
 }
 
diff --git a/components/renderers/cpp/src/splatter.cu b/components/renderers/cpp/src/splatter.cu
index 3b1ae4b47ef0fe6b29b15d1fa20fdc9a0fd0b9bb..6b615fa6b9c092cc9bc7856b8e8d36ceb1ddec0d 100644
--- a/components/renderers/cpp/src/splatter.cu
+++ b/components/renderers/cpp/src/splatter.cu
@@ -116,7 +116,7 @@ __global__ void dibr_attribute_contrib_kernel(
 		const float3 nearest = params.camera.screenToCam((int)(screenPos.x+u),(int)(screenPos.y+v),d);
 
         // What is contribution of our current point at this pixel?
-        const float weight = ftl::cuda::spatialWeighting(length(nearest - camPos), SMOOTHING_MULTIPLIER_C*(nearest.z/params.camera.fx));
+        const float weight = ftl::cuda::spatialWeighting(nearest, camPos, SMOOTHING_MULTIPLIER_C*(nearest.z/params.camera.fx));
         if (screenPos.x+u < colour_out.width() && screenPos.y+v < colour_out.height() && weight > 0.0f) {  // TODO: Use confidence threshold here
             const float4 wcolour = colour * weight;
 			//const float4 wnormal = normal * weight;
@@ -187,7 +187,7 @@ __global__ void dibr_attribute_contrib_kernel(
         const float3 nearest = params.camera.screenToCam((int)(screenPos.x+u),(int)(screenPos.y+v),d);
 
         // What is contribution of our current point at this pixel?
-        const float weight = ftl::cuda::spatialWeighting(length(nearest - camPos), SMOOTHING_MULTIPLIER_C*(nearest.z/params.camera.fx));
+        const float weight = ftl::cuda::spatialWeighting(nearest, camPos, SMOOTHING_MULTIPLIER_C*(nearest.z/params.camera.fx));
         if (screenPos.x+u < colour_out.width() && screenPos.y+v < colour_out.height() && weight > 0.0f) {  // TODO: Use confidence threshold here
             const float wcolour = colour * weight;
             //const float4 wnormal = normal * weight;