如何在 three.js 中仅绘制下降一半的样条曲线

how to draw only falling half of spline in three.js

我可以通过指定三个坐标在 three.js 中绘制样条曲线,即开始、中间和结束。这样做时,曲线从 'start' 的坐标开始,一直上升到中间,然后下降到 'end' 的坐标。这是相同的jsbin

不过,我现在只想画样条曲线下降的一半,也就是从'mid'到'end'的部分。

这是传统样条。

但是,我只想得到下落的一半,如下图,但又想适应场景。

编辑:添加下面的代码

<html>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r75/three.js"></script>

<script>
    // global variables
    var renderer;
    var scene;
    var camera;
    var geometry;

    var control;

    var count = 0;
    var animationTracker;

    init();
    drawSpline();

    function init()
    {
        // create a scene, that will hold all our elements such as objects, cameras and lights.
        scene = new THREE.Scene();

        // create a camera, which defines where we're looking at.
        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

        // create a render, sets the background color and the size
        renderer = new THREE.WebGLRenderer();
        renderer.setClearColor(0x000000, 1.0);
        renderer.setSize(window.innerWidth, window.innerHeight);

        // position and point the camera to the center of the scene
        camera.position.x = 0;
        camera.position.y = 40;
        camera.position.z = 40;
        camera.lookAt(scene.position);

        // add the output of the renderer to the html element
        document.body.appendChild(renderer.domElement);
    }

    function drawSpline(numPoints)
    {
        var numPoints = 100;
//        var start = new THREE.Vector3(-5, 0, 20);
        var start = new THREE.Vector3(-5, 0, 20);
        var middle = new THREE.Vector3(0, 35, 0);
        var end = new THREE.Vector3(5, 0, -20);

        var curveQuad = new THREE.QuadraticBezierCurve3(start, middle, end);

        var tube = new THREE.TubeGeometry(curveQuad, numPoints, 0.5, 20, false);
        var mesh = new THREE.Mesh(tube, new THREE.MeshNormalMaterial({
            opacity: 0.9,
            transparent: true
        }));

        scene.add(mesh);
        renderer.render(scene, camera);
    }
</script>
</body>
</html>

我提到过只想要 'fit the scene' 的下落部分。我的意思是,只是下降部分应该占据与整个图像现在占据的一样多 space。否则,如果要 trim 只从样条曲线中 'mid' 之后的顶点,那么样条曲线的部分将非常小,就像下面的第二张图(使用油漆裁剪掉的) .

我在下面展示了一种绘制 3d 二次贝塞尔曲线的一半(或任何比例)的方法。数学基于 DeCasteljau 的算法(如果我理解正确的话)。数学显示在我包含在代码中的额外函数中,即 splitQuadraticBezierCurvegetPointAtT。 THREE.js 有一些功能类似于 getPointAtT,特别是 getPoint,还有一个 getTangent 功能。但是,我还不太清楚如何使用 getTangent,所以我最终只是自己实现了数学运算。反正也没那么难。

下图可以更好地理解分割曲线的基本原理:

v代表矢量(或点),v0v1v2是从你的初始二次曲线中检索出来的,是你原来的startmiddleend 点。 v01v12 是沿指示线的距离 t(在您的情况下为 0.5),v012 是 [=24= 之间的距离 t ] 和 v12。函数 returns 一个双元素数组,具有原始二次曲线的第一个(元素 0)和第二个(元素 1)'halves'。第一条'half'曲线的起点、中点和终点分别是v0v01v012。第二条 'half' 曲线的起点、中点和终点是 v012v12v2

代码为第二条 'half' 曲线生成以下图像:

此图片是手动裁剪的。将形状设置为 "fill" 屏幕是手动完成的。要以编程方式执行此操作 "filling" 取决于您有兴趣更改 and/or 愿意 and/or 能够更改的内容:相机的位置?相机的角度?相机的视野?物体的位置?视图 width/height/proportions?因此,我没有在这里解决这个问题。但是,我希望这个答案至少能告诉您如何拆分二次贝塞尔曲线。

// global variables
var renderer;
var scene;
var camera;
var geometry;

var control;

var count = 0;
var animationTracker;

init();
drawSpline();

function init()
{
    // create a scene, that will hold all our elements such as objects, cameras and lights.
    scene = new THREE.Scene();

    // create a camera, which defines where we're looking at.
    camera = new THREE.PerspectiveCamera(20, window.innerWidth / window.innerHeight, 0.1, 1000);

    // create a render, sets the background color and the size
    renderer = new THREE.WebGLRenderer();
    renderer.setClearColor(0x000000, 1.0);
    renderer.setSize(window.innerWidth, window.innerHeight);

    // position and point the camera to the center of the scene
    camera.position.set(0, 40, 40);
    camera.lookAt(new THREE.Vector3(0, 15, 0));

    // add the output of the renderer to the html element
    document.body.appendChild(renderer.domElement);
}

function getPointAtT(vA, vB, t) {
    return new THREE.Vector3(
        vA.x + (vB.x - vA.x) * t,
        vA.y + (vB.y - vA.y) * t,
        vA.z + (vB.z - vA.z) * t
    );
}

function splitQuadraticBezierCurve(quad, t) {
    var v0   = quad.v0;
    var v1   = quad.v1;
    var v2   = quad.v2;
    var v01  = getPointAtT(v0,  v1,  t);
    var v12  = getPointAtT(v1,  v2,  t);
    var v012 = getPointAtT(v01, v12, t);
    var firstHalf  = new THREE.QuadraticBezierCurve3(v0,   v01, v012);
    var secondHalf = new THREE.QuadraticBezierCurve3(v012, v12, v2  );
    return [firstHalf, secondHalf];
}

function drawSpline()
{
    var numPoints = 100;
    var start = new THREE.Vector3(-5, 0, 20);
    var middle = new THREE.Vector3(0, 30, 0);
    var end = new THREE.Vector3(5, 0, -20);

    var curveQuad = new THREE.QuadraticBezierCurve3(start, middle, end);
    var FIRST_HALF = 0;
    var SECOND_HALF = 1;
    var curveProportion = 0.5;
    var secondHalfCurveQuad = splitQuadraticBezierCurve(curveQuad, curveProportion)[SECOND_HALF];
    var tube = new THREE.TubeGeometry(secondHalfCurveQuad, numPoints, 0.5, 20, false);
    var mesh = new THREE.Mesh(tube, new THREE.MeshNormalMaterial({
        opacity: 0.9,
        transparent: true
    }));

    scene.add(mesh);
    renderer.render(scene, camera);
}