three msdf text utils
1.0.0
使用位图字体和MSDF(多通道签名的距离字段)中的三个.j渲染文本渲染的实用程序类。
从三bmfont-Text分叉。
它包括:
为了获得此工作,您需要一些特定的文件,可以使用MSDF-BMFONT-XML或在线工具生成它们。您还可以检查我的MSDF-FONT-FARTORY,它已经包含了一些您可以使用的文件和一个可以轻松生成文件的脚本。
npm install three-msdf-text-utils import { MSDFTextGeometry , MSDFTextMaterial } from "three-msdf-text-utils" ;
import { FontLoader } from 'three/examples/jsm/loaders/FontLoader.js' ;
import * as THREE from 'three' ;
Promise . all ( [
loadFontAtlas ( "./fonts/roboto/roboto-regular.png" ) ,
loadFont ( "./fonts/roboto/roboto-regular.fnt" ) ,
] ) . then ( ( [ atlas , font ] ) => {
const geometry = new MSDFTextGeometry ( {
text : "Hello World" ,
font : font . data ,
} ) ;
const material = new MSDFTextMaterial ( ) ;
material . uniforms . uMap . value = atlas ;
const mesh = new THREE . Mesh ( geometry , material ) ;
} ) ;
function loadFontAtlas ( path ) {
const promise = new Promise ( ( resolve , reject ) => {
const loader = new THREE . TextureLoader ( ) ;
loader . load ( path , resolve ) ;
} ) ;
return promise ;
}
function loadFont ( path ) {
const promise = new Promise ( ( resolve , reject ) => {
const loader = new FontLoader ( ) ;
loader . load ( path , resolve ) ;
} ) ;
return promise ;
} const geometry = new MSDFTextGeometry ( options ) ;选项可以是一个对象,也可以是字符串 - 等效于{text:str}。
flipY (布尔值):纹理是否会被y-flipper(默认为true)multipage (布尔值):是否使用包含页面ID的额外缓冲区构建此几何形状。这对于多文本字体是必需的(默认为false) font (必需)具有字符,Kernings等的BMFONT定义text (字符串)要布局的文本。 Newline字符( n)将导致销售折断width (数字,可选)文本框的所需宽度会导致单词包装和剪辑在“ pre”模式下。离开时不确定以删除文字包裹(默认行为)mode (字符串)Word-wrapper的模式;可以是“ pre”(维持间距)或“ nowrap”(崩溃的空格崩溃,但仅在新线字符上断开),否则假定正常的单词包含行为(塌陷,空格崩溃,宽度或newlines)align (字符串)可以“左”,“中心”或“右”(默认:左)letterSpacing (编号)像素中的字母间距(默认:0)lineHeight (编号)像素中的线高(默认为font.common.lineheight)tabSize (编号)在单个选项卡中使用的空间数(默认4)start (编号)开始文本的启动索引要进行布局(默认为0)end (number)在文本中的结尾索引(独家)到布局(默认text.length) update(options)使用给定选项重新构建几何形状。此处未指定的任何选项默认为构造函数中的设置。此方法将重新计算文本布局并重建WebGL缓冲区。选项可以是一个对象,也可以是字符串 - 等效于{text:str}。
layout文本布局实例,您可以使用它来访问布局属性,例如:
宽度,高度,下降,升天,Xheight,基线,倾斜度,lineHeight,Linestotal,Letterstotal
visibleGlyphs从geometry.layout.glyphs的过滤集,旨在与基础bufferattributes使用的顶点数据对齐。
这是{ line, position, index, data }对象的数组,请参见此处。例如,这可以用来添加新的BufferAttribute以进行line偏移。
除了基本的几何属性。有一些特定文本的属性,主要用于动画目的。
positionuv :用于绘制正确字母的紫外线坐标center :每个字母四边形的中心layoutUv :全文块的紫外线坐标。glyphUv :每个字母Quad的紫外线坐标。glyphResolution :分辨每个单独的字母四边形。lineIndex :每行的索引lineLettersTotal :每行的总字母总量lineLetterIndex :每条字母的索引lineWordsTotal :按行的总单词总量lineWordIndex :每个单词的索引wordIndex :每个单词的索引letterIndex :每个字母的索引它延伸到三个。
您可以通过从字体设置Atlas纹理来使用它:
const material = new MSDFTextMaterial ( options ) ;
material . uniforms . uMap . value = atlas ; const defaultOptions = {
side : THREE . FrontSide ,
transparent : true ,
defines : {
IS_SMALL : false ,
} ,
extensions : {
derivatives : true ,
} ,
uniforms : {
// Common
uOpacity : { value : 1 } ,
uColor : { value : new Color ( "#ffffff" ) } ,
uMap : { value : null } ,
// Rendering
uThreshold : { value : 0.05 } ,
uAlphaTest : { value : 0.01 } ,
// Strokes
uStrokeColor : { value : new Color ( "#ff0000" ) } ,
uStrokeOutsetWidth : { value : 0.0 } ,
uStrokeInsetWidth : { value : 0.3 } ,
} ,
vertexShader ,
fragmentShader ,
} ;注意: IS_SMALL boolean对于渲染小字体很有用,它将切换alpha渲染计算以使它们在视觉上更加顺畅
如果您想制定一些特定的文本效果,则可以根据MSDFTEXTMATERIAL PANDER在着色器材料中创建自己的GLSL代码。
import { uniforms } from "three-msdf-text-utils" ;
import * as THREE from 'three' ;
const material = new THREE . ShaderMaterial ( {
side : DoubleSide ,
transparent : true ,
defines : {
IS_SMALL : false ,
} ,
extensions : {
derivatives : true ,
} ,
uniforms : {
// Common
... uniforms . common ,
// Rendering
... uniforms . rendering ,
// Strokes
... uniforms . strokes ,
} ,
vertexShader : `
// Attribute
attribute vec2 layoutUv;
attribute float lineIndex;
attribute float lineLettersTotal;
attribute float lineLetterIndex;
attribute float lineWordsTotal;
attribute float lineWordIndex;
attribute float wordIndex;
attribute float letterIndex;
// Varyings
varying vec2 vUv;
varying vec2 vLayoutUv;
varying vec3 vViewPosition;
varying vec3 vNormal;
varying float vLineIndex;
varying float vLineLettersTotal;
varying float vLineLetterIndex;
varying float vLineWordsTotal;
varying float vLineWordIndex;
varying float vWordIndex;
varying float vLetterIndex;
void main() {
// Output
vec4 mvPosition = vec4(position, 1.0);
mvPosition = modelViewMatrix * mvPosition;
gl_Position = projectionMatrix * mvPosition;
// Varyings
vUv = uv;
vLayoutUv = layoutUv;
vViewPosition = -mvPosition.xyz;
vNormal = normal;
vLineIndex = lineIndex;
vLineLettersTotal = lineLettersTotal;
vLineLetterIndex = lineLetterIndex;
vLineWordsTotal = lineWordsTotal;
vLineWordIndex = lineWordIndex;
vWordIndex = wordIndex;
vLetterIndex = letterIndex;
}
` ,
fragmentShader : `
// Varyings
varying vec2 vUv;
// Uniforms: Common
uniform float uOpacity;
uniform float uThreshold;
uniform float uAlphaTest;
uniform vec3 uColor;
uniform sampler2D uMap;
// Uniforms: Strokes
uniform vec3 uStrokeColor;
uniform float uStrokeOutsetWidth;
uniform float uStrokeInsetWidth;
// Utils: Median
float median(float r, float g, float b) {
return max(min(r, g), min(max(r, g), b));
}
void main() {
// Common
// Texture sample
vec3 s = texture2D(uMap, vUv).rgb;
// Signed distance
float sigDist = median(s.r, s.g, s.b) - 0.5;
float afwidth = 1.4142135623730951 / 2.0;
#ifdef IS_SMALL
float alpha = smoothstep(uThreshold - afwidth, uThreshold + afwidth, sigDist);
#else
float alpha = clamp(sigDist / fwidth(sigDist) + 0.5, 0.0, 1.0);
#endif
// Strokes
// Outset
float sigDistOutset = sigDist + uStrokeOutsetWidth * 0.5;
// Inset
float sigDistInset = sigDist - uStrokeInsetWidth * 0.5;
#ifdef IS_SMALL
float outset = smoothstep(uThreshold - afwidth, uThreshold + afwidth, sigDistOutset);
float inset = 1.0 - smoothstep(uThreshold - afwidth, uThreshold + afwidth, sigDistInset);
#else
float outset = clamp(sigDistOutset / fwidth(sigDistOutset) + 0.5, 0.0, 1.0);
float inset = 1.0 - clamp(sigDistInset / fwidth(sigDistInset) + 0.5, 0.0, 1.0);
#endif
// Border
float border = outset * inset;
// Alpha Test
if (alpha < uAlphaTest) discard;
// Output: Common
vec4 filledFragColor = vec4(uColor, uOpacity * alpha);
// Output: Strokes
vec4 strokedFragColor = vec4(uStrokeColor, uOpacity * border);
gl_FragColor = filledFragColor;
}
` ,
} ) ;
material . uniforms . uMap . value = atlas ; npm installnpm run dev