4
\$\begingroup\$

I've been messing around with different algorithms trying to make a grid based map look smooth, I have tested with various shader based methods and wrote a few of my own but none of them look right.

A grid based map:

The result I'm trying to achieve

So my question is, are there any algorithms or known methods out there to achieve this?

\$\endgroup\$
0
1
\$\begingroup\$

You could try with a simple filter:

//<![CDATA[
var input = [
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
  1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
  1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
  1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0,
  1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
  1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
];

function Texture(w, h) {
    this.width = w;
    this.height = h;
    this.getTexAt = function(i, j) {
        return this[j * this.width + i] ? "red" : "green";
    };
}
Texture.call(input, input.length / 12, 12);

var canvas = document.createElement("canvas");
canvas.width = input.width * 20;
canvas.height = input.height * 20;

function rect(g, x, y, cx, cy, fillStyle, strokeStyle, strokeStrength) {
    g.beginPath();
    g.moveTo(x, y);
    g.lineTo(x, y+cy);
    g.lineTo(x+cx, y+cy);
    g.lineTo(x+cx, y);
    g.closePath();
    if(fillStyle !== undefined) {
        g.fillStyle = fillStyle;
        g.fill();
    }
    if(strokeStyle !== undefined) {
        if(strokeStrength !== undefined)
            g.lineWidth = strokeStrength;
        g.strokeStyle = strokeStyle;
        g.stroke();
    }
}

function paintTexture(tex) {
    var g = canvas.getContext("2d");
    var w = canvas.width;
    var h = canvas.height;
    var size, offX = 0, offY = 0;
    if(w / tex.width < h / tex.height) {
        size = w / tex.width;
        offY = 0.5 * (h - tex.height * size);
    } else {
        size = h / tex.height;
        offX = 0.5 * (w - tex.width * size);
    }
    for(var j = 0, y = offY; j < tex.height; ++j, y += size)
        for(var i = 0, x = offX; i < tex.width; ++i, x += size)
            rect(g, x, y, size+1, size+1, tex.getTexAt(i, j));
}

function subsample(tex, sw, sh) {
    if(!sw || sh < 0) sw = 2;
    if(!sh || sh < 0) sh = sw;
    var out = [];
    for(var j = 0; j < tex.height; ++j) {
        for(var subj = 0; subj < sh; ++subj) {
            for(var i = 0; i < tex.width; ++i) {
                var sample = tex[j * tex.width + i];
                for(var subi = 0; subi < sw; ++subi) {
                    out.push(sample);
                }
            }
        }
    }
    Texture.call(out, tex.width * sw, tex.height * sh);
    return out;
}

function erode(tex, sw, sh) {
    if(!sw || sh < 0) sw = 1;
    if(!sh || sh < 0) sh = sw;
    var out = tex.slice(); // hack: copy data
    for(var j = sh; j + sh < tex.height; ++j) {
        for(var i = sw; i + sw < tex.width; ++i) {
            // <--- Adjust to your filter criteria --->
            var count = 0;
            for(var v = -sh; v <= sh; ++v)
                for(var u = -sw; u <= sw; ++u)
                    count += tex[(j + v) * tex.width + i + u];
            var sample = count > 0.5 * (2*sw+1) * (2*sh+1) ? 1 : 0;
            out[j * tex.width + i] = sample;
        }
    }
    for(var j = sh; j + sh < tex.height; ++j)
        for(var i = sw; i + sw < tex.width; ++i)
            tex[j * tex.width + i] = out[j * tex.width + i];
    Texture.call(out, tex.width, tex.height);
    return out;
}

paintTexture(input);
document.getElementById("body").appendChild(canvas);

setTimeout(function() {
    var subsampled = subsample(input, 16);
    var eroded = erode(subsampled, 7);
    paintTexture(eroded);
}, 1000);
//]]>
<div id="body"></div>

\$\endgroup\$
0
\$\begingroup\$

Apart from using shaders, you can implement the Marching Squares algorithm to generate contours for your grid (see picture in the linked article).

A great marching squares tutorial here. It's for Unity, but the idea's still the same.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.