中心凹渲染:WebGL可以从屏幕中心向外螺旋渲染顶点/片段着色器吗?

中心凹渲染:WebGL可以从屏幕中心向外螺旋渲染顶点/片段着色器吗?,webgl,Webgl,如何告诉WebGL从屏幕中心渲染,然后按顺时针方向向外扩展,如果时间过长,如何取消/停止渲染 或者我需要自己手动平铺多张画布,并在所有画布上投影吗?作为我对您问题的评论示例,下面是一个过于简单的中心凹渲染示例。我从渲染到纹理的示例开始 那个 将带纹理的立方体渲染为纹理 将立方体的纹理渲染为画布上的立方体 这个 将纹理立方体渲染为低分辨率纹理 将带纹理的立方体渲染为高分辨率纹理 渲染填充画布的低分辨率纹理 渲染中心的高分辨率纹理 有很多瑕疵,低分辨率纹理的分辨率太低,你需要更好的算法来混合它们,但

如何告诉WebGL从屏幕中心渲染,然后按顺时针方向向外扩展,如果时间过长,如何取消/停止渲染


或者我需要自己手动平铺多张画布,并在所有画布上投影吗?

作为我对您问题的评论示例,下面是一个过于简单的中心凹渲染示例。我从渲染到纹理的示例开始

那个

将带纹理的立方体渲染为纹理 将立方体的纹理渲染为画布上的立方体 这个

将纹理立方体渲染为低分辨率纹理 将带纹理的立方体渲染为高分辨率纹理 渲染填充画布的低分辨率纹理 渲染中心的高分辨率纹理 有很多瑕疵,低分辨率纹理的分辨率太低,你需要更好的算法来混合它们,但它显示了效果

唯一不寻常的事情

将视口更改为仅渲染到中心。也可以通过缩放平面来实现这一点

        // Tell WebGL how to convert from clip space to pixels
        gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
        drawRenderTarget(lowResRT);
        // Tell WebGL how to convert from clip space to pixels
        gl.viewport(
            gl.canvas.width  / 4, 
            gl.canvas.height / 4,
            gl.canvas.width  / 2, 
            gl.canvas.height / 2);
        drawRenderTarget(highResRT);    
使用平截头体函数来计算平截头体,而不是更传统的透视函数。平截头体函数采用左、右、下、上、近、远参数,并计算一个投影矩阵,眼睛位于0、0,左、右、上、下描述眼睛前方的矩形。它比透视函数更灵活,因为它允许消失点位于任何位置,而不仅仅是中心

在这种情况下,该代码计算一个截头体的正确值,其中心和近平面的中心是2单位高和2×纵横单位宽。它计算一个子矩形,而不是。这就是我们如何使高分辨率纹理与低分辨率纹理匹配

        // Compute the projection matrix
        var near = 1;

        // compute a near plane 2 units tall, 2 * aspect high
        var vTop = near * Math.tan(fieldOfViewRadians * 0.5);
        var vHeight = 2 * vTop;
        var vWidth = aspect * vHeight;
        var vLeft = -0.5 * vWidth;

        // how compute a subrect of that near plane where
        // left, bottom are offsets into the computed near plane 
        // and width, height are the dimensions of the sub rect
        vLeft += left * vWidth / 2;
        vTop -= bottom * vHeight / 2;
        vWidth *= width / 2;
        vHeight *= height / 2;

        var projectionMatrix =
            m4.frustum(vLeft, vLeft + vWidth, vTop - vHeight, vTop, near, 2000);
