Blender Asked by Rick T on November 20, 2021
I can update a text curve object when I change the frame and it doesn’t create multiple objects but how can I do the same with a mesh object.
Code:
import bpy
scene = bpy.context.scene
font_curve = bpy.data.curves.new(type="FONT",name="Font Curve")
font_curve.body = 'Current Frame: ' + str(scene.frame_current)
font_obj = bpy.data.objects.new("Font Object", font_curve)
scene.collection.objects.link(font_obj)
def recalculate_obj(scene):
font_curve.body = 'Current Frame: ' + str(scene.frame_current)
def register():
bpy.app.handlers.frame_change_post.append(recalculate_obj)
def unregister():
bpy.app.handlers.frame_change_post.remove(recalculate_obj)
register()
It doesn’t create multiple Font objects (this is what I want it just replaces the last one)
But when I try and do it with a mesh object I run into problems due to the "_add"
import bpy
scene = bpy.context.scene
font_curve = bpy.data.curves.new(type="FONT",name="Font Curve")
font_curve.body = 'Current Frame: ' + str(scene.frame_current)
font_obj = bpy.data.objects.new("Font Object", font_curve)
scene.collection.objects.link(font_obj)
cyl_obj = bpy.ops.mesh.primitive_cylinder_add(radius = 1)
def recalculate_obj(scene):
font_curve.body = 'Current Frame: ' + str(scene.frame_current)
cyl_obj = bpy.ops.mesh.primitive_cylinder_add(radius = scene.frame_current)
def register():
bpy.app.handlers.frame_change_post.append(recalculate_obj)
def unregister():
bpy.app.handlers.frame_change_post.remove(recalculate_obj)
register()
My goal is to replace the line bpy.ops.mesh.primitive_cylinder_add command with the python line below but have the a, b, c and d variables in the x_eq, y_eq, z_eq animated with out creating multiple objects.
cyl_obj = bpy.ops.mesh.primitive_xyz_function_surface(x_eq = "a+v", y_eq = "b*sin(2*pi*u+c)", z_eq = "cos(2*pi*u)/d")
Another way you can do this is by just using Python. (Don't use this way, unless you have to. This will increase your memory usage every-time you scrub the time-line and the memory WILL NOT GO DOWN!!!)
Python code to run:
import bpy
import math
def my_handler(scene):
# Deselect all
bpy.ops.object.select_all(action='DESELECT')
# Select the object
if bpy.data.objects.get("Hyperboloid") is not None:
bpy.data.objects['Hyperboloid'].select_set(True)
bpy.ops.object.delete()
# mesh arrays
verts = []
faces = []
# mesh variables
numX = 50
numY = 50
# get frame value
frame = bpy.context.scene.frame_current
# fill verts array
for i in range (0, numX):
for j in range(0,numY):
# nomalize range
u = 8*(i/numX-1/2)
v = 2*math.pi*(j/(numY-1)-1/2)
x = 2*math.sqrt(1+u*u)*math.cos(v)*(frame/12)
y = 2*math.sqrt(1+u*u)*math.sin(v)*(frame/12)
z = 12*u/(frame/12+0.01)
vert = (x,y,z)
verts.append(vert)
# fill faces array
count = 0
for i in range (0, numY *(numX-1)):
if count < numY-1:
A = i
B = i+1
C = (i+numY)+1
D = (i+numY)
face = (A,B,C,D)
faces.append(face)
count = count + 1
else:
count = 0
# create mesh and object
mesh = bpy.data.meshes.new("Hyperboloid")
object = bpy.data.objects.new("Hyperboloid",mesh)
# set mesh location
object.location = bpy.context.scene.cursor.location
bpy.context.collection.objects.link(object)
# create mesh from python data
mesh.from_pydata(verts,[],faces)
mesh.update(calc_edges=True)
# assign a material to the newly created curve
mat = bpy.data.materials.get("Material")
object.data.materials.append(mat)
# active smooth shading to object
bpy.data.objects['Hyperboloid'].select_set(True)
bpy.ops.object.shade_smooth()
bpy.ops.object.select_all(action='DESELECT')
# Add the handler to handlers
bpy.app.handlers.frame_change_pre.clear()
bpy.app.handlers.frame_change_pre.append(my_handler)
Answered by Rick T on November 20, 2021
To avoid mixing context and handlers together as @batFINGER mentioned a workaround is below.
Combine some Python code with the Animation Nodes plugin.
Python Code Used in eq_2:
import bpy
import math
def parametricfunc(val1):
# mesh arrays
verts = []
faces = []
# mesh variables
numX = 50
numY = 50
# fill verts array
for i in range (0, numX):
for j in range(0,numY):
# nomalize range
u = 8*(i/numX-1/2)
v = 2*math.pi*(j/(numY-1)-1/2)
x = 2*math.sqrt(1+u*u)*math.cos(v)*(val1/12)
y = 2*math.sqrt(1+u*u)*math.sin(v)*(val1/12)
z = 12*u/(val1/12+0.01)
vert = (x,y,z)
verts.append(vert)
count = 0
for i in range (0, numY *(numX-1)):
if count < numY-1:
A = i
B = i+1
C = (i+numY)+1
D = (i+numY)
face = (A,B,C,D)
faces.append(face)
count = count + 1
else:
count = 0
edges = AN.algorithms.mesh_generation.grid.quadEdges(numX, numY)
polys = AN.algorithms.mesh_generation.grid.quadPolygons(numX, numY)
return x, y, z, verts, A, B, C, D, faces, edges, polys
x, y, z, verts, A, B, C, D, faces, edges, polys = parametricfunc(val1)
Answered by Rick T on November 20, 2021
Swap out the mesh
Just like the font change handler is swapping out the body of the font, ie the data part of the text object, can do same with meshes.
Proof of concept
Use the create surface operator to create an object stepping along v changing the steps and the point to step to, max.
After each call, save the mesh, remove the object.
Script to create the meshes via operator
import bpy
from addon_utils import enable
from math import pi
from bpy import context
enable("add_mesh_extra_objects") # make sure addon is enabled
# default 4pi in 128 steps
step_value = pi / 32
steps = 10
for step in range(1, 129, steps):
bpy.ops.mesh.primitive_xyz_function_surface(
range_v_max=step * step_value,
range_v_step=step,
)
me = context.object.data
me.name = f"XXXX{step}"
me.use_fake_user = True
bpy.data.objects.remove(context.object)
After running this script have a number of "XXXX" meshes
>>> D.meshes['XXXX
1']
101']
11']
111']
121']
21']
31']
41']
51']
61']
71']
81']
91']
Now simply a case of writing a handler to use these.
Handler to swap in the meshes created
import bpy
def swap_ob_mesh(ob_name, mesh_base_name):
def handler(scene, depsgraph):
ob = scene.objects.get(ob_name)
f = scene.frame_current
me = bpy.data.meshes.get(f"{mesh_base_name}{f}")
if ob and me:
ob.data = me
return handler
# while testing
bpy.app.handlers.frame_change_post.clear()
# test call
bpy.app.handlers.frame_change_post.append(
swap_ob_mesh("Cube", "XXXX")
)
Notes: IMO never mix context and handlers. When it comes to render most likely wont work.
Consider shape keys. If instead simply ran the operator only changing v max (not steps) if all the meshes produced have the same number of verts / edges / faces simply join them as shapes and animate the shape key.
To demonstrate the "stepping" nature of swapping the mesh have used 10 frame steps. Reducing this to 1 will be as smooth as it gets.
On a side note this is a "proof of concept" scrubbing the timeline may produce unexpected results since the mesh is only swapped when exists.
Answered by batFINGER on November 20, 2021
Get help from others!
Recent Questions
Recent Answers
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP