javascript - 从 WebGL Canvas 读取似乎不一致
问题描述
我遇到了这种非常奇怪的情况,我试图从 WebGL 画布中读取像素,但没有成功。然后我编写了同一个程序的另一个版本,只是没有类,并且由于某种原因它在这里工作。也许我犯了一些非常基本的错误,但我真的无法发现这两者之间的(语义)差异。
在下面的代码片段中,我(Linux 5.11.15-arch1-2 上的 Firefox 88.0)看到控制台打印 128 和 0,128 源于类外部的代码,这似乎是正确的,因为着色器为每个像素和通道,以及源自类内部代码的 0。
[编辑] 我已经看到了这个问题,但是他们说读取必须与抽签发生在同一事件中,据我所知,这对于我的两种情况(连续两行)都是正确的。他们还在谈论屏幕上的画布,而我渲染到帧缓冲区时,不确定这是否会有所不同,但我认为帧缓冲区更持久。
class Gpgpu {
constructor(w, h, vs, fs, ans, uns) {
this.gl = document.createElement("canvas").getContext("webgl");
this.gl.canvas.width = w;
this.gl.canvas.height = h;
this.gl.viewport(0, 0, w, h);
this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, this.gl.createFramebuffer());
this.out = new Uint8Array(w * h * 4);
}
spg(vs, fs, ans, uns) {
let p = this.gl.createProgram();
for (let ss of [
{ t: this.gl.VERTEX_SHADER, d: vs },
{ t: this.gl.FRAGMENT_SHADER, d: fs }
]) {
let s = this.gl.createShader(ss.t);
this.gl.shaderSource(s, ss.d);
this.gl.compileShader(s);
this.gl.attachShader(p, s);
}
this.gl.linkProgram(p);
this.gl.useProgram(p);
this.als = {};
for (let an of ans) {
this.als[an] = {
l: this.gl.getAttribLocation(p, an),
b: this.gl.createBuffer()
};
}
this.uls = {};
for (let un of uns) {
this.uls[un] = this.gl.getUniformLocation(p, un);
}
}
sad(n, ads) {
this.n = n;
for (let an in ads) {
let al = this.als[an];
let ad = ads[an];
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, al.b);
this.gl.bufferData(
this.gl.ARRAY_BUFFER,
Float32Array.from(ad),
this.gl.STATIC_DRAW
);
this.gl.enableVertexAttribArray(al.l);
this.gl.vertexAttribPointer(al.l, 2, this.gl.FLOAT, false, 0, 0);
}
}
drw() {
this.gl.drawArrays(this.gl.TRIANGLES, 0, this.n);
}
}
class Cloth {
constructor(w, h) {
this.gpu = new Gpgpu(w, h);
this.tex = this.gpu.gl.createTexture();
this.gpu.spg(
document.getElementById("vs").innerHTML,
document.getElementById("fs").innerHTML,
["a_position"],
[]
);
this.gpu.sad(6, {
a_position: [-1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1]
});
this.gpu.gl.bindTexture(this.gpu.gl.TEXTURE_2D, this.tex);
this.gpu.gl.texImage2D(
this.gpu.gl.TEXTURE_2D,
0,
this.gpu.gl.RGBA,
w,
h,
0,
this.gpu.gl.RGBA,
this.gpu.gl.UNSIGNED_BYTE,
null
);
}
t() {
this.gpu.gl.framebufferTexture2D(
this.gpu.gl.FRAMEBUFFER,
this.gpu.gl.COLOR_ATTACHMENT0,
this.gpu.gl.TEXTURE_2D,
this.tex,
0
);
this.gpu.drw();
this.gpu.gl.readPixels(
0,
0,
this.w,
this.h,
this.gpu.gl.RGBA,
this.gpu.gl.UNSIGNED_BYTE,
this.gpu.out
);
console.log(this.gpu.out[0]);
}
}
const w = 10;
const h = 10;
const gpu = new Gpgpu(w, h);
const tex = gpu.gl.createTexture();
gpu.spg(
document.getElementById("vs").innerHTML,
document.getElementById("fs").innerHTML,
["a_position"],
[]
);
gpu.sad(6, {
a_position: [-1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1]
});
gpu.gl.bindTexture(gpu.gl.TEXTURE_2D, tex);
gpu.gl.texImage2D(
gpu.gl.TEXTURE_2D,
0,
gpu.gl.RGBA,
w,
h,
0,
gpu.gl.RGBA,
gpu.gl.UNSIGNED_BYTE,
null
);
gpu.gl.framebufferTexture2D(
gpu.gl.FRAMEBUFFER,
gpu.gl.COLOR_ATTACHMENT0,
gpu.gl.TEXTURE_2D,
tex,
0
);
gpu.drw();
gpu.gl.readPixels(0, 0, w, h, gpu.gl.RGBA, gpu.gl.UNSIGNED_BYTE, gpu.out);
console.log(gpu.out[0]);
new Cloth(10, 10).t();
<script type="x-shader/x-vertex" id="vs">
attribute vec4 a_position;
void main() {
gl_Position = a_position;
}
</script>
<script type="x-shader/x-fragment" id="fs">precision highp float;
void main() {
gl_FragColor = vec4(0.5, 0.5, 0.5, 0.5);
}
</script>
解决方案
这是一个简单的错字,您从未为 Cloth 实例定义this.w
和属性,但是在进行调用时,您尝试使用它。this.h
t()
readPixel
只需在构造函数中定义这些,就可以了。
class Gpgpu {
constructor(w, h, vs, fs, ans, uns) {
this.gl = document.createElement("canvas").getContext("webgl");
this.gl.canvas.width = w;
this.gl.canvas.height = h;
this.gl.viewport(0, 0, w, h);
this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, this.gl.createFramebuffer());
this.out = new Uint8Array(w * h * 4);
}
spg(vs, fs, ans, uns) {
let p = this.gl.createProgram();
for (let ss of [
{ t: this.gl.VERTEX_SHADER, d: vs },
{ t: this.gl.FRAGMENT_SHADER, d: fs }
]) {
let s = this.gl.createShader(ss.t);
this.gl.shaderSource(s, ss.d);
this.gl.compileShader(s);
this.gl.attachShader(p, s);
}
this.gl.linkProgram(p);
this.gl.useProgram(p);
this.als = {};
for (let an of ans) {
this.als[an] = {
l: this.gl.getAttribLocation(p, an),
b: this.gl.createBuffer()
};
}
this.uls = {};
for (let un of uns) {
this.uls[un] = this.gl.getUniformLocation(p, un);
}
}
sad(n, ads) {
this.n = n;
for (let an in ads) {
let al = this.als[an];
let ad = ads[an];
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, al.b);
this.gl.bufferData(
this.gl.ARRAY_BUFFER,
Float32Array.from(ad),
this.gl.STATIC_DRAW
);
this.gl.enableVertexAttribArray(al.l);
this.gl.vertexAttribPointer(al.l, 2, this.gl.FLOAT, false, 0, 0);
}
}
drw() {
this.gl.drawArrays(this.gl.TRIANGLES, 0, this.n);
}
}
class Cloth {
constructor(w, h) {
this.w = w;
this.h = h;
this.gpu = new Gpgpu(w, h);
this.tex = this.gpu.gl.createTexture();
this.gpu.spg(
document.getElementById("vs").innerHTML,
document.getElementById("fs").innerHTML,
["a_position"],
[]
);
this.gpu.sad(6, {
a_position: [-1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1]
});
this.gpu.gl.bindTexture(this.gpu.gl.TEXTURE_2D, this.tex);
this.gpu.gl.texImage2D(
this.gpu.gl.TEXTURE_2D,
0,
this.gpu.gl.RGBA,
w,
h,
0,
this.gpu.gl.RGBA,
this.gpu.gl.UNSIGNED_BYTE,
null
);
}
t() {
this.gpu.gl.framebufferTexture2D(
this.gpu.gl.FRAMEBUFFER,
this.gpu.gl.COLOR_ATTACHMENT0,
this.gpu.gl.TEXTURE_2D,
this.tex,
0
);
this.gpu.drw();
this.gpu.gl.readPixels(
0,
0,
this.w,
this.h,
this.gpu.gl.RGBA,
this.gpu.gl.UNSIGNED_BYTE,
this.gpu.out
);
console.log(this.gpu.out[0]);
}
}
const w = 10;
const h = 10;
const gpu = new Gpgpu(w, h);
const tex = gpu.gl.createTexture();
gpu.spg(
document.getElementById("vs").innerHTML,
document.getElementById("fs").innerHTML,
["a_position"],
[]
);
gpu.sad(6, {
a_position: [-1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1]
});
gpu.gl.bindTexture(gpu.gl.TEXTURE_2D, tex);
gpu.gl.texImage2D(
gpu.gl.TEXTURE_2D,
0,
gpu.gl.RGBA,
w,
h,
0,
gpu.gl.RGBA,
gpu.gl.UNSIGNED_BYTE,
null
);
gpu.gl.framebufferTexture2D(
gpu.gl.FRAMEBUFFER,
gpu.gl.COLOR_ATTACHMENT0,
gpu.gl.TEXTURE_2D,
tex,
0
);
gpu.drw();
gpu.gl.readPixels(0, 0, w, h, gpu.gl.RGBA, gpu.gl.UNSIGNED_BYTE, gpu.out);
console.log(gpu.out[0]);
new Cloth(10, 10).t();
<script type="x-shader/x-vertex" id="vs">
attribute vec4 a_position;
void main() {
gl_Position = a_position;
}
</script>
<script type="x-shader/x-fragment" id="fs">precision highp float;
void main() {
gl_FragColor = vec4(0.5, 0.5, 0.5, 0.5);
}
</script>
推荐阅读
- r - 是否有一个 R 函数可以根据另一列中的最小值删除索引变量的重复项?
- amazon-web-services - 如何将查询字符串和标头映射到 AWS C# lambda 函数参数
- spring - 用dokku部署spring api:app容器启动失败
- javascript - Ajax.Reload - 不刷新数据表
- android - java.lang.IllegalArgumentException onActivityResult
- javascript - Vue.js CLI 3 - 如何为 CSS/Sass 创建供应商包?
- keras-layer - 关于 Keras 嵌入层的一个快速问题
- unity3d - Photon Engine:客户端无法连接到现有房间并创建同一个房间
- unity3d - 使用虚拟按钮控制多个图像对象的行为
- xml - Powershell使用-replace编辑节点中的部分文本?