math - 沿着曲线创建螺旋线
问题描述
我希望创建一个遵循曲线的螺旋线,看看我在追求什么,这个链接有一个 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 做更多的事情,我认为它遵循任何曲线,我可能需要在点处得到切线?
我只是无法理解数学,如果有人能指出我正确的方向,我将不胜感激
解决方案
让螺旋跟随螺旋......这很有趣。可能有更好的方法来做到这一点,但这是我的解决方案:
我以与获得初始螺旋线(我的演示中的黄线)相同的方式定义了一条曲线。调用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>
推荐阅读
- javascript - VueJs 可拖动对象动画
- c - 我有一个字符串,我想删除任何 - ,( ,) ,& ,$ ,# ,! ,[ ,] ,{ ,} ," ,' 从单词的开头或结尾
- android - 有没有办法实现路由器来管理 Android 上的片段?
- java - 以编程方式触发 MouseMove java
- sql - Oracle - 将持续时间与不同的 15 分钟间隔相关联
- python - Selenium 单击并选择下拉值(jsslot)
- cors - 从客户端调用 api 的跨源错误
- visual-studio - 如何在 Azure 应用服务网站上获取 Debug.WriteLine 数据(或类似输出)?
- kdb - 随机发送数据到另一个 kdb 进程
- google-chrome - 对 SameSite 更改与 Chrome 的混淆