Textgeometry作为对象属性

时间:2016-11-10 15:45:09

标签: javascript three.js

我目前正在开发一个项目来创建包含三个js的Web组件。为此,我必须为不同的组件创建对象。 我有几个问题来创建具有text作为属性的对象。 我想在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/),但文本没有显示,我在控制台中没有任何错误消息...

有人知道如何解决这个问题吗? 在此先感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

抛出错误只是因为您实际上没有返回网格,而是从null - 方法返回createText()

您的代码的简化版本如下所示:

function createText() {
  var text = null;

  fontLoader.load(fontUrl, function(font) {
    text = createTextMesh(font);
  })

  return text;
}

现在,您需要了解javascript中的异步函数是如何工作的。在此示例中,当您致电createText()时会发生三件事:

  1. 变量text初始化为null
  2. 加载字体的请求是已启动
  3. 返回text(此时始终为null)的值。
  4. 为什么? HTTP-Request采用(就代码的速度而言)年龄,最终返回结果。因此,在已经返回值之后很长一段时间内调用接收加载字体的回调函数。它仍然会创建网格,但结果不再使用,因为返回已经发生。

    有一些选项可以解决这个问题,但无论如何,在将对象添加到组之前,您需要等到字体加载完毕。

    你可以这样试试:

    function addTextMesh(parent) {
      fontLoader.load(fontUrl, function(font) {
        parent.add(createTextMesh(font));
      })
    }
    

    或者你确定在发生任何变化之前已经加载了字体。

    还有一点需要注意:我不知道你的用例,但如果你需要渲染大量的文本,使用文本网格可能会浪费资源(因为涉及大量的顶点和计算在渲染它们)。

    查看渲染文本的其他替代方案可能是个好主意: