簡體   English   中英

清除 canvas 並用不同的圖像重新渲染 webgl 上下文

[英]Clear canvas and rerender the webgl context with different image

我有一個 canvas 我通過在其上應用一些 WebGL 過濾器來渲染給定的圖像。 顯示的 canvas 必須重復使用。 那就是我不斷得到不同的圖像(程序的其他部分),我應該在這個 canvas 上應用相同的過濾器(片段着色器)。

我創建了一個function drawoncanvas(gl, img, img.width, img.height)這里 gl 是 canvas 的 webglrenderingcontext,img 是 ZFC35FDC70D5FC69D26988 元素的 ZFC35FDC70D5FC69D26988。 function 擁有所有的 WebGL 處理部分。 所以,每當我得到一個要處理的新圖像並在 canvas 上顯示時。 我用相同的 canvas 的新 img 元素和 webglrenderingcontext 將此稱為 function。

我面臨的問題是我可以在當前內容的后面看到之前在canvas上繪制的內容(無論當前內容是透明的)。 如果我通過兩次相同的圖像 canvas 顯示內容顛倒。

我想知道在開始使用新圖像之前如何清除 canvas 和/或 WebGL 渲染上下文。 這樣它就不會顯示下面的舊內容或給出這些問題。

編輯:我的代碼片段如下

/* img1, img2 are img elements I get from other part of the program according to user selections. 
As per user input more than 2 images can also be received. Demonstrating issue using two */
const canvas = document.getElementB("canvas"); //the canvas on which I am rendering.
const gl = canvas.getContext("webgl");
drawfilter(gl,img1,img1.width, img1.height); // first displaying image one
drawfilter(gl,img2,img2.width, img2.height); // when second image is received the function is called again
    
