javascript - 在 WebGL + JavaScript 中更改颜色

标签 javascript animation graphics webgl render

我正在使用以下代码生成粒子动画。我想在每帧中将单个粒子的颜色更改为随机颜色。是否可以这样做,如果可以,我该如何实现?此外,是否可以更改每个渲染中粒子的旋转?任何对这些问题的帮助将不胜感激。

<!doctype html>

<head>
  <title>Triangles</title>
  <style>
    html,
    body {
      background: #000;
      height: 100%;
      margin: 0;
    }
    
    canvas {
      width: 1280px;
      height: 720px;
      position: absolute;
      margin: auto;
      top: 0;
      right: 0;
      left: 0;
      bottom: 0;
    }
  </style>
</head>

<body>
  <script>
    'use strict';

    const triangleCount = 2e5;
    const antialias = true;

    const generateTriangles = (count, width, height) => {
      const coords = new Float32Array(9 * count);
      for (var i = 0; i < coords.length;) {
        const x = Math.random() * 2 - 1;
        const y = Math.random() * 2 - 1;
        const z = Math.random() * 2 - 1;
        const theta = Math.random() * Math.PI;

        const ax = 10 * Math.cos(theta) / width;
        const ay = 10 * Math.sin(theta) / height;
        const bx = 10 * Math.cos(theta + 0.1) / width;
        const by = 10 * Math.sin(theta + 0.1) / height;

        coords[i++] = x + ax;
        coords[i++] = y + ay;
        coords[i++] = z;
        coords[i++] = x + bx;
        coords[i++] = y + by;
        coords[i++] = z;
        coords[i++] = x - ax;
        coords[i++] = y - ay;
        coords[i++] = z;

        coords[i++] = x - ax;
        coords[i++] = y - ay;
        coords[i++] = z;
        coords[i++] = x - bx;
        coords[i++] = y - by;
        coords[i++] = z;
        coords[i++] = x + ax;
        coords[i++] = y + ay;
        coords[i++] = z;
      }
      return coords;
    };

    const vertexShaderSource = `
        precision lowp float;
        attribute vec3 aPosition;
        uniform float uWobble;
        void main() {
            float p = 0.1 / (0.3 * aPosition.z - 0.14 + 0.1 * uWobble);
            gl_Position = vec4(p * aPosition.x, p * aPosition.y, aPosition.z, 1);
        }
    `;

    const fragmentShaderSource = `
        precision lowp float;
        void main() {
            float z = gl_FragCoord.z;
            gl_FragColor = vec4(1.5 * z, z * z, z, 1.7);
        }
    `;

    const canvas = document.createElement('canvas');
    document.body.appendChild(canvas);
    canvas.width = canvas.clientWidth;
    canvas.height = canvas.clientHeight;
    const gl = canvas.getContext('webgl', {
      alpha: false,
      antialias
    });
    const vertexShader = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(vertexShader, vertexShaderSource);
    gl.compileShader(vertexShader);
    const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(fragmentShader, fragmentShaderSource);
    gl.compileShader(fragmentShader);
    const program = gl.createProgram();
    gl.attachShader(program, vertexShader);
    gl.attachShader(program, fragmentShader);
    gl.linkProgram(program);
    gl.useProgram(program);

    const aVertexPosition = gl.getAttribLocation(program, 'aPosition');
    gl.enableVertexAttribArray(aVertexPosition);
    const uWobble = gl.getUniformLocation(program, 'uWobble');
    gl.uniform1f(uWobble, 1);

    const vertices = generateTriangles(triangleCount, canvas.width, canvas.height);
    const vertexBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
    gl.vertexAttribPointer(aVertexPosition, 3, gl.FLOAT, false, 0, 0);

    const render = (timestamp) => {
      requestAnimationFrame(render);
      gl.uniform1f(uWobble, Math.sin(0.00002 * timestamp));
      gl.drawArrays(gl.TRIANGLES, 0, vertices.length / 3);
    };
    window.requestAnimationFrame(render);
  </script>
</body>

最佳答案

这是为每个帧的每个粒子获取半随机颜色的解决方案 - 将您的 fragmentShaderSource 更改为以下内容:

