three-glyph
Version:
Provide geometry and material in THREE.js for MSDF (multi-channel signed distance fields) glyph and more
163 lines (117 loc) • 3.32 kB
JavaScript
import { Color, GLSL3, ShaderMaterial, UniformsUtils, MathUtils } from 'three'
import { defaultChunks, negateChunks, progressChunks } from './pure/chunks.js';
const includePattern = /^[ \t]*
const progressUniforms = {
total: { value: 0 },
progress: { value: 0 },
duration: { value: 1 },
stagger: { value: 0.1 }
}
const GlyphShader = {
name: 'Glyph',
glslVersion: GLSL3,
transparent: true,
depthTest: false,
defines: {},
uniforms: {
map: { value: null },
color: { value: new Color(0xffffff) },
opacity: { value: 1 },
},
vertexShader: /* glsl */`
in vec2 uv;
in vec2 guv;
in vec4 position;
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
out vec2 vUv;
out vec2 vGuv;
void main() {
vUv = uv;
vGuv = guv;
vec3 transformed = vec3( position );
vec4 mvPosition = vec4(transformed, 1.0);
mvPosition = modelViewMatrix * mvPosition;
vec4 pos = projectionMatrix * mvPosition;
gl_Position = pos;
}
`,
fragmentShader: /* glsl */`
precision highp float;
uniform sampler2D map;
in vec2 vUv;
in vec2 vGuv;
out vec4 myOutputColor;
float median(float r, float g, float b) {
return max(min(r, g), min(max(r, g), b));
}
void main() {
vec3 diffuseColor = vec3(1.0);
float alpha = 1.0;
vec3 msd = texture(map, vGuv).rgb;
float sd = median(msd.r, msd.g, msd.b) - 0.5;
alpha *= clamp(sd/fwidth(sd) + 0.5, 0.0, 1.0);
myOutputColor = vec4(diffuseColor, alpha);
}
`
};
class GlyphMaterial extends ShaderMaterial {
constructor( parameters ) {
const { addons } = parameters;
GlyphShader.uniforms = UniformsUtils.merge( [
GlyphShader.uniforms,
parameters.uniforms,
(addons && addons.progress) ? progressUniforms : {}
]);
super(GlyphShader);
this.computeChunks(parameters);
this.isRawShaderMaterial = true;
this.type = 'GlyphMaterial';
// TODO refactory CacheKey
this.customProgramCacheKey = function() {
return MathUtils.generateUUID();
}
this.onBeforeCompile = shader => {
let { fragmentShader: fragment, vertexShader: vertex } = shader;
vertex = this.resolveIncludes(vertex);
shader.vertexShader = vertex;
fragment = this.resolveIncludes(fragment);
shader.fragmentShader = fragment;
};
}
computeChunks(parameters) {
const { addons = {} } = parameters;
const { negate, progress, shaderChunks } = addons;
this.chunks = Object.assign({}, defaultChunks);
if (negate) {
Object.assign(this.chunks, negateChunks);
}
if (progress) {
Object.assign(this.chunks, progressChunks);
}
if (shaderChunks) {
Object.assign(this.chunks, shaderChunks);
}
}
resolveIncludes( string ) {
return string.replace( includePattern, this.includeReplacer.bind(this) );
}
includeReplacer( match, include ) {
let string = this.chunks[ include ];
return string || '';
}
}
export { GlyphShader };
export default GlyphMaterial;