Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

draw a texture pixelated

Tags:

graphics

webgl

I have a bitmap that I want to draw zoomed in and with straight, defined edges between pixels.

I have tried setting the MAG filter to NEAREST:

gl.bindTexture(gl.TEXTURE_2D,this.tex);
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.NEAREST);
...
gl.drawArrays(gl.TRIANGLES,0,6); // draw the texture

However, when I draw it the pixels bleed together:

enter image description here

This is webGL so I have shaders. My shader code is super-simple:

Vertex shader:

...
attribute vec2 texCoord;
varying vec2 texel;
void main() {
    texel = texCoord;
    ...

And fragment shader:

...
varying vec2 texel;
uniform sampler2D texture;
void main() {
    vec4 fragColour = texture2D(texture,texel);
    ...

Here's a larger snippet of the relative code:

map = {
    vbo: gl.createBuffer(),
    tex: gl.createTexture(),
    program: createProgram(
        "precision mediump float;\n"+
        "uniform mat4 mvMatrix, pMatrix;\n"+
        "attribute vec3 vertex;\n"+
        "attribute vec2 texCoord;\n"+
        "varying vec2 texel;\n"+
        "void main() {\n"+
        "   texel = texCoord;\n"+
        "   gl_Position = pMatrix * mvMatrix * vec4(vertex,1.0);\n"+
        "}\n",
        "precision mediump float;\n"+
        "uniform vec4 colour;\n"+
        "uniform float fogDensity;\n"+
        "uniform vec4 fogColour;\n"+
        "varying vec2 texel;\n"+
        "uniform sampler2D texture;\n"+
        "const float LOG2 = 1.442695;\n"+
        "void main() {\n"+
        "   float z = gl_FragCoord.z / gl_FragCoord.w;\n"+
        "   float fogFactor = exp2(-fogDensity*fogDensity*z*z*LOG2);\n"+
        "   fogFactor = clamp(fogFactor,0.0,1.0);\n"+
        "   vec4 fragColour = texture2D(texture,texel) * colour;\n"+
        "   gl_FragColor = mix(fogColour,fragColour,fogFactor);\n"+
        "}\n",
        ["mvMatrix","pMatrix","colour","fogDensity","fogColour","texture"],
        ["vertex","texCoord"]),
    plane: [[0,0,0],[0,1,0]],
    init: function(w,h) {
        this.w = w;
        this.h = h;
        var vertices = [
            w,0,0,  1,0,
            0,0,0,  0,0,
            w,0,h,  1,1,
            w,0,h,  1,1,
            0,0,0,  0,0,
            0,0,h,  0,1,
        ];
        gl.bindBuffer(gl.ARRAY_BUFFER,this.vbo);
        gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(vertices),gl.STATIC_DRAW);
        gl.bindBuffer(gl.ARRAY_BUFFER,null);
        this._mapArrayBuffer = new ArrayBuffer(w*h*4);
        this._mapByteBuffer = new Uint8Array(this._mapArrayBuffer);
        this.map = new Uint32Array(this._mapArrayBuffer);
        for(var i=0; i<w*h; i++) // test data: red and green pixels
            this.map[i] = Math.random()>0.5? 0xff000080: 0xff008000;
        createTexture(this.tex,w,h,this._mapByteBuffer,true);
    },
    draw: function() {
        var program = this.program;
        gl.useProgram(program);
        gl.uniformMatrix4fv(program.pMatrix,false,camera.pMatrix);
        gl.uniformMatrix4fv(program.mvMatrix,false,camera.mvMatrix);
        gl.uniform4f(program.colour,1,1,1,1);
        gl.uniform4f(program.fogColour,1,1,1,1);
        gl.uniform1f(program.fogDensity,0.03);
        gl.bindTexture(gl.TEXTURE_2D,this.tex);
        gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.NEAREST);
        gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.NEAREST);
        gl.bindBuffer(gl.ARRAY_BUFFER,this.vbo);
        gl.enableVertexAttribArray(program.vertex);
        gl.vertexAttribPointer(program.vertex,3,gl.FLOAT,false,5*4,0);
        gl.enableVertexAttribArray(program.texCoord);
        gl.vertexAttribPointer(program.texCoord,2,gl.FLOAT,false,5*4,3*4);
        gl.drawArrays(gl.TRIANGLES,0,6);
        gl.disableVertexAttribArray(program.texCoord);
        gl.disableVertexAttribArray(program.vertex);
        gl.bindBuffer(gl.ARRAY_BUFFER,null);
        gl.bindTexture(gl.TEXTURE_2D,null);
        gl.useProgram(null);
    },
};

function createTexture(tex,width,height,data,noMipMap) {
    tex = tex || gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D,tex);
    tex.width = width || data.width;
    tex.height = height || data.height;
    if(width != null)
        gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,width,height,0,gl.RGBA,gl.UNSIGNED_BYTE,data || null);
    else
        gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,gl.RGBA,gl.UNSIGNED_BYTE,data);
    if(anisotropy)
        gl.texParameterf(gl.TEXTURE_2D,anisotropic.TEXTURE_MAX_ANISOTROPY_EXT,anisotropy);
    gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.LINEAR);
    if(!noMipMap && !(tex.width&(tex.width-1)) && !(tex.height&(tex.height-1))) { //pow2
        gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR_MIPMAP_LINEAR);
        gl.generateMipmap(gl.TEXTURE_2D);
    } else
        gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR);
    gl.bindTexture(gl.TEXTURE_2D,null);
    _textures.push(tex);
    return tex;
}
like image 922
Will Avatar asked Mar 15 '13 08:03

Will


1 Answers

[SOLVED] The problem was that I was enabling anisotropy for the texture. Anisotropy trumps gl_NEAREST, it seems. If you want to use gl_NEAREST on a texture, its important to not also have anisotropy set.

like image 139
Will Avatar answered Nov 12 '22 05:11

Will