munHunger
munHunger

Reputation: 3001

three js background ends up blurry or pixelated

I have a setup where on my page there is an img element. I want to render three js on top of that image, and I want to pull that image into my three js canvas.

So I have created a render pass that just renders the image on a full screen quad. I know that this might be overkill as I can set the background on a scene to a texture, but that doesn't solve my issues, and I would prefer going with this approach.

The problem I am getting with this code is that the texture ends up either blurry or pixelated when compared to the underlying image.

If I set the filters to LinearFilter the image gets really blurry. If I set it to NearestFilter the image ends up more pixelated than the underlying image.

The img element is 520px wide (and so is the image). The canvas dom is 520px wide, but since I've set size and pixelratio on my three js webgl renderer, the width property ends up at 1040 (pixelratio = 2)

Is there something I can do to make the background look closer to the img element?

export class BackgroundImageRenderPass extends Pass {
    copyMaterial: ShaderMaterial;
    fsQuad: FullScreenQuad;

    textureLoader = new TextureLoader();
    texture: Texture;
    constructor() {
        super();
        this.copyMaterial =  new ShaderMaterial({

            name: "TextureShader",

            uniforms: {
                "tDiffuse": { value: null },
            },

            vertexShader: /* glsl */`
                varying vec2 vUv;
        
                void main() {
                    vUv = uv;
                    gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
                }`,

            fragmentShader: /* glsl */`
                uniform sampler2D tDiffuse;
        
                varying vec2 vUv;
    
                void main() {
                    gl_FragColor = texture2D(tDiffuse, vUv);
                }`
        });
        const img = document.querySelector("img") as HTMLImageElement;
        if (!img) {
            return;
        }
        this.loadTexture(img.src);

        this.fsQuad = new FullScreenQuad(this.copyMaterial);
    }

    dispose(): void {
        this.copyMaterial.dispose();
        this.fsQuad.dispose();
        this.texture.dispose();
    }

    private async loadTexture(src: string): Promise<void> {
        await new Promise(resolve => {
            this.textureLoader.load(src, texture => {
                texture.magFilter = NearestFilter;
                texture.minFilter = NearestFilter;
                texture.generateMipmaps = false;
                this.texture = texture;
                resolve(null);
            });
        });
    }

    render(renderer: WebGLRenderer, writeBuffer: WebGLRenderTarget, readBuffer: WebGLRenderTarget): void {
        renderer.setRenderTarget(writeBuffer);
        renderer.clear();
        this.copyMaterial.uniforms["tDiffuse"].value = this.texture;
        this.fsQuad.render(renderer);
    }
}

Upvotes: 0

Views: 51

Answers (0)

Related Questions