const int w = normalMap->width();
const int h = normalMap->height();
// Compute the laplacian once; it never changes
Image1::Ref laplacian = Image1::createEmpty(w, h, WrapMode::ERROR);
for (int x = 0; x < w; ++x) {
for (int y = 0; y < h; ++y) {
float ddx = normalMap->get(x + 1, y).r - normalMap->get(x - 1, y).r;
float ddy = normalMap->get(x, y + 1).g - normalMap->get(x, y - 1).g;
laplacian->set(x, y, Color1(ddx + signConvention * ddy) / 2.0f);
}
}
// Ping-pong buffers
Image1::Ref src = Image1::createEmpty(w, h, WrapMode::TILE);
Image1::Ref dst = Image1::createEmpty(w, h, WrapMode::TILE);
for (int x = 0; x < w; ++x) {
for (int y = 0; y < h; ++y) {
dst->set(x, y, Color1(0.5));
}
}
// Number of Poisson iterations
const int N = 100;
for (int i = 0; i < N; ++i) {
// Swap buffers
Image1::Ref tmp = src;
src = dst;
dst = tmp;
for (int x = 0; x < w; ++x) {
for (int y = 0; y < h; ++y) {
dst->set(x, y,
Color1((src->get(x - 1, y).value + src->get(x, y - 1).value +
src->get(x + 1, y).value + src->get(x, y + 1).value +
laplacian->get(x, y).value) * 0.25f));
}
}
}
float lo = inf(), hi = -inf();
for (int x = 0; x < w; ++x) {
for (int y = 0; y < h; ++y) {
float v = dst->get(x, y).value;
lo = min(lo, v);
hi = max(hi, v);
}
}
for (int x = 0; x < w; ++x) {
for (int y = 0; y < h; ++y) {
dst->set(x, y, Color1((dst->get(x, y).value - lo) / (hi - lo)));
}
}
Snippet:
Source: https://github.com/morgan3d/misc/blob/master/normal2bump/normal2bump.cpp