OpenGL ES 2.0-鱼眼着色器显示灰色图像

时间:2019-01-25 14:39:25

标签: opengl-es shader opengl-es-2.0 fragment-shader

我一直在尝试使用Shadertoy的鱼眼着色器。 我添加了自己的帧分辨率,并更改了一些关键字(texture-> texture2DfragColor-> gl_FragColor),仅此而已。 我真的不知道为什么它不起作用以及如何调试它。 结果,我得到了单色灰色图像。

这是我的片段着色器的代码:

precision mediump float;

uniform vec4 v_Color;
uniform sampler2D u_Texture;
varying vec2 v_TexCoordinate;

#define RESOLUTION_WIDTH 375.0
#define RESOLUTION_HEIGHT 211.0
#define POWER 2.0

void main() {

    vec2 fragCoord = v_TexCoordinate;
    vec2 iResolution = vec2(RESOLUTION_WIDTH, RESOLUTION_HEIGHT);

    vec2 p = fragCoord.xy / iResolution.x; // normalized coords with some cheat

    float prop = iResolution.x / iResolution.y;

    vec2 m = vec2(0.5, 0.5 / prop); // center coords
    vec2 d = p - m; // vector from center to current fragment
    float r = sqrt(dot(d, d)); // distance of pixel from center

    float power = POWER;

    float bind; // radius of 1:1 effect
    if (power > 0.0)
        bind = sqrt(dot(m, m)); // stick to corners
    else {
        if (prop < 1.0)
            bind = m.x;
        else
            bind = m.y;
    } // stick to borders

    // Weird formulas
    vec2 uv;
    if (power > 0.0) // fisheye
        uv = m + normalize(d) * tan(r * power) * bind / tan( bind * power);
    else if (power < 0.0) // antifisheye
        uv = m + normalize(d) * atan(r * -power * 10.0) * bind / atan(-power * bind * 10.0);
    else uv = p; // no effect for power = 1.0

    vec3 col = texture2D(u_Texture, vec2(uv.x, -uv.y * prop)).xyz; // Second part of cheat
    gl_FragColor = vec4(col, 1.0);
} 

这是我原来的着色器,用于显示效果理想的图像:

precision mediump float;

uniform vec4 v_Color;
uniform sampler2D u_Texture;
varying vec2 v_TexCoordinate;

void main() {
    // premultiplied alpha
    vec4 texColor = texture2D(u_Texture, v_TexCoordinate);
    // Scale the texture RGB by the vertex color
    texColor.rgb *= v_Color.rgb;
    // Scale the texture RGBA by the vertex alpha to reinstate premultiplication
    gl_FragColor = texColor * v_Color.a;
}

以下是ShaderToy上预期结果的链接:

ShaderToy fisheye

原始结果图片:

Original image

使用我的着色器:

With my shader

使用Rabbid76解决方案:

enter image description here

功率= 1.1时:

enter image description here

使用解决方案n2且功效= 10(更大的图片可以更好地看到):

enter image description here

文字后面有一些背景,不要关注它;)

1 个答案:

答案 0 :(得分:1)

在着色器代码fragCoord中假定为窗口坐标,最小值为(0,0),最大值为视口的宽度和高度。但是在您的代码中,v_TexCoordinate被分配给fragCoordv_TexCoordinate是[0,1]范围内的纹理Corodiante。

使用gl_FragCoord代替v_TexCoordinate

// vec2 fragCoord = v_TexCoordinate; <--- delete 
vec2 fragCoord = gl_FragCoord.xy;  
vec2 p = fragCoord.xy / iResolution.x;

或跳过除以窗口分辨率:

vec2 fragCoord = v_TexCoordinate;  
// vec2 p = fragCoord.xy / iResolution.x; <-- delete 
vec2 p = fragCoord.xy * vec2(1.0, iResolution.y/iResolution.x); 

如果不需要进行宽高比校正,那么甚至可以完成:

