diff --git a/gpgpu_matrix.html b/gpgpu_matrix.html index 29450b7..210339f 100644 --- a/gpgpu_matrix.html +++ b/gpgpu_matrix.html @@ -7,23 +7,20 @@ const camera = new THREE.OrthographicCamera( -0.5, 0.5, 0.5, -0.5, 0.0001, 10000 ); const scene = new THREE.Scene(); const renderer = new THREE.WebGLRenderer(); - renderer.setClearColor(new THREE.Color(1, 1, 1), 1); renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); - - - const NUM_ROWS = 80; + const numColumns = 80; // Creates the gpu computation class and sets it up - const gpuCompute = new GPUComputationRenderer( NUM_ROWS, NUM_ROWS, renderer ); + const gpuCompute = new GPUComputationRenderer( numColumns, numColumns, renderer ); const glyphValue = gpuCompute.createTexture(); // This is how one might initialize data const pixels = glyphValue.image.data; - for (let i = 0; i < NUM_ROWS * NUM_ROWS; i++) { - pixels[i * 4 + 0] = Math.random(); + for (let i = 0; i < numColumns * numColumns; i++) { + pixels[i * 4 + 0] = 0; pixels[i * 4 + 1] = Math.random(); pixels[i * 4 + 2] = 0; pixels[i * 4 + 3] = 0; @@ -32,7 +29,7 @@ const glyphVariable = gpuCompute.addVariable( "glyph", ` - // #include + precision highp float; #define PI 3.14159265359 #define SQRT_2 1.4142135623730951 #define SQRT_5 2.23606797749979 @@ -46,7 +43,7 @@ uniform float c; uniform float brightnessChangeBias; uniform float glyphSequenceLength; - uniform float numGlyphRows; + uniform float numGlyphColumns; highp float rand( const in vec2 uv ) { const highp float a = 12.9898, b = 78.233, c = 43758.5453; @@ -81,14 +78,14 @@ float glyphCycleSpeed = delta * cycleSpeed * 0.2 * pow(1.0 - brightness, 4.0); cycle = fract(cycle + glyphCycleSpeed); float symbol = floor(glyphSequenceLength * cycle); - float symbolX = mod(symbol, numGlyphRows); - float symbolY = (numGlyphRows - 1.0 - (symbol - symbolX) / numGlyphRows); + float symbolX = mod(symbol, numGlyphColumns); + float symbolY = ((numGlyphColumns - 1.0) - (symbol - symbolX) / numGlyphColumns); - gl_FragColor = vec4(0.5); + gl_FragColor = vec4(1.0); gl_FragColor.r = brightness; gl_FragColor.g = cycle; - gl_FragColor.b = symbolX / numGlyphRows; - gl_FragColor.a = symbolY / numGlyphRows; + gl_FragColor.b = symbolX / numGlyphColumns; + gl_FragColor.a = symbolY / numGlyphColumns; } ` , @@ -105,31 +102,88 @@ fallSpeed: { type: "f", value: 1 }, cycleSpeed: {type: "f", value: 1 }, glyphSequenceLength: { type: "f", value: glyphSequenceLength }, - numGlyphRows: {type: "f", value: 8}, + numGlyphColumns: {type: "f", value: 8}, a: { type: "f", value: 1.125 }, b: { type: "f", value: 1.125 }, c: { type: "f", value: 1.25 }, brightnessChangeBias: { type: "f", value: brightnessChangeBias }, }); - // This is how one might initialize a const - /* - Object.assign(glyphVariable.material.defines, { - BOUNDS: BOUNDS.toFixed( 1 ), - }); - */ const error = gpuCompute.init(); if ( error !== null ) { console.error( error ); } + const sharpness = 0.5; + const glyphRTT = gpuCompute.getCurrentRenderTarget( glyphVariable ).texture; + const plane = new THREE.Mesh( new THREE.PlaneBufferGeometry(), - new THREE.MeshBasicMaterial({ - map: gpuCompute.getCurrentRenderTarget( glyphVariable ).texture - // map: new THREE.TextureLoader().load( './matrixcode_msdf.png' ) + new THREE.RawShaderMaterial({ + uniforms: { + glyphs: { type: "t", value: glyphRTT }, + msdf: { type: "t", value: new THREE.TextureLoader().load( './matrixcode_msdf.png' ) }, + numColumns: {type: "f", value: numColumns}, + sharpness: { type: "f", value: sharpness }, + numGlyphColumns: {type: "f", value: 8}, + }, + vertexShader: ` + attribute vec2 uv; + attribute vec3 position; + uniform mat4 projectionMatrix; + uniform mat4 modelViewMatrix; + varying vec2 vUV; + void main() { + vUV = uv; + gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); + } + `, + fragmentShader: ` + #ifdef GL_OES_standard_derivatives + #extension GL_OES_standard_derivatives: enable + #endif + precision lowp float; + #define BIG_ENOUGH 0.001 + #define MODIFIED_ALPHATEST (0.02 * isBigEnough / BIG_ENOUGH) + uniform float sharpness; + uniform sampler2D msdf; + uniform sampler2D glyphs; + uniform float numColumns; + uniform float numGlyphColumns; + varying vec2 vUV; + + float median(float r, float g, float b) { + return max(min(r, g), min(max(r, g), b)); + } + + void main() { + + vec4 glyph = texture2D(glyphs, vUV); + float brightness = glyph.r; + vec2 symbolUV = glyph.ba; + vec4 sample = texture2D(msdf, fract(vUV * numColumns) / numGlyphColumns + symbolUV); + + // MSDF + float sigDist = median(sample.r, sample.g, sample.b) - 0.5; + float alpha = clamp(sigDist/fwidth(sigDist) + 0.5, 0.0, 1.0); + float dscale = 0.353505 / sharpness; + vec2 duv = dscale * (dFdx(vUV) + dFdy(vUV)); + float isBigEnough = max(abs(duv.x), abs(duv.y)); + if (isBigEnough > BIG_ENOUGH) { + float ratio = BIG_ENOUGH / isBigEnough; + alpha = ratio * alpha + (1.0 - ratio) * (sigDist + 0.5); + } + if (isBigEnough <= BIG_ENOUGH && alpha < 0.5) { discard; return; } + if (alpha < 0.5 * MODIFIED_ALPHATEST) { discard; return; } + + gl_FragColor = vec4(vec3(brightness * alpha), 1); + } + ` }) + /* + new THREE.MeshBasicMaterial({ map: glyphRTT }) + */ ); plane.geometry.computeVertexNormals(); scene.add( plane ); @@ -157,6 +211,29 @@ renderer.render( scene, camera ); } + const windowResize = () => { + const [width, height] = [window.innerWidth, window.innerHeight]; + const ratio = height / width; + const frac = 0.5; + if (ratio < 1) { + camera.left = -frac; + camera.right = frac; + camera.bottom = (camera.left - camera.right) * ratio + frac; + camera.top = frac; + } else { + camera.bottom = -frac; + camera.top = frac; + camera.left = camera.bottom / ratio; + camera.right = camera.top / ratio; + } + camera.updateProjectionMatrix(); + renderer.setSize(width, height); + // bloomPass.setSize( window.innerWidth, window.innerHeight ); + } + window.addEventListener("resize", windowResize, false); + window.addEventListener("orientationchange", windowResize, false); + windowResize(); + animate();