Home > OS >  WebGL set canvas size and aspect ratio
WebGL set canvas size and aspect ratio

Time:07-28

I am having issues when trying to scale the canvas to be always set to the image aspect ratio.

I have a WebGL canvas that I am drawing two textures into that are then masked together via a noise. The image size is always 900x1200px for both images and it needs to always be shown at this aspect ratio. If the display size is smaller than the image size then scale down the canvas, if bigger than use the imageMaxWidth and compute the remaining height to be the same as the aspect ratio. Essentially the same as an <img> tag would behave.

This is the resize function

const canvas = document.createElement("canvas");
    
function resizeCanvas(canvas) {
    // Lookup the size the browser is displaying the canvas in CSS pixels.
    const dpr = window.devicePixelRatio;
    var displayWidth  = Math.round(canvas.clientWidth * dpr);
    var displayHeight = Math.round(canvas.clientHeight * dpr);
 
    // Check if the canvas is not the same size.
    const needResize = canvas.width  !== displayWidth ||
                     canvas.height !== displayHeight;
    
    canvasAspect = displayWidth / displayHeight;
    imageAspect = 3 / 4;
    imageMaxWidth = 900;
    imageMaxHeight = 1200;

    if (needResize) {
        if (displayWidth <= imageMaxWidth) {
            canvas.width = displayWidth;
            canvas.height = Math.round(displayHeight * canvasAspect / imageAspect);
        } if (displayWidth > imageMaxWidth) {
            canvas.width = imageMaxWidth;
            canvas.height = imageMaxHeight;
        }
    }

    gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
    return needResize;
}

And I'm loading the images here:

        const loadImage = (d,i) => {
        gl.uniform1i(gl.getUniformLocation(p,`t${i 1}`), i);
        
        const srcType = gl.UNSIGNED_BYTE;
        const img = new Image();
        img.onload = function(){
                const [textureWidth, textureHeight] = [img.naturalWidth, img.naturalHeight];
                gl.uniform2f(gl[`t${(i 1)}res`], textureWidth, textureHeight); 
                // Flip the images
                gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
                gl.activeTexture(i=== 0 ? gl.TEXTURE0 : gl.TEXTURE1);
                gl.bindTexture(gl.TEXTURE_2D, gl.createTexture());
                // Set the parameters to render any size images
                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);
                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, srcType, this);
                if(i === images.length - 1){
                    resizeCanvas(gl.canvas);
                    gl_update(gl)                  
                }
        }
        img.src = d;

}

const tmp = start_gl("canvas1", getStringFromDOMElement('vs'), getStringFromDOMElement('fs'));
const gl = tmp.gl;
const p = tmp.program;

// base first, overlay second
const images = ["072.jpg","072_overlay.jpg"];

What happens now when changing the canvas.width or canvas.height is that it doesn't change the canvas size at all, but just stretches/compresses the image whilst still remaining fullscreen.

Thank you!

CodePudding user response:

The root of this issue is not your code actually. If we look at the CSS styles you apply to all <canvas> elements

canvas {
    width: 100%;
    height: 100%;
    display: block;
    /*width: 75vh;
    height: 100vh;
    max-width: 900px;
    max-height: 1200px;
    object-fit: contain;*/
}

we can see that you made it always stretch to the available horizontal and vertical screenspace. Get rid of:

width: 100%;
height: 100%;

and it should run as expected.

  • Related