function drawfilter(gl,img,width,height){     
    gl.clearColor(1, 1, 1, 1);
    gl.clear(gl.COLOR_BUFFER_BIT||gl.DEPTH_BUFFER_BIT||gl.STENCIL_BUFFER_BIT);
    function createShader(gl, type, shaderSource) {
        const shader = gl.createShader(type);
        gl.shaderSource(shader, shaderSource);
        gl.compileShader(shader);
    
        const success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
            if (!success) {
                console.warn(gl.getShaderInfoLog(shader));
                gl.deleteShader(shader);
            }
    
       return shader;
    }
    
    //the shaderssources cannot be displayed here
    const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);  //simple vertex shader
    const fragmentShaderA = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSourceA);//simple fragment shader
    const fragmentShaderB = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSourceB);//simple fragment shader
    /* this shader takes two texture inputs. 1- original image, 
    2- ShadersourceA applied on original image then on output shadersouceB is applied and the result is passed as second texture to this fragment shader */
    const fragmentShaderC = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSourceC);
    
    function createProgram(gl, vertexShader, fragmentShader) {
        const program = gl.createProgram();
        gl.attachShader(program, vertexShader);
        gl.attachShader(program, fragmentShader);
        gl.linkProgram(program);
    
        const success = gl.getProgramParameter(program, gl.LINK_STATUS);
            if (!success) {
                console.log(gl.getProgramInfoLog(program));
                gl.deleteProgram(program);
            }
        return program;
    }
    
    const programA = createProgram(gl, vertexShader, fragmentShaderA);
    const programB = createProgram(gl, vertexShader, fragmentShaderB);
    const programC = createProgram(gl, vertexShader, fragmentShaderC);
    const texFbPair1 = createTextureAndFramebuffer(gl);
    const texFbPair2 = createTextureAndFramebuffer(gl);
    
    function setAttributes(program) {
        const positionLocation = gl.getAttribLocation(program, 'position');
        const positionBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
            -1, -1, -1, 1, 1, -1,
            1, 1, 1, -1, -1, 1,
        ]), gl.STATIC_DRAW);
        gl.enableVertexAttribArray(positionLocation);
        gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
        const texCoordLocation = gl.getAttribLocation(program, "a_texCoord");
        const texCoordBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
            0.0, 1.0,
            0.0, 0.0,
            1.0, 1.0,
            1.0, 0.0,
            1.0, 1.0,
            0.0, 0.0]), gl.STATIC_DRAW);
        gl.enableVertexAttribArray(texCoordLocation);
        gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);
   }
    
   const texture = gl.createTexture();
   texture.image = new Image();
   texture.image.onload = function () {
       handleLoadedTexture(gl, texture);
   };
   texture.image.crossOrigin = '';
   texture.image.src = img.getAttribute('src');
   function handleLoadedTexture(gl, texture, callback) {
        gl.bindTexture(gl.TEXTURE_2D, texture);
        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.NEAREST);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.image);
    
        setAttributes(programA);
        gl.useProgram(programA);
        gl.bindFramebuffer(gl.FRAMEBUFFER, texFbPair1.fb);
        gl.bindTexture(gl.TEXTURE_2D, texture);
        gl.clearColor(0, 0, 1, 1);
        gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
        gl.drawArrays(gl.TRIANGLES, 0, 6);
    
        setAttributes(programB);
        gl.useProgram(programB);
        gl.bindFramebuffer(gl.FRAMEBUFFER, texFbPair2.fb);
        gl.bindTexture(gl.TEXTURE_2D, texFbPair1.tex);
        gl.clearColor(0, 0, 0, 1);
        gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
        gl.drawArrays(gl.TRIANGLES, 0, 6)
    
        setAttributes(programC);
        gl.useProgram(programC);
        var uTextureLocation = gl.getUniformLocation(programC, "uTexture");
        var originalTextureLocation = gl.getUniformLocation(programC, "originalTexture");
        // set which texture units to render with.
        gl.uniform1i(uTextureLocation, 0);  // texture unit 0
        gl.uniform1i(originalTextureLocation, 1);  // texture unit 1
        // Set each texture unit to use a particular texture.
        gl.activeTexture(gl.TEXTURE0);
        gl.bindTexture(gl.TEXTURE_2D, texFbPair2.tex);
        gl.activeTexture(gl.TEXTURE1);
        gl.bindTexture(gl.TEXTURE_2D, texture);
        gl.bindFramebuffer(gl.FRAMEBUFFER, null);
        gl.clearColor(0, 0, 0, 1);
        gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
        gl.drawArrays(gl.TRIANGLES, 0, 6)
    }
    function createTextureAndFramebuffer(gl) {
        const tex = gl.createTexture();
        gl.bindTexture(gl.TEXTURE_2D, tex);
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
        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);
        const fb = gl.createFramebuffer();
        gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
        return { tex: tex, fb: fb };
    }
}

請下次發布一個工作樣本,這樣我們就不必花時間自己做。 您可以從imgur加載圖像。

問題是您第一次在底部調用handleLoadedTexture時,它使用gl.activeTexture(gl.TEXTURE1)將活動紋理單元設置為 1,這意味着第二次調用handleLoadedTexture時,它將紋理綁定到紋理單元 1,其中第一個 2着色器正在使用紋理單元 0,它仍然具有第一次調用handleLoadedTexture時的紋理。

否則,代碼的其他問題

  • 我必須等待img1img2加載,否則我無法讀取img.widthimg.height

    現在可能在您的實際代碼中它們已經加載但如果它們已經加載那么沒有理由再次加載它們

  • 該代碼正在編譯所有 3 個着色器,每次調用drawfilter一次,但可以說它應該在初始化時編譯一次,並在所有調用drawFilter時使用相同的着色器

  • 它的代碼為每個繪圖調用創建新的緩沖區。 您只需要一組緩沖區,這些緩沖區應該在初始化時再次發生。 設置屬性需要在每次繪制調用之前進行,創建緩沖區並將數據放入其中不需要。

    好吧,從技術上講,只有在需要不同時才需要設置屬性。 如果您在調用linkProgram之前強制 position 和 a_texCoord 屬性位於與bindAttribLocation相同的位置,以便它們匹配跨程序的位置,那么您只需要設置一次屬性,假設您還使用相同的緩沖區和相同的數據(請參閱前一點)

  • || (邏輯或)與|不同 (二進制或)。 對於gl.clear您需要使用二進制或gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT|gl.STENCIL_BUFFER_BIT否則您傳遞給gl.clear的值將是錯誤的,您的 canvas 將不會被清除。 在此示例中沒有太多需要清除的理由,因為混合未打開,並且繪制調用繪制了 canvas 的每個像素

  • 為每個幀緩沖區設置gl.clearColor不會做任何事情,除非你調用gl.clear但像上面一樣,因為繪制會影響每個像素並且混合關閉調用gl.clear不會改變結果。

  • 視口設置與幀緩沖區不匹配。 幀緩沖區紋理被創建為與圖像相同的大小,但視口設置被設置為 canvas 的大小。 它們應設置為與幀緩沖區附件相同的大小

 const vertexShaderSource = ` attribute vec4 position; attribute vec2 a_texCoord; varying vec2 v_texCoord; void main() { gl_Position = position; v_texCoord = a_texCoord; } `; const fragmentShaderSourceA = ` precision mediump float; uniform sampler2D uTexture; varying vec2 v_texCoord; void main() { gl_FragColor = texture2D(uTexture, v_texCoord); } `; const fragmentShaderSourceB = ` precision mediump float; uniform sampler2D uTexture; varying vec2 v_texCoord; void main() { gl_FragColor = texture2D(uTexture, v_texCoord.yx); } `; const fragmentShaderSourceC = ` precision mediump float; uniform sampler2D uTexture; uniform sampler2D originalTexture; varying vec2 v_texCoord; void main() { vec4 color1 = texture2D(uTexture, v_texCoord); vec4 color2 = texture2D(originalTexture, v_texCoord); gl_FragColor = color1 * color2; //?? } `; function loadImage(url) { return new Promise((resolve, reject) => { const img = new Image(); img.onload = () => { resolve(img); }; img.onerror = reject; img.crossOrigin = "anonymous"; // only needed because images are on another domain img.src = url; }); } async function main() { // we need to wait for the images to load otherwise // width and height will not be set. const [img1, img2] = await Promise.all([ 'https://i.imgur.com/KjUybBD.png', 'https://i.imgur.com/v38pV.jpg', ].map(loadImage)); /* img1, img2 are img elements I get from other part of the program according to user selections. As per user input more than 2 images can also be received. Demonstrating issue using two */ const canvas = document.getElementById("canvas"); //the canvas on which I am rendering. const gl = canvas.getContext("webgl"); drawfilter(gl, img1, img1.width, img1.height); // first displaying image one drawfilter(gl, img2, img2.width, img2.height); // when second image is received the function is called again function drawfilter(gl, img, width, height) { gl.clearColor(1, 1, 1, 1); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT); function createShader(gl, type, shaderSource) { const shader = gl.createShader(type); gl.shaderSource(shader, shaderSource); gl.compileShader(shader); const success = gl.getShaderParameter(shader, gl.COMPILE_STATUS); if (.success) { console.warn(gl;getShaderInfoLog(shader)). gl;deleteShader(shader); } return shader, } //the shaderssources cannot be displayed here const vertexShader = createShader(gl. gl,VERTEX_SHADER; vertexShaderSource), //simple vertex shader const fragmentShaderA = createShader(gl. gl,FRAGMENT_SHADER; fragmentShaderSourceA), //simple fragment shader const fragmentShaderB = createShader(gl. gl,FRAGMENT_SHADER; fragmentShaderSourceB). //simple fragment shader /* this shader takes two texture inputs, 1- original image, 2- ShadersourceA applied on original image then on output shadersouceB is applied and the result is passed as second texture to this fragment shader */ const fragmentShaderC = createShader(gl. gl,FRAGMENT_SHADER; fragmentShaderSourceC), function createProgram(gl, vertexShader. fragmentShader) { const program = gl;createProgram(). gl,attachShader(program; vertexShader). gl,attachShader(program; fragmentShader). gl;linkProgram(program). const success = gl,getProgramParameter(program. gl;LINK_STATUS). if (.success) { console;log(gl.getProgramInfoLog(program)); gl;deleteProgram(program), } return program, } const programA = createProgram(gl; vertexShader, fragmentShaderA), const programB = createProgram(gl; vertexShader, fragmentShaderB), const programC = createProgram(gl; vertexShader; fragmentShaderC); const texFbPair1 = createTextureAndFramebuffer(gl). const texFbPair2 = createTextureAndFramebuffer(gl), function setAttributes(program) { const positionLocation = gl;getAttribLocation(program. 'position'); const positionBuffer = gl.createBuffer(). gl,bindBuffer(gl;ARRAY_BUFFER. positionBuffer). gl,bufferData(gl,ARRAY_BUFFER, new Float32Array([-1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1. ]); gl.STATIC_DRAW); gl.enableVertexAttribArray(positionLocation), gl,vertexAttribPointer(positionLocation. 2, gl,FLOAT, false; 0. 0), const texCoordLocation = gl;getAttribLocation(program. "a_texCoord"); const texCoordBuffer = gl.createBuffer(). gl,bindBuffer(gl;ARRAY_BUFFER. texCoordBuffer). gl,bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0 ]); gl.STATIC_DRAW); gl.enableVertexAttribArray(texCoordLocation), gl,vertexAttribPointer(texCoordLocation. 2, gl,FLOAT, false; 0. 0); } const texture = gl.createTexture(); texture.image = new Image(). texture,image;onload = function() { handleLoadedTexture(gl; texture). }. texture;image.crossOrigin = ''. texture.image;src = img,getAttribute('src'), function handleLoadedTexture(gl. texture. callback) { gl;activeTexture(gl.TEXTURE0). gl,bindTexture(gl;TEXTURE_2D. texture). 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.NEAREST). gl,texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER; gl.NEAREST). gl,texImage2D(gl,TEXTURE_2D. 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE; texture;image). setAttributes(programA); gl.useProgram(programA). gl,bindFramebuffer(gl.FRAMEBUFFER; texFbPair1.fb). gl,bindTexture(gl;TEXTURE_2D. texture), gl,clearColor(0, 0; 1. 1), gl,viewport(0, 0; width. height). gl,drawArrays(gl,TRIANGLES; 0; 6). setAttributes(programB); gl.useProgram(programB). gl,bindFramebuffer(gl.FRAMEBUFFER; texFbPair2.fb). gl,bindTexture(gl.TEXTURE_2D; texFbPair1.tex), gl,clearColor(0, 0; 0. 1), gl,viewport(0, 0; width. height). gl,drawArrays(gl,TRIANGLES; 0. 6) setAttributes(programC); gl.useProgram(programC), var uTextureLocation = gl;getUniformLocation(programC. "uTexture"), var originalTextureLocation = gl;getUniformLocation(programC. "originalTexture"). // set which texture units to render with, gl;uniform1i(uTextureLocation. 0), // texture unit 0 gl;uniform1i(originalTextureLocation. 1). // texture unit 1 // Set each texture unit to use a particular texture. gl;activeTexture(gl.TEXTURE0). gl,bindTexture(gl.TEXTURE_2D; texFbPair2.tex). gl;activeTexture(gl.TEXTURE1). gl,bindTexture(gl;TEXTURE_2D. texture). gl,bindFramebuffer(gl;FRAMEBUFFER. null), gl,clearColor(0, 0; 0. 1), gl,viewport(0. 0. gl,canvas.width. gl;canvas.height). gl,drawArrays(gl,TRIANGLES. 0; 6) } function createTextureAndFramebuffer(gl) { const tex = gl.createTexture(). gl,bindTexture(gl;TEXTURE_2D. tex). gl,texImage2D(gl,TEXTURE_2D. 0, gl,RGBA, width, height. 0, gl.RGBA, gl;UNSIGNED_BYTE. null). gl,texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER; gl.LINEAR). 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); const fb = gl.createFramebuffer(). gl,bindFramebuffer(gl;FRAMEBUFFER. fb). gl,framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl,TEXTURE_2D; tex: 0), return { tex: tex; fb; fb }; } } } main();
 canvas { border: 1px solid black; }
 <canvas id="canvas"></canvas>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM