In Blender 3.2.1, I need a unit mesh circle at origin and path on the x-axis with a length of $2\pi$. Object constraint on circle to follow path. Keyframe on unit circle at 0 & 250 with $360^{\circ}$ z-rotation. How do I get a single vertex on the unit circle to trace the sine or cosine wave?
-
could you pls tell us what your end goal is? – Chris Aug 01 '22 at 11:15
-
i want to trace the sine/cosine wave from the rotating unit circle. i just dont know how to get the vertex to trace the path. it is a step in a larger gear driven idea. – axiomatibus Aug 01 '22 at 11:19
-
i still don't get it. you only get a sin or cos wave, if you would move the circle while following path. If the circle is fixed, you only get a right left or up down movement. So what do you want? – Chris Aug 01 '22 at 11:23
-
do you want that? [1]: https://i.stack.imgur.com/o8cI9.gif – Chris Aug 01 '22 at 11:25
-
https://blender.stackexchange.com/questions/48866/draw-line-from-armature-animation/ https://blender.stackexchange.com/questions/104732/is-it-possible-to-achieve-a-spirograph-efect https://blender.stackexchange.com/questions/261399/how-can-i-trace-an-object-that-move-along-equation – Duarte Farrajota Ramos Aug 01 '22 at 11:35
-
If the circle is moving along the line while rotating, the path scribed by a point on its circumference is a cycloid, not a sine wave ? – Robin Betts Aug 01 '22 at 15:57
-
yes, the way i was describing it wouldn't give a sine wave. – axiomatibus Aug 02 '22 at 01:45
1 Answers
Just copy the script and execute then press spacebar in the Timeline to play the animation or you can scrub through the timeline from frame 0 to 250.
import bpy
import math
REVOLUTION = 360
TOTAL_FRAMES = 250
SINEWAVE_RESOLUTION = 64
RADIUS = 1
bpy.context.scene.frame_start = 1
bpy.context.scene.frame_end = TOTAL_FRAMES
bpy.context.scene.frame_current = 1
def get_object(name):
objects = bpy.context.scene.objects
if name in objects:
return objects[name]
m = bpy.data.meshes.new(name + "-mesh")
o = bpy.data.objects.new(name, m)
#o.modifiers.new(name, 'SKIN')
bpy.context.collection.objects.link(o)
return o
def get_empty(name):
objects = bpy.context.scene.objects
if name in objects:
return objects[name]
bpy.ops.object.empty_add(type='SPHERE', align='WORLD', location=(0, 0, 0))
empty = bpy.context.object
empty.name = name
empty.scale = 0.1, 0.1, 0.1
return empty
==================================================================================================
Descritpion: plot the sinwave with some points
==================================================================================================
def get_range(start, end, step = 2):
return [x * 0.1 for x in range(start * 10, end * 10, step)]
def get_sinewave_x(angle):
return RADIUS * math.cos(REVOLUTION - math.radians(angle))
def get_sinewave_y(angle):
return RADIUS * math.sin(math.radians(angle))
def get_sinewave_length():
return RADIUS * 4
def draw_sinwave(angle, id):
verts = []
xunits = get_sinewave_length()
for u in range(0, SINEWAVE_RESOLUTION + 1):
a = u / SINEWAVE_RESOLUTION * REVOLUTION
px = xunits / SINEWAVE_RESOLUTION * u
py = get_sinewave_y(a)
if (a <= angle):
verts.append([px, py, 0.0])
#verts.append([xunits, 0, 0.0])
edges = []
for i in range(len(verts)-1):
edges.append((i, i+1))
o = get_object("sinewave-" + id)
m = o.data
m.clear_geometry()
m.from_pydata(verts, edges, ())
==================================================================================================
Create Circle
==================================================================================================
def create_circle(n):
o = get_object("circle")
exists = len(o.data.vertices) > 0
if exists:
return o
verts = []
for i in range(n):
verts.append((0.0, 0.0, 0.0))
edges = []
for i in range(len(verts)-1):
edges.append((i, i+1))
edges.append((i+1, 0))
m = o.data
m.clear_geometry()
m.from_pydata(verts, edges, ())
return o
def draw_circle(r, segments = 32):
o = create_circle(segments)
o.location = 0.0, 0.0, 0.0
for i in range(segments):
a = 2 * math.pi / segments * i
o.data.vertices[i].co = math.cos(a) * r, math.sin(a) * r, 0.0
==================================================================================================
draw lines connecting circle and x-axis
==================================================================================================
def draw_line(x, y, px, py, id):
o = get_object("line-" + id)
m = o.data
verts = m.vertices
exists = len(verts) > 0
if exists:
verts[0].co = x, y, 0.0
verts[1].co = px, py, 0.0
return
verts = []
verts.append((x, y, 0.0))
verts.append((px, py, 0.0))
m.clear_geometry()
m.from_pydata(verts, [(0,1)], ())
==================================================================================================
draw geometry
==================================================================================================
def draw_empties(x, y, px, py):
get_empty("empty-1").location = x, y, 0.0
get_empty("empty-2").location = px, py, 0.0
def draw_circle_angle(angle):
rad = math.radians(angle)
draw_circle(RADIUS)
l1x = RADIUS * math.cos(math.pi * 2 - rad)
l1y = RADIUS * math.sin(rad)
l2x = angle / REVOLUTION * get_sinewave_length()
l2y = get_sinewave_y(angle)
draw_line(0, 0, l1x, l1y, "1")
draw_line(l2x, 0, l2x, l2y, "2")
draw_empties(l2x, l2y, l1x, l1y)
==================================================================================================
animation functions
==================================================================================================
def animate():
f = bpy.context.scene.frame_current
angle = REVOLUTION / TOTAL_FRAMES * f
draw_sinwave(angle, '1')
draw_circle_angle(angle)
==================================================================================================
execute code
==================================================================================================
def on_enter_frame(a,b):
animate()
bpy.app.handlers.frame_change_post.clear()
bpy.app.handlers.frame_change_post.append(on_enter_frame)
draw_sinwave(REVOLUTION, '2')
on_enter_frame(None, None)
for o in bpy.context.scene.objects:
o.select_set(True)
bpy.context.view_layer.objects.active = get_object("sinewave-1")
bpy.context.scene.objects['sinewave-2'].select_set(False)
- 10,995
- 8
- 23
- 51
