javascript - readPixels 函数返回未修改的纹理

标签 javascript webgl framebuffer

我正在尝试将图像(作为纹理)绘制到帧缓冲区,应用锐度过滤器(通过拖动 UI 上的 slider ),然后从帧缓冲区读取结果,并通过调用将数据复制到简单的 2d Canvas (不是 webgl) readPixels 与绑定(bind)的帧缓冲区,获取像素数组并将它们复制到 ImageData.data,但该函数返回原始纹理。

也许有人可以向我解释一下,因为据我了解,屏幕上的东西实际上是帧缓冲区的内容。

抱歉,代码太多,但我希望它可以帮助您理解我在做什么。

(function () {
  var anotherContext = null;
  var canvas = $("#canvas");

  main();
  setupCanvas();

  function setupCanvas () {
    anotherContext = document.getElementById("anothercanvas").getContext("2d");
  }

  function main () {
    var image = new Image();
    image.src = "http://localhost:9292/img/ava.jpg";
    image.onload = function () {
      render(image);
    }
  }

  function render (image) {
    //-----get contexts----
    var canvas = document.getElementById('canvas');
    var gl = canvas.getContext('experimental-webgl');

    //----define shaders-----
    var vs = document.getElementById('vshader').textContent;
    var fs = document.getElementById('fshader').textContent;

    //----create program-----
    var program = createProgram(vs, fs);
    gl.useProgram(program);

    //----setup vertex data-----
    var positionLocation = gl.getAttribLocation(program, "a_position");
    var texCoordLocation = gl.getAttribLocation(program, "a_texCoord");

    //----setup texture-----
    var texCoordBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
        0.0,  0.0,
        1.0,  0.0,
        0.0,  1.0,
        0.0,  1.0,
        1.0,  0.0,
        1.0,  1.0]), gl.STATIC_DRAW);
    gl.enableVertexAttribArray(texCoordLocation);
    gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);

    // Create a texture.
    var texture = createAndSetupTexture();
    // Upload the image into the texture.
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);

    //---framebuffer----
    var framebuffer = gl.createFramebuffer();
    gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);

    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
    var canRead = (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE);
    console.log("Can read: ", canRead);

    //----lookup uniforms and set the resolution-----
    var resolutionLocation = gl.getUniformLocation(program, "u_resolution");
    var textureSizeLocation = gl.getUniformLocation(program, "u_textureSize");
    var kernelLocation = gl.getUniformLocation(program, "u_kernel[0]");

    gl.uniform2f(textureSizeLocation, image.width, image.height);

    //----kernels-----
    var kernel = [
       0, 0, 0,
       0, 1, 0,
       0, 0, 0
    ];

    var sharpnessKernel = [
       0,-1, 0,
      -1, 5, -1,
       0,-1, 0
    ];

    //-----bind buffer------
    var vertexBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
    gl.enableVertexAttribArray(positionLocation);
    gl.vertexAttribPointer(program.vertexPosAttrib, 2, gl.FLOAT, false, 0, 0);

    setRectangle(gl, 0, 0, image.width, image.height);

    draw(kernel);

    function draw (krn) {
      // gl.bindTexture(gl.TEXTURE_2D, texture);

      setFramebuffer(framebuffer);
      drawWithKernel(krn);

      copyImage();

      // gl.bindTexture(gl.TEXTURE_2D, texture);
      setFramebuffer(null);

      gl.drawArrays(gl.TRIANGLES, 0, 6);
    }

    function setFramebuffer (fbuf) {
      gl.bindFramebuffer(gl.FRAMEBUFFER, fbuf);

      gl.uniform2f(resolutionLocation, canvas.width, canvas.height);

      gl.viewport(0, 0, canvas.width, canvas.height);
    }

    function drawWithKernel (kernel) {
      gl.uniform1fv(kernelLocation, kernel);

      //---draw
      gl.drawArrays(gl.TRIANGLES, 0, 6);
    }

    function createAndSetupTexture () {
      var texture = gl.createTexture();
      gl.bindTexture(gl.TEXTURE_2D, texture);

      // Set the parameters so we can render any size image.
      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_MIN_FILTER, gl.NEAREST);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);

      return texture;
    }

    function setRectangle (gl, x, y, width, height) {
      var x1 = x;
      var x2 = x + width;
      var y1 = y;
      var y2 = y + height;
      gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
         x1, y1,
         x2, y1,
         x1, y2,
         x1, y2,
         x2, y1,
         x2, y2]), gl.STATIC_DRAW);
    }

    function createShader(str, type) {
      var shader = gl.createShader(type);

      gl.shaderSource(shader, str);
      gl.compileShader(shader);

      return shader;
    }

    function createProgram (vstr, fstr) {
      var program = gl.createProgram();
      var vshader = createShader(vstr, gl.VERTEX_SHADER);
      var fshader = createShader(fstr, gl.FRAGMENT_SHADER);

      gl.attachShader(program, vshader);
      gl.attachShader(program, fshader);
      gl.linkProgram(program);

      return program;
    }

    function copyImage () {
      var pixels = new Uint8Array(image.width * image.height * 4);
      gl.readPixels(0, 0, image.width, image.height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);

      var imageData = anotherContext.createImageData(image.width, image.height);
      for (var i = pixels.length - 1; i >= 0; i--) {
        imageData.data[i] = pixels[i];
      };

      // console.log(imageData.data);
      anotherContext.putImageData(imageData, 0, 0);
    }

    $("#slider").slider({
      min: 0,
      max: 99,
      slide: function (event, ui) {
        var currentKernel = null;

        //do not use any filtering if slider is on 0 position
        if(ui.value == 0) {
          currentKernel = kernel;
        }
        else {
          currentKernel = sharpnessKernel.slice(0);
          currentKernel[4] -= (ui.value / 100);
        }

        draw(currentKernel);
      }
    });
  }
})()

最佳答案

您当前的函数和括号设置完全损坏,这也表明您没有使用 firebug或任何其他 web-console调试您的 JavaScript。

首先,您应该将一些函数移到主函数之外并获得 modern editor因为它们中的大多数都有显示属于一起的括号的方法。

编辑:看起来类似于 WebGL fundamentals 中的代码。回答您的问题:仅当绑定(bind)的帧缓冲区为空时(正如您可以在该网站上阅读的那样),您才会绘制到屏幕。

无论如何,您可能会在这方面得到帮助:Creating texture from getImageData (Javascript)或者可能fabric.js image filters

关于javascript - readPixels 函数返回未修改的纹理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17625671/

相关文章:

JavaScript DOM 图像预加载

javascript - 在 jQuery 中异步切换 Like 和 Unlike

javascript - 纹理 Splatted Terrain 上的法线贴图

three.js - 您可以将原始 WebGL 纹理与 Three.js 一起使用吗

android - OpenGL 渲染到纹理 - 黑屏

android - 没有 GL_OES_packed_depth_stencil 的 OpenGL 帧缓冲区 android(在 Nexus 7 2012 上)

Android读取fb0总是给我黑屏

javascript - 检测当前 Web 组件外部的点击

javascript - 导出的是从 module.exports 返回的对象

javascript - jsPlumb 的流程图