vec2 p = v_TexCoordinate.xy; 

请参阅WebGL示例,在该示例中,我使用您的原始着色器代码并应用了建议的更改:

(function loadscene() {

var gl, canvas, prog, bufObj = {};
var texture;

function render(deltaMS) {

  texture.bound = texture.bound || texture.bind( 0 );

  gl.viewport( 0, 0, vp_size[0], vp_size[1] );
  gl.enable( gl.DEPTH_TEST );
  gl.clearColor( 0.0, 0.0, 0.0, 1.0 );
  gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
  ShProg.Use( progDraw );
  ShProg.SetF2( progDraw, "resolution", vp_size );
  ShProg.SetI1( progDraw, "u_texture", 0 );
  VertexBuffer.Draw( bufRect );

  requestAnimationFrame(render);
}  

function initScene() {

  canvas = document.getElementById( "texture-canvas");
  gl = canvas.getContext( "experimental-webgl" );
  //gl = canvas.getContext( "webgl2" );
  if ( !gl )
    return;
    
  progDraw = ShProg.Create( 
    [ { source : "draw-shader-vs", stage : gl.VERTEX_SHADER },
      { source : "draw-shader-fs", stage : gl.FRAGMENT_SHADER }
    ] );
  progDraw.inPos = gl.getAttribLocation( progDraw.progObj, "inPos" );
  if ( progDraw.progObj == 0 )
      return;

  bufRect = VertexBuffer.Create(
  [ { data :  [ -1, -1, 1, -1, 1, 1, -1, 1 ], attrSize : 2, attrLoc : progDraw.inPos } ],
    [ 0, 1, 2, 0, 2, 3 ] );


  texture = new Texture( "https://raw.githubusercontent.com/Rabbid76/graphics-snippets/master/resource/texture/supermario.jpg" ); 
  texture.bound = false;

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

function resize() {
  //vp_size = [gl.drawingBufferWidth, gl.drawingBufferHeight];
  vp_size = [window.innerWidth, window.innerHeight]
  vp_size[0] = vp_size[1] = Math.min(vp_size[0], vp_size[1]); 
  //vp_size = [256, 256]
  canvas.width = vp_size[0];
  canvas.height = vp_size[1];
}

var ShProg = {
Create: function (shaderList) {
  var shaderObjs = [];
  for (var i_sh = 0; i_sh < shaderList.length; ++i_sh) {
      var shderObj = this.Compile(shaderList[i_sh].source, shaderList[i_sh].stage);
      if (shderObj) shaderObjs.push(shderObj);
  }
  var prog = {}
  prog.progObj = this.Link(shaderObjs)
  if (prog.progObj) {
      prog.attrInx = {};
      var noOfAttributes = gl.getProgramParameter(prog.progObj, gl.ACTIVE_ATTRIBUTES);
      for (var i_n = 0; i_n < noOfAttributes; ++i_n) {
          var name = gl.getActiveAttrib(prog.progObj, i_n).name;
          prog.attrInx[name] = gl.getAttribLocation(prog.progObj, name);
      }
      prog.uniLoc = {};
      var noOfUniforms = gl.getProgramParameter(prog.progObj, gl.ACTIVE_UNIFORMS);
      for (var i_n = 0; i_n < noOfUniforms; ++i_n) {
          var name = gl.getActiveUniform(prog.progObj, i_n).name;
          prog.uniLoc[name] = gl.getUniformLocation(prog.progObj, name);
      }
  }
  return prog;
},
AttrI: function (prog, name) { return prog.attrInx[name]; },
UniformL: function (prog, name) { return prog.uniLoc[name]; },
Use: function (prog) { gl.useProgram(prog.progObj); },
SetI1: function (prog, name, val) { if (prog.uniLoc[name]) gl.uniform1i(prog.uniLoc[name], val); },
SetF1: function (prog, name, val) { if (prog.uniLoc[name]) gl.uniform1f(prog.uniLoc[name], val); },
SetF2: function (prog, name, arr) { if (prog.uniLoc[name]) gl.uniform2fv(prog.uniLoc[name], arr); },
SetF3: function (prog, name, arr) { if (prog.uniLoc[name]) gl.uniform3fv(prog.uniLoc[name], arr); },
SetF4: function (prog, name, arr) { if (prog.uniLoc[name]) gl.uniform4fv(prog.uniLoc[name], arr); },
SetM33: function (prog, name, mat) { if (prog.uniLoc[name]) gl.uniformMatrix3fv(prog.uniLoc[name], false, mat); },
SetM44: function (prog, name, mat) { if (prog.uniLoc[name]) gl.uniformMatrix4fv(prog.uniLoc[name], false, mat); },
Compile: function (source, shaderStage) {
  var shaderScript = document.getElementById(source);
  if (shaderScript)
      source = shaderScript.text;
  var shaderObj = gl.createShader(shaderStage);
  gl.shaderSource(shaderObj, source);
  gl.compileShader(shaderObj);
  var status = gl.getShaderParameter(shaderObj, gl.COMPILE_STATUS);
  if (!status) alert(gl.getShaderInfoLog(shaderObj));
  return status ? shaderObj : null;
},
Link: function (shaderObjs) {
  var prog = gl.createProgram();
  for (var i_sh = 0; i_sh < shaderObjs.length; ++i_sh)
      gl.attachShader(prog, shaderObjs[i_sh]);
  gl.linkProgram(prog);
  status = gl.getProgramParameter(prog, gl.LINK_STATUS);
  if ( !status ) alert(gl.getProgramInfoLog(prog));
  return status ? prog : null;
} };

var VertexBuffer = {
Create: function(attribs, indices, type) {
  var buffer = { buf: [], attr: [], inx: gl.createBuffer(), inxLen: indices.length, primitive_type: type ? type : gl.TRIANGLES };
  for (var i=0; i<attribs.length; ++i) {
      buffer.buf.push(gl.createBuffer());
      buffer.attr.push({ size : attribs[i].attrSize, loc : attribs[i].attrLoc, no_of: attribs[i].data.length/attribs[i].attrSize });
      gl.bindBuffer(gl.ARRAY_BUFFER, buffer.buf[i]);
      gl.bufferData(gl.ARRAY_BUFFER, new Float32Array( attribs[i].data ), gl.STATIC_DRAW);
  }
  gl.bindBuffer(gl.ARRAY_BUFFER, null);
  if ( buffer.inxLen > 0 ) {
      gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer.inx);
      gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( indices ), gl.STATIC_DRAW);
      gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
  }
  return buffer;
},
Draw: function(bufObj) {
  for (var i=0; i<bufObj.buf.length; ++i) {
      gl.bindBuffer(gl.ARRAY_BUFFER, bufObj.buf[i]);
      gl.vertexAttribPointer(bufObj.attr[i].loc, bufObj.attr[i].size, gl.FLOAT, false, 0, 0);
      gl.enableVertexAttribArray( bufObj.attr[i].loc);
  }
  if ( bufObj.inxLen > 0 ) {
      gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, bufObj.inx);
      gl.drawElements(bufObj.primitive_type, bufObj.inxLen, gl.UNSIGNED_SHORT, 0);
      gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, null );
  }
  else
      gl.drawArrays(bufObj.primitive_type, 0, bufObj.attr[0].no_of );
  for (var i=0; i<bufObj.buf.length; ++i)
      gl.disableVertexAttribArray(bufObj.attr[i].loc);
  gl.bindBuffer( gl.ARRAY_BUFFER, null );
} };

