Point textures

by tfoller

HTML

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

<script type="x-shader/x-vertex" id="shapeTexture">

	float shapeTexture(vec2 shape, vec2 pc) {  
  	float maxdist = 0.5;
    vec2 center = vec2(0.5);
    float falloff = smoothstep(0.0, 1.0, maxdist - length(center - pc));
  	if(shape.x < 1.0) { // circle
      return falloff;
    } else if(shape.x < 2.0) { // 4-ray star
    	float x = pc.s - 0.5;
      float y = 0.5 - pc.t;
      float n = 1.0;
      float xy = x * y;
      if(xy != 0.0) n = abs(1.0 / xy);
      return falloff * shape.y * n;
    }
  	return 1.0;
  }
  
</script>

<script type="x-shader/x-vertex" id="hslRgb">
	vec3 hslRgb(vec3 c) {
		vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
		vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
		return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
	}
</script>

<script type="x-shader/x-vertex" id="vs_texpoint">

  uniform float point_size;

    void main() {
    
        gl_PointSize = point_size;

        vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);

        gl_Position = projectionMatrix * mvPosition;
    }
</script>

<script type="x-shader/x-fragment" id="fs_texpoint">
	
  uniform vec2 shape;
	uniform vec2 texsize;
  
  #include 'shapeTexture'
  #include 'hslRgb'

  void main() {
  
    vec3 color = vec3(1.0, 0.0, 1.0);
    //vec3 color = hslRgb(vec3(shapeTexture(shape, gl_PointCoord), 1.0, 1.0));
    color *= shapeTexture(shape, gl_PointCoord);
    gl_FragColor = vec4(color, 1.0);
    
	}
  
</script>

CSS

body {
            background: #000;
            color: #ccc;
        }

JavaScript

import * as THREE from 'https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.js'

const get = (id) => document.getElementById(id);

const canvas = get('main_canvas');

const [w, h] = [canvas.width, canvas.height];
const [w2, h2] = [w * 0.5, h * 0.5];
const renderer = new THREE.WebGLRenderer({
  antialias: false,
  alpha: false,
  canvas,
});
renderer.setPixelRatio(window.devicePixelRatio);

const gl = renderer.getContext();
gl.disable(gl.DITHER);

const [near, far] = [1, 200];
const fixedcam = new THREE.OrthographicCamera(-w2, w2, h2, -h2, near, far);

const getShader = (uiObj, id) => {
    let src = get(id).textContent;
    src = src.replace(/#include '([^']+)'/g,
        function () {
            return get(arguments[1]).textContent;
        });
    src = src.replace(/<sh ([^>]+)>/g,
        function () {
            return eval('uiObj.shader_expr.' + arguments[1]);
        });
    src = src.replace(/<js ([^>]+)>/g,
        function () {
            return eval('uiObj.js_expr.' + arguments[1]);
        });
    return src.replace(/<hub ([^>]+)>/g,
        function () {
            return eval('HUB.' + arguments[1]);
        });
}

function shaderPQuad(vert, w, h, psize, vs, fs, subx = 1, suby = 1, x = 0, y = 0, z = 0) {
  this.geo = new THREE.BufferGeometry();
  const pos = new THREE.Float32BufferAttribute(vert, 3);
  this.geo.setAttribute('position', pos);
  this.mat = new THREE.ShaderMaterial({
    vertexShader: getShader({}, vs),
    fragmentShader: getShader({}, fs),
    uniforms: {
      texsize: { value: [w, h] },
      point_size: { value: psize },
      shape: { value: [0, 0.002] } // shape-type, param
    },
  })
  this.mesh = new THREE.Points(this.geo, this.mat);
  this.mesh.position.set(x, y, z);
  scene.add(this.mesh);
}

const scene = new THREE.Scene();

const quad = new shaderPQuad(
[0,0,0], w, h, 200, 'vs_texpoint', 'fs_texpoint', 1, 1, 
0, 0, -0.5 * (near + far));

renderer.render(scene, fixedcam);