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

时间:2016-04-04 22:34:31

标签: javascript three.js spline

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

但是,我现在只想绘制样条的下半部分,即仅从'mid'到'end'的部分。

这是传统的样条线。 enter image description here

然而,我想只得到下面的一半,但是想要适合现场。 enter image description here

编辑:添加以下代码

<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>

我提到过只想要掉落部分来“适应场景”。我的意思是,只有下降部分应该占据整个图像占据的空间。否则,如果仅从样条曲线的'mid'之后修剪掉顶点,那么样条曲线的部分将非常小,就像在下面的第二张图片中一样(使用绘画裁剪掉)。

1 个答案:

答案 0 :(得分:1)

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

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

enter image description here

v代表向量(或点),v0v1v2是从您的初始二次曲线中检索到的,并且是您的原始start },middleend点。 v01v12沿指示的行距离为t(在您的情况下为0.5),而v012t之间的距离v01 }和v12。该函数返回一个2元素数组,其中原始二次曲线的第一个(元素0)和第二个(元素1)“一半”。第一个“半”曲线的起点,中点和终点为v0v01&amp; v012。第二个“半”曲线的起点,中点和终点为v012v12&amp; v2

代码为第二个“半”曲线生成以下图像:

enter image description here

手动裁剪此图像。获得形状“填充”屏幕是手动完成的。要以编程方式执行“填充”取决于您对更改和/或愿意和/或能够更改感兴趣的内容:相机的位置?相机的角度?相机的视野?对象的位置?视图宽度/高度/比例?因此,我在这里没有提到这一点。但是,我希望这个答案至少能告诉你如何分割二次贝塞尔曲线。

// 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);
}