diff --git a/phasefield/simplex_projection.pyx b/phasefield/simplex_projection.pyx
index 70b49b225c100c89c3407391f573772ef907c8aa..26fa3176c8db93947ce243ec2c1d1c1f573e50c1 100644
--- a/phasefield/simplex_projection.pyx
+++ b/phasefield/simplex_projection.pyx
@@ -47,3 +47,48 @@ def simplex_projection_2d(object[double, ndim=3] c):
 
             for a in range(num_phases):
                 c[x, y, a] /= phase_sum
+
+
+@cython.boundscheck(False)
+@cython.wraparound(False)
+@cython.cdivision(True)
+def simplex_projection_3d(object[double, ndim=4] c):
+    cdef int xs, ys, num_phases, x, y, z, a, b, local_phases
+    cdef unsigned int handled_mask = 0
+    cdef double threshold = 1e-18
+    cdef double phase_sum
+
+    xs, ys, zs, num_phases = c.shape
+
+    for z in range(zs):
+        for y in range(ys):
+            for x in range(xs):
+                local_phases = num_phases
+
+                ## Mark zero phases
+                for a in range(num_phases):
+                    if  -threshold < c[x, y, z, a] < threshold:
+                        local_phases -= 1
+                        handled_mask |= (1 << a)
+                        c[x, y, z, a] = 0
+
+                # Distribute negative phases to others
+                a = 0
+                while a < num_phases:
+                    if c[x, y, z, a] < 0.0:
+                        handled_mask |= (1 << a)
+                        local_phases -= 1
+                        for b in range(num_phases): # distribute to unhandled phases
+                            if handled_mask & (1 << b) == 0:
+                                c[x, y, z, b] += c[x, y, z, a] / local_phases
+                        c[x, y, z, a] = 0.0
+                        a = -1  # restart loop, since other phases might have become negative
+                    a += 1
+
+                # Normalize phases
+                phase_sum = 0.0
+                for a in range(num_phases):
+                    phase_sum += c[x, y, z, a]
+
+                for a in range(num_phases):
+                    c[x, y, z, a] /= phase_sum