class Texture {
    constructor( name, dflt ) {
        let texture = this;
        this.dflt = dflt || [128,128,128,255]
        let image = { "cx": this.dflt.w || 1, "cy": this.dflt.h || 1, "plane": this.dflt.p || this.dflt };
        this.size = [image.cx, image.cy];
        this.dummyObj = Texture.createTexture2D( image, true )
        this.image = new Image(64,64);
        this.image.setAttribute('crossorigin', 'anonymous');
        this.image.onload = function () {
            let cx = 1 << 31 - Math.clz32(texture.image.naturalWidth);
            if ( cx < texture.image.naturalWidth ) cx *= 2;
            let cy = 1 << 31 - Math.clz32(texture.image.naturalHeight);
            if ( cy < texture.image.naturalHeight ) cy *= 2;
            var canvas = document.createElement( 'canvas' );
            canvas.width  = cx;
            canvas.height = cy;
            var context = canvas.getContext( '2d' );
            context.drawImage( texture.image, 0, 0, canvas.width, canvas.height );
            texture.textureObj = Texture.createTexture2D( canvas, true );
            texture.size = [cx, cy];
        }
        this.image.src = name;
    }
    static createTexture2D( image, flipY ) {
        let t = gl.createTexture();
        gl.activeTexture( gl.TEXTURE0 );
        gl.bindTexture( gl.TEXTURE_2D, t );
        gl.pixelStorei( gl.UNPACK_FLIP_Y_WEBGL, flipY != undefined && flipY == true );
        if ( image.cx && image.cy && image.plane )
            gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, image.cx, image.cy, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(image.plane) );
        else
            gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image );
        gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR );
        gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR );
        gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT );
        gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT );
        gl.bindTexture( gl.TEXTURE_2D, null );
        return t;
    }
    bind( texUnit = 0 ) {
        gl.activeTexture( gl.TEXTURE0 + texUnit );
        if ( this.textureObj ) { 
            gl.bindTexture( gl.TEXTURE_2D, this.textureObj );
            return true;
        }
        gl.bindTexture( gl.TEXTURE_2D, this.dummyObj );
        return false;
    }
};

