WebGL - 当我从帧缓冲区读取像素数据时,图标失去透明度
Posted
技术标签:
【中文标题】WebGL - 当我从帧缓冲区读取像素数据时,图标失去透明度【英文标题】:WebGL - When I read pixel data from frame buffer, icon loses its transparency 【发布时间】: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)
我在画布上绘制了图标,但图标不透明。我想,也获取背景图片的像素,但我不想要这个。
有什么想法吗?我该怎么办?
【问题讨论】:
【参考方案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>
【讨论】:
谢谢,但我不想使用该图像。如果我不撤销图像,我就会有记忆问题。我需要在创建纹理后删除图像,所以我必须从帧缓冲区读取像素数据并在画布上绘制。以上是关于WebGL - 当我从帧缓冲区读取像素数据时,图标失去透明度的主要内容,如果未能解决你的问题,请参考以下文章
Framebuffer 和 Renderbuffer 的 Webgl 绑定