Versorgungsklassen für das Textrendern in drei.Js mit Bitmap-Schriftarten und MSDF (Multi-Channel-Signed Distiled Fields).
Vom Drei-Bmfont-Text gegabelt.
Es enthält:
Um diese Funktionsweise zu erhalten, benötigen Sie einige bestimmte Dateien. Sie können sie mit MSDF-BMFONT-XML oder dem Online-Tool generieren. Sie können auch meine MSDF-FONT-FAKTORY überprüfen. Es enthält bereits einige Dateien, die Sie verwenden können, und ein Skript, um Ihre Dateien einfach zu generieren.
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 ) ;Optionen können ein Objekt oder eine Zeichenfolge sein - äquivalent zu {text: st}.
flipY (boolean): Ob die Textur Y-Floped (Standard True) wirdmultipage (Boolean): Ob diese Geometrie mit einem zusätzlichen Puffer mit Seiten -IDs erstellt werden soll. Dies ist für Multi-Textur-Schriftarten erforderlich (Standardfehler) font (erforderlich) Die BMFONT -Definition, die Zeichen, Kernungen usw. enthälttext (Zeichenfolge) Der Text zum Layout. Newline -Charaktere ( n) verursachen Zeilenpausenwidth (Nummer, optional) Die gewünschte Breite des Textfelds führt zu Wörtern und Ausschneiden im "Pre" -Modus. Lassen Sie sich als undefiniert lassen, um Word-Wrapping zu entfernen (Standardverhalten)mode (String) Ein Modus für Word-Wrapper; Kann "pre" sein (Abstand halten) oder "nowrap" (Kollaps-Weißespace, aber nur neue Zeilenzeichen brechen), ansonsten nimmt das normale Wortschreiberverhalten an (Kollabieren Sie die Whitespace, brechen Sie in Breite oder Neuleitungen)align (String) kann "links", "zentrum" oder "rechts" sein (Standard: links)letterSpacing (Nummer) Der Buchstabenabstand in Pixeln (Standard: 0)lineHeight (Nummer) Die Linienhöhe in Pixeln (Standard für font.common.lineHeight)tabSize (Nummer) Die Anzahl der Leerzeichen in einer einzigen Registerkarte (Standard 4)start (Nummer) den Startindex in den Text zum Layout (Standard 0)end (Nummer) Der Endindex (exklusiv) in den Text zum Layout (Standardtext.Length) update(options)Bauen Sie die Geometrie mit den angegebenen Optionen erneut auf. Alle hier nicht angegebenen Optionen werden standardmäßig im Konstruktor festgelegt. Diese Methode wird das Textlayout neu berechnen und die WebGL -Puffer wieder aufbauen. Optionen können ein Objekt oder eine Zeichenfolge sein - äquivalent zu {text: st}.
layoutTextlayout -Instanz können Sie verwenden, um auf Layout -Attribute zuzugreifen, wie z. B.:
Breite, Höhe, Nachkommen, Ascender, XHeight, Baseline, Capheight, LineHeight, Linestotal, Letterstotal
visibleGlyphs Ein gefilterter Satz von geometry.layout.glyphs , mit denen sich die von den zugrunde liegenden Bufferattributes verwendeten Scheitelpunktdaten ausrichten sollen.
Dies ist ein Array von { line, position, index, data } Objekten, siehe hier. Dies könnte beispielsweise verwendet werden, um eine neue Bufferattribute für line hinzuzufügen.
Neben den grundlegenden Geometrieattributen. Es gibt einige textspezifische Attribute, die meistens für Animationszwecke nützlich sind.
positionuv : UV -Koordinaten, mit der der richtige Buchstabe im rechten Buchstaben Quad zugeordnet istcenter : Mitte jedes BuchstabenquadslayoutUv : UV -Koordinaten des Volltextblocks.glyphUv : UV -Koordinaten jedes einzelnen Buchstabens Quad.glyphResolution : Auflösung jedes einzelnen Buchstabens Quad.lineIndex : Index jeder ZeilelineLettersTotal : Gesamtanzahl der Buchstaben in jedem ZeilenlineLetterIndex : Index jedes Buchstabens nach LinielineWordsTotal : Gesamtmenge der Wörter nach ZeilelineWordIndex : Index jedes Wortes für ZeilewordIndex : Index jedes WortesletterIndex : Index jedes BuchstabensEs erstreckt sich von drei.js Shadermaterialial
Sie können es nur verwenden, indem Sie die Atlas -Textur aus Ihrer Schrift einstellen:
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 ,
} ; Hinweis: IS_SMALL Boolean ist nützlich, um kleine Schriftarten zu rendern. Es wechselt die Alpha -Rendering -Berechnung, um sie visuell reibungsloser zu machen
Wenn Sie einige spezifische Texteffekte erstellen möchten, können Sie Ihren eigenen GLSL -Code in Ihrem Shader -Material basierend auf dem MSDFtextMaterial Shader erstellen.
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