【Blender
效果
源码(blender3.2)
# bpy
import math
import numpy as npdef get_grease_pencil(gpencil_obj_name='GPencil') -> bpy.types.GreasePencil:"""Return the grease-pencil object with the given name. Initialize one if not already present.:param gpencil_obj_name: name/key of the grease pencil object in the scene"""# If not present already, create grease pencil objectif gpencil_obj_name not in bpy.context.scene.objects:bpy.ops.object.gpencil_add(location=(0, 0, 0), type='EMPTY')# rename grease pencilbpy.context.scene.objects[-1].name = gpencil_obj_name# Get grease pencil objectgpencil = bpy.context.scene.objects[gpencil_obj_name]return gpencildef get_grease_pencil_layer(gpencil: bpy.types.GreasePencil, gpencil_layer_name='GP_Layer',clear_layer=False) -> bpy.types.GPencilLayer:"""Return the grease-pencil layer with the given name. Create one if not already present.:param gpencil: grease-pencil object for the layer data:param gpencil_layer_name: name/key of the grease pencil layer:param clear_layer: whether to clear all previous layer data"""# Get grease pencil layer or create one if none existsif gpencil.data.layers and gpencil_layer_name in gpencil.data.layers:gpencil_layer = gpencil.data.layers[gpencil_layer_name]else:gpencil_layer = gpencil.data.layers.new(gpencil_layer_name, set_active=True)if clear_layer:gpencil_layer.clear() # clear all previous layer data# bpy.ops.gpencil.paintmode_toggle() # need to trigger otherwise there is no framereturn gpencil_layer# Util for default behavior merging previous two methods
def init_grease_pencil(gpencil_obj_name='GPencil', gpencil_layer_name='GP_Layer',clear_layer=True) -> bpy.types.GPencilLayer:gpencil = get_grease_pencil(gpencil_obj_name)gpencil_layer = get_grease_pencil_layer(gpencil, gpencil_layer_name, clear_layer=clear_layer)return gpencil_layerdef draw_line(gp_frame, p0: tuple, p1: tuple):# Init new strokegp_stroke = gp_frame.strokes.new()gp_stroke.display_mode = '3DSPACE' # allows for editing# Define stroke geometrygp_stroke.points.add(count=2)gp_stroke.points[0].co = p0gp_stroke.points[1].co = p1return gp_strokedef draw_circle(gp_frame, center: tuple, radius: float, segments: int):# Init new strokegp_stroke = gp_frame.strokes.new()gp_stroke.display_mode = '3DSPACE' # allows for editing#gp_stroke.draw_cyclic = True # closes the stroke#gp_stroke.line_width = 100#gp_stroke.material_index = 1# Define stroke geometryangle = 2*math.pi/segments # angle in radiansgp_stroke.points.add(count=segments)for i in range(segments):x = center[0] + radius*math.cos(angle*i)y = center[1] + radius*math.sin(angle*i)z = center[2]gp_stroke.points[i].co = (x, y, z)return gp_strokedef rotate_stroke(stroke, angle, axis='z'):# Define rotation matrix based on axisif axis.lower() == 'x':transform_matrix = np.array([[1, 0, 0],[0, math.cos(angle), -math.sin(angle)],[0, math.sin(angle), math.cos(angle)]])elif axis.lower() == 'y':transform_matrix = np.array([[math.cos(angle), 0, -math.sin(angle)],[0, 1, 0],[math.sin(angle), 0, math.cos(angle)]])# default on zelse:transform_matrix = np.array([[math.cos(angle), -math.sin(angle), 0],[math.sin(angle), math.cos(angle), 0],[0, 0, 1]])# Apply rotation matrix to each pointfor i, p in enumerate(stroke.points):p.co = transform_matrix @ np.array(p.co).reshape(3, 1)def draw_sphere(gp_frame, center: tuple, radius: int, circles: int):angle = math.pi / circlesfor i in range(circles):circle = draw_circle(gp_frame, center, radius, 32)rotate_stroke(circle, angle*i, 'x')print(angle * i)gp_layer = init_grease_pencil()
total_frame = 122
bpy.context.scene.frame_start = 0
bpy.context.scene.frame_end = total_frame - 1
for frame in range(0, total_frame):if frame == 0: gp_frame = gp_layer.frames.new(frame) # 注意这两行,实现了保存以前帧的内容else: gp_frame = gp_layer.frames.copy(gp_frame)circle = draw_circle(gp_frame, (0, 0, 0), frame, 30)rotate_stroke(circle, math.pi/50*frame, 'x')rotate_stroke(circle, math.pi/100*frame, 'y')rotate_stroke(circle, math.pi/150*frame, 'z')
【Blender
效果
源码(blender3.2)
# bpy
import math
import numpy as npdef get_grease_pencil(gpencil_obj_name='GPencil') -> bpy.types.GreasePencil:"""Return the grease-pencil object with the given name. Initialize one if not already present.:param gpencil_obj_name: name/key of the grease pencil object in the scene"""# If not present already, create grease pencil objectif gpencil_obj_name not in bpy.context.scene.objects:bpy.ops.object.gpencil_add(location=(0, 0, 0), type='EMPTY')# rename grease pencilbpy.context.scene.objects[-1].name = gpencil_obj_name# Get grease pencil objectgpencil = bpy.context.scene.objects[gpencil_obj_name]return gpencildef get_grease_pencil_layer(gpencil: bpy.types.GreasePencil, gpencil_layer_name='GP_Layer',clear_layer=False) -> bpy.types.GPencilLayer:"""Return the grease-pencil layer with the given name. Create one if not already present.:param gpencil: grease-pencil object for the layer data:param gpencil_layer_name: name/key of the grease pencil layer:param clear_layer: whether to clear all previous layer data"""# Get grease pencil layer or create one if none existsif gpencil.data.layers and gpencil_layer_name in gpencil.data.layers:gpencil_layer = gpencil.data.layers[gpencil_layer_name]else:gpencil_layer = gpencil.data.layers.new(gpencil_layer_name, set_active=True)if clear_layer:gpencil_layer.clear() # clear all previous layer data# bpy.ops.gpencil.paintmode_toggle() # need to trigger otherwise there is no framereturn gpencil_layer# Util for default behavior merging previous two methods
def init_grease_pencil(gpencil_obj_name='GPencil', gpencil_layer_name='GP_Layer',clear_layer=True) -> bpy.types.GPencilLayer:gpencil = get_grease_pencil(gpencil_obj_name)gpencil_layer = get_grease_pencil_layer(gpencil, gpencil_layer_name, clear_layer=clear_layer)return gpencil_layerdef draw_line(gp_frame, p0: tuple, p1: tuple):# Init new strokegp_stroke = gp_frame.strokes.new()gp_stroke.display_mode = '3DSPACE' # allows for editing# Define stroke geometrygp_stroke.points.add(count=2)gp_stroke.points[0].co = p0gp_stroke.points[1].co = p1return gp_strokedef draw_circle(gp_frame, center: tuple, radius: float, segments: int):# Init new strokegp_stroke = gp_frame.strokes.new()gp_stroke.display_mode = '3DSPACE' # allows for editing#gp_stroke.draw_cyclic = True # closes the stroke#gp_stroke.line_width = 100#gp_stroke.material_index = 1# Define stroke geometryangle = 2*math.pi/segments # angle in radiansgp_stroke.points.add(count=segments)for i in range(segments):x = center[0] + radius*math.cos(angle*i)y = center[1] + radius*math.sin(angle*i)z = center[2]gp_stroke.points[i].co = (x, y, z)return gp_strokedef rotate_stroke(stroke, angle, axis='z'):# Define rotation matrix based on axisif axis.lower() == 'x':transform_matrix = np.array([[1, 0, 0],[0, math.cos(angle), -math.sin(angle)],[0, math.sin(angle), math.cos(angle)]])elif axis.lower() == 'y':transform_matrix = np.array([[math.cos(angle), 0, -math.sin(angle)],[0, 1, 0],[math.sin(angle), 0, math.cos(angle)]])# default on zelse:transform_matrix = np.array([[math.cos(angle), -math.sin(angle), 0],[math.sin(angle), math.cos(angle), 0],[0, 0, 1]])# Apply rotation matrix to each pointfor i, p in enumerate(stroke.points):p.co = transform_matrix @ np.array(p.co).reshape(3, 1)def draw_sphere(gp_frame, center: tuple, radius: int, circles: int):angle = math.pi / circlesfor i in range(circles):circle = draw_circle(gp_frame, center, radius, 32)rotate_stroke(circle, angle*i, 'x')print(angle * i)gp_layer = init_grease_pencil()
total_frame = 122
bpy.context.scene.frame_start = 0
bpy.context.scene.frame_end = total_frame - 1
for frame in range(0, total_frame):if frame == 0: gp_frame = gp_layer.frames.new(frame) # 注意这两行,实现了保存以前帧的内容else: gp_frame = gp_layer.frames.copy(gp_frame)circle = draw_circle(gp_frame, (0, 0, 0), frame, 30)rotate_stroke(circle, math.pi/50*frame, 'x')rotate_stroke(circle, math.pi/100*frame, 'y')rotate_stroke(circle, math.pi/150*frame, 'z')