WebGL中的高斯模糊错误

3
我正在尝试在WebGL中编写一个简单的高斯模糊着色器。我已经搜索了很多关于这个问题的内容,我认为我理解了其中的思路。给定这个3X3的卷积核,如何将其应用到我的顶点着色器中呢?这是我的当前输出
[ 0.0625  0.125  0.0625 ]
[ 0.125   0.25   0.125  ]
[ 0.0625  0.125  0.0625 ]

特别是如何获取相邻像素?

这个逻辑有意义吗?

precision mediump float;
varying vec2 vUV;

uniform sampler2D uTexture;

void main(){
     gl_FragColor = texture2D(uTexture, vUV + vec2(????,????)*0.0625;


}

我需要在vec2()里输入什么?如果我想获取卷积核的左上角纹理值。假设vUv为(20,20),那么为了获取(19,19),我应该写什么?

     gl_FragColor = vec4(0.0);
     gl_FragColor += texture2D(uTexture, vUV  +  vec2(vUV.x-1.0,vUV.y-1.0))*0.0625;
     gl_FragColor += texture2D(uTexture, vUV + vec2(vUV.x,vUV.y-1.0))*0.125;    
     gl_FragColor += texture2D(uTexture, vUV + vec2(vUV.x+1.0,vUV.y-1.0))*0.0625;

     gl_FragColor += texture2D(uTexture, vUV  +  vec2(vUV.x-1.0,vUV.y))*0.125;
     gl_FragColor += texture2D(uTexture, vUV + vec2(vUV.x,vUV.y))*0.25; 
     gl_FragColor += texture2D(uTexture, vUV + vec2(vUV.x+1.0,vUV.y))*0.125;    


     gl_FragColor += texture2D(uTexture, vUV  +  vec2(vUV.x-1.0,vUV.y+1.0))*0.0625;
     gl_FragColor += texture2D(uTexture, vUV + vec2(vUV.x,vUV.y+1.0))*0.125;    
     gl_FragColor += texture2D(uTexture, vUV + vec2(vUV.x+1.0,vUV.y+1.0))*0.0625;   

@Rabbid76,我该怎么做?这是我的当前输出 https://jsbin.com/nuvenotoqe/edit?html,js,output - anekix
@Rabbid76,这里的实现似乎没有除以任何东西?https://github.com/phoboslab/WebGLImageFilter/blob/master/webgl-image-filter.js - anekix
@Rabbid76,你能在回答中简单解释一下吗?因为我对WebGL非常新手。 - anekix
2
Rabbid76在他们的回答中链接了webglfundamentals,所以我想添加这篇文章实现了模糊效果 - gman
@gman 非常感谢,我一定会仔细阅读 :) - anekix
1个回答

6

用于通过texture2D查找纹理的纹理坐标必须在[0.0, 1.0]范围内。

另请参阅

为了使您的着色器工作,您必须定义一个包含用于创建模糊效果的像素的偏移量的统一变量:

uniform vec2 offs_blur;

使用此偏移量进行9个纹理查询:
gl_FragColor = vec4(0.0);
gl_FragColor += texture2D(uTexture, vUV + vec2(-offs_blur.x, -offs_blur.y))*0.0625;
gl_FragColor += texture2D(uTexture, vUV + vec2(         0.0, -offs_blur.y))*0.125;  
gl_FragColor += texture2D(uTexture, vUV + vec2( offs_blur.x, -offs_blur.y))*0.0625;

gl_FragColor += texture2D(uTexture, vUV + vec2(-offs_blur.x,          0.0))*0.125;
gl_FragColor += texture2D(uTexture, vUV + vec2(         0.0,          0.0))*0.25;   
gl_FragColor += texture2D(uTexture, vUV + vec2( offs_blur.x,          0.0))*0.125;  


gl_FragColor += texture2D(uTexture, vUV + vec2(-offs_blur.x, offs_blur.y))*0.0625;
gl_FragColor += texture2D(uTexture, vUV + vec2(         0.0, offs_blur.y))*0.125;   
gl_FragColor += texture2D(uTexture, vUV + vec2( offs_blur.x, offs_blur.y))*0.0625;  

邻近纹理的偏移量为纹理大小的倒数 (1/width, 1/height)
但是,为达到模糊效果,偏移量无需准确。增加偏移量会增强模糊效果,但会导致质量下降。随着偏移量的增加,伪影和条纹效应也会增加。为了避免这种情况,您需要增加所查找的纹理数量(例如,查询5x5个纹理)。
将 uniform 设置为以下内容:
offs_blur = gl.getUniformLocation(program,"offs_blur");

