คลาสยูทิลิตี้สำหรับการเรนเดอร์ข้อความในสาม.JSโดยใช้แบบอักษรบิตแมปและ MSDF (ฟิลด์ระยะทางที่ลงนามหลายช่องทาง)
ฟอร์คจากข้อความสาม-bmfont
มันรวมถึง:
ในการทำงานนี้คุณจะต้องใช้ไฟล์เฉพาะบางไฟล์คุณสามารถสร้างไฟล์เหล่านั้นด้วย MSDF-BMFONT-XML หรือด้วยเครื่องมือออนไลน์ นอกจากนี้คุณยังสามารถตรวจสอบโรงงาน MSDF-Font ของฉันมีไฟล์บางไฟล์ที่คุณสามารถใช้และสคริปต์เพื่อสร้างไฟล์ของคุณได้อย่างง่ายดาย
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 (Boolean): พื้นผิวจะถูกลิ้มลอง (ค่าเริ่มต้นจริง)multipage (Boolean): ไม่ว่าจะสร้างรูปทรงเรขาคณิตนี้ด้วยบัฟเฟอร์พิเศษที่มี ID หน้าหรือไม่ สิ่งนี้จำเป็นสำหรับแบบอักษรหลายพื้นผิว (ค่าเริ่มต้นที่ผิดพลาด) font (จำเป็น) คำจำกัดความ BMFONT ซึ่งถือ chars, kernings ฯลฯtext (สตริง) ข้อความเป็นเค้าโครง อักขระใหม่ ( n) จะทำให้บรรทัดแตกwidth (หมายเลข, เสริม) ความกว้างที่ต้องการของกล่องข้อความทำให้เกิดการห่อคำและการตัดในโหมด "pre" ปล่อยให้ไม่ได้กำหนดเพื่อลบการห่อคำ (พฤติกรรมเริ่มต้น)mode (String) โหมดสำหรับคำ Word-wrapper; สามารถเป็น 'pre' (รักษาระยะห่าง) หรือ 'NowRap' (ล่มสลายช่องว่าง แต่จะทำลายตัวอักษรใหม่เท่านั้น) มิฉะนั้นจะถือว่าพฤติกรรมการห่อคำปกติalign (สตริง) สามารถเป็น "ซ้าย", "กึ่งกลาง" หรือ "ขวา" (ค่าเริ่มต้น: ซ้าย)letterSpacing (หมายเลข) ระยะห่างของตัวอักษรในพิกเซล (ค่าเริ่มต้น: 0)lineHeight (หมายเลข) ความสูงของบรรทัดเป็นพิกเซล (ค่าเริ่มต้นเป็น font.common.lineHeight)tabSize (หมายเลข) จำนวนช่องว่างที่ใช้ในแท็บเดียว (ค่าเริ่มต้น 4)start (หมายเลข) ดัชนีเริ่มต้นลงในข้อความเป็นเค้าโครง (ค่าเริ่มต้น 0)end (หมายเลข) ดัชนีการสิ้นสุด (พิเศษ) ลงในข้อความเป็นเค้าโครง (text -text.length) update(options)สร้างเรขาคณิตอีกครั้งโดยใช้ตัวเลือกที่กำหนด ตัวเลือกใด ๆ ที่ไม่ได้ระบุไว้ที่นี่จะเป็นค่าเริ่มต้นสำหรับตัวที่ตั้งไว้ในตัวสร้าง วิธีนี้จะคำนวณเค้าโครงข้อความอีกครั้งและสร้างบัฟเฟอร์ WebGL ใหม่ ตัวเลือกสามารถเป็นวัตถุหรือสตริง - เทียบเท่ากับ {text: str}
layoutอินสแตนซ์การจัดวางข้อความคุณสามารถใช้เพื่อเข้าถึงแอตทริบิวต์เลย์เอาต์เช่น:
ความกว้าง, ความสูง, descender, Ascender, xheight, baseline, capheight, lineheight, linestotal, letterstotal
visibleGlyphs ชุดที่กรองจาก geometry.layout.glyphs ตั้งใจที่จะจัดแนวกับข้อมูลจุดสุดยอดที่ใช้โดย bufferattributes พื้นฐาน
นี่คืออาร์เรย์ของ { line, position, index, data } วัตถุดูที่นี่ ตัวอย่างเช่นสิ่งนี้สามารถใช้เพื่อเพิ่ม bufferAttribute ใหม่สำหรับการชดเชย line
นอกจากคุณลักษณะเรขาคณิตพื้นฐาน มีแอตทริบิวต์เฉพาะข้อความส่วนใหญ่มีประโยชน์สำหรับวัตถุประสงค์ในการเคลื่อนไหว
positionuv : พิกัด UV ที่ใช้ในการแมปจดหมายที่ถูกต้องในจดหมายที่ถูกต้องcenter : จุดศูนย์กลางของแต่ละตัวอักษร QuadlayoutUv : พิกัด UV ของบล็อกข้อความเต็มglyphUv : พิกัด UV ของแต่ละตัวอักษรแต่ละตัวglyphResolution : ความละเอียดของตัวอักษรแต่ละตัวlineIndex : ดัชนีของแต่ละบรรทัดlineLettersTotal : จำนวนตัวอักษรทั้งหมดในแต่ละบรรทัดlineLetterIndex : ดัชนีของตัวอักษรแต่ละตัวทีละตัวlineWordsTotal : จำนวนคำทั้งหมดตามบรรทัดlineWordIndex : ดัชนีของแต่ละคำต่อบรรทัดwordIndex : ดัชนีของแต่ละคำletterIndex : ดัชนีของตัวอักษรแต่ละตัวมันขยายจากสาม 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 มีประโยชน์ในการแสดงแบบอักษรขนาดเล็กมันจะเปลี่ยนการคำนวณการเรนเดอร์อัลฟ่าเพื่อให้พวกเขามองเห็นได้ราบรื่นขึ้นมาก
หากคุณต้องการสร้างเอฟเฟกต์ข้อความที่เฉพาะเจาะจงคุณสามารถสร้างรหัส GLSL ของคุณเองในวัสดุ shader ของคุณตาม msdftextmaterial shader
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