# How do I make a curve in the shape of a simple wave form (sine)?

I am trying to create a curve with a simple wave form to use it as animation path. Although I have a bunch of possibilities to add different curves:

.. I did not find a solution yet. This is exactly what I want to achieve:

I did this by adding a Nurbs Curve and in Edit Mode deformed it, duplicated/rotated/replaced it so that I have a longer curve (because I cannot use Array Modifier for curves).

Problem is: When my object follows the path (Follow Path Contraint) it will stop directly after the first original section of the curve.

So: Is there an Addon, a setting for the default available curves by which I can achieve to get a sine wave path? Google only showed me older Q&A with Python scripting but I think there must (hopefully) be another way?

• I think the best solution will be python script. I'm sure if it's acceptable then someone (me if nobody beats me to it) could produce a simple script to generate a sine wave to a specified number of cycles. – Rich Sedman Feb 1 '18 at 15:02
• It's possible to add math function mesh (via Add Mesh: Extra Objects, Z Math Surface)) and then convert it to curve. I didn't hear about the same for curves – Mr Zak Feb 1 '18 at 15:26
• Does it have to be a perfect function curve or is an approximation OK? – Haunt_House Feb 2 '18 at 5:41
• @MrZak thx, I already have the "Add Curve: Extra Objects" Addon installed, but with this I did not figure out a proper solution yet (maybe I just don't see it :-)) - I will try the Z Math Surface approach though – ho.s Feb 4 '18 at 8:44

Animation Node can be used here, a simple sine wave spline can be generated as follows:

Animating an object along the wave can be done by evaluating it at some point as follows:

Where the divide controls the speed of the motion.

To align the rotation of the object, you can compute the angle that the tangent to the curve makes with the x axis, the tangent is equal to the derivative which is dy/dt(sin(t)) = cos(t) so the angle is equal to arctan(cos(t)), and the node tree becomes as follows:

First of all, I think the reason the follow path constraint stops is because it appears you have breaks in your curve after every repeated segment.Hard to say form the images alone though. If that is the case, since there is no merge option for curves, then select both points, fill them with F and scale them to 0. Then select one point, delete it, and use the dissolve vertices option. This will merge the two points, which should fix your issue.

As Mr Zak mentioned, the Extra objects addon has a Z Math surface, and by using the two middle loops and collapsing them into one, we get a perfect sine curve. This can be duplicated and flipped, then using vertex snapping it can be aligned with the first section. Once you have one wave, it can be duplicated as many times as necessary, then the doubles removed with W, and converted to a curve with Alt+C.

I would suggest an alternative though, one that would give you much more control. This may or may not work depending on your exact situation, but if all you want is motion along a sine curve along one axis only than this will work great.

First, animate your object along the axis you want it to travel. In my example I will use a simple mesh arrow so we can easily see where it is pointing, and I will have it move along the X axis. I animated it to move 10 units in 100 frames. Animate your object using the LocRot keyframe, so that we will have access to the location and rotation curves. The rest will all be done using the graph editor.

Here is where I'm at so far:

The first step is to change the interpolation type on the X location curve to be linear, so that it moves with uniform motion, instead of accelerating then decelerating. So we can select the curve, press T and choose linear. This should give us a nice straight line.

Like so:

Now, in order to get our object to move along a sine curve, we need to modify the Z location and the Y rotation. To do this, we will use the modifiers in the Graph Editor. Open the properties Panel in the Graph Editor with N and choose the modifier tab. Now select the Z location from the list on the left, and add a Built-In Function modifier. The default function is Sine, so we could call this done, but the frequency of the wave is pretty high, so we can turn that down with the Phase Multiplier option. I set it to .1 so that it has nice smooth motion.

Here are the setting so far:

The final step is to add a sine function to the Y rotation curve. So lets select that one and add the modifier. Make sure you copy all of the setting from the Z location modifier to the Y rotation one, otherwise they will be out of sync. Since we are dealing with rotation though, the same amplitude will result in a much taller wave, which is what we want. In my case, all I had to change was the Phase Multiplier. Is you play the animation, it won't look right, and that is because we need to offset the Y rotation curve. Since we want the object to have no rotation and the peaks and troughs, and have the maximum rotation while halfway in between, we will need to offset the curve by pi/2, or approximately 1.571 (this is what blender rounds it to). Depending on the rotation of your object as well, it may have to be negative. One you set the Phase Offset to that value, we are finished.

Here's the Y rotation curve and modifier:

And here is the final result:

• Thanks a lot for your solution and detailed explanation! I gave the "Extra Objects - Z Math surface" method a shot. I have a perfectly closed and smooth sine curve now but couldn't get the object to follow it properly. To explain would make a whole new question i suppose :-) But your approach is nice, it helped me a lot to understand more about the possibilities of modifying animation curves (did not do this before). – ho.s Feb 4 '18 at 10:01

Here's my take on this...

Open a Text Editor window and paste the following code :

import bpy
import math

def create_sine(numCycles = 1, stepsPerCycle = 16, curvelen=2, yscale=1):

curve = bpy.data.curves.new('sinepath', type='CURVE')
curve.dimensions = '2D'
curve.resolution_u = 1
spline = curve.splines.new('NURBS')

#cursor = bpy.context.scene.cursor_location
xscale = float(curvelen)/stepsPerCycle/numCycles

for x in range(0, stepsPerCycle * numCycles+1):
y = math.sin(float(x) / stepsPerCycle * math.pi*2)

#Add first point for start of Nurbs (needs extra point)
if x == 0:
spline.points[0].co = (x*xscale,y*yscale, 0.0,1)

spline.points[-1].co = (x*xscale, y*yscale,0.0,1)

spline.points[-1].co = (x*xscale, y*yscale,0.0,1)

curveObject = bpy.data.objects.new('sinepath', curve)

create_sine(numCycles = 4, stepsPerCycle = 16, yscale=1,curvelen=2)


Name it something like 'sine.py'.

Note the last line that invokes the function - amend the parameters as you require.

• numCycles is the number of complete sine waves
• stepsPerCycle is the number of points per cycle
• yscale is the amplitude of the wave
• curveLen is the length of the curve

Note that the curve will be created at the world origin.

Click Run Script to run the script and a new Nurbs path should be created :

Click the path and go into Edit mode (Tab) and back to Object mode to ensure the new geometry is committed (I think I'm just missing a function call for this - I'll update it when I figure it out). You can then use the wave for a Follow Path constraint.

• Thank you very much for your solution - it made me open the text editor and run a script the very first time, thanks again for that. It worked fine: The "sinepath" was created successfully and I could use it for my Follow Path constraint. BUT I do not know why, it deformed my object (cube looks like a trapezoid). So I am going with another solution, but your answer was very helpful, too. – ho.s Feb 4 '18 at 8:26

This'll get you most of the way there. I don't know how to target curve handles in Python, so you'll have to right-click the furthest handle nodes then delete >> vertices. You'll do the same with the little initial floating segment below. Easy enough to do. I'm just not that familiar with scripting curves in Blender.

import bpy
import math

strokes = []
for x in range(-10, 10):
y = math.sin(x)
strokes.append({ "name":"",      "location":(x, y, 0),
"mouse":(0, 0), "pressure":1,
"size":0,       "pen_flip":False,
"time":0,       "is_start":False
})