Skip to content

Commit 679d270

Browse files
committed
fixed tracer for obj offset from origin
1 parent 970e370 commit 679d270

File tree

113 files changed

+1027
-4
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

113 files changed

+1027
-4
lines changed

GreaseWriter/README.rst

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
.. image:: https://i.imgur.com/VKEhIx3.gif
2+
3+
Installation
4+
============
5+
**This only works on Blender 2.8**
6+
7+
1. Download the latest .zip file from the releases_ page
8+
2. Open Blender and go to Edit > Preferences > Install Add-on from File... Then navigate to the .zip file you downloaded and select it
9+
3. Check the box that appears next to "Grease Writer"
10+
11+
.. _releases: https://www.github.com/doakey3/GreaseWriter/releases
12+
13+
Usage
14+
=====
15+
Writing
16+
-------
17+
1. Create a new Grease Pencil object in the 3D view (Shift + A > Grease Pencil > Blank)
18+
2. With the Grease Pencil object selected, go to the data section of the Properties window where you will find the Grease Writer panel.
19+
3. Create a text file with the desired text
20+
21+
- Right-click at the edge of a window and split the area
22+
- Change the Window's view to the Text Editor
23+
- click the "New" button to start editing a text file
24+
25+
.. image:: https://i.imgur.com/YqZd5Ji.gif
26+
27+
4. Enter the name of the Text file in the source text property in the Grease Writer panel
28+
5. Adjust settings and click the "Write" button
29+
6. Optionally add a decorator to the added text
30+
31+
.. image:: https://i.imgur.com/LpXjgNk.gif
32+
33+
Animating
34+
---------
35+
If you draw on a grease pencil object, you can automatically animate it by clicking the "Reanimate" button. Strokes will be drawn in the order they were created.
36+
37+
Tracing
38+
-------
39+
Select a tracer object and click trace. The tracer object's X and Y position will change to keep up with the animated grease pencil as it is being drawn.
40+
41+
.. image:: https://i.imgur.com/2XGSq6H.gif

