gpt4 book ai didi

javascript - 使用 WebGL 将两个 Canvas 混合到一个 Canvas 上

转载 作者:数据小太阳 更新时间:2023-10-29 05:06:15 32 4
gpt4 key购买 nike

我想要做的是将两个 Canvas 混合到一个 Canvas 上,用于我正在创建的绘图应用程序。我非常了解 Javascript,但我真的不知道从哪里开始使用 WebGL,因为这不是一项非常艰巨的任务,我假设如果我不使用它会产生更快的处理速度另一个库,如 Three.js 或其他类似的库。

我已经拥有用户将在其上绘制的 Canvas (我们称它们为 Canvas A 和 B),它们都是隐藏的, Canvas C 正在显示。

<canvas id='C' width=800 height=600></canvas>

<canvas id='A' width=800 height=600 style='display:none'></canvas>
<canvas id='B' width=800 height=600 style='display:none'></canvas>

我已经完成了主要的绘图应用程序,供用户选择要绘制的图层并在其上绘制,但是我如何才能使用 WebGL 使用某种混合模式(即:乘法)将两个图层混合在一起) 随着用户继续使用 WebGL 编辑 Canvas ?

起初我尝试关注这里的另一篇文章:https://stackoverflow.com/a/11596922/1572938但我很困惑。

如果有人想为另一篇文章填补我的 jsfiddle 上的空白,那将非常有效! http://jsfiddle.net/W3fVV/1/

最佳答案

这里有一个用图像绘制的例子: https://webglfundamentals.org/webgl/lessons/webgl-image-processing.html

WebGL 不关心源是图像、 Canvas 还是视频。所以把样本从

gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, someImage);

gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, someCanvas);

然后编写一个片段着色器来混合 2 个纹理

precision mediump float;

// our 2 canvases
uniform sampler2D u_canvas1;
uniform sampler2D u_canvas2;

// the texCoords passed in from the vertex shader.
// note: we're only using 1 set of texCoords which means
// we're assuming the canvases are the same size.
varying vec2 v_texCoord;

void main() {
// Look up a pixel from first canvas
vec4 color1 = texture2D(u_canvas1, v_texCoord);

// Look up a pixel from second canvas
vec4 color2 = texture2D(u_canvas2, v_texCoord);

// return the 2 colors multiplied
gl_FragColor = color1 * color2;
}

您需要设置 2 个纹理并告诉您的 GLSL 程序您将它们放在哪个纹理单元上。

function setupTexture(canvas, textureUnit, program, uniformName) {
var tex = gl.createTexture();

updateTextureFromCanvas(tex, canvas, textureUnit);

// 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);

var location = gl.getUniformLocation(program, uniformName);
gl.uniform1i(location, textureUnit);
}

function updateTextureFromCanvas(tex, canvas, textureUnit) {
gl.activeTexture(gl.TEXTURE0 + textureUnit);
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas);
}

var tex1 = setupTexture(canvas1, 0, program, "u_canvas1");
var tex2 = setupTexture(canvas2, 1, program, "u_canvas2");

示例在这里:

function main() {
var canvas1 = document.getElementById("canvas1");
var canvas2 = document.getElementById("canvas2");
var ctx1 = canvas1.getContext("2d");
var ctx2 = canvas2.getContext("2d");
ctx1.fillStyle = "purple";
ctx1.arc(64, 64, 30, 0, Math.PI * 2, false);
ctx1.fill();
ctx2.fillStyle = "cyan";
ctx2.fillRect(50, 10, 28, 108);

// Get A WebGL context
var canvas = document.getElementById("webgl");
var gl = canvas.getContext("webgl");
if (!gl) {
return;
}

// setup GLSL program
var program = twgl.createProgramFromScripts(gl, ["2d-vertex-shader", "2d-fragment-shader"]);
gl.useProgram(program);

// look up where the vertex data needs to go.
var positionLocation = gl.getAttribLocation(program, "a_position");
var texCoordLocation = gl.getAttribLocation(program, "a_texCoord");

// provide texture coordinates for the rectangle.
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);

// lookup uniforms
var resolutionLocation = gl.getUniformLocation(program, "u_resolution");

// set the resolution
gl.uniform2f(resolutionLocation, canvas1.width, canvas1.height);

// Create a buffer for the position of the rectangle corners.
var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);

// Set a rectangle the same size as the image.
setRectangle(gl, 0, 0, canvas.width, canvas.height);

function setupTexture(canvas, textureUnit, program, uniformName) {
var tex = gl.createTexture();

updateTextureFromCanvas(tex, canvas, textureUnit);

// 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);

var location = gl.getUniformLocation(program, uniformName);
gl.uniform1i(location, textureUnit);
}

function updateTextureFromCanvas(tex, canvas, textureUnit) {
gl.activeTexture(gl.TEXTURE0 + textureUnit);
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas);
}

var tex1 = setupTexture(canvas1, 0, program, "u_canvas1");
var tex2 = setupTexture(canvas2, 1, program, "u_canvas2");

// Draw the rectangle.
gl.drawArrays(gl.TRIANGLES, 0, 6);
}

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);
}

main();
canvas {
border: 2px solid black;
width: 128px;
height: 128px;
}
<script src="https://twgljs.org/dist/3.x/twgl.min.js"></script>
<!-- vertex shader -->
<script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;
attribute vec2 a_texCoord;

uniform vec2 u_resolution;

varying vec2 v_texCoord;

void main() {
// convert the rectangle from pixels to 0.0 to 1.0
vec2 zeroToOne = a_position / u_resolution;

// convert from 0->1 to 0->2
vec2 zeroToTwo = zeroToOne * 2.0;

// convert from 0->2 to -1->+1 (clipspace)
vec2 clipSpace = zeroToTwo - 1.0;

gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);

// pass the texCoord to the fragment shader
// The GPU will interpolate this value between points.
v_texCoord = a_texCoord;
}
</script>
<!-- fragment shader -->
<script id="2d-fragment-shader" type="x-shader/x-fragment">
precision mediump float;

// our 2 canvases
uniform sampler2D u_canvas1;
uniform sampler2D u_canvas2;

// the texCoords passed in from the vertex shader.
// note: we're only using 1 set of texCoords which means
// we're assuming the canvases are the same size.
varying vec2 v_texCoord;

void main() {
// Look up a pixel from first canvas
vec4 color1 = texture2D(u_canvas1, v_texCoord);

// Look up a pixel from second canvas
vec4 color2 = texture2D(u_canvas2, v_texCoord);

// return the 2 colors multiplied
gl_FragColor = color1 * color2;
}
</script>
<!-- fragment shader -->
<script id="aa2d-fragment-shader" type="x-shader/x-fragment">
precision mediump float;

// our texture
uniform sampler2D u_canvas1;
uniform sampler2D u_canvas2;

// the texCoords passed in from the vertex shader.
varying vec2 v_texCoord;

void main() {
gl_FragColor = texture2D(u_canvas1, v_texCoord);
}
</script>
<canvas id="canvas1" width="128" height="128"></canvas>
<canvas id="canvas2" width="128" height="128"></canvas>
<canvas id="webgl" width="128" height="128"></canvas>

关于javascript - 使用 WebGL 将两个 Canvas 混合到一个 Canvas 上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12590685/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com