비트 맵 글꼴과 MSDF (다 채널 사인 된 거리 필드)를 사용하여 3.js의 텍스트 렌더링을위한 유틸리티 클래스.
3 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 ) ;옵션은 객체 또는 문자열 - {text : str}에 해당 할 수 있습니다.
flipY (부울) : 텍스처가 yfliped 될지 여부 (기본값)multipage (부울) : 페이지 ID가 포함 된 추가 버퍼 로이 지오메트리를 구성할지 여부. 이것은 다중 텍스트 글꼴 (기본 거짓)에 필요합니다. font (필수) Chars, Kernings 등을 담은 BMFONT 정의text (문자열) 텍스트에 대한 텍스트. Newline 문자 ( n)는 라인이 파손됩니다width (숫자, 선택 사항) 텍스트 상자의 원하는 너비는 "사전"모드에서 단어 포장 및 클리핑을 유발합니다. 단어 포장을 제거하기 위해 정의되지 않은 상태로 남겨 둡니다 (기본 동작)mode (문자열) Word-Wrapper의 모드; '사전'(간격 유지) 또는 'nowrap'(whitespace를 붕괴 시키지만 Newline 문자에서만 끊어짐) 일 수 있습니다. 그렇지 않으면 정상적인 워드 랩 동작 (붕괴, 공백, 너비 또는 최신 라인의 파손)을 가정합니다.align (문자열)은 "왼쪽", "센터"또는 "오른쪽"(기본값 : 왼쪽) 일 수 있습니다.letterSpacing (번호) 픽셀로 문자 간격 (기본값 : 0)lineHeight (번호) 픽셀의 선 높이 (font.common.lineHeight에서 기본값)tabSize (번호) 단일 탭에서 사용할 공간 수 (기본값 4)start (번호) 텍스트로의 시작 인덱스를 레이아웃으로 (기본값 0)end (숫자) 종료 인덱스 (독점) 텍스트로 레이아웃 (기본 텍스트) update(options)주어진 옵션을 사용하여 지오메트리를 다시 작성합니다. 여기에 지정되지 않은 옵션은 생성자에 설정된 옵션에 기본값이됩니다. 이 메소드는 텍스트 레이아웃을 다시 작성하고 WebGL 버퍼를 재구성합니다. 옵션은 객체 또는 문자열 - {text : str}에 해당 할 수 있습니다.
layout텍스트 레이아웃 인스턴스,이를 사용하여 레이아웃 속성에 액세스 할 수 있습니다.
너비, 높이, 하강, Ascender, Xheight, 기준선, Capheight, LineHeight, Linestotal, Letterstotal
visibleGlyphs geometry.layout.glyphs 의 필터링 된 세트. 기본 버퍼 율 트리 부스에서 사용되는 정점 데이터와 정렬되었습니다.
이것은 { line, position, index, data } 개체의 배열입니다. 여기를 참조하십시오. 예를 들어, 이것은 line 오프셋에 대한 새로운 버퍼 attribute를 추가하는 데 사용될 수 있습니다.
기본 지오메트리 속성 외에. 일부 텍스트 별 속성이 있으며, 주로 애니메이션 목적에 유용합니다.
positionuv : 오른쪽 문자 쿼드에서 오른쪽 문자를 매핑하는 데 사용되는 UV 좌표center : 각 문자 쿼드의 중심layoutUv : 전체 텍스트 블록의 UV 좌표.glyphUv : 각 개별 문자 쿼드의 UV 좌표.glyphResolution : 각 개별 문자 쿼드의 해상도.lineIndex : 각 라인의 색인lineLettersTotal : 각 줄의 총 문자 양lineLetterIndex : 각 문자의 인덱스별로lineWordsTotal : 라인 별 총 단어량lineWordIndex : 각 단어의 인덱스별로wordIndex : 각 단어의 색인letterIndex : 각 문자의 색인Three.js Shadermaterial에서 연장됩니다
글꼴에서 아틀라스 텍스처를 설정하면 사용할 수 있습니다.
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 Shader를 기반으로 셰이더 자료에 고유 한 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