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);