沿着曲线创建螺旋

时间:2018-06-22 17:21:44

标签: math three.js

我希望创建一条沿着曲线的螺旋线,以查看我的目标,此链接具有表示它的gif ...

https://www.mapleprimes.com/posts/202940-Spiral-Around-The-Curve

(我对动画或其他几何图形仅生成的粉红色螺旋线不感兴趣)

理想情况下,我应该能够具有任意形状的曲线,知道我想要的螺旋线的直径/半径,并从中生成第二条曲线(螺旋线),并以恒定的螺距行进

我正在用JavaScript(threeJS)进行此操作,但我认为它更多是一个通用的数学问题。

使用以下内容,我可以在直线段周围得到一个螺旋线,但是当它改变方向/弯曲时,它会惨败...

let helixPoints = [];
let helixDiameter = 30;

for (let t = 0; t < 1; t += 0.01) {
    let curvePoint = curve.getPointAt(t);
    let helixX = curvePoint.x + (helixDiameter * Math.cos(t*100));
    let helixY = curvePoint.y +(helixDiameter * Math.sin(t*100))
    let helixZ = curvePoint.z;

    helixPoints.push(new THREE.Vector3(helixX, helixY, helixZ));
}

let helixCurve = new THREE.CatmullRomCurve3(helixPoints);

我知道我需要对helixZ做更多的事情,并且我认为它遵循任何曲线,我可能需要获取这些点的切线?

我只是无法理解数学,如果有人能指出正确的方向,我将不胜感激

1 个答案:

答案 0 :(得分:6)

让一个螺旋跟随一个螺旋...这很有趣。可能有更好的方法,但这是我的解决方案:

我用与获得初始螺旋(演示中的黄线)相同的方式定义了一条曲线。调用getPoints会得到一堆Vector3对象,然后我将它们投入工作。

首先,从第二点开始,我回头看前一个点,并形成了一个方向。这接近曲线的切线,但是如果您从曲线上收集的点较少,则准确性会降低。

接下来,我将其与up向量交叉。我使用了(0, 1, 0),但是原始螺旋线的方向可能要求您使用其他螺旋线。这个想法是,up始终与切线相对,这样,与它们的切线相交将产生垂直于曲线的向量。

谈到交叉向量,这就是我接下来要做的,得到了​​一个很好的统一向量。然后,我使用applyAxisAngle将垂直矢量绕切线旋转 一个从当前点的索引计算出的量。

最后,将原始点位置添加到旋转向量中,可以在3D空间中获得与旋转点等效的点,但要遵循原始曲线。

您可以使用不同的值,例如temp的长度以及用于获得不同半径,频率等的间隔。

那是一个很大的挑战。感谢您的锻炼!如果您有任何疑问,请发表评论,我会尽力回答。

// prepare the renderer

let WIDTH
let HEIGHT
let aspectRatio = function() {
  return WIDTH / HEIGHT
}

const renderer = new THREE.WebGLRenderer({
  antialias: true,
  alpha: true
})
document.body.appendChild(renderer.domElement)

const camera = new THREE.PerspectiveCamera(32, aspectRatio(), 1, 1000)
camera.position.set(0, 0, 50)

function resize() {
  WIDTH = window.innerWidth
  HEIGHT = window.innerHeight
  renderer.setSize(WIDTH, HEIGHT)
  camera.aspect = aspectRatio()
  camera.updateProjectionMatrix()
}
resize()

window.addEventListener("resize", resize)

const scene = new THREE.Scene()

const light = new THREE.DirectionalLight(0xffffff, 1, Infinity)
light.position.set(0, 0, 1)
camera.add(light)

scene.add(camera)

// populate the scene

let group = new THREE.Group()
group.scale.set(5, 5, 5)
scene.add(group)

let curvePoints = []
let rad = Math.PI / 4
for (let i = -10; i <= 10; ++i) {
  curvePoints.push(new THREE.Vector3(i / 5, Math.sin(rad * i), Math.cos(rad * i)))
}
let curve = new THREE.CatmullRomCurve3(curvePoints)

let geoPoints = curve.getPoints(500);

let geo = new THREE.BufferGeometry().setFromPoints(geoPoints)
let mat = new THREE.LineBasicMaterial({
  color: "yellow"
})
let mesh = new THREE.Line(geo, mat)
group.add(mesh)

let dir = new THREE.Vector3()
let up = new THREE.Vector3(0, 1, 0)
let temp = new THREE.Vector3()
let amount = 0.25;
let innerHelixPoints = []
geoPoints.forEach(function(point, index, arr) {
  if (index > 0) {
    dir.subVectors(point, arr[index - 1])
    dir.normalize()
    temp.crossVectors(dir, up)
    temp.applyAxisAngle(dir, amount * index)
    temp.setLength(0.5)
    temp.add(arr[index - 1])
    innerHelixPoints.push(temp.clone())
  }
})

geo = new THREE.BufferGeometry().setFromPoints(innerHelixPoints)
mat = new THREE.LineBasicMaterial({
  color: "blue"
})
mesh = new THREE.Line(geo, mat)
group.add(mesh)

/* let geo = new THREE.BoxBufferGeometry(10, 10, 10)
let mat = new THREE.MeshLambertMaterial({
    color: "red"
})
let mesh = new THREE.Mesh(geo, mat)
scene.add(mesh) */

function updateObjects() {
  group.rotation.x += 0.001
  group.rotation.y += 0.002
}

// rendering functions

function render() {
  renderer.render(scene, camera)
}

let animationLoopId = null

function animationLoop() {
  animationLoopId = requestAnimationFrame(animationLoop)
  updateObjects()
  render()
}

animationLoop()
html,
body {
  padding: 0;
  margin: 0;
  overflow: hidden;
  background: slateGray;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/93/three.js"></script>