【问题标题】:WebGL - When I read pixel data from frame buffer, icon loses its transparencyWebGL - 当我从帧缓冲区读取像素数据时,图标失去透明度
【发布时间】:2021-01-14 17:28:38
【问题描述】:

我有一个透明的图标图。 256x256

我使用这张图片创建了一个纹理。

    AddIconMap(imageUrl) {
        const image = new Image()
        const { gl } = this
        image.onload = () => {
            const iconMapTexture = gl.createTexture()
            gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false)
            gl.bindTexture(gl.TEXTURE_2D, iconMapTexture)
            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image)
            gl.generateMipmap(gl.TEXTURE_2D)

            gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR)
            gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
            gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
            gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
            gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true)
            this.mapTexture.push(iconMapTexture) 
            window.URL.revokeObjectURL(image.src)
        }
        image.crossOrigin = ''
        image.src = imageUrl
    }

然后,我想在此纹理中获取最后一个小图标并将其绘制在画布上。画布的高度和宽度为 256px。每个small的高宽都是32px。

     var frameBuffer = gl.createFramebuffer();
     gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer)
     gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.Sphere.mapTexture[0], 0)
     const pixel = new Uint8Array(4 * 32 * 32)
     gl.readPixels(224, 224, 32, 32, gl.RGBA, gl.UNSIGNED_BYTE, pixel)
     var imageData = this.ctx.createImageData(32, 32)
     imageData.data.set(pixel)
     this.ctx.putImageData(imageData, offset.x, offset.y, 0, 0, 32, 32)

我在画布上绘制了图标,但图标不透明。我想,也获取背景图片的像素,但我不想要这个。

有什么想法吗?我该怎么办?

【问题讨论】:

    标签: webgl textures framebuffer


    【解决方案1】:

    检查

    const gl = document.createElement('canvas').getContext('webgl');
    const r = max => Math.random() * max;
    
    class Foo {
      constructor(gl) {
        this.mapTexture = [];
        this.gl = gl;
      }
      AddIconMap(imageUrl) {
        const image = new Image()
        const {
          gl
        } = this
        image.onload = () => {
          const iconMapTexture = gl.createTexture()
          gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false)
          gl.bindTexture(gl.TEXTURE_2D, iconMapTexture)
          gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image)
          gl.generateMipmap(gl.TEXTURE_2D)
    
          gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR)
          gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
          gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
          gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
          gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true)
          this.mapTexture.push(iconMapTexture)
          window.URL.revokeObjectURL(image.src)
        }
        image.crossOrigin = ''
        image.src = imageUrl
      }
    }
    
    class Bar {
      constructor() {
        this.ctx = document.querySelector('canvas').getContext('2d');
        this.Sphere = new Foo(gl);
        this.Sphere.AddIconMap('https://i.imgur.com/1zS9of5.png');
    
      }
      drawInReallyStrangeWay(offset) {
        var frameBuffer = gl.createFramebuffer();
        gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer)
        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.Sphere.mapTexture[0], 0)
        const pixel = new Uint8Array(4 * 32 * 32)
        gl.readPixels(224, 224, 32, 32, gl.RGBA, gl.UNSIGNED_BYTE, pixel)
        var imageData = this.ctx.createImageData(32, 32)
        imageData.data.set(pixel)
        this.ctx.putImageData(imageData, offset.x, offset.y, 0, 0, 32, 32)
      }
    
    }
    
    const b = new Bar();
    setInterval(() => {
      if (b.Sphere.mapTexture.length) {
        b.drawInReallyStrangeWay({
          x: r(300 - 32),
          y: r(150 - 32)
        });
      }
    }, 200);
    canvas {
      background-color: #C0C0C0;
      background-image: linear-gradient(45deg, #808080 25%, transparent 25%), linear-gradient(-45deg, #808080 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #808080 75%), linear-gradient(-45deg, transparent 75%, #808080 75%);
      background-size: 20px 20px;
      background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
    }
    <canvas></canvas>

    它对我有用。目前尚不清楚为什么要使用 WebGL 加载纹理,然后使用 readPixels 将数据从纹理中提取出来,并将其放入 2D 画布中而不是 drawing it with WebGL。但是,putImageData 替换了画布中的数据。它不混合。如果你想混合,那么你需要使用drawImage 在这种情况下使用 WebGL 根本没有意义,只需加载图像并绘制你想要的部分

    const r = max => Math.random() * max;
    
    class Foo {
      constructor() {
        this.mapTexture = [];
      }
      AddIconMap(imageUrl) {
        const image = new Image()
        image.onload = () => {
          this.mapTexture.push(image)
        }
        image.crossOrigin = ''
        image.src = imageUrl
      }
    }
    
    class Bar {
      constructor() {
        this.ctx = document.querySelector('canvas').getContext('2d');
        this.Sphere = new Foo();
        this.Sphere.AddIconMap('https://i.imgur.com/1zS9of5.png');
    
      }
      draw(offset) {
        const image = b.Sphere.mapTexture[0];
        this.ctx.drawImage(
            image, 
            224, 224, 32, 32,            // src rect
            offset.x, offset.y, 32, 32,  // dst rect
        );
      }
    }
    
    const b = new Bar();
    setInterval(() => {
      if (b.Sphere.mapTexture.length) {
        b.draw({
          x: r(300 - 32),
          y: r(150 - 32)
        });
      }
    }, 200);
    canvas {
      background-color: #C0C0C0;
      background-image: linear-gradient(45deg, #808080 25%, transparent 25%), linear-gradient(-45deg, #808080 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #808080 75%), linear-gradient(-45deg, transparent 75%, #808080 75%);
      background-size: 20px 20px;
      background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
    }
    <canvas></canvas>

    【讨论】:

    • 谢谢,但我不想使用该图像。如果我不撤销图像,我就会有记忆问题。我需要在创建纹理后删除图像,所以我必须从帧缓冲区读取像素数据并在画布上绘制。
    猜你喜欢
    • 2015-03-26
    • 2015-07-02
    • 2011-09-04
    • 2013-05-17
    • 1970-01-01
    • 2014-07-13
    • 1970-01-01
    • 2020-07-13
    • 1970-01-01
    相关资源
    最近更新 更多