In this post I'll explain the geometrical/mathematical ideas behind the piece "Conical Spiral".
Part one: The Spiral
What is a conical spiral? Well it's a curve on the surface of a cone that resembles a spiral. On a 2d plane, a spiral can be easily described in polar coordinates: r = f(φ).
Let's talk about two types of spirals. First, the "Logarithmic spiral" is formulated as: r = exp(a φ). In this case, each time we rotate a full turn around the origin (φ goes to φ + 2π) the value of r is multiplied(or divided) by a constant value: exp(2aπ).
The other type is the "Archimedean spiral": r = φ × (δ / 2π). In this case, rotating a full turn around the origin increases (or decreases) the value of r by a constant number (r goes to r ± δ ).
Now look at the gif above. Considering that the thickness of the rope is constant, what kind of spiral do you think we are going to use? That's right! It's going to be the Archimedean, and the value of δ is the thickness of the rope.
Note: If you want to make a looped animation in which you keep zooming in (or out) on a spiral structure, Then your preferred spiral type should be logarithmic, Because of it's scaling property.
Now let's define the "Archimedean Conical Spiral". From now on we consider the cone's apex to be on the the origin, it's symmetry axis is the z direction, and it's apex angle 2λ. Let's also use the conventional 3d spherical coordinate system (r,θ,φ) . We define the Archimedean Conical Spiral like this:
As you may notice we can use either of r or φ as our curve parameter, but r is a better choice, because φ(r) is a single valued function but r(φ) is not. The next mathematical tool we need is a curve length function: s(r) that tells us how much is the length of the curve from the origin to the point r. We are not able to solve the integrals used to find s(r) analytically for most of the curves. But luckily for the Archimedean Conical Spiral, it is calculatable, and the answer is (Thank you Stephen Wolfram🤗) :
Part Two: The SDF
Now we have all the mathematical tools needed. How we can draw a conical spiral using raymarching. Well we need the SDF (Signed Distance Function). It takes a position in space and tells you how far away is the nearest point on the surface of the object you want to render. Here we are going to represent an approximate method to find the SDF for the conical spiral.
Step one: Project onto the cone
consider the given position is p , project it onto the cone and call the projected point p'. By projecting I mean, p' is the nearest point on the cone to p.
Step Two: Cut the curve
You may not want your curve to go from r = 0 to r = infinity. So get the r value of p' and clamp it between two inputted limits r_1 and r_2.
Step Three: Project on the spiral
Find the nearest point on the spiral to p'. Here we are going to spend a lot of our approximation tokens! Just take the r and φ values of p' and do this:
Then bring back this (r, λ, φ) to the Cartesian coordinates, and you'll get the nearest point of the spiral to the input point p, which I'll call p''.
What's next? We can stop here, and use length(p-p'') as our distance function. But if you want to obtain the rope structure that is used in the gif above, you'll need to do a little bit more calculation. You'll need to follow the instruction in one of my previous tutorials in this blog called "Untangled Fractals". In that post I show you how you can create a rope structure using a simple coordinate mapping.
Note: To do the transformation you must use p and p'' to find another vector in a new transformed coordinate that reshapes a cylinder into a rope structure. To do that you'll need three normalized vectors emitting from the point p'' as your new coordinate vectors, those three vectors are the TNB vectors of the spiral curve. I encourage you to study the TNB coordinate of a curve (It is really fun and useful in computer graphics), and then come back and do this part. After you project p onto the TNB coordinates of p'', you must offset the y value of the resulting vector by the amount of s(r''). This is the final trick that we also used in the Untangled Fractals article.
Part Three: The Animation
As you can see, the rope is being transferred from the flat spiral to the conical spiral (and vise versa), but in a way that the total length of the rope remains constant. So if we consider the conical spiral is extended from r = 0 to r = R and the flat spiral is from r = R to r = infinity, then this puts a constraint on the variables describing both spirals. These constraints are needed if we want the value of R to be animated freely. The constrain is:
As you can see in the original GIF, in the first few seconds, the sin(λ(t)) value on the conical part of the rope is 1/2 and on the flat spiral is 1. At the same time you can see that the value of δ on the flat spiral is twice the value of δ on the conical spiral. So the above equation holds. There is also a portion of time in the animation that the value of λ(t) starts changing, in those moments, δ of the conical spiral changes in a way that the above equation still holds.
As for now, we have two spirals, with appropriate lengths, but these two are not connected! The flat spiral is still on the ground but the conical one should rotate in a way that it's end connects perfectly to the start of the flat part. How this can be done?
We need to do a special transformation of the coordinates before rendering the conical spiral for this to happen. This transformation is a pure rotation (why?) it takes the point at the end of conical spiral to the beginning of the flat spiral. Is it possible to find a rotation (axis + angle) that takes vector v1 to v2? The answer is yes, but the result is not unique. To make it unique we should force another constraint that is: the rotation should transform the normal vector of the curve's plane at the end of the conical spiral to the corresponding vector of the beginning of the flat spiral (Why normal and not tangent? Because this is also an approximation). These two vectors are easily the normalized vectors in the direction of θ of the two points we want to connect.
So this is our problem now:
Find a rotation (axis + angle) that takes v1 to v2 and takes v3 to v4. (v1.v3 = v2.v4)
Take your time trying to solve this problem. It's a fun problem that tests your vector algebra skills.
I also tweeted this problem a while back, check that out here.
This is the answer: The axis is perpendicular to v1-v2 and is also perpendicular to v3-v4 so the axis can only be: normalize(cross(v1-v2, v3-v4)). There are also some exceptional cases you have to study separately. After you find the axis of rotation, finding the angle is not a challenge at all.
Now considering you have both the axis and angle of a rotation, how can you write a function that gives you the result of the action of this rotation on a given vector?
This is the answer: (b is the input vector, and t is the angle of rotation)
Now we have all the tools needed. All we have to do is to animate R from 0 to a reasonable value. After that, animate λ(t) from π/6 to π - π/6 (This is the spirals going through each other part), and when it's done animate R back to 0, and that's all. Don't forget to do the animations smoothly.
Note: How to do the animations smoothly? Whenever a variable t is going from 0 to 1, add this line of code to make the transition smooth: t = 0.5 - 0.5 * cos(t * π)
I hope for this article to be helpful for someone out there. Thanks for reading. Goodbye and Bedrood!
Really enjoyed your write up.
ReplyDeleteMany thanks. This helped visualize an important property. Now we need to connect this field to the acoustics (Damru is the instrument around which the Maheshvar Sutrani's production of sound in the sanskrit pratyahara constructs). Deep.
ReplyDelete