gpgpu on point geom RT3

gpgpu on point geometry RT3

by tfoller

HTML

<div id="grid">

  <canvas id="main_canvas" style="border: solid 1px red;" width=400 height=400>
  </canvas>

  <div id="stats_holder"></div>

  <div>
    <label id="label" style="padding-right:10px;"></label>
    <button id="btn">play</button>
  </div>

</div>


<script type="x-shader/x-vertex" id="gpgpu_vs">
  #version 100
  attribute vec3 position;

  attribute vec3 data;

  #ifdef GL_FRAGMENT_PRECISION_HIGH
    uniform highp float point_size;
  #else
    uniform mediump float point_size;
  #endif

  varying vec3 rft;

  void main() {

    gl_PointSize = point_size;
    gl_Position = vec4(position, 1.0);

    rft = data;
  }
</script>

<script type='x-shader/x-fragment' id='gpgpu_fs'>
  #version 100

  #ifdef GL_FRAGMENT_PRECISION_HIGH
    precision highp float;
    float digits = 5.0; // digits to extract
  #else
    float digits = 4.0;
  #endif

  vec4 floatToVec4(float f) { // [8 bits exp] [sign + 23 fract bits]
    float sign = 0.0;
    if(f < 0.0) { sign = 128.0; f = -f;}
      const float ln10 = log(10.0);
      float exp = f > 0.0 ? ceil(log(f)/ln10) : 0.0;
      exp = digits - exp;
      float f24 = f * pow(10.0, exp);

      f24 /= 256.0 * 256.0;
      float byte2 = floor(f24);
      float b10 = (f24 - byte2) * 256.0;
      float byte1 = floor(b10);
      float byte0 = (b10 - byte1) * 256.0;

      return vec4(exp, byte2 + sign, byte1, byte0)/255.0;
  }

  uniform float time;
  uniform float point_size;
  uniform float hd;

  varying vec3 rft;

  void main() {

  	float r = rft[0];
    float fi = rft[1] + time;
    float th = rft[2] + time;

    int ind = int(point_size * ((gl_PointCoord.t - hd) * point_size + (gl_PointCoord.s - hd)));

    float rsinth = r * sin(th);

    if(ind == 0) {
    	float x = rsinth * cos(fi);
      gl_FragColor = floatToVec4(x);
    }
    else if(ind == 1) {
    	float y = rsinth * sin(fi);
      gl_FragColor = floatToVec4(y);
    }
    else if(ind == 2) {
    	float z = r * cos(th);
      gl_FragColor = floatToVec4(z);
   ...

CSS

body {
            background: #0c2733;
        }

        #grid {
            display: grid;
            grid-template-columns: min-content min-content;
            grid-template-rows: min-content min-content;
            gap: 20px;
        }

JavaScript

import * as THREE from "https://threejs.org/build/three.module.js";
import { OrbitControls } from "https://threejs.org/examples/jsm/controls/OrbitControls.js";

let stats;
import Stats from 'https://threejs.org/examples/jsm/libs/stats.module.js';

const init_stats = () => {
  stats = new Stats();
  var elem = stats.dom;
  elem.setAttribute('id', 'stats');
  elem.style.position = null;
  const cont = document.getElementById('stats_holder');
  cont.insertBefore(elem, cont.children[0]);
};

/* parallel computing on point primitives WebGL 1.0
 * input - array of numbers
 * sizein - number of input values in the array needed for one computaion, [1...4]
 * sizeout - number of output values produced from each input
 *
 * example:
 * convert 10 [r, fi, th] values from spherical coord sys to Cartesian [x, y, z]
 * input = [r0, fi0, th0,  r1, fi1, th1, ...,  r9, fi9, th9]
 * sizein = 3; sizeout = 3;
 * output = [x0(float in RGBA), y0, z0, ..., x9, y9, z9]
 */
function GpGpuWebGL1(renderer, input, sizein, sizeout) {

  const point_size = Math.ceil(Math.sqrt(sizeout));
  const attr_size = sizein;
  const inp_len = input.length;
  const threads = Math.ceil(inp_len / attr_size); // number of vertices

  // zero pad input array
  const pad_len = threads * attr_size - inp_len;
  input.length += pad_len;
  for (let i = inp_len; i < input.length; i++) input[i] = 0;

  // canvas size
  const blocks = Math.ceil(Math.sqrt(threads));
  const tw = point_size * blocks;
  const th = tw;
  this.tw = tw;
  this.th = th;

  console.log(`GpGpuWebGL1 init\n
  	inp_len: ${inp_len}, sizein: ${sizein}, pad_len: ${input.length}, \n
    point: ${point_size} x ${point_size}, attr_size: ${attr_size}, \n
    threads: ${threads}, blocks: ${blocks}, texture: ${tw} x ${th}`);

  this.camera = new THREE.OrthographicCamera(-tw / 2, tw / 2, th / 2, -th / 2, 0, 1);

  this.scene = new THREE.Scene();

  this.renderer = renderer;

  this.renderTarget = new THREE.WebGLRenderTarget(tw, th);

  this.mat = new...