Skip to content

Commit

Permalink
Revert "Revert "WIP SmoothHeightMesh by Kevsnz" as a test"
Browse files Browse the repository at this point in the history
This reverts commit 3f0c5e8.
  • Loading branch information
lhog committed Feb 13, 2021
1 parent 536fdac commit 4e34993
Showing 1 changed file with 62 additions and 81 deletions.
143 changes: 62 additions & 81 deletions rts/Sim/Misc/SmoothHeightMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,13 +151,13 @@ inline static void FindRadialMaximum(
) {
const float cury = y * resolution;

for (int x = 0; x <= maxx; ++x) {
for (int x = 0; x < maxx; ++x) {
float maxRowHeight = -std::numeric_limits<float>::max();

// find current maximum within radius smoothRadius
// (in every column stack) along the current row
const int startx = std::max(x - winSize, 0);
const int endx = std::min(maxx, x + winSize);
const int endx = std::min(maxx - 1, x + winSize);

for (int i = startx; i <= endx; ++i) {
assert(i >= 0);
Expand Down Expand Up @@ -256,50 +256,27 @@ inline static void BlurHorizontal(
const int maxy,
const int blurSize,
const float resolution,
const std::vector<float>& mesh,
const std::vector<float>& kernel,
std::vector<float>& mesh,
std::vector<float>& smoothed
) {
const float n = 2.0f * blurSize + 1.0f;
const float recipn = 1.0f / n;
const int lineSize = maxx + 1;

for_mt(0, maxy+1, [&](const int y) {
float avg = 0.0f;

for (int x = 0; x <= 2 * blurSize; ++x) {
avg += mesh[x + y * lineSize];
}
const int lineSize = maxx;

for (int x = 0; x <= maxx; ++x) {
const int idx = x + y * lineSize;

if (x <= blurSize || x > (maxx - blurSize)) {
// map-border case
smoothed[idx] = 0.0f;
for_mt(0, maxy, [&](const int y)
{
for (int x = 0; x < maxx; ++x)
{
float avg = 0.0f;
for (int x1 = x - blurSize; x1 <= x + blurSize; ++x1)
avg += kernel[abs(x1 - x)] * mesh[std::max(0, std::min(maxx-1, x1)) + y * lineSize];

const int xstart = std::max(x - blurSize, 0);
const int xend = std::min(x + blurSize, maxx);

for (int x1 = xstart; x1 <= xend; ++x1) {
smoothed[idx] += mesh[x1 + y * lineSize];
}
const float ghaw = CGround::GetHeightAboveWater(x * resolution, y * resolution);

const float gh = CGround::GetHeightAboveWater(x * resolution, y * resolution);
const float sh = smoothed[idx] / (xend - xstart + 1);
smoothed[x + y * lineSize] = std::max(ghaw, avg);

smoothed[idx] = std::min(readMap->GetCurrMaxHeight(), std::max(gh, sh));
} else {
// non-border case
avg += mesh[idx + blurSize] - mesh[idx - blurSize - 1];

const float gh = CGround::GetHeightAboveWater(x * resolution, y * resolution);
const float sh = recipn * avg;

smoothed[idx] = std::min(readMap->GetCurrMaxHeight(), std::max(gh, sh));
}

assert(smoothed[idx] <= std::max(readMap->GetCurrMaxHeight(), 0.0f));
assert(smoothed[idx] >= readMap->GetCurrMinHeight() );
assert(smoothed[x + y * lineSize] <= std::max(readMap->GetCurrMaxHeight(), 0.0f));
assert(smoothed[x + y * lineSize] >= readMap->GetCurrMinHeight() );
}
});
}
Expand All @@ -309,50 +286,27 @@ inline static void BlurVertical(
const int maxy,
const int blurSize,
const float resolution,
const std::vector<float>& mesh,
const std::vector<float>& kernel,
std::vector<float>& mesh,
std::vector<float>& smoothed
) {
const float n = 2.0f * blurSize + 1.0f;
const float recipn = 1.0f / n;
const int lineSize = maxx + 1;

for_mt(0, maxx+1, [&](const int x) {
float avg = 0.0f;

for (int y = 0; y <= 2 * blurSize; ++y) {
avg += mesh[x + y * lineSize];
}
const int lineSize = maxx;

for (int y = 0; y <= maxy; ++y) {
const int idx = x + y * lineSize;
for_mt(0, maxx, [&](const int x)
{
for (int y = 0; y < maxy; ++y)
{
float avg = 0.0f;
for (int y1 = y - blurSize; y1 <= y + blurSize; ++y1)
avg += kernel[abs(y1 - y)] * mesh[ x + std::max(0, std::min(maxy-1, y1)) * lineSize];

if (y <= blurSize || y > (maxy - blurSize)) {
// map-border case
smoothed[idx] = 0.0f;
const float ghaw = CGround::GetHeightAboveWater(x * resolution, y * resolution);

const int ystart = std::max(y - blurSize, 0);
const int yend = std::min(y + blurSize, maxy);
smoothed[x + y * lineSize] = std::max(ghaw, avg);

for (int y1 = ystart; y1 <= yend; ++y1) {
smoothed[idx] += mesh[x + y1 * lineSize];
}

const float gh = CGround::GetHeightAboveWater(x * resolution, y * resolution);
const float sh = smoothed[idx] / (yend - ystart + 1);

smoothed[idx] = std::min(readMap->GetCurrMaxHeight(), std::max(gh, sh));
} else {
// non-border case
avg += mesh[x + (y + blurSize) * lineSize] - mesh[x + (y - blurSize - 1) * lineSize];

const float gh = CGround::GetHeightAboveWater(x * resolution, y * resolution);
const float sh = recipn * avg;

smoothed[idx] = std::min(readMap->GetCurrMaxHeight(), std::max(gh, sh));
}

assert(smoothed[idx] <= std::max(readMap->GetCurrMaxHeight(), 0.0f));
assert(smoothed[idx] >= readMap->GetCurrMinHeight() );
assert(smoothed[x + y * lineSize] <= std::max(readMap->GetCurrMaxHeight(), 0.0f));
assert(smoothed[x + y * lineSize] >= readMap->GetCurrMinHeight() );
}
});
}
Expand Down Expand Up @@ -405,8 +359,35 @@ void SmoothHeightMesh::MakeSmoothMesh()
// Nth row has indices [maxx*(N-1) + (N-1), maxx*(N) + (N-1)] inclusive
//
// use sliding window of maximums to reduce computational complexity
const int winSize = smoothRadius / resolution;
constexpr int blurSize = 3;
const int winSize = smoothRadius / resolution;
const int blurSize = std::max(1, winSize / 2);
constexpr int blurPassesCount = 2;

const auto fillGaussianKernelFunc = [blurSize](std::vector<float>& gaussianKernel, const float sigma) {
gaussianKernel.resize(blurSize + 1);

const auto gaussianG = [](const int x, const float sigma) {
// 0.3989422804f = 1/sqrt(2*pi)
return 0.3989422804f * exp(-0.5f * x * x / (sigma * sigma)) / sigma;
};

float sum;
gaussianKernel[0] = gaussianG(0, sigma);
sum = gaussianKernel[0];

for (int i = 1; i < blurSize + 1; ++i) {
gaussianKernel[i] = gaussianG(i, sigma);
sum += 2.0f * gaussianKernel[i];
}

for (auto& gk : gaussianKernel) {
gk /= sum;
}
};

constexpr float gSigma = 5.0f;
std::vector<float> gaussianKernel;
fillGaussianKernelFunc(gaussianKernel, gSigma);

assert(mesh.empty());
mesh.resize((maxx + 1) * (maxy + 1), 0.0f);
Expand All @@ -430,9 +411,9 @@ void SmoothHeightMesh::MakeSmoothMesh()
}

// actually smooth with approximate Gaussian blur passes
for (int numBlurs = 3; numBlurs > 0; --numBlurs) {
BlurHorizontal(maxx, maxy, blurSize, resolution, mesh, origMesh); mesh.swap(origMesh);
BlurVertical(maxx, maxy, blurSize, resolution, mesh, origMesh); mesh.swap(origMesh);
for (int numBlurs = blurPassesCount; numBlurs > 0; --numBlurs) {
BlurHorizontal(maxx, maxy, blurSize, resolution, gaussianKernel, mesh, origMesh); mesh.swap(origMesh);
BlurVertical(maxx, maxy, blurSize, resolution, gaussianKernel, mesh, origMesh); mesh.swap(origMesh);
}

// <mesh> now contains the final smoothed heightmap, save it in origMesh
Expand Down

0 comments on commit 4e34993

Please sign in to comment.