如何在 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 的算法(如果我理解正确的话)。数学显示在我包含在代码中的额外函数中,即 splitQuadraticBezierCurve
和 getPointAtT
。 THREE.js 有一些功能类似于 getPointAtT
,特别是 getPoint
,还有一个 getTangent
功能。但是,我还不太清楚如何使用 getTangent
,所以我最终只是自己实现了数学运算。反正也没那么难。
下图可以更好地理解分割曲线的基本原理:
v
代表矢量(或点),v0
、v1
和v2
是从你的初始二次曲线中检索出来的,是你原来的start
、middle
和 end
点。 v01
和 v12
是沿指示线的距离 t
(在您的情况下为 0.5),v012
是 [=24= 之间的距离 t
] 和 v12
。函数 returns 一个双元素数组,具有原始二次曲线的第一个(元素 0)和第二个(元素 1)'halves'。第一条'half'曲线的起点、中点和终点分别是v0
、v01
和v012
。第二条 'half' 曲线的起点、中点和终点是 v012
、v12
和 v2
。
代码为第二条 '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);
}
我可以通过指定三个坐标在 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 的算法(如果我理解正确的话)。数学显示在我包含在代码中的额外函数中,即 splitQuadraticBezierCurve
和 getPointAtT
。 THREE.js 有一些功能类似于 getPointAtT
,特别是 getPoint
,还有一个 getTangent
功能。但是,我还不太清楚如何使用 getTangent
,所以我最终只是自己实现了数学运算。反正也没那么难。
下图可以更好地理解分割曲线的基本原理:
v
代表矢量(或点),v0
、v1
和v2
是从你的初始二次曲线中检索出来的,是你原来的start
、middle
和 end
点。 v01
和 v12
是沿指示线的距离 t
(在您的情况下为 0.5),v012
是 [=24= 之间的距离 t
] 和 v12
。函数 returns 一个双元素数组,具有原始二次曲线的第一个(元素 0)和第二个(元素 1)'halves'。第一条'half'曲线的起点、中点和终点分别是v0
、v01
和v012
。第二条 'half' 曲线的起点、中点和终点是 v012
、v12
和 v2
。
代码为第二条 '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);
}