twgl.js/examples/transform-feedback-particles.html
Gregg Tavares 67551111b4 Fix CSS
There was a time when 100vh was correct but mobile browsers changed.
2025-10-13 14:54:12 -07:00

228 lines
6.7 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf8">
<!--
@license twgl.js Copyright (c) 2015, Gregg Tavares All Rights Reserved.
Available via the MIT license.
see: http://github.com/greggman/twgl.js for details
-->
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<meta property="og:title" content="TWGL.js - transform feedback particles" />
<meta property="og:type" content="website" />
<meta property="og:image" content="http://twgljs.org/examples/screenshots/transform-feedback.png" />
<meta property="og:description" content="TWGL.js - transform feedback" />
<meta property="og:url" content="http://twgljs.org" />
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@greggman">
<meta name="twitter:creator" content="@greggman">
<meta name="twitter:domain" content="twgljs.org">
<meta name="twitter:title" content="TWGL.js - transform feedback">
<meta name="twitter:url" content="http://twgljs.org/examples/transform-feedback.html">
<meta name="twitter:description" content="TWGL.js - transform feedback">
<meta name="twitter:image:src" content="http://twgljs.org/examples/screenshots/transform-feedback.png">
<link href="/resources/images/twgljs-icon.png" rel="shortcut icon" type="image/png">
<title>twgl.js - transform feedback</title>
<style>
html, body {
margin: 0;
font-family: monospace;
height: 100%;
}
canvas {
display: block;
width: 100%;
height: 100%;
}
#b {
position: absolute;
top: 10px;
width: 100%;
text-align: center;
z-index: 2;
color: white;
}
#b a {
color: lightblue;
}
</style>
</head>
<body>
<canvas id="c"></canvas>
<div id="b"><a href="http://twgljs.org">twgl.js</a> - transform feedback particles</div>
<div id="no-webgl2" style="display: none;">
<div>Sorry but your browser doesn't appear to support WebGL2</div>
</div>
</body>
<script src="../3rdparty/chroma.min.js"></script>
<script type="module">
import * as twgl from '../dist/7.x/twgl-full.module.js';
const tfVS = `#version 300 es
in vec2 a_positionIn;
in vec2 a_velocity;
out vec2 a_positionOut;
uniform float u_deltaTime;
uniform float u_time;
void main() {
vec2 localMult = vec2(
sin((a_positionIn.x + a_positionIn.y + float(gl_VertexID) * 0.01) * 5.127 + u_time),
cos(atan(a_positionIn.x, a_positionIn.y + float(gl_VertexID) * 0.0) * 2.713 + u_time * 0.791)) * 0.5 ;
a_positionOut = mod((a_positionIn + 3.0) + a_velocity * u_deltaTime * localMult, vec2(2)) - 1.0;
}
`;
const tfFS = `#version 300 es
precision mediump float;
out vec4 o;
void main() {
o = vec4(0);
}
`;
const vs = `#version 300 es
in vec4 a_position;
in vec4 a_color;
out vec4 v_color;
void main() {
gl_Position = a_position;
gl_PointSize = 4.0;
v_color = a_color;
}
`;
const fs = `#version 300 es
precision mediump float;
in vec4 v_color;
out vec4 fragColor;
void main() {
fragColor = v_color;
}
`;
function rand(min, max) {
return min + Math.random() * (max - min);
}
const baseHue = rand(0, 360);
function randColor32() {
return chroma.hsv((baseHue + rand(0, 60)) % 360, rand(0.4, 1), rand(0.25, 1)).gl().map(v => v * 255 | 0);
}
function main() {
const gl = document.getElementById("c").getContext("webgl2");
if (!gl) {
document.querySelector("#no-webgl2").style.display = "";
return;
}
const drawProgramInfo = twgl.createProgramInfo(gl, [vs, fs]);
const feedbackProgramInfo = twgl.createProgramInfo(gl, [tfVS, tfFS], {
transformFeedbackVaryings: [
"a_positionOut",
],
});
const numParticles = 100000;
const positions = [];
const velocities = [];
const colors = [];
for (let i = 0; i < numParticles; ++i) {
positions.push(rand(-1, 1), rand(-1, 1));
velocities.push(rand(-1, 1), rand(-1, 1));
colors.push(...randColor32());
}
const tfBufferInfo1 = twgl.createBufferInfoFromArrays(gl, {
a_positionIn: { numComponents: 2, data: new Float32Array(positions) },
a_positionOut: { numComponents: 2, data: positions.length },
a_velocity: { numComponents: 2, data: new Float32Array(velocities) },
});
const tfBufferInfo2 = twgl.createBufferInfoFromArrays(gl, {
a_positionIn: { numComponents: 2, buffer: tfBufferInfo1.attribs.a_positionOut.buffer },
a_positionOut: { numComponents: 2, buffer: tfBufferInfo1.attribs.a_positionIn.buffer },
a_velocity: { numComponents: 2, buffer: tfBufferInfo1.attribs.a_velocity.buffer },
});
const drawBufferInfo1 = twgl.createBufferInfoFromArrays(gl, {
a_position: { numComponents: 2, buffer: tfBufferInfo1.attribs.a_positionOut.buffer },
a_color: new Uint8Array(colors),
});
const drawBufferInfo2 = twgl.createBufferInfoFromArrays(gl, {
a_position: { numComponents: 2, buffer: tfBufferInfo2.attribs.a_positionOut.buffer },
a_color: { type: gl.UNSIGNED_BYTE, buffer: drawBufferInfo1.attribs.a_color.buffer },
});
const feedback1 = twgl.createTransformFeedback(gl, feedbackProgramInfo, tfBufferInfo1);
const feedback2 = twgl.createTransformFeedback(gl, feedbackProgramInfo, tfBufferInfo2);
const sets = [
{
feedback: feedback1,
tfBufferInfo: tfBufferInfo1,
drawBufferInfo: drawBufferInfo1,
},
{
feedback: feedback2,
tfBufferInfo: tfBufferInfo2,
drawBufferInfo: drawBufferInfo2,
},
];
let setNdx = 0;
let then = 0;
function render(now) {
now *= 0.001;
const deltaTime = now - then;
then = now;
twgl.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
const {feedback, tfBufferInfo, drawBufferInfo} = sets[setNdx];
setNdx = 1 - setNdx;
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// update
gl.enable(gl.RASTERIZER_DISCARD);
gl.useProgram(feedbackProgramInfo.program);
gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, feedback);
gl.beginTransformFeedback(gl.POINTS);
twgl.setBuffersAndAttributes(gl, feedbackProgramInfo, tfBufferInfo);
twgl.setUniforms(feedbackProgramInfo, {
u_deltaTime: deltaTime,
u_time: now,
});
twgl.drawBufferInfo(gl, tfBufferInfo, gl.POINTS);
gl.endTransformFeedback();
gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, null);
gl.disable(gl.RASTERIZER_DISCARD);
// draw
gl.useProgram(drawProgramInfo.program);
twgl.setBuffersAndAttributes(gl, drawProgramInfo, drawBufferInfo);
twgl.drawBufferInfo(gl, drawBufferInfo, gl.POINTS);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
</script>
</html>