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

2 Answers 2

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\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .