Javascript 如何防止webgl在每一帧绘制时清洁画布

Javascript 如何防止webgl在每一帧绘制时清洁画布,javascript,webgl,Javascript,Webgl,我试图在一个画布中显示来自不同流的多个帧,使用视口并在每个需要渲染的帧上调用draw函数。我试图复制的是一个只使用一个画布和一个webgl上下文的摄像头视频墙。问题是,每次我将一个帧渲染到特定的视口中,然后之前在不同的视口中渲染的其他帧都会消失 我甚至尝试将webgl上下文设置“preserveDrawingBuffer”属性设置为true,但没有解决这个问题 下面是我正在使用的代码: this.drawNextOuptutPictureGL = function (par) {

我试图在一个画布中显示来自不同流的多个帧,使用视口并在每个需要渲染的帧上调用draw函数。我试图复制的是一个只使用一个画布和一个webgl上下文的摄像头视频墙。问题是,每次我将一个帧渲染到特定的视口中,然后之前在不同的视口中渲染的其他帧都会消失

我甚至尝试将webgl上下文设置“preserveDrawingBuffer”属性设置为true,但没有解决这个问题

下面是我正在使用的代码:

this.drawNextOuptutPictureGL = function (par) {

        var gl = this.contextGL;

        var texturePosBuffer = this.texturePosBuffer;
        var uTexturePosBuffer = this.uTexturePosBuffer;
        var vTexturePosBuffer = this.vTexturePosBuffer;

        var yTextureRef = this.yTextureRef;
        var uTextureRef = this.uTextureRef;
        var vTextureRef = this.vTextureRef;

        var width = this.width;
        var height = this.height;

        var yData = par.yData;
        var uData = par.uData;
        var vData = par.vData;

        var yDataPerRow = par.yDataPerRow || width;
        var yRowCnt = par.yRowCnt || height;

        var uDataPerRow = par.uDataPerRow || (width / 2);
        var uRowCnt = par.uRowCnt || (height / 2);

        var vDataPerRow = par.vDataPerRow || uDataPerRow;
        var vRowCnt = par.vRowCnt || uRowCnt;

        var viewportRow = par.viewportRow;
        var viewportColumn = par.viewportColumn;

        // Calculate coordinates basing on a square matrix
        var square = Math.sqrt(this.viewports.length);
        var x = (this.canvasElement.width / square) * (viewportColumn - 1);
        var y = (this.canvasElement.height / square) * (square - viewportRow);

        gl.viewport(x, y, width, height);

        var tTop = 0;
        var tLeft = 0;
        var tBottom = height / yRowCnt;
        var tRight = width / yDataPerRow;
        var texturePosValues = new Float32Array([tRight, tTop, tLeft, tTop, tRight, tBottom, tLeft, tBottom]);

        gl.bindBuffer(gl.ARRAY_BUFFER, texturePosBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, texturePosValues, gl.DYNAMIC_DRAW);

        if (this.customYUV444) {
          tBottom = height / uRowCnt;
          tRight = width / uDataPerRow;
        } else {
          tBottom = (height / 2) / uRowCnt;
          tRight = (width / 2) / uDataPerRow;
        };
        var uTexturePosValues = new Float32Array([tRight, tTop, tLeft, tTop, tRight, tBottom, tLeft, tBottom]);

        gl.bindBuffer(gl.ARRAY_BUFFER, uTexturePosBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, uTexturePosValues, gl.DYNAMIC_DRAW);


        if (this.customYUV444) {
          tBottom = height / vRowCnt;
          tRight = width / vDataPerRow;
        } else {
          tBottom = (height / 2) / vRowCnt;
          tRight = (width / 2) / vDataPerRow;
        };
        var vTexturePosValues = new Float32Array([tRight, tTop, tLeft, tTop, tRight, tBottom, tLeft, tBottom]);

        gl.bindBuffer(gl.ARRAY_BUFFER, vTexturePosBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, vTexturePosValues, gl.DYNAMIC_DRAW);

        gl.activeTexture(gl.TEXTURE0);
        gl.bindTexture(gl.TEXTURE_2D, yTextureRef);
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, yDataPerRow, yRowCnt, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, yData);

        gl.activeTexture(gl.TEXTURE1);
        gl.bindTexture(gl.TEXTURE_2D, uTextureRef);
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, uDataPerRow, uRowCnt, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, uData);

        gl.activeTexture(gl.TEXTURE2);
        gl.bindTexture(gl.TEXTURE_2D, vTextureRef);
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, vDataPerRow, vRowCnt, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, vData);

        // draw image
        gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
有没有一种方法可以只更新特定视口而不清理整个上下文


谢谢

您需要打开剪刀测试并设置剪刀矩形

gl.enable(gl.SCISSOR_TEST);
gl.scissor(x, y, width, height);
例如:

const m4=twgl.m4;
const gl=document.querySelector('canvas').getContext('webgl');
常数vs=`
属性向量4位置;
一致mat4矩阵;
void main(){
gl_位置=矩阵*位置;
}
`;
常数fs=`
精密中泵浮子;
vec4颜色均匀;
void main(){
gl_FragColor=颜色;
}
`;
//编译着色器、链接程序、查找位置
const programInfo=twgl.createProgramInfo(gl[vs,fs]);
//调用gl.createBuffer、gl.bindBuffer、gl.bufferData
const bufferInfo=twgl.primitives.createCylinderBufferInfo(gl,1,1,24,1);
常量场景=[
{ 
视口:[0,0,150,150],
xRot:0,
zRot:0,
背景:[1,0,0,1],
颜色:[0,1,1,1],
},
{ 
视口:[150,0,150,50],
xRot:Math.PI*.5,
zRot:0,
背景:[0,1,0,1],
颜色:[1,0,1,1],
},
{ 
视口:[150,50,150,100],
xRot:0,
zRot:Math.PI*0.25,
背景:[0,0,1,1],
颜色:[1,1,0,1],
},
];
函数渲染(时间){
时间*=0.001;
总帐启用(总帐剪刀测试);
scenes.forEach((scene,ndx)=>{
总图视口(…场景视口);
gl.scissor(…场景.视口);
gl.clearColor(…scene.bg);
总账清除(总账颜色缓冲位);
常数fov=Math.PI*0.25;
const aspect=scene.viewport[2]/scene.viewport[3];
常数近=0.1;
常数far=10;
常数矩阵=m4.透视图(视野、纵横比、近距离、远距离);
m4.转换(矩阵,[Math.sin(time+ndx),0,-4],矩阵);
m4.rotateX(矩阵,scene.xRot,矩阵);
m4.rotateZ(矩阵,scene.zRot,矩阵);
m4.旋转(矩阵、时间、矩阵);
总账使用程序(programInfo.program);
//调用gl.bindBuffer、gl.enableVertexAttributeArray、gl.VertexAttributePointer
twgl.setBuffersAndAttributes(总帐、程序信息、缓冲信息);
//调用gl.uniformXXX
twgl.设置制服(程序信息{
颜色:scene.color,
矩阵:矩阵,
});
//调用gl.DrawArray或gl.drawElements
twgl.drawBufferInfo(总账,bufferInfo);
});
请求动画帧(渲染);
}
请求动画帧(渲染)


我认为您需要渲染到纹理,然后将这些纹理渲染到画布。这只是一个暗示。更多细节见此:是的,我已经看过那篇文章了。所以方法应该是使用帧缓冲区绘制纹理,然后渲染到默认缓冲区(画布),然后使用上一个纹理作为下一帧的输入,对吗?如何检索修改后的纹理以重新用作输入尚不清楚。。