const fragmentShaderSource = `
    precision lowp float;
    uniform float uWobble;
    void main() {
        float r = fract(sin(uWobble*10000.0*gl_FragCoord.z));
        float g = fract(cos(uWobble*10000.0*gl_FragCoord.z)*43758.5453);
        float b = fract(cos(uWobble*10000.0*gl_FragCoord.z)*12.9898);
        gl_FragColor = vec4(r, g, b, 1.7);
    }
`;

工作示例 here on fiddle (便于编辑)或以下:

'use strict';

const triangleCount = 2e5;
const antialias = true;

const generateTriangles = (count, width, height) => {
  const coords = new Float32Array(9 * count);
  for (var i = 0; i < coords.length;) {
    const x = Math.random() * 2 - 1;
    const y = Math.random() * 2 - 1;
    const z = Math.random() * 2 - 1;
    const theta = Math.random() * Math.PI;

    const ax = 10 * Math.cos(theta) / width;
    const ay = 10 * Math.sin(theta) / height;
    const bx = 10 * Math.cos(theta + 0.1) / width;
    const by = 10 * Math.sin(theta + 0.1) / height;

    coords[i++] = x + ax;
    coords[i++] = y + ay;
    coords[i++] = z;
    coords[i++] = x + bx;
    coords[i++] = y + by;
    coords[i++] = z;
    coords[i++] = x - ax;
    coords[i++] = y - ay;
    coords[i++] = z;

    coords[i++] = x - ax;
    coords[i++] = y - ay;
    coords[i++] = z;
    coords[i++] = x - bx;
    coords[i++] = y - by;
    coords[i++] = z;
    coords[i++] = x + ax;
    coords[i++] = y + ay;
    coords[i++] = z;
  }
  return coords;
};

const vertexShaderSource = `
    precision lowp float;
    attribute vec3 aPosition;
    uniform float uWobble;
    void main() {
        float p = 0.1 / (0.3 * aPosition.z - 0.14 + 0.1 * uWobble);
        gl_Position = vec4(p * aPosition.x, p * aPosition.y, aPosition.z, 1);
    }
`;

const fragmentShaderSource = `
    precision lowp float;
    uniform float uWobble;
    void main() {
        float r = fract(sin(uWobble*10000.0*gl_FragCoord.z));
        float g = fract(cos(uWobble*10000.0*gl_FragCoord.z)*43758.5453);
        float b = fract(cos(uWobble*10000.0*gl_FragCoord.z)*12.9898);
        gl_FragColor = vec4(r, g, b, 1.7);
    }
`;

const canvas = document.createElement('canvas');
document.body.appendChild(canvas);
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
const gl = canvas.getContext('webgl', {
  alpha: false,
  antialias
});
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSource);
gl.compileShader(vertexShader);
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(fragmentShader);
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);

const aVertexPosition = gl.getAttribLocation(program, 'aPosition');
gl.enableVertexAttribArray(aVertexPosition);
const uWobble = gl.getUniformLocation(program, 'uWobble');
gl.uniform1f(uWobble, 1);

const vertices = generateTriangles(triangleCount, canvas.width, canvas.height);
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.vertexAttribPointer(aVertexPosition, 3, gl.FLOAT, false, 0, 0);

const render = (timestamp) => {
  requestAnimationFrame(render);
  gl.uniform1f(uWobble, Math.sin(0.00002 * timestamp));
  gl.drawArrays(gl.TRIANGLES, 0, vertices.length / 3);
};
window.requestAnimationFrame(render);
html,
body {
  background: #000;
  height: 100%;
  margin: 0;
}

canvas {
  width: 1280px;
  height: 720px;
  position: absolute;
  margin: auto;
  top: 0;
  right: 0;
  left: 0;
  bottom: 0;
}

关于javascript - 在 WebGL + JavaScript 中更改颜色,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53571798/

相关文章:

javascript - 将事件监听器状态作为 Prop 传递

javascript - 使用 jQuery 更新 div 未显示在 DOM 上

c++ - 如何获取平面描述的多边形的顶点

opengl - OpenGL 的每个组件 alpha channel ?

javascript - 使用 OnMouseOver 函数在页面中定位图像

javascript - Uncaught TypeError:无法在playAudio读取null的属性 'play'

jquery - CSS 动画一次一行

objective-c - 如何获取CABasicAnimation进度?

jquery - animation-duration 属性完成后如何重新计算 css 属性?

java - 来自另一个线程的 Graphics.drawImage 不会在 Java Swing 中绘制任何内容