var blur = 20.0;
gl.uniform2fv(offs_blur,[blur/image.width, blur/image.height]);

请看这个例子,它将回答中的建议应用到了你问题的原始代码中。

var canvas = document.createElement('canvas')
 canvas.width = window.innerWidth
 canvas.height = window.innerHeight
 document.body.appendChild(canvas)
 

 var gl = canvas.getContext('webgl')
 //  clear canvas with any color you want
 gl.clearColor(0.75, 0.85, 0.8, 1.0)
 gl.clear(gl.COLOR_BUFFER_BIT)


 function main() {
   var image = new Image();
     image.crossOrigin = "anonymous";

   image.src = "https://i.imgur.com/GdkFHnw.jpg";
   image.onload = function() {
  render(image);
   }
 }

 // generic function to create shaders
 function createShader(gl, source, type){
  var shader = gl.createShader(type);
  gl.shaderSource(shader, source);
  gl.compileShader(shader);
    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
  console.error('ERROR compiling shader type=>'+ type, gl.getShaderInfoLog(shader));
  return;
   }
 return shader
 }


 function createBuffer(data) {
   data = data instanceof Float32Array ? data : new Float32Array(data);
   var buffer = gl.createBuffer();
   gl.bindBuffer(gl.ARRAY_BUFFER,buffer);
   gl.bufferData(gl.ARRAY_BUFFER,data,gl.STATIC_DRAW);
   return buffer;
 }


 // function that returns a `program` from compiled vertex & fragment shaders
 function createProgram(gl, vertexShader, fragmentShader) {
   var program = gl.createProgram();
   gl.attachShader(program, vertexShader);
   gl.attachShader(program, fragmentShader);
   gl.linkProgram(program);
   var success = gl.getProgramParameter(program, gl.LINK_STATUS);
   if (!success) {
    // something went wrong with the link
    throw ("program filed to link:" + gl.getProgramInfoLog (program));
   }
   return program;
 };

  var texture_width = 1, texture_height = 1; 

 // Creates a texture from an existing canvas or HTMLImage (new Image())
 // without needing width & height or with a typed array (Uint8Array) that has
 // a specified width & height
 // e.g.
 // createTexture(HTMLImageElement) will work just fine
 // createTexture(Uint8Array,width,height), remember that a texture needs four values for one pixel
 function createTexture(image,width,height) {
   
    var texture = gl.createTexture();
   
   // Set the active texture slot to 0
   // WebGL has ~30 texture slots, meaning you could have about 30 textures bound at once
   // Think of it as an array of 30 pointers to texture objects that you can set
   gl.activeTexture(gl.TEXTURE0); // Sets the current 'index'
   gl.bindTexture(gl.TEXTURE_2D,texture); // binds the selected texture object to the current pointer
   
   // How to filter the texture when it needs resizing when sampled
   // (Is it going to be blurred when streched?)
   // (gl.NEAREST means no blur)
   gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.NEAREST);
   gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.NEAREST);
   
   // What to do if UV coordinates go outside the texture's size
   // gl.CLAMP_TO_EDGE repeats the pixel at the texture's border.
   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);
   
   width === undefined && height === undefined ?
  gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,gl.RGBA,gl.UNSIGNED_BYTE,image):
  gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,width,height,0,gl.RGBA,gl.UNSIGNED_BYTE,image);

   return texture;
 }


 function render(image){
  //alert('rendering...')
 //vertex shader source

 const vertexShaderSource = [  
   'attribute vec2 aPosition;',
   'attribute vec2 aUV;',
   'varying vec2 vUV;',
   'void main(){',
   '  gl_Position = vec4(aPosition, 0.0, 1.0);',
   '  vUV = aUV;',
   '}',
 ].join("\n");


 //fragment shader source
 const fragShaderSource = `

   precision mediump float;
   varying vec2 vUV;
   uniform sampler2D uTexture;
   void main(){
   float brightness = 1.1;

   gl_FragColor = texture2D(uTexture, vUV);
   gl_FragColor.rgb *= brightness;

   }`


 const blurShader = `

 precision mediump float;
 varying vec2 vUV;

 uniform sampler2D uTexture;
  uniform vec2 offs_blur;

 //[ 0.0625  0.125  0.0625 ]
 //[ 0.125   0.25   0.125  ]
 //[ 0.0625  0.125  0.0625 ]
 void main(){
  
     gl_FragColor = vec4(0.0);
   gl_FragColor += texture2D(uTexture, vUV + vec2(-offs_blur.x, -offs_blur.y))*0.0625;
   gl_FragColor += texture2D(uTexture, vUV + vec2(         0.0, -offs_blur.y))*0.125; 
   gl_FragColor += texture2D(uTexture, vUV + vec2( offs_blur.x, -offs_blur.y))*0.0625;
   
   gl_FragColor += texture2D(uTexture, vUV + vec2(-offs_blur.x,          0.0))*0.125;
   gl_FragColor += texture2D(uTexture, vUV + vec2(         0.0,          0.0))*0.25; 
   gl_FragColor += texture2D(uTexture, vUV + vec2( offs_blur.x,          0.0))*0.125; 


   gl_FragColor += texture2D(uTexture, vUV + vec2(-offs_blur.x, offs_blur.y))*0.0625;
   gl_FragColor += texture2D(uTexture, vUV + vec2(         0.0, offs_blur.y))*0.125; 
   gl_FragColor += texture2D(uTexture, vUV + vec2( offs_blur.x, offs_blur.y))*0.0625; 
 }
 `
 // const fragShaderSource =  [
 //     'precision highp float;',
 //     'varying vec2 vUV;',
 //     'uniform sampler2D texture;',
 //     '',
 //     'void main(void) {',
 //     'vec4 c = texture2D(texture, vUV);',
 //     'gl_FragColor = vec4(1.0 - c.r, 1.0 - c.g, 1.0 - c.b, c.a);',
 //     '}'
 // ].join('\n');
 //create vertex shader
 var vertexShader = createShader(gl, vertexShaderSource, gl.VERTEX_SHADER);

 //create fragment shader
 var fragShader = createShader(gl, blurShader, gl.FRAGMENT_SHADER);

 //create program
 var program = createProgram(gl,vertexShader, fragShader);

 // get location of attributes & uniforms
 aPosition = gl.getAttribLocation(program,"aPosition");
 aUV = gl.getAttribLocation(program,"aUV");
 uTexture = gl.getUniformLocation(program,"uTexture");
  offs_blur = gl.getUniformLocation(program,"offs_blur");
  

 var buffer = createBuffer([
   // X  Y     U   V
    0.5, 0.5,  1.0,0.0,
   -0.5, 0.5,  0.0,0.0,
    0.5,-0.5,  1.0,1.0,
    
    0.5,-0.5,  1.0,1.0,
   -0.5, 0.5,  0.0,0.0,
   -0.5,-0.5,  0.0,1.0,
 ]);

  texture = createTexture(image);

  // Setup GL State
 gl.useProgram(program); 
 gl.uniform1i(uTexture,0);
  var blur = 20.0;
  gl.uniform2fv(offs_blur,[blur/image.width, blur/image.height]);

  gl.activeTexture(gl.TEXTURE0);
 gl.bindTexture(gl.TEXTURE_2D,texture);

 gl.bindBuffer(gl.ARRAY_BUFFER,buffer);

 // These functions tell WebGL how to interpret the vertexbuffer data

 // Every sixteen bytes, use the first eight (4 bytes is a float) for the 'aPosition' attribute
 gl.vertexAttribPointer(aPosition,2,gl.FLOAT,gl.FALSE,16,0);

 // Every sixteen bytes, use the last eight bytes for the 'aUV' attribute
 gl.vertexAttribPointer(aUV,2,gl.FLOAT,gl.FALSE,16,8);

 // These need to be enabled or the vertex data isn't fed indo the vertex shader
 gl.enableVertexAttribArray(aPosition);
 gl.enableVertexAttribArray(aUV);

  window.onresize = resize;
  resize();
  requestAnimationFrame(draw);
}

function draw(delteMS){

 gl.clearColor(0.5,0.5,0.5,1.0);
 gl.clear(gl.COLOR_BUFFER_BIT);
 gl.drawArrays(gl.TRIANGLES,0,6);

  requestAnimationFrame(draw);
}

function resize() {
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
  gl.viewport( 0, 0, canvas.width, canvas.height );
}

main();

  


非常感谢。我需要一些时间来消化这一切。 - anekix

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接