CodePenネタです。
凄く綺麗でいつか何かに使えそうだったのでメモ。
WebGLを使って綺麗なパーティクルを描いています。
ちょっといじればホタルの光みたいなのが作れそうです。
JavaScriptはwebgl-utils.jsを読み込んでいます。

https://webglfundamentals.org/webgl/resources/webgl-utils.js

WebGLの基本」ってページ、読み応えありそう。

サンプル

See the Pen WebGL Particles by Rogier Koppejan (@rogierkoppejan) on CodePen.

HTML

<canvas id="canvas"></div>
<script id="vertex-shader" type="x-shader/x-vertex">
  attribute vec2 a_position;

  void main(void) {
    gl_Position = vec4(a_position, 0, 1);
  }
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
  #ifdef GL_ES
  precision mediump float;
  #endif

  uniform vec2 u_resolution;
  uniform float u_millis;

  const int PARTICLES = 18;
  const float ENERGY = 0.2;
  const float BLOBINESS = 1.6;
  const float BRIGHTNESS = 1.1;
  const float OFFSET = 30000.0;

  float rand(vec2 co) {
    return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453);
  }

  void main(void) {
    vec2 pixel = (gl_FragCoord.xy / u_resolution.x);
    float t = (u_millis + OFFSET ) * 0.001 * ENERGY;

    float a = 0.0;
    float b = 0.0;
    float c = 0.0;

    vec2 particle;
    vec2 center = vec2(0.5, 0.5 * (u_resolution.y / u_resolution.x));

    float na, nb, nc, nd, d;
    float size = float(PARTICLES);
    float step = 1.0 / size;
    float n = step;

    for (int i = 0; i < PARTICLES; i++) {
      vec2 np = vec2(n, 0.0);

      na = rand(np * 1.1);
      nb = rand(np * 2.8);
      nc = rand(np * 0.7);
      nd = rand(np * 3.2);

      particle = center;
      particle.x += sin(t*na) * cos(t*nb) * 0.6;
      particle.y += cos(t*nc) * sin(t*nd) * 0.4;

      d = pow(1.2 * na / length(particle - pixel), BLOBINESS);

      if (float(i) < size * 0.3333) {
        a += d;
      } else if (float(i) < size * 0.6666) {
        b += d;
      } else {
        c += d;
      }

      n += step;
    }

    vec3 col = vec3(a*c, b*c, a*b) * 0.0001 * BRIGHTNESS;
    gl_FragColor = vec4(col, 1.0);
  }
</script>

CSS

html, body {
  background: #111;
  overflow: hidden;
  margin: 0;
}

canvas {
  width: 100vw;
  height: 100vh;
}

JavaScript

'use strict';

// Create program
const canvas = document.getElementById("canvas");
const gl = canvas.getContext('webgl');
const program = webglUtils.createProgramFromScripts(gl, ['vertex-shader', 'fragment-shader']);

// Create and initialize buffer
const geometryBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, geometryBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
  -1.0, -1.0,
   1.0, -1.0,
  -1.0,  1.0,
   1.0,  1.0
]), gl.STATIC_DRAW);

// Set up attributes and uniforms
const attributes = {
  position: gl.getAttribLocation(program, 'a_position')
};

const uniforms = {
  resolution: gl.getUniformLocation(program, 'u_resolution'),
  millis: gl.getUniformLocation(program, 'u_millis')
};

// Set WebGL program here (we have only one)
gl.useProgram(program);

// Setup canvas
window.onresize = resize;
resize();

// Start rendering
requestAnimationFrame(draw);

// Resize canvas and viewport
function resize () {
  webglUtils.resizeCanvasToDisplaySize(gl.canvas);
  gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
}

// Draw frame
function draw (now) {
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  gl.bindBuffer(gl.ARRAY_BUFFER, geometryBuffer);

  gl.enableVertexAttribArray(attributes.position);
  gl.vertexAttribPointer(attributes.position, 2, gl.FLOAT, false, 0, 0);
  gl.uniform2f(uniforms.resolution, window.innerWidth, window.innerHeight);
  gl.uniform1f(uniforms.millis, now);

  gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);

  requestAnimationFrame(draw);
}

一言

描画にメモリ食う。


コメントを投稿する

* が付いている項目は必須です。
メールアドレスが公開されることはありません。