JSFiddle - React, Tailwind, and code Playground
HTML
<title>WebGL Particle System</title>
<script type="text/javascript" src="https://cvs.khronos.org/svn/repos/registry/trunk/public/webgl/sdk/demos/common/webgl-utils.js"></script>
<script type="text/javascript" src="https://www.khronos.org/registry/webgl/sdk/debug/webgl-debug.js"></script>
<script src="https://cvs.khronos.org/svn/repos/registry/trunk/public/webgl/sdk/demos/webkit/resources/J3DI.js"> </script>
<script src="https://cvs.khronos.org/svn/repos/registry/trunk/public/webgl/sdk/demos/webkit/resources/J3DIMath.js"
type="text/javascript"> </script>
<canvas id="example">
If you're seeing this your web browser doesn't support the <canvas>> element. Ouch!
</canvas>
<div id="framerate"></div>
<script id="render_vshader" type="x-shader/x-vertex">
attribute vec4 vPosition;
uniform mat4 u_modelViewProjMatrix;
uniform sampler2D mParticleTex;
void main()
{
vec2 particleSampleCoords = vPosition.xy;
vec4 particlePos = texture2D(mParticleTex, particleSampleCoords);
gl_Position = u_modelViewProjMatrix * particlePos;
gl_PointSize = 10.0;
}
</script>
<script id="render_fshader" type="x-shader/x-fragment">
precision mediump float;
uniform sampler2D mSpriteTex;
void main()
{
vec4 texColor = texture2D(mSpriteTex, gl_PointCoord);
gl_FragColor = texColor;
}
</script>
<script id="particle_vshader" type="x-shader/x-vertex">
attribute vec4 vPosition;
void main()
{
// Dummy VS
gl_Position = vPosition;
}
</script>
<script id="particle_fshader" type="x-shader/x-fragment">
precision mediump float;
uniform sampler2D mParticleTex;
void main()
{
// Current pixel is the particle's position on the texture
vec2 particleSampleCoords = gl_FragCoord.xy;
vec4 particlePos = texture2D(mParticleTex, particleSampleCoords);
// Move the particle up
particlePos.y += 0.1;
...
CSS
body, html {
margin: 0px;
width: 100%;
height: 100%;
overflow: hidden;
}
#framerate {
position: absolute;
top: 10px;
left: 10px;
background-color: rgba(0,0,0,0.3);
padding: 1em;
color: white;
}
#example {
width: 100%;
height: 100%;
}
canvas {
border: 2px solid black;
}
JavaScript
var g = { };
var numParticles = 512;
var particleSize = 0.1;
var particleSpread = 4.0;
var maxTex = 16384;
start();
// Get best texture size (must be square powers of 2)
function getTexSize(n)
{
var retval = { };
for(var height = 1; height<maxTex; height *= 2)
{
for(var width = 1; width<maxTex; width *= 2)
{
if(width*height >= n)
{
retval.width = width;
retval.height = height;
return retval;
}
}
}
retval.width = -1;
retval.height = -1;
return retval;
}
function createScreenQuad(gl)
{
// Returned particle system object
var retval = { };
// 4 3D corners = 12 vertices / particle
var vertexBuffer = new Float32Array(12);
// -1,-1 to 1,1 screen quad
vertexBuffer[0] = -1;
vertexBuffer[1] = -1;
vertexBuffer[2] = -1;
vertexBuffer[3] = 1;
vertexBuffer[4] = 1;
vertexBuffer[5] = 1;
vertexBuffer[6] = -1;
vertexBuffer[7] = -1;
vertexBuffer[8] = 1;
vertexBuffer[9] = 1;
vertexBuffer[10] = 1;
vertexBuffer[11] = -1;
// Create GL buffers with this data
retval.vertexObject = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, retval.vertexObject);
gl.bufferData(gl.ARRAY_BUFFER, vertexBuffer, gl.STATIC_DRAW);
return retval;
}
// Loads a texture from the absolute or relative URL "src".
// Returns a WebGLTexture object.
// The texture is downloaded in the background using the browser's
// built-in image handling. Upon completion of the download, our
// onload event handler will be called which uploads the image into
// the WebGLTexture.
function loadTexture(src) {
// Create and initialize the WebGLTexture object.
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
//...