GreaseWriter/__init__.py

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
import bpy
2+
3+
from .operators import *
4+
5+
bl_info = {
6+
"name": "Grease Writer",
7+
"description": "Automatic hand-drawn text animation",
8+
"author": "doakey3",
9+
"version": (0, 0, 1),
10+
"blender": (2, 80, 0),
11+
"wiki_url": "https://github.com/doakey3/GreaseDraw",
12+
"tracker_url": "https://github.com/doakey3/GreaseDraw/issues",
13+
"category": "Animation",
14+
"location": "Properties, Grease Pencil Data"
15+
}
16+
17+
class GREASEPENCIL_PT_greasewriter(bpy.types.Panel):
18+
bl_label = "Grease Writer"
19+
bl_idname = "GREASEPENCIL_PT_greasewriter"
20+
bl_space_type = "PROPERTIES"
21+
bl_region_type = "WINDOW"
22+
bl_context = "data"
23+
24+
@classmethod
25+
def poll(self, context):
26+
if type(context.active_object.data).__name__ == "GreasePencil":
27+
return True
28+
else:
29+
return False
30+
31+
def draw(self, context):
32+
scene = context.scene
33+
gpencil = context.active_object.data
34+
layout = self.layout
35+
layout.prop(gpencil, 'draw_speed')
36+
layout.prop(gpencil, 'kerning')
37+
layout.prop(gpencil, 'line_height')
38+
layout.prop(gpencil, 'write_thickness')
39+
layout.prop(gpencil, 'write_color')
40+
#layout.prop(gpencil, 'interpolation_mode')
41+
layout.prop(gpencil, 'font')
42+
row = layout.row()
43+
row.operator("grease_writer.write", icon="FILE_TEXT")
44+
row.prop_search(gpencil, 'source_text', bpy.data, "texts", text="")
45+
row = layout.row()
46+
row.operator("grease_writer.decorate", icon="LIGHT_SUN")
47+
row.prop(gpencil, "decorator_style", text="")
48+
layout.operator("grease_writer.reanimate", icon="HAND")
49+
row = layout.row()
50+
row.operator("grease_writer.trace", icon="PIVOT_CURSOR")
51+
row.prop_search(gpencil, 'tracer_obj', scene, "objects", text="")
52+
53+
54+
def init_props():
55+
bpy.types.GreasePencil.draw_speed = bpy.props.FloatProperty(
56+
name="Draw Speed",
57+
description="The distance a stroke lengthens with each frame of animation",
58+
default=0.1,
59+
min=0.01
60+
)
61+
62+
bpy.types.GreasePencil.kerning = bpy.props.FloatProperty(
63+
name="Kerning",
64+
description="Affects the distance between characters. Default is 0.5 x the width of letter M",
65+
default=0.5,
66+
min=0
67+
)
68+
69+
bpy.types.GreasePencil.line_height = bpy.props.FloatProperty(
70+
name="Line Height",
71+
description="Affects the height of a line. Default is 1.25 x the height of the letter M",
72+
default=1.25,
73+
min=0
74+
)
75+
76+
bpy.types.GreasePencil.write_thickness = bpy.props.IntProperty(
77+
name="Thickness",
78+
description="Affects the default line thickness.",
79+
default=100,
80+
min=1
81+
)
82+
83+
bpy.types.GreasePencil.write_color = bpy.props.FloatVectorProperty(
84+
subtype='COLOR_GAMMA',
85+
name="Color",
86+
description="Color to use when writing",
87+
size=3,
88+
default=(0, 0, 0),
89+
min=0.0,
90+
max=1.0
91+
)
92+
93+
"""
94+
It might be cool to someday have different interpolation modes.
95+
For now, linear is ok
96+
97+
interpolation_modes = [
98+
("linear", "Linear", "Draw all strokes at the given draw speed"),
99+
("derivative", "Derivative", "Draw strokes at a rate that varies based on the stroke's rate of change in direction; the more curvaceous, the slower the draw"),
100+
("random", "Random", "Draw with a random speed that is +/- the given draw speed"),
101+
]
102+
103+
bpy.types.GreasePencil.interpolation_mode = bpy.props.EnumProperty(
104+
name="Interpolation",
105+
items=interpolation_modes,
106+
description="Select a mode for calculating how fast strokes should be drawn",
107+
default="linear",
108+
)
109+
"""
110+
111+
fonts = [
112+
("consolas", "Consolas", "A monospace font based on Consolas")
113+
]
114+
115+
bpy.types.GreasePencil.font = bpy.props.EnumProperty(
116+
name="Font",
117+
items=fonts,
118+
description="The font to be used for writing",
119+
default="consolas",
120+
)
121+
122+
bpy.types.GreasePencil.source_text = bpy.props.StringProperty(
123+
name="source_text",
124+
description="The text to be written with grease pencil"
125+
)
126+
127+
decorators = [
128+
("underline", "Underline", "Draw an underline beneath the grease pencil layer"),
129+
("over-underline", "Over-underline", "Draw an overline and underline"),
130+
("box", "Box", "Draw a box around the grease pencil layer"),
131+
("ellipse", "Ellipse", "Draw an ellipse around the grease pencil layer"),
132+
("circle", "Circle", "Draw a circle around the grease pencil layer"),
133+
("strike-through", "Strike-through", "Horizontally strike out the grease pencil layer"),
134+
("x-out", "X-out", "X out the grease pencil layer"),
135+
("helioid", "Helioid", "Make a sun-like decorator (spiked ellipse)")
136+
]
137+
138+
bpy.types.GreasePencil.decorator_style = bpy.props.EnumProperty(
139+
name="Decorators",
140+
items=decorators,
141+
description="The decorator to draw",
142+
default="underline",
143+
)
144+
145+
bpy.types.GreasePencil.tracer_obj = bpy.props.StringProperty()
146+
147+
148+
classes = [
149+
GREASEPENCIL_PT_greasewriter,
150+
GREASEPENCIL_OT_reanimate,
151+
GREASEPENCIL_OT_write,
152+
GREASEPENCIL_OT_trace,
153+
GREASEPENCIL_OT_decorate
154+
]
155+
156+
def register():
157+
init_props()
158+
159+
from bpy.utils import register_class
160+
for cls in classes:
161+
register_class(cls)
162+
163+
def unregister():
164+
from bpy.utils import unregister_class
165+
for cls in reversed(classes):
166+
unregister_class(cls)

GreaseWriter/operators/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from .reanimate import GREASEPENCIL_OT_reanimate
2+
from .write import GREASEPENCIL_OT_write
3+
from .trace import GREASEPENCIL_OT_trace
4+
from .decorate import GREASEPENCIL_OT_decorate