initScene();

})();
<script id="draw-shader-vs" type="x-shader/x-vertex">
precision mediump float;

attribute vec2 inPos;

void main()
{
    gl_Position = vec4( inPos.xy, 0.0, 1.0 );
}
</script>
  
<script id="draw-shader-fs" type="x-shader/x-fragment">
precision mediump float;
  
uniform vec2 resolution;

uniform sampler2D u_Texture;

#define RESOLUTION_WIDTH 375.0
#define RESOLUTION_HEIGHT 211.0
#define POWER 2.0

void main( void )
{
  vec2 fragCoord = gl_FragCoord.xy;
  vec2 iResolution = resolution; 
  //vec2 fragCoord = v_TexCoordinate;
  //vec2 iResolution = vec2(RESOLUTION_WIDTH, RESOLUTION_HEIGHT);

  vec2 p = fragCoord.xy / iResolution.x; // normalized coords with some cheat

  float prop = iResolution.x / iResolution.y;

  vec2 m = vec2(0.5, 0.5 / prop); // center coords
  vec2 d = p - m; // vector from center to current fragment
  float r = sqrt(dot(d, d)); // distance of pixel from center

  float power = POWER;

  float bind; // radius of 1:1 effect
  if (power > 0.0)
      bind = sqrt(dot(m, m)); // stick to corners
  else {
      if (prop < 1.0)
          bind = m.x;
      else
          bind = m.y;
  } // stick to borders

  // Weird formulas
  vec2 uv;
  if (power > 0.0) // fisheye
      uv = m + normalize(d) * tan(r * power) * bind / tan( bind * power);
  else if (power < 0.0) // antifisheye
      uv = m + normalize(d) * atan(r * -power * 10.0) * bind / atan(-power * bind * 10.0);
  else uv = p; // no effect for power = 1.0

  vec3 col = texture2D(u_Texture, vec2(uv.x, -uv.y * prop)).xyz; // Second part of cheat
  gl_FragColor = vec4(col, 1.0);
}

</script>

<body>
<canvas id="texture-canvas" style="border: none"></canvas>
</body>