ThreeJS:创建动画2d分段甜甜圈/戒指的最佳方法

时间:2013-12-21 19:20:49

标签: javascript three.js geometry

这是我用来制作带有可动画片段的甜甜圈的对象。有一种方法可以传递一个值数组来更新段,然后通过多次重新创建窗口小部件来“补间”到新值。

更新12/21

  

此方法导致内存泄漏/垃圾回收问题。是否有更高效/更有效的方法来实现这一目标?

内存泄漏是一个已经解决的单独问题。这篇文章主要是为了找到一种更有效的方法来为这个网格生成和动画几何体。

donut = function(values, inner_radius, outer_radius) {

    var _inner_radius = inner_radius;
    var _outer_radius = outer_radius;
    var _cur_angle = 0.0;
    var _sector_spacing = (Math.PI * 2) / 150.0;   
    var _container = 0;
    var _cur_values = values.slice(0);
    var _animation_speed = 0.85;

    createWidget(_cur_values);

    function createWidget(values) {

        if ( _container != 0 ) {
            var geometry_for_deletion = [];

            _container.traverse(function (node) {

                if (node instanceof THREE.Mesh) {
                    geometry_for_deletion.push(node);
                }
            });

            for (var each = 0; each < geometry_for_deletion.length; ++each) {
                geometry_for_deletion[each].parent.remove(geometry_for_deletion[each]);
            }

            geometry_for_deletion = null;
        }
        else {
            _container = new THREE.Object3D();
            _container.name = 'wedge_container';
        }

        var total_value = 0;
        for (var i = 0; i < values.length; ++i) {
            total_value += values[i];
        };

        for (var i = 0; i < values.length; ++i) {

            var angle_1 = _cur_angle;
            var angle_2 = _cur_angle + (values[i] / total_value) *
                                ( Math.PI * 2 - ( values.length ) * _sector_spacing );

            var mesh = createSegment(i,angle_1, angle_2, _inner_radius, outer_radius);
            _container.add(mesh);

            _cur_angle = angle_2 + _sector_spacing;
        }

        scene.add(_container);
    }


    function createSegment(i,begin_angle, end_angle, _inner_radius, outer_radius) {

        var sector_pts = [];

        var num_verts_per_arc = 16;

        for (var j = 0; j < num_verts_per_arc; ++j) {
            var a = begin_angle + (j / (num_verts_per_arc - 1)) * (end_angle - begin_angle);
            var x = outer_radius * Math.cos(a);
            var y = outer_radius * Math.sin(a);
            sector_pts.push(new THREE.Vector2(x, y));
        }

        for (var j = 0; j < num_verts_per_arc; ++j) {
            var a = end_angle - (j / (num_verts_per_arc - 1)) * (end_angle - begin_angle);
            var x = _inner_radius * Math.cos(a);
            var y = _inner_radius * Math.sin(a);
            sector_pts.push(new THREE.Vector2(x, y));
        }

        var sector_shape = new THREE.Shape(sector_pts);

        var geometry = new THREE.ShapeGeometry(sector_shape); //, { material: i });
            geometry.name = 'wedge';

        var material = new THREE.MeshBasicMaterial({
            color: color,
            overdraw: true
        });

        var segment_mesh = new THREE.Mesh(geometry, material );

        return segment_mesh;
    }

    this.getParent = function() {
        return _container;
    }

    this.updateValues = function(new_values) {

        if ( new_values.length != values.length ) {
            console.error("Different number of values in update not allowed");
            return;
        }

        var tween_values = _cur_values.slice(0);

        TweenMax.to(
            { val: 0 },
            _animation_speed,
            { 
                val: 1,
                ease: Power3.easeOut,
                onUpdate: function(that,tween_values,_cur_values,new_values) {

                    for(var i=0; i < tween_values.length;++i) {
                        tween_values[i] = _cur_values[i] + ( new_values[i] - _cur_values[i] ) * that.target.val;
                    }

                    createWidget(tween_values);
                },
                onUpdateParams: ["{self}",tween_values,_cur_values,new_values],
                onComplete: function(tween_values,_cur_values) {
                    _cur_values = tween_values.slice(0);
                },
                onCompleteParams: [tween_values,_cur_values]
            }
        );
    }
};

用法如下:

var mydonut1 = new donut( [20,20,20,20,20], 75, 100 );
mydonut1.updateValues( [30,10,40,10,10] );

var mydonut2 = new donut( [20,20,20,20,20], 75, 100 );
mydonut2.updateValues( [30,10,40,10,10] );

0 个答案:

没有答案