我想通过首先获取当前值,然后将其替换为稍微修改的新颜色来更改 webGL 画布的一个像素的颜色。对于 2d 画布上下文,这很容易,但我很快就迷失了尝试对 webGl 画布上下文做同样的事情。
这是我首先尝试读取像素颜色,然后用更改后的颜色将其绘制回来。我更喜欢只获取一个数组,更改一个值,然后将其放回去,而不是绘图,但我也找不到这样做的方法。
var gl = canvas.getContext('webgl');// get the context of Canvas or OffscreenCanvas
// allocate buffer
const out = new Uint8Array(4);
// read RGBA value of pixel
gl.readPixels(98, 122, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, out);
// change red value of pixel
out[0] = 255;
// convert changed array to Float32Array
var float32Data = new Float32Array(out);
// So far everything works but I don't know how to put the changed values back onto the canvas/context
var vbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
gl.bufferData(gl.ARRAY_BUFFER, float32Data, gl.DYNAMIC_DRAW);
gl.vertexAttribPointer(1, 3, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.POINTS, 0, float32Data.length / 3);
编辑 添加了注释以澄清获取像素颜色值的工作原理。我想知道如何恢复更改后的值。我真的必须画画吗?我不能简单地“编辑”底层数据缓冲区/数组吗?
例如,2d 画布有
getImageData()
和 putImageData()
如果我理解这里的问题就是一个解决方案。
首先,我在画布上绘制(我使用基本的 WebGL 功能,剪刀)。
然后我再次运行绘图指令,但这次目的地不是画布,这就是最可怕的,帧缓冲区(空),而是带有附加纹理的帧缓冲区。
gl.framebufferTexture2D(gl.FRAMEBUFFER,gl.COLOR_ATTACHMENT0,gl.TEXTURE_2D,copietextureEcran,0)
现在该纹理包含绘图。
然后我构建一个 WebGL 代码来读取该纹理并在其中一个坐标处绘制一个点。
if (gl_FragCoord.xy==vec2(3.5,3.5)) gl_FragColor=vec4(0,1,0,1);
const canvas = document.querySelector('canvas');
let width=7;
let height=7;
canvas.width=7;
canvas.height=7;
const gl = canvas.getContext('webgl');
function a() {
gl.viewport(0, 0, width, height);
gl.clearColor(1,0,0,1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.enable(gl.SCISSOR_TEST);
gl.scissor(2, 2, 3, 3);
gl.clearColor(1, 0, 1, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.disable(gl.SCISSOR_TEST);
let copietextureEcran = gl.createTexture();
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, copietextureEcran);
gl.texImage2D(
gl.TEXTURE_2D,
0,
gl.RGBA,
width,
height,
0,
gl.RGBA,
gl.UNSIGNED_BYTE,
null
);
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);
let fbEcran = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER,fbEcran); gl.framebufferTexture2D(gl.FRAMEBUFFER,gl.COLOR_ATTACHMENT0,gl.TEXTURE_2D,copietextureEcran,0);
gl.viewport(0, 0, 7, 7);
gl.clearColor(1,0,0,1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.enable(gl.SCISSOR_TEST);
gl.scissor(2, 2, 3, 3);
gl.clearColor(1, 0, 1, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.disable(gl.SCISSOR_TEST);
}
a();
function b() {
let vs=`
attribute vec2 aPosition;
varying vec2 vtexCoords;
void main() {
gl_Position=vec4(aPosition,0,1);
vtexCoords = (aPosition+1.0)/2.0;
}
`;
let fs=`
precision highp float;
uniform sampler2D copietextureEcran;
varying vec2 vtexCoords;
void main() {
vec4 color = texture2D(copietextureEcran,vtexCoords);
gl_FragColor = vec4(color);
if (gl_FragCoord.xy==vec2(3.5,3.5)) gl_FragColor=vec4(0,1,0,1);
}
`;
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader,vs);
gl.compileShader(vertexShader);
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader,fs);
gl.compileShader(fragmentShader);
const program = gl.createProgram();
gl.attachShader(program,vertexShader);
gl.attachShader(program,fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
let positionAttributeLocation = gl.getAttribLocation(program, "aPosition");
let positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
-1, -1,
+1, -1,
-1, +1,
-1, +1,
+1, -1,
+1, +1,
]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(positionAttributeLocation);
gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0);
gl.bindFramebuffer(gl.FRAMEBUFFER,null);
gl.viewport(0, 0, 7, 7);
gl.clearColor(0,0,0,1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 6);
}
canvas {
width: 100x;
height: 100px;
image-rendering: pixelated;
}
<canvas id="canvas"></canvas>
<button onclick="b()">Click me</button>