diff --git a/test/createMSDFShader.js b/test/createMSDFShader.js new file mode 100644 index 0000000..f43d357 --- /dev/null +++ b/test/createMSDFShader.js @@ -0,0 +1,56 @@ +var assign = require('object-assign'); + +module.exports = function createSDFShader (opt) { + opt = opt || {}; + var opacity = typeof opt.opacity === 'number' ? opt.opacity : 1; + var alphaTest = typeof opt.alphaTest === 'number' ? opt.alphaTest : 0.0001; + var precision = opt.precision || 'highp'; + var color = opt.color; + var map = opt.map; + + // remove to satisfy r73 + delete opt.map; + delete opt.color; + delete opt.precision; + delete opt.opacity; + + return assign({ + uniforms: { + opacity: { type: 'f', value: opacity }, + map: { type: 't', value: map || new THREE.Texture() }, + color: { type: 'c', value: new THREE.Color(color) } + }, + vertexShader: [ + 'attribute vec2 uv;', + 'attribute vec4 position;', + 'uniform mat4 projectionMatrix;', + 'uniform mat4 modelViewMatrix;', + 'varying vec2 vUv;', + 'void main() {', + 'vUv = uv;', + 'gl_Position = projectionMatrix * modelViewMatrix * position;', + '}' + ].join('\n'), + fragmentShader: [ + '#ifdef GL_OES_standard_derivatives', + '#extension GL_OES_standard_derivatives : enable', + '#endif', + 'precision ' + precision + ' float;', + 'uniform float opacity;', + 'uniform vec3 color;', + 'uniform sampler2D map;', + 'varying vec2 vUv;', + + 'float median(float r, float g, float b) {', + ' return max(min(r, g), min(max(r, g), b));', + '}', + + 'void main() {', + ' vec3 sample = 1.0 - texture2D(map, vUv).rgb;', + ' float sigDist = median(sample.r, sample.g, sample.b) - 0.5;', + ' float alpha = clamp(sigDist/fwidth(sigDist) + 0.5, 0.0, 1.0);', + ' gl_FragColor = vec4(color.xyz, alpha * opacity);', + '}' + ].join('\n') + }, opt); +}; diff --git a/test/fontPreloader.js b/test/fontPreloader.js new file mode 100644 index 0000000..155215a --- /dev/null +++ b/test/fontPreloader.js @@ -0,0 +1,35 @@ +const parallel = require('run-parallel'); +const loadBmfont = require('load-bmfont'); +const noop = () => {}; + +var loadedResult; +var isFinished = false; + +module.exports = function (cb = noop) { + if (isFinished) { + process.nextTick(() => { + cb(null, loadedResult); + }); + return loadedResult; + } + parallel({ + texture: (next) => { + var texture = new THREE.TextureLoader().load('../output/sheet0.png', () => { + next(null, texture); + }, noop, () => { + next(new Error('Could not load font image')); + }); + }, + font: (next) => { + loadBmfont('../output/font.fnt', (err, font) => { + if (err) return next(err); + next(null, font); + }); + } + }, (err, results) => { + isFinished = true; + if (err) return cb(err); + loadedResult = results; + cb(null, results); + }); +}; diff --git a/test/test.js b/test/test.js new file mode 100644 index 0000000..1312b76 --- /dev/null +++ b/test/test.js @@ -0,0 +1,57 @@ +const THREE = require('three'); +global.THREE = THREE; +const createTextGeometry = require('three-bmfont-text'); +const createMSDFShader = require('./createMSDFShader'); +const fontPreloader = require('./fontPreloader'); + +var cubeMesh, scene, camera, renderer, mesh; + +function init () { + var canvas = document.createElement('canvas'); + document.body.appendChild(canvas); + canvas.width = window.innerWidth * window.devicePixelRatio; + canvas.height = window.innerHeight * window.devicePixelRatio; + canvas.style.width = window.innerWidth + 'px'; + canvas.style.height = window.innerHeight + 'px'; + + scene = new THREE.Scene(); + camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 1000); + camera.position.z = 100; + + renderer = new THREE.WebGLRenderer({canvas}); + renderer.setClearColor(0xffffff); + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate () { + render(); + window.requestAnimationFrame(animate); +} + +function render () { + renderer.render(scene, camera); +} + +init(); +animate(); + +fontPreloader((err, data) => { + if (err) console.log(err); + const material = new THREE.RawShaderMaterial(createMSDFShader({ + map: data.texture, + side: THREE.DoubleSide, + transparent: true, + depthTest: false, + depthWrite: false, + color: '#000000' + })); + var geometry = createTextGeometry({ + font: data.font + }); + geometry.update('test text'); + mesh = new THREE.Mesh(geometry, material); + mesh.rotation.x = Math.PI; + // mesh.position.z = -130; + mesh.position.x = -70; + scene.add(mesh); +});