支持 Three.js 中的 Farsi/Arabic 文本
Support for Farsi/Arabic texts in Three.js
我需要用 Persian/Arabic 语言显示一些文本。我加载了一个包含字符的字体,并使用 TextGeometry 在场景中创建了一个文本:
var loader = new THREE.FontLoader();
loader.load('B Zar_Regular.js', function (font) {
var textGeo = new THREE.TextGeometry('سلام!', {
font: font,
size: 1,
height: 0.05,
curveSegments: 12,
});
var material = new THREE.MeshNormalMaterial();
var textMesh = new THREE.Mesh(textGeo, material);
textMesh.position.x = 15;
scene.add(textMesh);
});
我期待看到 سلام!
但输出是:
字母分开,字符顺序错误颠倒。毕竟 threejs 似乎不支持 rtl 语言。我是对的还是我错过了什么?是否有任何解决方法作为快速解决方案?谢谢。
这是一个复杂的问题。连字是连接字母的书法笔画,西方读者最熟悉的是草书英语的一个组成部分,但在阿拉伯语中不是可选的。连字是语言固有的,它改变了文本的含义和形式。 font.js class is designed to take each letter (glyph) one by one and convert it to a shape path. This doesn't work in Arabic because joining rules are complex 取决于特定的字母组合。
我认为 three.js 中没有可以实施的修复程序。尽管我很想知道 O.P 提到的潜在解决方案是什么。
可以将孤立的字母转换为最终的阿拉伯语连字形式 via this script, or maybe this one 等等。然后可能会将最终的表示形式发送到 Three.js 进行显示,以便已经处理连字连接并且 three.js 接收最终的连字形式而不是孤立的字形。
使用 text to path converter 将文本转换为 svg 路径然后使用 three.js 中的 SVGLoader.js 加载字母作为挤压路径可能是一项更简单的任务。但这必须进行测试以确保文本到路径的转换完全可以处理阿拉伯语,然后如果可以,则还需要检查连字连接的准确性。
首先我发现非常有用的博客 post here by Chris Loer. He has written a plugin (mapbox-gl-rtl-text.js) 解决了这个问题。
用法示例:
var rtlText = require('mapbox-gl-rtl-text');
var arabicString = "سلام";
var shapedArabicText = rtlText.applyArabicShaping(arabicString);
var readyForDisplay = rtlText.processBidirectionalText(shapedArabicText, []);
PS: 当我将这个插件与常见的波斯语字体一起使用时,一些字母没有显示,所以我添加了一些 extra code 来修复它。
RtlTextHelper.farsify("سلام");
用法示例:
private createTextMesh(font, text) {
var shapedText = RtlTextHelper.farsify(text);
var fontSize = 0.3;
var textHieght = 0.2;
var material = new THREE.MeshBasicMaterial({
color: this.colors.label.normal,
side: THREE.DoubleSide
});
var textGeo = new THREE.TextGeometry(shapedText, {
font: font,
size: fontSize,
height: 0.05,
curveSegments: 12
});
var textMesh = new THREE.Mesh(textGeo, material);
textGeo.computeBoundingBox();
var box = new THREE.Box3().setFromObject(textMesh);
var textLength = box.max.x;
return {
mesh: textMesh,
hieght: textHieght,
font: {
size: fontSize
},
length: textLength
};
}
我需要用 Persian/Arabic 语言显示一些文本。我加载了一个包含字符的字体,并使用 TextGeometry 在场景中创建了一个文本:
var loader = new THREE.FontLoader();
loader.load('B Zar_Regular.js', function (font) {
var textGeo = new THREE.TextGeometry('سلام!', {
font: font,
size: 1,
height: 0.05,
curveSegments: 12,
});
var material = new THREE.MeshNormalMaterial();
var textMesh = new THREE.Mesh(textGeo, material);
textMesh.position.x = 15;
scene.add(textMesh);
});
我期待看到 سلام!
但输出是:
字母分开,字符顺序错误颠倒。毕竟 threejs 似乎不支持 rtl 语言。我是对的还是我错过了什么?是否有任何解决方法作为快速解决方案?谢谢。
这是一个复杂的问题。连字是连接字母的书法笔画,西方读者最熟悉的是草书英语的一个组成部分,但在阿拉伯语中不是可选的。连字是语言固有的,它改变了文本的含义和形式。 font.js class is designed to take each letter (glyph) one by one and convert it to a shape path. This doesn't work in Arabic because joining rules are complex 取决于特定的字母组合。
我认为 three.js 中没有可以实施的修复程序。尽管我很想知道 O.P 提到的潜在解决方案是什么。
可以将孤立的字母转换为最终的阿拉伯语连字形式 via this script, or maybe this one 等等。然后可能会将最终的表示形式发送到 Three.js 进行显示,以便已经处理连字连接并且 three.js 接收最终的连字形式而不是孤立的字形。
使用 text to path converter 将文本转换为 svg 路径然后使用 three.js 中的 SVGLoader.js 加载字母作为挤压路径可能是一项更简单的任务。但这必须进行测试以确保文本到路径的转换完全可以处理阿拉伯语,然后如果可以,则还需要检查连字连接的准确性。
首先我发现非常有用的博客 post here by Chris Loer. He has written a plugin (mapbox-gl-rtl-text.js) 解决了这个问题。
用法示例:
var rtlText = require('mapbox-gl-rtl-text');
var arabicString = "سلام";
var shapedArabicText = rtlText.applyArabicShaping(arabicString);
var readyForDisplay = rtlText.processBidirectionalText(shapedArabicText, []);
PS: 当我将这个插件与常见的波斯语字体一起使用时,一些字母没有显示,所以我添加了一些 extra code 来修复它。
RtlTextHelper.farsify("سلام");
用法示例:
private createTextMesh(font, text) {
var shapedText = RtlTextHelper.farsify(text);
var fontSize = 0.3;
var textHieght = 0.2;
var material = new THREE.MeshBasicMaterial({
color: this.colors.label.normal,
side: THREE.DoubleSide
});
var textGeo = new THREE.TextGeometry(shapedText, {
font: font,
size: fontSize,
height: 0.05,
curveSegments: 12
});
var textMesh = new THREE.Mesh(textGeo, material);
textGeo.computeBoundingBox();
var box = new THREE.Box3().setFromObject(textMesh);
var textLength = box.max.x;
return {
mesh: textMesh,
hieght: textHieght,
font: {
size: fontSize
},
length: textLength
};
}