自定义THREE.Curve.create显示不正确

时间:2014-08-01 16:49:11

标签: javascript three.js

根据this answer的建议,我创建了一个线性插值曲线,如下所示:

THREE.Linear3 = THREE.Curve.create(

  function ( points, label /* array of Vector3 */) {

    this.points = (points == undefined) ? [] : points;
    this.label = label;

  },

  function ( t ) {    
    var v = new THREE.Vector3();
    var c = [];
    var points = this.points, point, intPoint, weight;
    point = ( points.length - 1 ) * t;

    intPoint = Math.floor( point );
    weight = point - intPoint;

    c[ 1 ] = intPoint;
    c[ 2 ] = intPoint  > points.length - 2 ? points.length - 1 : intPoint + 1;

    var pt1 = points[ c[1] ],
      pt2 = points[ c[2] ];

    v.copy( pt1 ).lerp( pt2, weight );

    return v;

  }

);

然而,当我试图以不同的长度(以动画的方式)显示轨迹时,我得到以下行为,即不是通过点的曲线,它有点穿过空间,注意在下面的例子中,每个轨迹应该通过每个球体的坐标(下面的动画gif):

Imgur

我不确定我是否了解getPoint函数或它应该返回什么。非常感谢任何帮助。

的jsfiddle

这是一个最小的例子,但你可以看到当管扩展时右角有一个不平稳的动作。

http://jsfiddle.net/ElDeveloper/3uyf3sq3/1/

1 个答案:

答案 0 :(得分:2)

清理一些代码

这帮助我调查了这个问题。

  • 您正在泄漏几何图形,需要在从场景中删除网格后处理几何图形

    scene.remove(c_mesh)
    c_tube && c_tube.dispose();
    
  • 使用WebGLRenderer。 CanvasRenderer leaks removed objects,您在每个帧上创建新对象。 (如果您出于某种原因困扰CanvasRenderer,对不起你)

  • (对于小提琴)减慢动作,requestAnimationFrame不是测试所必需的,setTimeout(animate, 500);允许用户查看发生了什么。

  • 0段管的重点是什么?

    if (index >= points.length - 1){
        index = 1; //start with 2 points
    }
    

按预期工作

  • TubeGeometry执行N管(构造函数中的第二个参数,小提琴中的16个)段。 (我稍后会再回过头来看,但我认为你总是不想要16段)

  • Curve.getPoinAt(TubeGeometry使用的方法以及可能是许多其他几何)的默认行为是返回等距点。您可以预期:distance(getPointAt(0),getPointAt(0.1)) == distance(getPointAt(0.1),getPointAt(0.2))为真。

  • 由于这些要点,无论您在路径中放置多少个点,TubeGeometry都会构建一个16段的管,所有段的长度相同,从路径的第一个点到最后一个点。 15个中间点中的一个几乎不可能完全位于边缘位置。这应该可以解释你所看到的内容。

尝试修复这些东西

  • 首先摆脱TubeGeometry + Path的等距方式。重载getUtoTmapping应该足够了(我发现阅读源代码):

    THREE.Linear3.prototype.getUtoTmapping = function(u) {
        return u;
    };
    
  • 我更改了您的getPoint。它可能做同样的事情,但我对我的代码调查更为舒服

    function ( t ) {    
        var points = this.points;
        var index = ( points.length - 1 ) * t;
        var floorIndex = Math.floor(index);
        if(floorIndex == points.length-1)
            return points[floorIndex];
        var floorPoint = points[floorIndex];
        var ceilPoint = points[floorIndex+1];
        return floorPoint.clone().lerp(ceilPoint, index - floorIndex);
    }
    
  • 为TubeGeometry构造函数提供正确数量的段:

    var pathPoints = points.slice(0, index);
    c_path = new THREE.Linear3(pathPoints, 'Test');
    c_tube = new THREE.TubeGeometry(c_path, pathPoints.length-1, 10, 16, false, true);
    

    此时,你应该大致有你所期待的

  • 你应该看到管子总是穿过边缘。您还应该看到TubeGeometry并不意味着有角度。你可以通过查看TubeGeometry和Curve如何处理切线来改善这个角度问题,或者(如果你不关心慢度)通过将段数增加到一个非常大的数字来改善这个角度问题:

    c_tube = new THREE.TubeGeometry(c_path, 200/*pathPoints.length-1*/, 10, 16, false, true);
    

这都是答案。您可以在此处找到我的实验的最新版本:http://jsfiddle.net/dqn73m98/5/。您也可以询问three.js开发人员是否存在这样的功能,或者在github问题中请求实现(如果某人有时间),here