4
$\begingroup$

enter image description here Red circle is moving along path with location pivot as "P" and scale along pivot "C". How could i achieve this animation in Blender?

$\endgroup$
2
  • $\begingroup$ Just for understanding: so you want a circle moving with its center P along the curve. And the radius should always match so that the circle goes through point C? $\endgroup$ Commented Jul 14, 2022 at 8:44
  • $\begingroup$ yes correct sir $\endgroup$
    – karthik C
    Commented Jul 14, 2022 at 9:03

3 Answers 3

9
$\begingroup$

You can do this in Geometry Nodes. First I add an empty representig the "C" circle. Then I add a curve and give a new Geometry Nodes nodetree.

Inside the nodetree, I use Sample Curve to get the position on the curve at the given Factor, where start is at 0 and end at 1. Then I add a Mesh Primitive > Circle and plug it into a Set Position node.

The Offset is the Position from the Sample Curve node. If you animate the Factor, the Mesh Primitive circle follows the curve.

I bring the Empty into the nodetree with a Object Info node. Its location and the Sample Curve position I plug into a Vector Math node set to Distance. The result I plug into the Radius of the Mesh Primitive.

curve pivot

Now if you animate the Factor from 0 to 1 and back you get something like this (I joined the moving circle with a small one with fixed radius so you can see the traveling center better):

circle moving

Since this is done in Geometry Nodes and fully procedural, of course it doesn't matter where the Empty is placed to define the radius, it can move around as well:

moving empty

Not even the curve has to be fixed, because shape keys are evaluated before the Geometry Nodes modifier:

moving curve

$\endgroup$
3
  • 2
    $\begingroup$ 😲 amazing work $\endgroup$
    – karthik C
    Commented Jul 15, 2022 at 4:32
  • $\begingroup$ @karthikC Thanks, you're welcome. My solution is more for freestyle curves, Robin's answer works with real mathematical functions. It depends on what you're after, but of course you could use any mathematically calculated or freehand curve with my solution as well, and like the empty you don't necessarily need to have the GN node tree on a curve object, you could bring the curve in with an Object Info node as well. $\endgroup$ Commented Jul 15, 2022 at 7:11
  • 1
    $\begingroup$ Very nice, I do love an elegant Geometry Nodes solution $\endgroup$
    – J Sargent
    Commented Jul 16, 2022 at 1:09
8
$\begingroup$

@Gordon Brinkmann nipped in while this answer was being built.. so this is just an variation of his, with other bits and pieces. His answer covers the basic points:

  • Construct a circle at the t parametric location on your parabola, by making your parabola as a curve, and using GN's Sample Curve.
  • Set the radius of the circle to be the Distance between that point and your chosen (0,Y)

It turns out that the parabola y**2 == 8x can be represented by on a Quadratic Bezier curve primitive, with its points at (8,-8,0),(-8,0,0), and (8,8,0).

The rest is plumbing:

enter image description here

This version exposes t, and the y of your (0,y) point to the modifier, but you could choose other parameters for the interface..

enter image description here

$\endgroup$
7
  • 1
    $\begingroup$ +3 for consistently naming the reroutes! ;-) $\endgroup$
    – quellenform
    Commented Jul 14, 2022 at 10:58
  • 1
    $\begingroup$ @quellenform hmmmm. yes, that does look a bit overdone :) I don't type the names again and again. I just Shift-D copy the named reroutes and drop them on the noodles. $\endgroup$
    – Robin Betts
    Commented Jul 14, 2022 at 11:16
  • 1
    $\begingroup$ +8 for recognizing it before me ;-) $\endgroup$
    – quellenform
    Commented Jul 14, 2022 at 11:22
  • 3
    $\begingroup$ +99 for bothering to do it with real maths. I just tried to demonstrate that it's possible to move a circle on any given curve and fit the radius to some other specified point ;) $\endgroup$ Commented Jul 14, 2022 at 12:31
  • 1
    $\begingroup$ @Gordon.... this one could be a 'wait for complaints' :D $\endgroup$
    – Robin Betts
    Commented Jul 14, 2022 at 12:54
2
$\begingroup$

All the answers previously given are awesome and I think Geometry Nodes is definitely the way to go. But it might be interesting to see this plotted and animated in python as well especially if you have very complicated Implicit Equations that are really hard to input in Geometry Nodes if not impossible.

enter image description here

Delete everything in the scene then just copy & paste the script in the Text Editor and click Run Script button. Press 7 in the 3D Viewport for top view and then press Spacebar to play animation or you can also just scrub through the keyframes.

import bpy
import math

FRAMES_TOTAL = 150

bpy.context.scene.frame_start = 1
bpy.context.scene.frame_end = FRAMES_TOTAL
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 = 1, 1, 1
    return empty

# ==================================================================================================
# Equation: https://www.wolframalpha.com/input?i=y%5E2+-+8+x+%3D+0
# Descritpion: plot the parabola (y^2 = 8x) 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_parabola_x(y):
    return y**2 / 8

def get_parabola_y(x):
    return math.sqrt(8 * x)

def draw_parabola():
    verts = []

    for py in get_range(-10, 10):
        px = get_parabola_x(py)
        verts.append([px, py, 0.0])

    edges = []
    for i in range(len(verts)-1):
        edges.append((i, i+1))

    o = get_object("parabola")
    m = o.data
    m.clear_geometry()
    m.from_pydata(verts, edges, ())

# ==================================================================================================
# Equation: https://www.emathhelp.net/calculators/algebra-2/circle-calculator/?type=f&f=x%5E2+%2B+y%5E2+-+4x+%2B+8y+%2B+12+%3D+0&cx=&cy=&r=&d=&c=&a=&p1x=&p1y=&p2x=&p2y=&p3x=&p3y=
# Description: circle (x^2 + y^2 - 4x + 9y + 18 = 0) has center at (-2,4) & radius 2*sqrt(2) or 2.82843
# ==================================================================================================

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, y, px, py, segments = 32):
    o = create_circle(segments)
    o.location = px, py, 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 line connecting circle center to point c
# ==================================================================================================

def draw_line(x, y, px, py):
    o = get_object("line")
    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_from(x, y, py):
    px = get_parabola_x(py)
    r =  math.sqrt((py - y)**2 + (px - x)**2)
    draw_circle(r, y, px, py)
    draw_line(x, y, px, py)
    draw_empties(x, y, px, py) 

# ==================================================================================================
# animation functions
# ==================================================================================================

def animate_p(frame, frames_total):
    py_start = 10
    py_end = -4
    py_range = math.fabs(py_end - py_start)
    py = py_end + (frames_total - frame) / frames_total * py_range
    draw_circle_from(0,-6,py)

def animate_y(frame, frames_total):
    y_start = -6
    y_end = 8
    y_range = math.fabs(y_end - y_start)
    y = y_start + frame / frames_total * y_range
    draw_circle_from(0,y,-4)

def animate():
    HALF_TOTAL = FRAMES_TOTAL * 0.5
    frame = bpy.context.scene.frame_current

    if frame < HALF_TOTAL:
        animate_p(frame, HALF_TOTAL)
    else:
        animate_y(frame - HALF_TOTAL, HALF_TOTAL)

# ==================================================================================================
# 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_parabola()
on_enter_frame(None, None)

for o in bpy.context.scene.objects:
    o.select_set(True)
bpy.context.view_layer.objects.active = get_object("circle")
$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .