ビットマップフォントとMSDF(マルチチャネル署名距離フィールド)を使用して、3.jsでレンダリングするテキストのユーティリティクラス。
Three-BMFont-Textからフォーク。
それは以下を含みます:
これを機能させるには、特定のファイルが必要になり、MSDF-BMFont-XMLまたはオンラインツールで生成できます。また、MSDF-Font-Factoryを確認することもできます。これには、使用できるファイルとスクリプトが含まれており、ファイルを簡単に生成します。
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 ) ;オプションは、{テキスト:str}に相当するオブジェクト、または文字列です。
flipY (boolean):テクスチャがy-fliptになるかどうか(デフォルト真)multipage (Boolean):ページIDを含む追加のバッファーでこのジオメトリを構築するかどうか。これは、マルチテクスチャフォントに必要です(デフォルトのfalse) font (必須)chars、kerningsなどを保持するbmfont定義text (文字列)テキストからレイアウト。 Newline文字( n)は、ラインブレークを引き起こしますwidth (数字、オプション)テキストボックスの目的の幅は、「Pre」モードでワードラップとクリッピングを引き起こします。ワードラッピングを削除するために未定義のままにしてください(デフォルトの動作)mode (文字列)ワードラッパーのモード。 「pre」(間隔を維持)または「nowrap」(崩壊の白い空間崩壊が新しいライン文字でのみ破損)である場合があります。そうでなければ、通常の単語の動作(崩壊の白文学、幅で壊れる、またはニューライン)を想定します。align (string)は「左」、「中央」または「右」にすることができます(デフォルト:左)letterSpacing (番号)ピクセルの文字間隔(デフォルト:0)lineHeight (number)ピクセルのライン高さ(font.common.lineheightにデフォルト)tabSize (number)単一のタブで使用するスペースの数(デフォルト4)start (number)(デフォルト0)end (number)テキストからレイアウトへの終了インデックス(排他)(デフォルトのテキスト.length) update(options)指定されたオプションを使用してジオメトリを再構築します。ここで指定されていないオプションは、コンストラクターに設定されたオプションにデフォルトです。このメソッドは、テキストレイアウトを再計算し、WebGLバッファーを再構築します。オプションは、{テキスト:str}に相当するオブジェクト、または文字列です。
layoutテキストレイアウトインスタンスを使用して、次のようなレイアウト属性にアクセスできます。
幅、高さ、デセンダー、アセンダー、Xheight、ベースライン、Capheight、LineHeeight、Linestotal、LetterStotal
visibleGlyphs geometry.layout.glyphsからフィルタリングされたセットは、基礎となるbufferattributesが使用する頂点データと一致することを目的としています。
これは{ line, position, index, data }オブジェクトの配列です。こちらを参照してください。たとえば、これを使用して、 lineオフセット用の新しいバッファラトリブを追加できます。
基本的なジオメトリ属性に加えて。いくつかのテキスト固有の属性があり、主にアニメーションの目的に役立ちます。
positionuv :右の文字クワッドに右の文字をマッピングするために使用されるUV座標center :各文字の中央クワッドlayoutUv :フルテキストブロックのUV座標。glyphUv :個々の文字クワッドのUV座標。glyphResolution :個々の文字クワッドの解像度。lineIndex :各行のインデックスlineLettersTotal :各行の文字の合計量lineLetterIndex :各文字のインデックスを行ごとにlineWordsTotal :単語の合計量lineWordIndex :各単語ごとのインデックスwordIndex :各単語のインデックスletterIndex :各文字のインデックスThree.js Shadermaterialから拡張されます
フォントから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は小さなフォントをレンダリングするのに役立ちます。アルファレンダリング計算を切り替えて、視覚的にはるかに滑らかにする
いくつかの特定のテキスト効果を作成する場合は、MSDFTExtMaterialシェーダーに基づいてシェーダー素材に独自の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