Search code examples
javascriptwebglwebgl2

WebGL Textures are blurry, even with gl.NEAREST


I am trying to create a texture for an object, but it will appear blurry, whether I have gl.LINEAR or gl.NEAREST for my MAG and MIN filters

Here is where I initialize my textures (By calling new Texture())

class Texture {
    #texture;
    get texture() {
        return this.#texture;
    }
    constructor(location, cb) {
        const texture = main.gl.createTexture();
        main.gl.bindTexture(main.gl.TEXTURE_2D, texture);
        main.gl.texImage2D(main.gl.TEXTURE_2D, 0, main.gl.RGBA, 16, 16, 0, main.gl.RGBA, main.gl.UNSIGNED_BYTE, null);
        const image = new Image();
        image.onload = () => {
            main.gl.bindTexture(main.gl.TEXTURE_2D, texture);
            // main.gl.texImage2D(main.gl.TEXTURE_2D, 0, main.gl.RGBA, fbWidth, fbHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
            main.gl.texImage2D(main.gl.TEXTURE_2D, 0, main.gl.RGBA, main.gl.RGBA, main.gl.UNSIGNED_BYTE, image);
            if ((image.width & (image.width - 1)) == 0 && (image.height & (image.height - 1)) == 0) {
                main.gl.generateMipmap(main.gl.TEXTURE_2D);
            } else {
                console.log(image.width);
                main.gl.texParameteri(main.gl.TEXTURE_2D, main.gl.TEXTURE_WRAP_S, main.gl.CLAMP_TO_EDGE);
                main.gl.texParameteri(main.gl.TEXTURE_2D, main.gl.TEXTURE_WRAP_T, main.gl.CLAMP_TO_EDGE);
                main.gl.texParameteri(main.gl.TEXTURE_2D, main.gl.TEXTURE_WRAP_R, main.gl.CLAMP_TO_EDGE);
                main.gl.texParameteri(main.gl.TEXTURE_2D, main.gl.TEXTURE_MIN_FILTER, main.gl.NEAREST); // Neither LINEAR nor NEAREST will help with the blur
                main.gl.texParameteri(main.gl.TEXTURE_2D, main.gl.TEXTURE_MAG_FILTER, main.gl.NEAREST);
                main.gl.texParameteri(main.gl.TEXTURE_2D, main.gl.TEXTURE_COMPARE_FUNC, main.gl.LEQUAL);
            }
            this.#texture = texture;
            setTimeout(cb);
            return;
        };
        image.src = location.toString();
        return;
    }
}

It is initialized by this function:

var tex;
tex = new Texture(`${src}`, () => {
    // Stored in tex.texture
});

Here are my fragment and vertex shaders: Vertex Shader:

attribute vec3 position;
attribute vec2 texcoord;
uniform mat4 model;
varying highp vec2 vTextureCoord;
void main() {
    gl_Position = model * vec4(position, 1.0);
    vTextureCoord = texcoord;
}

Fragment Shader:

precision highp float;
varying highp vec2 vTextureCoord;
uniform sampler2D uSampler;
void main(void) {
    gl_FragColor = texture2D(uSampler, vTextureCoord);
}

Renderer:

/*
Execution order:

start -> render -> add (Cubes) -> draw -> end
*/
class GL {
    static #verticies = 0;
    static render() {
        this.#verticies = 0;
        main.gl.clearColor(0.0, 0.0, 0.0, 1.0);
        main.gl.clearDepth(1.0);
        main.gl.viewport(0, 0, main.width, main.height);
        main.gl.enable(main.gl.DEPTH_TEST);
        main.gl.enable(main.gl.CULL_FACE);
        main.gl.depthFunc(main.gl.LEQUAL);
        main.gl.clear(main.gl.COLOR_BUFFER_BIT | main.gl.DEPTH_BUFFER_BIT);
        return;
    }
    static draw(type = main.gl.TRIANGLES) {
        main.gl.useProgram(main.program); // Program with vertex/fragment shaders
        main.gl.drawElements(type, this.#verticies == 0 ? 36 : this.#verticies, main.gl.UNSIGNED_SHORT, 0);
        return;
    }
    static add(obj) {
        try {
            var cps = obj.vertex;
            this.#verticies += (obj.vertex.length / 2);
            var cl = [
                0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0,
                0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0,
                0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0,
                0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0,
                0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0,
                0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0
            ];
            var cel = [
                0, 1, 2, 0, 2, 3,
                4, 5, 6, 4, 6, 7,
                8, 9, 10, 8, 10, 11,
                12, 13, 14, 12, 14, 15,
                16, 17, 18, 16, 18, 19,
                20, 21, 22, 20, 22, 23
            ]
            var bps = main.gl.createBuffer();
            main.gl.bindBuffer(main.gl.ARRAY_BUFFER, bps);
            main.gl.bufferData(main.gl.ARRAY_BUFFER, new Float32Array(cps), main.gl.STATIC_DRAW);
            var bcl = main.gl.createBuffer();
            main.gl.bindBuffer(main.gl.ARRAY_BUFFER, bcl);
            main.gl.bufferData(main.gl.ARRAY_BUFFER, new Float32Array(cl), main.gl.STATIC_DRAW);
            var bel = main.gl.createBuffer();
            main.gl.bindBuffer(main.gl.ELEMENT_ARRAY_BUFFER, bel);
            main.gl.bufferData(main.gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cel), main.gl.STATIC_DRAW);
            var matrix = main.camera;
            var vertex = matrix.Matrix;
            var md = main.gl.getUniformLocation(main.program, `model`);
            var ps = main.gl.getAttribLocation(main.program, `position`);
            var cl = main.gl.getAttribLocation(main.program, `texcoord`);
            main.gl.uniformMatrix4fv(md, false, new Float32Array(vertex));
            main.gl.enableVertexAttribArray(ps);
            main.gl.bindBuffer(main.gl.ARRAY_BUFFER, bps);
            main.gl.vertexAttribPointer(ps, 3, main.gl.FLOAT, false, 0, 0);
            main.gl.enableVertexAttribArray(cl);
            main.gl.bindBuffer(main.gl.ARRAY_BUFFER, bcl);
            main.gl.vertexAttribPointer(cl, 2, main.gl.FLOAT, false, 0, 0);
            main.gl.enableVertexAttribArray(cl);
            main.gl.bindBuffer(main.gl.ELEMENT_ARRAY_BUFFER, bel);
            main.gl.activeTexture(main.gl.TEXTURE0);
            main.gl.bindTexture(main.gl.TEXTURE_2D, obj.texture);
            main.gl.uniform1i(main.gl.getUniformLocation(main.program, `uSampler`), 0);
        } catch (err) {
            // I have this stop the main loop ;)
        }
    }

 }


Solution

  • You're only applying the texture parameters if the textures dimensions are not a power of two:

                if ((image.width & (image.width - 1)) == 0 && (image.height & (image.height - 1)) == 0) {
                    main.gl.generateMipmap(main.gl.TEXTURE_2D);
    >>>>>>>>>>  } else {
                    console.log(image.width);
                    main.gl.texParameteri(...