I have the following code to draw a black grease pencil line segment, from the points [0, 0, 0]
to [1, 1, 0]
:
from typing import Tuple
from bpy.types import GreasePencil, GPencilLayer, GPencilFrame, GPencilStroke
import bpy
def create_gp(gp_data: GreasePencil, name) -> GreasePencil:
if name not in bpy.context.scene.objects:
gp_obj = bpy.data.objects.new(name, gp_data)
bpy.context.scene.objects[-1].name = name
bpy.context.scene.collection.objects.link(gp_obj)
return bpy.context.scene.objects.get(name)
def create_gp_layer(gp_obj, layer_name, clear_layer) -> GPencilLayer:
# Get grease pencil layer or create one if none exists
if layer_name in gp_obj.data.layers:
gp_layer = gp_obj.data.layers.get(layer_name)
else:
gp_layer = gp_obj.data.layers.new(layer_name, set_active=True)
if clear_layer:
gp_layer.clear()
return gp_layer
def init_gp(name) -> Tuple[GreasePencil, GreasePencil]:
gp_data = bpy.data.grease_pencils.new(name)
gp_obj = create_gp(gp_data, name)
return gp_data, gp_obj
def stroke_polyline(gp_frame: GPencilFrame, vertices, line_width) -> GPencilStroke:
gp_stroke = gp_frame.strokes.new()
gp_stroke.points.add(len(vertices))
for ix, vertex in enumerate(vertices):
gp_stroke.points[ix].co = vertex
gp_stroke.line_width = line_width
return gp_stroke
def create_gp_material(name: str, color) -> bpy.types.Material:
gp_mat = bpy.data.materials.new(name)
bpy.data.materials.create_gpencil_data(gp_mat)
gp_mat.grease_pencil.color = color
return gp_mat
gp_dat, gp_obj = init_gp("TestPencil")
gp_layer = create_gp_layer(gp_obj, "TestLayer", True)
gp_frame = gp_layer.frames.new(0)
gp_mat = create_gp_material("BlackLine", [0., 0., 0., 1.])
gp_dat.materials.append(gp_mat)
gp_stroke = stroke_polyline(gp_frame, [[0, 0, 0], [1, 1, 0]], 10)
print("Success!")
It produces the following output:
So far, so good. Now, I want to draw lots of different things, on many different layers, each with many different frames, etc. This will require proper management of the grease pencil objects, but since I put together this code by scrounging around on the internet, I do not understand some of the central concepts.
What is the difference between
gp_dat
, andgp_obj
? Both have typeGreasePencil
, so why is it thatgp_dat
has amaterials
attribute, butgp_obj
does not? Why do they need to be linked together by thebpy.context.scene.collection.objects.link(gp_obj)
instruction? (I learned I must do this from: Creating a Grease Pencil Material in Blender 2.8)Assuming I have only one Blender scene, how many
gp_dat/gp_obj
pairs should one create? I think I could do all my drawing using only one grease pencil object, with many associated materials. (Although, I haven't yet figured out how to assign a particular material to a drawing instruction.) So, under what circumstances will I need to create multiple grease pencil objects?
bpy.context.selected_objects[0].data.materials[0]
$\endgroup$ – Alex bries Nov 4 '20 at 9:45