GreaseWriter/operators/decorate.py

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
import bpy
2+
import math
3+
import numpy as np
4+
from .utils import draw_glyph
5+
from .utils import process_stroke_verts_linearly
6+
7+
def ellipse(t, a, b):
8+
return [a * math.cos(t), b * math.sin(t)]
9+
10+
11+
def ellipse_points(origin_x, origin_y, a, b, count=100):
12+
"""
13+
Return the points that make up an ellipse with radii of a & b
14+
"""
15+
points = []
16+
for t in np.linspace(0, 2 * math.pi, count):
17+
points.append(ellipse(t, a, b))
18+
for point in points:
19+
point[0] += origin_x
20+
point[1] += origin_y
21+
return points
22+
23+
24+
def get_glyph_size(gpencil):
25+
"""
26+
Get the size of a grease_pencil object
27+
"""
28+
layer = gpencil.layers[0]
29+
frame = layer.frames[-1]
30+
31+
x_points = []
32+
y_points = []
33+
for stroke in frame.strokes:
34+
for point in stroke.points:
35+
x_points.append(point.co.x)
36+
y_points.append(point.co.y)
37+
38+
min_x = min(x_points)
39+
max_x = max(x_points)
40+
41+
min_y = min(y_points)
42+
max_y = max(y_points)
43+
44+
return min_x, max_x, min_y, max_y
45+
46+
47+
class GREASEPENCIL_OT_decorate(bpy.types.Operator):
48+
bl_label = "Decorate"
49+
bl_idname = "grease_writer.decorate"
50+
bl_description = "Decorates the selected grease pencil layer"
51+
bl_options = {"REGISTER", "UNDO"}
52+
53+
@classmethod
54+
def poll(self, context):
55+
obj = bpy.context.view_layer.objects.active
56+
gpencil = obj.data
57+
if (len(gpencil.layers) > 0 and
58+
len(gpencil.layers[0].frames) > 0):
59+
return True
60+
else:
61+
return False
62+
63+
def execute(self, context):
64+
obj = bpy.context.view_layer.objects.active
65+
gpencil = obj.data
66+
67+
obj_name = obj.name
68+
speed = gpencil.draw_speed
69+
thickness = gpencil.write_thickness
70+
line_height = gpencil.line_height
71+
72+
color = gpencil.write_color
73+
74+
left, right, bottom, top = get_glyph_size(gpencil)
75+
width = right - left
76+
height = top - bottom
77+
78+
style = gpencil.decorator_style
79+
thickness = gpencil.write_thickness
80+
81+
glyph_strokes = []
82+
83+
padding_fac = 0.125
84+
85+
origin_x = (width / 2) + left
86+
origin_y = (height / 2) + bottom
87+
88+
if style == "underline":
89+
v1 = [left - (width * padding_fac) - origin_x, bottom - (line_height * padding_fac) - origin_y]
90+
v2 = [right * (1 + padding_fac) - origin_x, bottom - (line_height * padding_fac) - origin_y]
91+
glyph_strokes.append([v1, v2])
92+
93+
elif style == "over-underline":
94+
v1 = [left - (width * padding_fac) - origin_x, top + (line_height * padding_fac) - origin_y]
95+
v2 = [right * (1 + padding_fac) - origin_x, top + (line_height * padding_fac) - origin_y]
96+
glyph_strokes.append([v1, v2])
97+
98+
v1 = [left - (width * padding_fac) - origin_x, bottom - (line_height * padding_fac) - origin_y]
99+
v2 = [right * (1 + padding_fac) - origin_x, bottom - (line_height * padding_fac) - origin_y]
100+
glyph_strokes.append([v1, v2])
101+
102+
elif style == "x-out":
103+
v1 = [left - (width * padding_fac) - origin_x, top + (line_height * padding_fac) - origin_y]
104+
v2 = [right * (1 + padding_fac) - origin_x, top + (line_height * padding_fac) - origin_y]
105+
v3 = [right * (1 + padding_fac) - origin_x, bottom - (line_height * padding_fac) - origin_y]
106+
v4 = [left - (width * padding_fac) - origin_x, bottom - (line_height * padding_fac) - origin_y]
107+
glyph_strokes.append([v1, v3])
108+
glyph_strokes.append([v2, v4])
109+
110+
elif style == "strike-through":
111+
v1 = [left - (width * padding_fac) - origin_x, bottom + (height / 2) - origin_y]
112+
v2 = [right * (1 + padding_fac) - origin_x, bottom + (height / 2) - origin_y]
113+
glyph_strokes.append([v1, v2])
114+
115+
elif style == "box":
116+
v1 = [left - (width * padding_fac) - origin_x, top + (line_height * padding_fac) - origin_y]
117+
v2 = [right * (1 + padding_fac) - origin_x, top + (line_height * padding_fac) - origin_y]
118+
v3 = [right * (1 + padding_fac) - origin_x, bottom - (line_height * padding_fac) - origin_y]
119+
v4 = [left - (width * padding_fac) - origin_x, bottom - (line_height * padding_fac) - origin_y]
120+
glyph_strokes.append([v1, v2, v3, v4, v1])
121+
122+
elif style == "ellipse":
123+
w_fac = height / width
124+
h_fac = width / height
125+
126+
a = (width / 2) + (width * (padding_fac * 3) * w_fac)
127+
b = (height / 2) + (height * (padding_fac * 3) * h_fac)
128+
glyph_strokes.append(ellipse_points(0, 0, a, b))
129+
130+
elif style == "circle":
131+
if width > height:
132+
longer = width
133+
elif height > width:
134+
longer = height
135+
a = (longer / 2) + (longer * padding_fac)
136+
b = (longer / 2) + (longer * padding_fac)
137+
glyph_strokes.append(ellipse_points(0, 0, a, b))
138+
139+
elif style == "helioid":
140+
if width > height:
141+
w_fac = height / width
142+
h_fac = width / height
143+
a = (width / 2) + (width * (padding_fac * 3) * w_fac)
144+
b = (height / 2) + (height * (padding_fac * 3) * h_fac)
145+
glyph_strokes.append(ellipse_points(0, 0, a, b))
146+
147+
longer = max([a, b])
148+
149+
starts = ellipse_points(0, 0, a * (1 + padding_fac * 2), b * (1 + padding_fac * 2), count=12)
150+
ends = ellipse_points(0, 0, a * (1 + padding_fac * 2) + (longer / 3), b * (1 + padding_fac * 2) + (longer / 3), count=12)
151+
152+
for i in range(len(starts)):
153+
glyph_strokes.append([starts[i], ends[i]])
154+
155+
156+
last_point = gpencil.layers[0].frames[-1].strokes[-1].points[-1]
157+
last_vert = [last_point.co.x, last_point.co.y]
158+
new_vert = glyph_strokes[0][0]
159+
count = len(process_stroke_verts_linearly([last_vert, new_vert], speed)) - 1
160+
161+
bpy.context.scene.frame_current = gpencil.layers[0].frames[-1].frame_number + count
162+
163+
new_gpencil = bpy.data.grease_pencil.new('gpencil')
164+
new_gpencil.draw_speed = speed
165+
new_gpencil.write_thickness = thickness
166+
new_gpencil.write_color = gpencil.write_color
167+
168+
new_obj = bpy.data.objects.new(obj_name + '_' + style, new_gpencil)
169+
bpy.context.scene.collection.objects.link(new_obj)
170+
new_obj.location[0] = origin_x
171+
new_obj.location[1] = origin_y
172+
173+
new_obj.empty_display_size = 0.2
174+
new_obj.parent = obj
175+
176+
bpy.context.view_layer.objects.active = new_obj
177+
178+
draw_glyph(glyph_strokes)
179+
180+
return {"FINISHED"}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[[0.15828, 0.58609], [0.12932, 0.58048], [0.10457, 0.57265], [0.08358, 0.56292], [0.06593, 0.55159], [0.05124, 0.53892], [0.03914, 0.52518], [0.02931, 0.5106], [0.02142, 0.4954], [0.01038, 0.46391], [0.00408, 0.4321], [0.0, 0.37144], [0.00196, 0.31835], [0.00872, 0.27345], [0.01412, 0.2538], [0.02093, 0.2359], [0.02914, 0.21967], [0.03872, 0.20506], [0.04958, 0.19203], [0.06162, 0.18057], [0.07468, 0.17066], [0.08858, 0.16233], [0.10312, 0.15558], [0.1181, 0.15045], [0.13335, 0.14695], [0.14871, 0.14511], [0.16401, 0.14495], [0.17912, 0.14649], [0.1939, 0.14975], [0.20823, 0.15475], [0.22202, 0.16153], [0.23515, 0.1701], [0.24754, 0.18051], [0.2591, 0.1928], [0.26977, 0.20705], [0.27946, 0.22334], [0.28811, 0.24177], [0.29567, 0.26245], [0.30728, 0.31114], [0.31368, 0.37037], [0.31401, 0.40356], [0.31121, 0.43824], [0.30389, 0.47328], [0.298, 0.49048], [0.29028, 0.50717], [0.28045, 0.5231], [0.2682, 0.53801], [0.25321, 0.5516], [0.23511, 0.56356], [0.21353, 0.57354], [0.18806, 0.58118], [0.15828, 0.58609]]
2+
[[0.30242, 0.47723], [0.01168, 0.2634]]

0 commit comments

Comments
 (0)