严格使用; 主要功能{ //获取WebGL上下文 /**@type{HTMLCanvasElement}*/ var canvas=document.getElementByIdcanvas; var gl=canvas.getContextwebgl; 如果!德国劳埃德船级社{ 回来 } //安装GLSL程序 var program=webglUtils.createProgramFromScriptsgl,[3d顶点着色器,3d片段着色器]; //查找顶点数据需要去的地方。 var positionLocation=gl.GetAttriblLocationProgram,一个位置; var texcoordLocation=gl.getAttribLocationprogram,a_texcoord; //查找制服 var matrixLocation=gl.GetUniformLocation程序,u_矩阵; var textureLocation=gl.getUniformLocationprogram,u_纹理; //为位置创建缓冲区 var positionBuffer=gl.createBuffer; //将其绑定到ARRAY\u BUFFER将其视为ARRAY\u BUFFER=positionBuffer gl.bindbuffer gl.ARRAY_BUFFER,positionBuffer; //把位置放在缓冲器里 setGeometrygl; //为矩形提供纹理坐标。 var texcoordBuffer=gl.createBuffer; gl.bindBuffergl.ARRAY_BUFFER,texcoordBuffer; //设置Texcoords。 setTexcoordsgl; //为位置创建缓冲区 var planePositionBuffer=gl.createBuffer; //将其绑定到ARRAY\u BUFFER将其视为ARRAY\u BUFFER=positionBuffer gl.bindbuffer gl.ARRAY_BUFFER,planePositionBuffer; //把位置放在缓冲器里 gl.bufferDatagl.ARRAY\U缓冲区,新浮点数组[ -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1, ],gl.静态图; //为矩形提供纹理坐标。 var planeTexcoordBuffer=gl.createBuffer; gl.bindBuffergl.ARRAY_BUFFER,PlaneteCoordBuffer; //设置Texcoords。 gl.bufferDatagl.ARRAY\U缓冲区,新浮点数组[ 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, ],gl.静态图; //仅为立方体创建纹理。 var texture=gl.createTexture; gl.bindTexturegl.TEXTURE_2D,纹理; { //使用3x2像素填充纹理 常数级=0; const internalFormat=gl.亮度; 常数宽度=3; 常数高度=2; 常数边界=0; 常量格式=gl.亮度; 常量类型=gl.无符号字节; 常数数据=新的UINT8阵列[ 128, 64, 128, 0, 192, 0, ]; 常量对齐=1; gl.pixelStoreigl.UNPACK_校准,校准; gl.texImage2Dgl.TEXTURE_2D,级别,内部格式,宽度,高度,边框, 格式、类型、数据; //设置筛选,这样我们就不需要mips,也不会对其进行筛选 gl.texParameterigl.TEXTURE_2D,gl.TEXTURE_MIN_过滤器,gl.NEAREST; gl.texParameterigl.TEXTURE_2D,gl.TEXTURE_MAG_过滤器,gl.NEAREST; gl.texParameterigl.TEXTURE_2D、gl.TEXTURE_WRAP_S、gl.CLAMP_TO_EDGE; gl.texParameterigl.TEXTURE_2D、gl.TEXTURE_WRAP_T、gl.CLAMP_至边; } //创建要渲染到的纹理 函数CreateRenderTargetTargetTextRewidth,TargetTextReHeight{ const targetTexture=gl.createTexture; gl.bindTexturegl.TEXTURE_2D,targetTexture; { //定义级别0的大小和格式 常数级=0; const internalFormat=gl.RGBA; 常数边界=0; 常量格式=gl.RGBA; 常量类型= gl.无符号字节; const data=null; gl.texImage2Dgl.TEXTURE_2D,级别,内部格式, TargetTextRewidth、TargetTextReheight、border、, 格式、类型、数据; //设置筛选,这样我们就不需要mips了 gl.texParameterigl.TEXTURE_2D,gl.TEXTURE_MIN_过滤器,gl.LINEAR; gl.texParameterigl.TEXTURE_2D、gl.TEXTURE_WRAP_S、gl.CLAMP_TO_EDGE; gl.texParameterigl.TEXTURE_2D、gl.TEXTURE_WRAP_T、gl.CLAMP_至边; } //创建并绑定帧缓冲区 const fb=gl.createFramebuffer; gl.bindframebuffer gl.FRAMEBUFFER,fb; //将纹理作为第一个颜色附着 const attachmentPoint=gl.COLOR\u ATTACHMENT0; 常数级=0; gl.framebufferTexture2Dgl.FRAMEBUFFER,attachmentPoint,gl.TEXTURE_2D,targetTexture,level; 返回{ 帧缓冲区:fb, 纹理:targetTexture, 宽度:targetTextRewidth, 高度:目标高度, }; } const lowResRT=createRenderTarget32,32; const highResRT=createRenderTarget256,256; 函数degToRadd{ 返回d*Math.PI/180; } var fieldOfViewRadians=degToRad60; var ModelX旋转弧度=degToRad0; var模型旋转弧度=degToRad0; //获取开始时间。 var=0; requestAnimationFramedrawScene; 函数drawCubeaspect,左侧,底部,宽度,高度{ //告诉它使用我们的程序对着色器 gl.useprogrammProgram; //启用“位置”属性 gl.EnableVertexAttributeArrayPositionLocation; //绑定位置缓冲区。 gl.bindbuffer gl.ARRAY_BUFFER,positionBuffer; //告诉position属性如何从positionBuffer数组\u BUFFER中获取数据 var size=3;//每次迭代3个组件 var type=gl.FLOAT;//数据为32位浮点 var normalize=false;//不规范化数据 var stride=0;//0=向前移动大小*大小键入每个迭代以获得下一个位置 var offset=0;//从缓冲区的开头开始 gl.VertexAttribute指针 位置、位置、尺寸、类型、规格化、步幅、偏移; //启用teccord属性 gl.EnableVertexAttributeArrayExcoordLocation; //绑定位置缓冲区。 gl.bindBuffergl.ARRAY_BUFFER,texcoordBuffer; //告诉position属性如何从positionBuffer数组\u BUFFER中获取数据 var size=2;//每次迭代2个组件 var type=gl.FLOAT;//数据为32位浮点 var normalize=false;//不规范化数据 var stride=0;//0=向前移动大小*大小键入每个迭代以获得下一个位置 var offset=0;//从缓冲区的开头开始 gl.VertexAttribute指针 texcoordLocation、大小、类型、规格化、跨步、偏移; //计算投影矩阵 var近=1; //计算一个近平面,2个单位高,2*纵横比高 var vTop=近*Math.tanfieldOfViewRadians*0.5; var vHight=2*vTop; var vWidth=宽高比*高高比; var vLeft=-0.5*vWidth; //如何计算平面附近的子矩形 //左下角是计算的近平面中的偏移 //和宽度、高度是子矩形的尺寸 vLeft+=左*宽/2; vTop-=底部*vHight/2; vWidth*=宽度/2; vHeight*=高度/2; 向量投影矩阵= m4.VrustumvLeft,vLeft+vWidth,vTop-vHeight,vTop,近,2000年; var cameraPosition=[0,0,2]; var-up=[0,1,0]; var目标=[0,0,0]; //使用“查看”计算相机的矩阵。 var cameraMatrix=m4.lookAtcameraPosition,target,up; //从摄影机矩阵创建视图矩阵。 var viewMatrix=m4.inversecameraMatrix; var viewProjectionMatrix=m4.multipleProjectionMatrix,viewMatrix; var矩阵=m4.x旋转视图投影矩阵,X型旋转弧度; 矩阵=m4.0旋转矩阵,模型旋转弧度; //设定矩阵。 gl.UniformMatrix4FvMatrixlLocation,false,矩阵; //告诉着色器对u_纹理使用纹理单元0 gl.uniform1,0; //绘制几何图形。 gl.drawArraysgl.TRIANGLES,0,6*6; } 功能方面{ //告诉它使用我们的程序对着色器 gl.useprogrammProgram; //启用“位置”属性 gl.EnableVertexAttributeArrayPositionLocation; //绑定位置缓冲区。 gl.bindbuffer gl.ARRAY_BUFFER,planePositionBuffer; //告诉position属性如何从positionBuffer数组\u BUFFER中获取数据 var size=2;//每次迭代2个组件 var type=gl.FLOAT;//数据为32位浮点 var normalize=false;//不规范化数据 var stride=0;//0=向前移动大小*大小键入每个迭代以获得下一个位置 var offset=0;//从缓冲区的开头开始 gl.VertexAttribute指针 位置、位置、尺寸、类型、, 正常化、步幅、偏移; //启用teccord属性 gl.EnableVertexAttributeArrayExcoordLocation; //绑定位置缓冲区。 gl.bindBuffergl.ARRAY_BUFFER,PlaneteCoordBuffer; //告诉position属性如何从positionBuffer数组\u BUFFER中获取数据 变量大小=2;//每次迭代2个组件 变量类型=gl.FLOAT;//数据是32位浮点数 var normalize=false;//不要规范化数据 var stride=0;//0=向前移动大小*大小键入每个迭代以获得下一个位置 变量偏移量=0;//从缓冲区的开头开始 gl.VertexAttribute指针 texcoordLocation、大小、类型、规格化、跨步、偏移; //计算投影矩阵 var矩阵=m4.1; //设定矩阵。 gl.UniformMatrix4FvMatrixlLocation,false,矩阵; //告诉着色器对u_纹理使用纹理单元0 gl.uniform1,0; //绘制几何图形。 gl.drawArraysgl.TRIANGLES,0,6; } //画场景。 函数drawScenetime{ //转换为秒 时间*=0.001; //从当前时间中减去上一时间 var deltaTime=时间-然后; //记住下一帧的当前时间。 然后=时间; //为旋转设置动画 模型旋转弧度+=-0.7*deltaTime; 型号X旋转弧度+=-0.4*deltaTime; webglUtils.resizeCanvasToDisplaySizegl.canvas; gl.enablegl.CULL_面; gl.enablegl.DEPTH_测试; 功能图UnderTargetRT,左侧,底部,宽度,高度{ //通过绑定帧缓冲区渲染到我们的targetTexture gl.bindframebuffer gl.FRAMEBUFFER,rt.FRAMEBUFFER; //使用我们的颜色纹理渲染立方体 gl.bindTexturegl.TEXTURE_2D,纹理; //告诉WebGL如何将剪辑空间转换为像素 gl.viewport0,0,rt.width,rt.height; //清除附件。 gl.clearColor0,0,1,1;//清除为蓝色 gl.cleargl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT; const aspect=gl.canvas.clientWidth/gl.canvas.clientHeight; drawCubeaspect,左侧,底部,宽度,高度; } drawToRenderTargetlowResRT,0,0,2,2; drawToRenderTargethighResRT,0.5,0.5,1,1; 函数drawRenderTargetrt{ //渲染到画布 gl.bindframebuffer gl.FRAMEBUFFER,空; //使用刚才渲染到的纹理渲染立方体 gl.bindTexturegl.TEXTURE_2D、rt.TEXTURE; const aspect=gl.canvas.clientWidth/gl.canvas.clientHeight; 绘画方面; } gl.disablegl.DEPTH_测试; //告诉WebGL如何将剪辑空间转换为像素 gl.viewport0,0,gl.canvas.width,gl.canvas.height; drawRenderTargetlowResRT; //告诉WebGL如何将剪辑空间转换为像素 总图视口 gl.canvas.width/4, gl.canvas.height/4, gl.canvas.width/2, gl.canvas.height/2; drawRenderTargethighResRT; requestAnimationFramedrawScene; } } //用定义多维数据集的值填充缓冲区。 函数集GeometryGL{ 变量位置=新的浮动数组 [ -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, ]; gl.bufferDatagl.ARRAY_缓冲区、位置、gl.STATIC_绘图; } //使用立方体的纹理坐标填充缓冲区。 函数setTexcoordsgl{ 缓冲数据 gl.ARRAY\u缓冲区, 新浮点数组 [ 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, ], gl.静态绘制; } 主要的 身体{ 保证金:0; } 帆布{ 宽度:100vw; 高度:100vh; 显示:块; } 属性向量4 a_位置; 属性向量2 a_texcoord; 均匀mat4u_矩阵; 可变矢量2 v_texcoord; 虚迈 n{ //将位置乘以矩阵。 gl_位置=u_矩阵*a_位置; //将texcoord传递给片段着色器。 v_texcoord=a_texcoord; } 精密中泵浮子; //从顶点着色器传入。 可变矢量2 v_texcoord; //纹理。 均匀的二维u_纹理; 真空总管{ gl_FragColor=纹理2 du_纹理,v_texcoord; }
AFAICT大多数中心凹渲染都不是这样工作的。IIUC大多数中心凹渲染的工作原理是渲染不同分辨率的纹理,然后使用各种技术将它们组合在一起。好吧,格曼说的没错,中心凹渲染不是这样工作的。将画布平铺在一起会非常低效,因为您无法在始终绑定到单个画布的webgl上下文之间共享资源,更不用说您无法以这种方式使用WebVR API,因为这也假设了单个画布。