合并两个 canvas。把第一个放在第二个上
Combine two canvas. Put the first on the second
我正在尝试做类似这种抽象的事情。
据我了解,需要将两者结合起来canvas
,将它们放在一起。但是如何做到这一切?
这里我举两个实现为例。
第一
let vertices = [];
let gl = particle.getContext('webgl');
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
resize();
function resize() {
particle.width = innerWidth;
particle.height = innerHeight;
let step = 10,
w = Math.floor(particle.width/step),
h = Math.floor(particle.height/step);
vertices = [];
for (var x=0; x<w*3; x++)
for (var y=0; y<10; y++)
vertices.push(1/w + x*10/w - 5, 1/h + y*2/h - 1)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
}
let pid = gl.createProgram();
shader(`
attribute vec2 v;
uniform float time;
varying vec3 c;
mat3 rotateX(float a) {
return mat3(vec3( 1.0, 0.0, 0.0),
vec3( -1.0, cos(a), -sin(a)),
vec3( 0.0, sin(a), cos(a)));
}
mat3 rotateY(float a){
return mat3(vec3( cos(a), 0.0, sin(a)),
vec3( 0.0, 1.0, 0.0),
vec3(-sin(a), 0.0, cos(a)));
}
mat3 rotateZ(float a){
return mat3(vec3( cos(a), -sin(a), 0.0),
vec3( sin(a), cos(a), 0.0),
vec3( 0.0, 0.0, 1.0));
}
void main(void) {
vec2 p = v;
p.y += 0.3;
p.x += sin(time/4. + p.y);
vec3 pos = vec3(p.xy, 0.0)*rotateX(p.x*3. + time);
//pos.y += sin(pos.x) - sin(time/5.)*0.5 + cos(pos.y/3.1415)*0.5;
gl_Position = vec4(pos, 1.);
gl_PointSize = 2.7;
gl_Position.z = 0.0;
c.rgb=vec3(1.0, 0.5, 0.0);
}
`, gl.VERTEX_SHADER);
shader(`
precision highp float;
varying vec3 c;
void main(void) {
gl_FragColor = vec4(c, 1.);
}
`, gl.FRAGMENT_SHADER);
gl.linkProgram(pid);
gl.useProgram(pid);
let v = gl.getAttribLocation(pid, "v");
gl.vertexAttribPointer(v, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(v);
let timeUniform = gl.getUniformLocation(pid, 'time');
requestAnimationFrame(draw);
addEventListener('resize', resize)
function draw(t) {
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.clearColor(0, 0, 0, 0);
gl.uniform1f(timeUniform, t/1000);
gl.drawArrays(gl.POINTS, 0, vertices.length/2);
requestAnimationFrame(draw);
}
function shader(src, type) {
let sid = gl.createShader(type);
gl.shaderSource(sid, src);
gl.compileShader(sid);
var message = gl.getShaderInfoLog(sid);
gl.attachShader(pid, sid);
if (message.length > 0) {
console.log(src.split("\n")
.map((str, i) => (""+(1+i))
.padStart(4, "0")+": "+str)
.join("\n"));
throw message;
}
}
<canvas id="particle" />
<style>
canvas {
background-image:url(https://i.imgur.com/HiAlf85.jpg);
}
</style>
第二
let vertices = [];
let gl = canvas.getContext('webgl');
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
resize();
function resize() {
canvas.width = innerWidth;
canvas.height = innerHeight;
let step = 10,
w = Math.floor(canvas.width/step),
h = Math.floor(canvas.height/step);
vertices = [];
for (var x=0; x<w*3; x++)
for (var y=0; y<10; y++)
vertices.push(1/w + x*10/w - 5, 1/h + y*2/h - 1)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
}
let pid = gl.createProgram();
shader(`
attribute vec2 v;
uniform float time;
varying vec3 c;
mat3 rotateX(float a) {
return mat3(vec3( -1.0, -1.0, 0.0),
vec3( 0.0, cos(a), -sin(a)),
vec3( 0.0, sin(a), cos(a)));
}
mat3 rotateY(float a){
return mat3(vec3( cos(a), 0.0, sin(a)),
vec3( 0.0, 1.0, 0.0),
vec3(-sin(a), 0.0, cos(a)));
}
mat3 rotateZ(float a){
return mat3(vec3( cos(a), -sin(a), 0.0),
vec3( sin(a), cos(a), 0.0),
vec3( 0.0, 0.0, 1.0));
}
void main(void) {
vec2 p = v;
p.y += 0.3;
p.x += sin(time/4. + p.y);
vec3 pos = vec3(p.xy, 0.0)*rotateX(p.x*3. + time);
//pos.y += sin(pos.x) - sin(time/5.)*0.5 + cos(pos.y/3.1415)*0.5;
gl_Position = vec4(pos, 1.);
gl_PointSize = 2.7;
gl_Position.z = 0.0;
c.rgb=vec3(1., 0., 0.);
}
`, gl.VERTEX_SHADER);
shader(`
precision highp float;
varying vec3 c;
void main(void) {
gl_FragColor = vec4(c, 1.);
}
`, gl.FRAGMENT_SHADER);
gl.linkProgram(pid);
gl.useProgram(pid);
let v = gl.getAttribLocation(pid, "v");
gl.vertexAttribPointer(v, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(v);
let timeUniform = gl.getUniformLocation(pid, 'time');
requestAnimationFrame(draw);
addEventListener('resize', resize)
function draw(t) {
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.clearColor(0, 0, 0, 0);
gl.uniform1f(timeUniform, t/1000);
gl.drawArrays(gl.POINTS, 0, vertices.length/2);
requestAnimationFrame(draw);
}
function shader(src, type) {
let sid = gl.createShader(type);
gl.shaderSource(sid, src);
gl.compileShader(sid);
var message = gl.getShaderInfoLog(sid);
gl.attachShader(pid, sid);
if (message.length > 0) {
console.log(src.split("\n")
.map((str, i) => (""+(1+i))
.padStart(4, "0")+": "+str)
.join("\n"));
throw message;
}
}
<canvas id="canvas" />
<style>
canvas {
background-image:url(https://i.imgur.com/HiAlf85.jpg);
}
</style>
告诉我如何组合它们?
如果您访问您链接的网站并查看他们的代码,您会注意到他们只是将两个 canvas 放在同一个 div 中,并将它们放在彼此有点css
canvas {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: -1px;
}
在链接示例中,由于绝对定位,两个 canvas 相互重叠。
但是对于您的示例,即使您将它们放置在彼此之上,您也只会看到一个,因为您为每个 canvas.
添加了一个非透明背景图像
链接示例依赖于每个 canvas 是透明的。这意味着,只对 canvas 中需要着色的像素进行着色,除非有透明度,否则没有背景颜色或图像。
您需要设置 CSS 以便 2 canvas 重叠并从顶部移除背景 canvas
body {
margin: 0;
}
canvas {
display: block;
}
#particle {
background-image:url(https://i.imgur.com/HiAlf85.jpg);
}
#canvas {
position: absolute;
left: 0;
top: 0;
}
此外,您需要弄清楚如何合并您的 2 个片段。就像快速破解一样,我将两者都包含在它们自己的函数中,这样变量就不会冲突,但这意味着一堆代码是重复的。
最后一件事是自动关闭 canvas 因为 <canvas />
是非法的 HTML。您需要使用 <canvas></canvas>
中的实际结束标记。
您可以通过检查
来查看
<canvas />
<canvas />
在浏览器的开发工具中
注意一个 canvas 在另一个里面而不是分开的。那是因为 />
实际上并没有结束 canvas 标签。 Canvas 标签不在内部显示任何 HTML,因此不显示内部 canvas。
'use strict';
(function() {
let vertices = [];
let gl = particle.getContext('webgl');
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
resize();
function resize() {
particle.width = innerWidth;
particle.height = innerHeight;
let step = 10,
w = Math.floor(particle.width/step),
h = Math.floor(particle.height/step);
vertices = [];
for (var x=0; x<w*3; x++)
for (var y=0; y<10; y++)
vertices.push(1/w + x*10/w - 5, 1/h + y*2/h - 1)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
}
let pid = gl.createProgram();
shader(`
attribute vec2 v;
uniform float time;
varying vec3 c;
mat3 rotateX(float a) {
return mat3(vec3( 1.0, 0.0, 0.0),
vec3( -1.0, cos(a), -sin(a)),
vec3( 0.0, sin(a), cos(a)));
}
mat3 rotateY(float a){
return mat3(vec3( cos(a), 0.0, sin(a)),
vec3( 0.0, 1.0, 0.0),
vec3(-sin(a), 0.0, cos(a)));
}
mat3 rotateZ(float a){
return mat3(vec3( cos(a), -sin(a), 0.0),
vec3( sin(a), cos(a), 0.0),
vec3( 0.0, 0.0, 1.0));
}
void main(void) {
vec2 p = v;
p.y += 0.3;
p.x += sin(time/4. + p.y);
vec3 pos = vec3(p.xy, 0.0)*rotateX(p.x*3. + time);
//pos.y += sin(pos.x) - sin(time/5.)*0.5 + cos(pos.y/3.1415)*0.5;
gl_Position = vec4(pos, 1.);
gl_PointSize = 2.7;
gl_Position.z = 0.0;
c.rgb=vec3(1.0, 0.5, 0.0);
}
`, gl.VERTEX_SHADER);
shader(`
precision highp float;
varying vec3 c;
void main(void) {
gl_FragColor = vec4(c, 1.);
}
`, gl.FRAGMENT_SHADER);
gl.linkProgram(pid);
gl.useProgram(pid);
let v = gl.getAttribLocation(pid, "v");
gl.vertexAttribPointer(v, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(v);
let timeUniform = gl.getUniformLocation(pid, 'time');
requestAnimationFrame(draw);
addEventListener('resize', resize)
function draw(t) {
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.clearColor(0, 0, 0, 0);
gl.uniform1f(timeUniform, t/1000);
gl.drawArrays(gl.POINTS, 0, vertices.length/2);
requestAnimationFrame(draw);
}
function shader(src, type) {
let sid = gl.createShader(type);
gl.shaderSource(sid, src);
gl.compileShader(sid);
var message = gl.getShaderInfoLog(sid);
gl.attachShader(pid, sid);
if (message.length > 0) {
console.log(src.split("\n")
.map((str, i) => (""+(1+i))
.padStart(4, "0")+": "+str)
.join("\n"));
throw message;
}
}
}());
// ----------------------
(function() {
let vertices = [];
let gl = canvas.getContext('webgl');
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
resize();
function resize() {
canvas.width = innerWidth;
canvas.height = innerHeight;
let step = 10,
w = Math.floor(canvas.width/step),
h = Math.floor(canvas.height/step);
vertices = [];
for (var x=0; x<w*3; x++)
for (var y=0; y<10; y++)
vertices.push(1/w + x*10/w - 5, 1/h + y*2/h - 1)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
}
let pid = gl.createProgram();
shader(`
attribute vec2 v;
uniform float time;
varying vec3 c;
mat3 rotateX(float a) {
return mat3(vec3( -1.0, -1.0, 0.0),
vec3( 0.0, cos(a), -sin(a)),
vec3( 0.0, sin(a), cos(a)));
}
mat3 rotateY(float a){
return mat3(vec3( cos(a), 0.0, sin(a)),
vec3( 0.0, 1.0, 0.0),
vec3(-sin(a), 0.0, cos(a)));
}
mat3 rotateZ(float a){
return mat3(vec3( cos(a), -sin(a), 0.0),
vec3( sin(a), cos(a), 0.0),
vec3( 0.0, 0.0, 1.0));
}
void main(void) {
vec2 p = v;
p.y += 0.3;
p.x += sin(time/4. + p.y);
vec3 pos = vec3(p.xy, 0.0)*rotateX(p.x*3. + time);
//pos.y += sin(pos.x) - sin(time/5.)*0.5 + cos(pos.y/3.1415)*0.5;
gl_Position = vec4(pos, 1.);
gl_PointSize = 2.7;
gl_Position.z = 0.0;
c.rgb=vec3(1., 0., 0.);
}
`, gl.VERTEX_SHADER);
shader(`
precision highp float;
varying vec3 c;
void main(void) {
gl_FragColor = vec4(c, 1.);
}
`, gl.FRAGMENT_SHADER);
gl.linkProgram(pid);
gl.useProgram(pid);
let v = gl.getAttribLocation(pid, "v");
gl.vertexAttribPointer(v, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(v);
let timeUniform = gl.getUniformLocation(pid, 'time');
requestAnimationFrame(draw);
addEventListener('resize', resize)
function draw(t) {
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.clearColor(0, 0, 0, 0);
gl.uniform1f(timeUniform, t/1000);
gl.drawArrays(gl.POINTS, 0, vertices.length/2);
requestAnimationFrame(draw);
}
function shader(src, type) {
let sid = gl.createShader(type);
gl.shaderSource(sid, src);
gl.compileShader(sid);
var message = gl.getShaderInfoLog(sid);
gl.attachShader(pid, sid);
if (message.length > 0) {
console.log(src.split("\n")
.map((str, i) => (""+(1+i))
.padStart(4, "0")+": "+str)
.join("\n"));
throw message;
}
}
}());
body {
margin: 0;
}
canvas {
display: block;
}
#particle {
background-image:url(https://i.imgur.com/HiAlf85.jpg);
background-size: cover;
}
#canvas {
position: absolute;
left: 0;
top: 0;
}
<canvas id="particle"></canvas>
<canvas id="canvas"></canvas>
当然不清楚你为什么要这样做。使用 1 canvas 可能会更快,但我假设您有自己的理由。
'use strict';
let vertices = [];
let gl = particle.getContext('webgl');
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
resize();
function resize() {
particle.width = innerWidth;
particle.height = innerHeight;
let step = 10,
w = Math.floor(particle.width/step),
h = Math.floor(particle.height/step);
vertices = [];
for (var x=0; x<w*3; x++)
for (var y=0; y<10; y++)
vertices.push(1/w + x*10/w - 5, 1/h + y*2/h - 1)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
}
let pid1 = createProgram(`
attribute vec2 v;
uniform float time;
varying vec3 c;
mat3 rotateX(float a) {
return mat3(vec3( 1.0, 0.0, 0.0),
vec3( -1.0, cos(a), -sin(a)),
vec3( 0.0, sin(a), cos(a)));
}
mat3 rotateY(float a){
return mat3(vec3( cos(a), 0.0, sin(a)),
vec3( 0.0, 1.0, 0.0),
vec3(-sin(a), 0.0, cos(a)));
}
mat3 rotateZ(float a){
return mat3(vec3( cos(a), -sin(a), 0.0),
vec3( sin(a), cos(a), 0.0),
vec3( 0.0, 0.0, 1.0));
}
void main(void) {
vec2 p = v;
p.y += 0.3;
p.x += sin(time/4. + p.y);
vec3 pos = vec3(p.xy, 0.0)*rotateX(p.x*3. + time);
//pos.y += sin(pos.x) - sin(time/5.)*0.5 + cos(pos.y/3.1415)*0.5;
gl_Position = vec4(pos, 1.);
gl_PointSize = 2.7;
gl_Position.z = 0.0;
c.rgb=vec3(1.0, 0.5, 0.0);
}
`,
`
precision highp float;
varying vec3 c;
void main(void) {
gl_FragColor = vec4(c, 1.);
}
`);
let pid2 = createProgram(`
attribute vec2 v;
uniform float time;
varying vec3 c;
mat3 rotateX(float a) {
return mat3(vec3( -1.0, -1.0, 0.0),
vec3( 0.0, cos(a), -sin(a)),
vec3( 0.0, sin(a), cos(a)));
}
mat3 rotateY(float a){
return mat3(vec3( cos(a), 0.0, sin(a)),
vec3( 0.0, 1.0, 0.0),
vec3(-sin(a), 0.0, cos(a)));
}
mat3 rotateZ(float a){
return mat3(vec3( cos(a), -sin(a), 0.0),
vec3( sin(a), cos(a), 0.0),
vec3( 0.0, 0.0, 1.0));
}
void main(void) {
vec2 p = v;
p.y += 0.3;
p.x += sin(time/4. + p.y);
vec3 pos = vec3(p.xy, 0.0)*rotateX(p.x*3. + time);
//pos.y += sin(pos.x) - sin(time/5.)*0.5 + cos(pos.y/3.1415)*0.5;
gl_Position = vec4(pos, 1.);
gl_PointSize = 2.7;
gl_Position.z = 0.0;
c.rgb=vec3(1., 0., 0.);
}
`, `
precision highp float;
varying vec3 c;
void main(void) {
gl_FragColor = vec4(c, 1.);
}
`);
let v1 = gl.getAttribLocation(pid1, "v");
let timeUniform1 = gl.getUniformLocation(pid1, 'time');
let v2 = gl.getAttribLocation(pid2, "v");
let timeUniform2 = gl.getUniformLocation(pid2, 'time');
requestAnimationFrame(draw);
addEventListener('resize', resize)
function draw(t) {
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.clearColor(0, 0, 0, 0);
gl.useProgram(pid1);
// normally you'd bind a buffer here but since you only
// have one and the vertex data is the same for both programs
// we don't need to bind a different buffer
gl.vertexAttribPointer(v1, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(v1);
gl.uniform1f(timeUniform1, t/1000);
gl.drawArrays(gl.POINTS, 0, vertices.length/2);
gl.useProgram(pid2);
gl.vertexAttribPointer(v2, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(v2);
gl.uniform1f(timeUniform2, t/1000);
gl.drawArrays(gl.POINTS, 0, vertices.length/2);
requestAnimationFrame(draw);
}
function createProgram(vs, fs) {
const pid = gl.createProgram();
shader(vs, gl.VERTEX_SHADER, pid);
shader(fs, gl.FRAGMENT_SHADER, pid);
gl.linkProgram(pid);
// should check for link error here!
return pid;
}
function shader(src, type, pid) {
let sid = gl.createShader(type);
gl.shaderSource(sid, src);
gl.compileShader(sid);
var message = gl.getShaderInfoLog(sid);
gl.attachShader(pid, sid);
if (message.length > 0) {
console.log(src.split("\n")
.map((str, i) => (""+(1+i))
.padStart(4, "0")+": "+str)
.join("\n"));
throw message;
}
}
body {
margin: 0;
}
canvas {
display: block;
}
#particle {
background-image:url(https://i.imgur.com/HiAlf85.jpg);
background-size: cover;
}
<canvas id="particle"></canvas>
我正在尝试做类似这种抽象的事情。
据我了解,需要将两者结合起来canvas
,将它们放在一起。但是如何做到这一切?
这里我举两个实现为例。 第一
let vertices = [];
let gl = particle.getContext('webgl');
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
resize();
function resize() {
particle.width = innerWidth;
particle.height = innerHeight;
let step = 10,
w = Math.floor(particle.width/step),
h = Math.floor(particle.height/step);
vertices = [];
for (var x=0; x<w*3; x++)
for (var y=0; y<10; y++)
vertices.push(1/w + x*10/w - 5, 1/h + y*2/h - 1)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
}
let pid = gl.createProgram();
shader(`
attribute vec2 v;
uniform float time;
varying vec3 c;
mat3 rotateX(float a) {
return mat3(vec3( 1.0, 0.0, 0.0),
vec3( -1.0, cos(a), -sin(a)),
vec3( 0.0, sin(a), cos(a)));
}
mat3 rotateY(float a){
return mat3(vec3( cos(a), 0.0, sin(a)),
vec3( 0.0, 1.0, 0.0),
vec3(-sin(a), 0.0, cos(a)));
}
mat3 rotateZ(float a){
return mat3(vec3( cos(a), -sin(a), 0.0),
vec3( sin(a), cos(a), 0.0),
vec3( 0.0, 0.0, 1.0));
}
void main(void) {
vec2 p = v;
p.y += 0.3;
p.x += sin(time/4. + p.y);
vec3 pos = vec3(p.xy, 0.0)*rotateX(p.x*3. + time);
//pos.y += sin(pos.x) - sin(time/5.)*0.5 + cos(pos.y/3.1415)*0.5;
gl_Position = vec4(pos, 1.);
gl_PointSize = 2.7;
gl_Position.z = 0.0;
c.rgb=vec3(1.0, 0.5, 0.0);
}
`, gl.VERTEX_SHADER);
shader(`
precision highp float;
varying vec3 c;
void main(void) {
gl_FragColor = vec4(c, 1.);
}
`, gl.FRAGMENT_SHADER);
gl.linkProgram(pid);
gl.useProgram(pid);
let v = gl.getAttribLocation(pid, "v");
gl.vertexAttribPointer(v, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(v);
let timeUniform = gl.getUniformLocation(pid, 'time');
requestAnimationFrame(draw);
addEventListener('resize', resize)
function draw(t) {
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.clearColor(0, 0, 0, 0);
gl.uniform1f(timeUniform, t/1000);
gl.drawArrays(gl.POINTS, 0, vertices.length/2);
requestAnimationFrame(draw);
}
function shader(src, type) {
let sid = gl.createShader(type);
gl.shaderSource(sid, src);
gl.compileShader(sid);
var message = gl.getShaderInfoLog(sid);
gl.attachShader(pid, sid);
if (message.length > 0) {
console.log(src.split("\n")
.map((str, i) => (""+(1+i))
.padStart(4, "0")+": "+str)
.join("\n"));
throw message;
}
}
<canvas id="particle" />
<style>
canvas {
background-image:url(https://i.imgur.com/HiAlf85.jpg);
}
</style>
第二
let vertices = [];
let gl = canvas.getContext('webgl');
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
resize();
function resize() {
canvas.width = innerWidth;
canvas.height = innerHeight;
let step = 10,
w = Math.floor(canvas.width/step),
h = Math.floor(canvas.height/step);
vertices = [];
for (var x=0; x<w*3; x++)
for (var y=0; y<10; y++)
vertices.push(1/w + x*10/w - 5, 1/h + y*2/h - 1)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
}
let pid = gl.createProgram();
shader(`
attribute vec2 v;
uniform float time;
varying vec3 c;
mat3 rotateX(float a) {
return mat3(vec3( -1.0, -1.0, 0.0),
vec3( 0.0, cos(a), -sin(a)),
vec3( 0.0, sin(a), cos(a)));
}
mat3 rotateY(float a){
return mat3(vec3( cos(a), 0.0, sin(a)),
vec3( 0.0, 1.0, 0.0),
vec3(-sin(a), 0.0, cos(a)));
}
mat3 rotateZ(float a){
return mat3(vec3( cos(a), -sin(a), 0.0),
vec3( sin(a), cos(a), 0.0),
vec3( 0.0, 0.0, 1.0));
}
void main(void) {
vec2 p = v;
p.y += 0.3;
p.x += sin(time/4. + p.y);
vec3 pos = vec3(p.xy, 0.0)*rotateX(p.x*3. + time);
//pos.y += sin(pos.x) - sin(time/5.)*0.5 + cos(pos.y/3.1415)*0.5;
gl_Position = vec4(pos, 1.);
gl_PointSize = 2.7;
gl_Position.z = 0.0;
c.rgb=vec3(1., 0., 0.);
}
`, gl.VERTEX_SHADER);
shader(`
precision highp float;
varying vec3 c;
void main(void) {
gl_FragColor = vec4(c, 1.);
}
`, gl.FRAGMENT_SHADER);
gl.linkProgram(pid);
gl.useProgram(pid);
let v = gl.getAttribLocation(pid, "v");
gl.vertexAttribPointer(v, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(v);
let timeUniform = gl.getUniformLocation(pid, 'time');
requestAnimationFrame(draw);
addEventListener('resize', resize)
function draw(t) {
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.clearColor(0, 0, 0, 0);
gl.uniform1f(timeUniform, t/1000);
gl.drawArrays(gl.POINTS, 0, vertices.length/2);
requestAnimationFrame(draw);
}
function shader(src, type) {
let sid = gl.createShader(type);
gl.shaderSource(sid, src);
gl.compileShader(sid);
var message = gl.getShaderInfoLog(sid);
gl.attachShader(pid, sid);
if (message.length > 0) {
console.log(src.split("\n")
.map((str, i) => (""+(1+i))
.padStart(4, "0")+": "+str)
.join("\n"));
throw message;
}
}
<canvas id="canvas" />
<style>
canvas {
background-image:url(https://i.imgur.com/HiAlf85.jpg);
}
</style>
告诉我如何组合它们?
如果您访问您链接的网站并查看他们的代码,您会注意到他们只是将两个 canvas 放在同一个 div 中,并将它们放在彼此有点css
canvas {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: -1px;
}
在链接示例中,由于绝对定位,两个 canvas 相互重叠。
但是对于您的示例,即使您将它们放置在彼此之上,您也只会看到一个,因为您为每个 canvas.
添加了一个非透明背景图像链接示例依赖于每个 canvas 是透明的。这意味着,只对 canvas 中需要着色的像素进行着色,除非有透明度,否则没有背景颜色或图像。
您需要设置 CSS 以便 2 canvas 重叠并从顶部移除背景 canvas
body {
margin: 0;
}
canvas {
display: block;
}
#particle {
background-image:url(https://i.imgur.com/HiAlf85.jpg);
}
#canvas {
position: absolute;
left: 0;
top: 0;
}
此外,您需要弄清楚如何合并您的 2 个片段。就像快速破解一样,我将两者都包含在它们自己的函数中,这样变量就不会冲突,但这意味着一堆代码是重复的。
最后一件事是自动关闭 canvas 因为 <canvas />
是非法的 HTML。您需要使用 <canvas></canvas>
中的实际结束标记。
您可以通过检查
来查看<canvas />
<canvas />
在浏览器的开发工具中
注意一个 canvas 在另一个里面而不是分开的。那是因为 />
实际上并没有结束 canvas 标签。 Canvas 标签不在内部显示任何 HTML,因此不显示内部 canvas。
'use strict';
(function() {
let vertices = [];
let gl = particle.getContext('webgl');
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
resize();
function resize() {
particle.width = innerWidth;
particle.height = innerHeight;
let step = 10,
w = Math.floor(particle.width/step),
h = Math.floor(particle.height/step);
vertices = [];
for (var x=0; x<w*3; x++)
for (var y=0; y<10; y++)
vertices.push(1/w + x*10/w - 5, 1/h + y*2/h - 1)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
}
let pid = gl.createProgram();
shader(`
attribute vec2 v;
uniform float time;
varying vec3 c;
mat3 rotateX(float a) {
return mat3(vec3( 1.0, 0.0, 0.0),
vec3( -1.0, cos(a), -sin(a)),
vec3( 0.0, sin(a), cos(a)));
}
mat3 rotateY(float a){
return mat3(vec3( cos(a), 0.0, sin(a)),
vec3( 0.0, 1.0, 0.0),
vec3(-sin(a), 0.0, cos(a)));
}
mat3 rotateZ(float a){
return mat3(vec3( cos(a), -sin(a), 0.0),
vec3( sin(a), cos(a), 0.0),
vec3( 0.0, 0.0, 1.0));
}
void main(void) {
vec2 p = v;
p.y += 0.3;
p.x += sin(time/4. + p.y);
vec3 pos = vec3(p.xy, 0.0)*rotateX(p.x*3. + time);
//pos.y += sin(pos.x) - sin(time/5.)*0.5 + cos(pos.y/3.1415)*0.5;
gl_Position = vec4(pos, 1.);
gl_PointSize = 2.7;
gl_Position.z = 0.0;
c.rgb=vec3(1.0, 0.5, 0.0);
}
`, gl.VERTEX_SHADER);
shader(`
precision highp float;
varying vec3 c;
void main(void) {
gl_FragColor = vec4(c, 1.);
}
`, gl.FRAGMENT_SHADER);
gl.linkProgram(pid);
gl.useProgram(pid);
let v = gl.getAttribLocation(pid, "v");
gl.vertexAttribPointer(v, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(v);
let timeUniform = gl.getUniformLocation(pid, 'time');
requestAnimationFrame(draw);
addEventListener('resize', resize)
function draw(t) {
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.clearColor(0, 0, 0, 0);
gl.uniform1f(timeUniform, t/1000);
gl.drawArrays(gl.POINTS, 0, vertices.length/2);
requestAnimationFrame(draw);
}
function shader(src, type) {
let sid = gl.createShader(type);
gl.shaderSource(sid, src);
gl.compileShader(sid);
var message = gl.getShaderInfoLog(sid);
gl.attachShader(pid, sid);
if (message.length > 0) {
console.log(src.split("\n")
.map((str, i) => (""+(1+i))
.padStart(4, "0")+": "+str)
.join("\n"));
throw message;
}
}
}());
// ----------------------
(function() {
let vertices = [];
let gl = canvas.getContext('webgl');
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
resize();
function resize() {
canvas.width = innerWidth;
canvas.height = innerHeight;
let step = 10,
w = Math.floor(canvas.width/step),
h = Math.floor(canvas.height/step);
vertices = [];
for (var x=0; x<w*3; x++)
for (var y=0; y<10; y++)
vertices.push(1/w + x*10/w - 5, 1/h + y*2/h - 1)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
}
let pid = gl.createProgram();
shader(`
attribute vec2 v;
uniform float time;
varying vec3 c;
mat3 rotateX(float a) {
return mat3(vec3( -1.0, -1.0, 0.0),
vec3( 0.0, cos(a), -sin(a)),
vec3( 0.0, sin(a), cos(a)));
}
mat3 rotateY(float a){
return mat3(vec3( cos(a), 0.0, sin(a)),
vec3( 0.0, 1.0, 0.0),
vec3(-sin(a), 0.0, cos(a)));
}
mat3 rotateZ(float a){
return mat3(vec3( cos(a), -sin(a), 0.0),
vec3( sin(a), cos(a), 0.0),
vec3( 0.0, 0.0, 1.0));
}
void main(void) {
vec2 p = v;
p.y += 0.3;
p.x += sin(time/4. + p.y);
vec3 pos = vec3(p.xy, 0.0)*rotateX(p.x*3. + time);
//pos.y += sin(pos.x) - sin(time/5.)*0.5 + cos(pos.y/3.1415)*0.5;
gl_Position = vec4(pos, 1.);
gl_PointSize = 2.7;
gl_Position.z = 0.0;
c.rgb=vec3(1., 0., 0.);
}
`, gl.VERTEX_SHADER);
shader(`
precision highp float;
varying vec3 c;
void main(void) {
gl_FragColor = vec4(c, 1.);
}
`, gl.FRAGMENT_SHADER);
gl.linkProgram(pid);
gl.useProgram(pid);
let v = gl.getAttribLocation(pid, "v");
gl.vertexAttribPointer(v, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(v);
let timeUniform = gl.getUniformLocation(pid, 'time');
requestAnimationFrame(draw);
addEventListener('resize', resize)
function draw(t) {
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.clearColor(0, 0, 0, 0);
gl.uniform1f(timeUniform, t/1000);
gl.drawArrays(gl.POINTS, 0, vertices.length/2);
requestAnimationFrame(draw);
}
function shader(src, type) {
let sid = gl.createShader(type);
gl.shaderSource(sid, src);
gl.compileShader(sid);
var message = gl.getShaderInfoLog(sid);
gl.attachShader(pid, sid);
if (message.length > 0) {
console.log(src.split("\n")
.map((str, i) => (""+(1+i))
.padStart(4, "0")+": "+str)
.join("\n"));
throw message;
}
}
}());
body {
margin: 0;
}
canvas {
display: block;
}
#particle {
background-image:url(https://i.imgur.com/HiAlf85.jpg);
background-size: cover;
}
#canvas {
position: absolute;
left: 0;
top: 0;
}
<canvas id="particle"></canvas>
<canvas id="canvas"></canvas>
当然不清楚你为什么要这样做。使用 1 canvas 可能会更快,但我假设您有自己的理由。
'use strict';
let vertices = [];
let gl = particle.getContext('webgl');
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
resize();
function resize() {
particle.width = innerWidth;
particle.height = innerHeight;
let step = 10,
w = Math.floor(particle.width/step),
h = Math.floor(particle.height/step);
vertices = [];
for (var x=0; x<w*3; x++)
for (var y=0; y<10; y++)
vertices.push(1/w + x*10/w - 5, 1/h + y*2/h - 1)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
}
let pid1 = createProgram(`
attribute vec2 v;
uniform float time;
varying vec3 c;
mat3 rotateX(float a) {
return mat3(vec3( 1.0, 0.0, 0.0),
vec3( -1.0, cos(a), -sin(a)),
vec3( 0.0, sin(a), cos(a)));
}
mat3 rotateY(float a){
return mat3(vec3( cos(a), 0.0, sin(a)),
vec3( 0.0, 1.0, 0.0),
vec3(-sin(a), 0.0, cos(a)));
}
mat3 rotateZ(float a){
return mat3(vec3( cos(a), -sin(a), 0.0),
vec3( sin(a), cos(a), 0.0),
vec3( 0.0, 0.0, 1.0));
}
void main(void) {
vec2 p = v;
p.y += 0.3;
p.x += sin(time/4. + p.y);
vec3 pos = vec3(p.xy, 0.0)*rotateX(p.x*3. + time);
//pos.y += sin(pos.x) - sin(time/5.)*0.5 + cos(pos.y/3.1415)*0.5;
gl_Position = vec4(pos, 1.);
gl_PointSize = 2.7;
gl_Position.z = 0.0;
c.rgb=vec3(1.0, 0.5, 0.0);
}
`,
`
precision highp float;
varying vec3 c;
void main(void) {
gl_FragColor = vec4(c, 1.);
}
`);
let pid2 = createProgram(`
attribute vec2 v;
uniform float time;
varying vec3 c;
mat3 rotateX(float a) {
return mat3(vec3( -1.0, -1.0, 0.0),
vec3( 0.0, cos(a), -sin(a)),
vec3( 0.0, sin(a), cos(a)));
}
mat3 rotateY(float a){
return mat3(vec3( cos(a), 0.0, sin(a)),
vec3( 0.0, 1.0, 0.0),
vec3(-sin(a), 0.0, cos(a)));
}
mat3 rotateZ(float a){
return mat3(vec3( cos(a), -sin(a), 0.0),
vec3( sin(a), cos(a), 0.0),
vec3( 0.0, 0.0, 1.0));
}
void main(void) {
vec2 p = v;
p.y += 0.3;
p.x += sin(time/4. + p.y);
vec3 pos = vec3(p.xy, 0.0)*rotateX(p.x*3. + time);
//pos.y += sin(pos.x) - sin(time/5.)*0.5 + cos(pos.y/3.1415)*0.5;
gl_Position = vec4(pos, 1.);
gl_PointSize = 2.7;
gl_Position.z = 0.0;
c.rgb=vec3(1., 0., 0.);
}
`, `
precision highp float;
varying vec3 c;
void main(void) {
gl_FragColor = vec4(c, 1.);
}
`);
let v1 = gl.getAttribLocation(pid1, "v");
let timeUniform1 = gl.getUniformLocation(pid1, 'time');
let v2 = gl.getAttribLocation(pid2, "v");
let timeUniform2 = gl.getUniformLocation(pid2, 'time');
requestAnimationFrame(draw);
addEventListener('resize', resize)
function draw(t) {
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.clearColor(0, 0, 0, 0);
gl.useProgram(pid1);
// normally you'd bind a buffer here but since you only
// have one and the vertex data is the same for both programs
// we don't need to bind a different buffer
gl.vertexAttribPointer(v1, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(v1);
gl.uniform1f(timeUniform1, t/1000);
gl.drawArrays(gl.POINTS, 0, vertices.length/2);
gl.useProgram(pid2);
gl.vertexAttribPointer(v2, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(v2);
gl.uniform1f(timeUniform2, t/1000);
gl.drawArrays(gl.POINTS, 0, vertices.length/2);
requestAnimationFrame(draw);
}
function createProgram(vs, fs) {
const pid = gl.createProgram();
shader(vs, gl.VERTEX_SHADER, pid);
shader(fs, gl.FRAGMENT_SHADER, pid);
gl.linkProgram(pid);
// should check for link error here!
return pid;
}
function shader(src, type, pid) {
let sid = gl.createShader(type);
gl.shaderSource(sid, src);
gl.compileShader(sid);
var message = gl.getShaderInfoLog(sid);
gl.attachShader(pid, sid);
if (message.length > 0) {
console.log(src.split("\n")
.map((str, i) => (""+(1+i))
.padStart(4, "0")+": "+str)
.join("\n"));
throw message;
}
}
body {
margin: 0;
}
canvas {
display: block;
}
#particle {
background-image:url(https://i.imgur.com/HiAlf85.jpg);
background-size: cover;
}
<canvas id="particle"></canvas>