我目前正在开发一个使用三个 js 创建 Web 组件的项目。为了做到这一点,我必须为不同的组件创建对象。 我在创建以文本为属性的对象时遇到几个问题。 我想在 THREE.Group() 对象中添加文本网格,以便在需要添加修改时更易于访问和使用。
var Button = {
init : function(text, textSize, textFont, textMaterial, other attributes ...) {
this._geo = new THREE.Group();
this.createTextDesign(text, textSize, textFont, textMaterial);
this._textMesh = this.createText()
this._geo.add(this._textMesh);
...
},
createTextDesign : function() {
this._text = text;
this._textMaterial = textMaterial;
this._textFont = textfont;
if (textSize == "lg") {
this._textSize = 2.5;
} else if (textSize == "sm"){
this._textSize = 1.5;
} else if (textSize == "xs"){
this._textSize = 1;
} else {
this._textSize = 2;
},
createText : function(){
var text = null;
var fontLoader = new THREE.FontLoader();
fontLoader.load('fonts/' + this._textFont + '.typeface.json', function(font) {
var textGeometry = new THREE.TextGeometry(this._text, {
font: font,
size: this._textSize,
height: this._textSize
});
fontLoader.load();
text = new THREE.Mesh(textGeometry, this._textMaterial);
});
return text;
},
getGroup : function(){
return this._geo;
},
...
};
问题是,当我尝试使用以下通用代码实例化该对象时(实例化+显示对象):
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js - ASCII Effect</title>
<meta charset="utf-8">
<style>
body {
font-family: Monospace;
background-color: #f0f0f0;
margin: 0px;
overflow: hidden;
}
</style>
</head>
<body>
<script src="js/build/three.js"></script>
<script src="components/Button.js"></script>
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var mat2 = new THREE.MeshBasicMaterial( {color: 0xff0000} );
var mat3 = new THREE.MeshBasicMaterial( {color: 0x00ff00} );
var mat4 = new THREE.MeshBasicMaterial( {color: 0x0000ff} );
var button = Object.create(Button);
button.init("test", "lg", "optimer_regular", mat2, mat3, mat4);
scene.add(button.getGroup());
camera.position.z = 50;
var render = function () {
requestAnimationFrame( render );
renderer.render(scene, camera);
};
render();
</script>
</body>
</html>
我收到以下错误:
THREE.Object3D.add: object not an instance of THREE.Object3D. nullthree.js:10826:5
.add() three.js:10826
Button.init() Button.js:10
<anonymous> test4.html:31
button.js:10 是我将 this._textMesh 添加到 this._geo 的行。
我还尝试了不同的技术来创建文本网格,而不使用 textLoader(例如: http://blog.andrewray.me/creating-a-3d-font-in-three-js/ ),但文本不显示,并且控制台中没有任何错误消息...
有人知道如何解决这个问题吗? 预先感谢您的帮助!
最佳答案
抛出错误只是因为您实际上没有返回网格,而是从 createText()
方法返回 null
。
代码的简化版本如下所示:
function createText() {
var text = null;
fontLoader.load(fontUrl, function(font) {
text = createTextMesh(font);
})
return text;
}
现在,您需要了解 javascript 中的异步函数是如何工作的。在此示例中,当您调用 createText()
时,会发生三件事:
- 变量
text
初始化为null
- 加载字体的请求已开始
- 返回
text
的值(此时始终为null
)。
这是为什么呢? HTTP 请求需要很长时间(就代码的速度而言)才能最终返回结果。因此,在返回值很长时间后,会调用接收加载字体的回调函数。然后它仍然创建网格,但结果不再使用,因为返回已经发生。
有一些选项可以解决此问题,但无论如何,您都需要等到字体加载后才能将对象添加到组中。
你可以这样尝试:
function addTextMesh(parent) {
fontLoader.load(fontUrl, function(font) {
parent.add(createTextMesh(font));
})
}
或者您确保在发生任何情况之前字体已经加载。
还有一点:我不知道你的用例,但是如果你需要渲染大量文本,使用文本网格可能会浪费资源(因为涉及大量的顶点和计算)渲染它们)。
看看其他渲染文本的替代方案可能是个好主意:
- 将文本渲染到 Canvas 并将其用作纹理
- 使用位图字体之类的东西:https://github.com/Jam3/three-bmfont-text
关于javascript - 文本几何作为对象属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40531559/