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="vs_texpoint">

  attribute float psize;
  varying float psz;

    void main() {
    
        gl_PointSize = psize;

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

        gl_Position = projectionMatrix * mvPosition;
        
        psz = psize;
    }
</script>

<script type="x-shader/x-fragment" id="fs_texpoint">
	
  uniform sampler2D map;
  uniform vec2 text_size;
  
  varying float psz;
  
  void main() {
  
    vec2 uv = vec2(gl_PointCoord.x, 1.0 - gl_PointCoord.y) * text_size * psz;
    
    gl_FragColor = uv.x < 1.0 && uv.y < 1.0 ? texture2D(map, uv) : vec4(1.0, 0.0, 1.0, 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 texldr = new THREE.TextureLoader();

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, 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);
  
  const psz = new THREE.Float32BufferAttribute(psize, 1);
  this.geo.setAttribute('psize', psz);
  
  this.mat = new THREE.ShaderMaterial({
    vertexShader: getShader({}, vs),
    fragmentShader: getShader({}, fs),
    uniforms: {
      map: { value: texldr.load(
  			'https://source.unsplash.com/random/75x100',
  			render,
  			undefined,
  			err => { console.log('texture load err:', err) }
     )},
     text_size: {value: [1/75, 1/100]}
   },
  });
  
  this.mesh = new THREE.Points(this.geo, this.mat);
  this.mesh.position.set(x, y, z);
 ...