Update for 2.8
[blender-addons.git] / camera_dolly_crane_rigs.py
blob0eceebf3ead4ace289994a14acea840cea7a9d9a
1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
20 bl_info = {
21 "name": "Add Camera Rigs",
22 "author": "Wayne Dixon, Kris Wittig",
23 "version": (1, 1, 1),
24 "blender": (2, 77, 0),
25 "location": "View3D > Add > Camera > Dolly or Crane Rig",
26 "description": "Adds a Camera Rig with UI",
27 "warning": "Enable Auto Run Python Scripts in User Preferences > File",
28 "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/"
29 "Py/Scripts/Rigging/Add_Camera_Rigs",
30 "category": "Camera",
33 import bpy
34 from bpy.types import (
35 Operator,
36 Panel,
38 from rna_prop_ui import rna_idprop_ui_prop_get
39 from math import radians
42 # =========================================================================
43 # Define the functions to build the Widgets
44 # =========================================================================
45 def create_widget(self, name):
46 """ Creates an empty widget object for a bone, and returns the object."""
47 obj_name = "WDGT_" + name
48 scene = bpy.context.scene
50 # Check if it already exists
51 if obj_name in scene.objects:
52 return None
53 else:
54 mesh = bpy.data.meshes.new(obj_name)
55 obj = bpy.data.objects.new(obj_name, mesh)
56 scene.objects.link(obj)
58 # this will put the Widget objects out of the way on layer 19
59 WDGT_layers = (False, False, False, False, False, False, False, False, False, True,
60 False, False, False, False, False, False, False, False, False, False)
61 obj.layers = WDGT_layers
63 return obj
66 def create_root_widget(self, name):
67 # Creates a compass-shaped widget.
69 obj = create_widget(self, name)
70 if obj is not None:
71 verts = [(0.2102552056312561, -0.0012103617191314697, 0.21025514602661133),
72 (0.11378927528858185, -0.001210339367389679, 0.274711549282074),
73 (-3.070153553608179e-08, -0.0012103626504540443, 0.29734566807746887),
74 (-0.11378933489322662, -0.0012103542685508728, 0.27471157908439636),
75 (-0.2102552056312561, -0.0012103617191314697, 0.21025516092777252),
76 (-0.27471160888671875, -0.0012103617191314697, 0.11378928273916245),
77 (-0.29734569787979126, -0.0012103617191314697, -1.6809221392577456e-07),
78 (0.29734572768211365, -0.001210331916809082, -1.0901101177296368e-07),
79 (0.2747114598751068, -0.0012103617191314697, 0.11378948390483856),
80 (0.07152898609638214, -0.0012103691697120667, 0.5070746541023254),
81 (-0.07152895629405975, -0.0012103617191314697, 0.5070746541023254),
82 (-0.07152898609638214, -0.0012103915214538574, 0.38030144572257996),
83 (0.07152898609638214, -0.0012103691697120667, 0.38030144572257996),
84 (-0.1325872540473938, -0.0012103617191314697, 0.5070746541023254),
85 (0.13258719444274902, -0.0012103617191314697, 0.5070746541023254),
86 (-3.070154264150915e-08, -0.0012104818597435951, 0.6688110828399658),
87 (-0.274711549282074, -0.0012103617191314697, -0.11378948390483856),
88 (0.274711549282074, -0.001210331916809082, -0.1137893795967102),
89 (0.21025514602661133, -0.001210331916809082, -0.21025525033473969),
90 (0.11378927528858185, -0.001210339367389679, -0.27471160888671875),
91 (-9.030617320604506e-08, -0.0012103328481316566, -0.29734572768211365),
92 (-0.11378933489322662, -0.0012103542685508728, -0.27471157908439636),
93 (-0.2102552056312561, -0.001210331916809082, -0.21025516092777252),
94 (-0.6688110828399658, -0.0012103915214538574, 5.982118267411352e-08),
95 (-0.5070747137069702, -0.0012103915214538574, 0.13258729875087738),
96 (-0.5070747137069702, -0.001210331916809082, -0.1325872540473938),
97 (-0.38030147552490234, -0.0012103617191314697, 0.07152903825044632),
98 (-0.38030147552490234, -0.0012103617191314697, -0.07152897119522095),
99 (-0.5070747137069702, -0.001210331916809082, -0.07152896374464035),
100 (-0.5070747137069702, -0.0012103915214538574, 0.07152900844812393),
101 (0.5070745944976807, -0.001210331916809082, -0.07152891904115677),
102 (0.5070745944976807, -0.001210331916809082, 0.07152905315160751),
103 (0.38030144572257996, -0.0012103617191314697, 0.07152903825044632),
104 (0.38030141592025757, -0.001210331916809082, -0.07152897119522095),
105 (0.5070745944976807, -0.001210331916809082, 0.13258734345436096),
106 (0.5070745944976807, -0.001210331916809082, -0.13258720934391022),
107 (0.6688110828399658, -0.001210331916809082, 5.279173720396102e-08),
108 (1.4811239168466273e-07, -0.001210303045809269, -0.6688110828399658),
109 (-0.13258716464042664, -0.0012103021144866943, -0.5070746541023254),
110 (0.13258737325668335, -0.0012103021144866943, -0.5070746541023254),
111 (-0.07152889668941498, -0.0012103617191314697, -0.38030150532722473),
112 (0.07152910530567169, -0.0012103095650672913, -0.38030150532722473),
113 (0.07152910530567169, -0.0012103095650672913, -0.5070746541023254),
114 (-0.07152886688709259, -0.0012103021144866943, -0.5070746541023254)]
116 edges = [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (7, 8), (0, 8),
117 (10, 11), (9, 12), (11, 12), (10, 13), (9, 14), (13, 15), (14, 15),
118 (16, 22), (17, 18), (18, 19), (19, 20), (20, 21), (21, 22), (7, 17),
119 (6, 16), (23, 24), (23, 25), (24, 29), (25, 28), (26, 27), (26, 29),
120 (27, 28), (31, 32), (30, 33), (32, 33), (31, 34), (30, 35), (34, 36),
121 (35, 36), (37, 38), (37, 39), (38, 43), (39, 42), (40, 41), (40, 43), (41, 42)]
122 mesh = obj.data
123 mesh.from_pydata(verts, edges, [])
124 mesh.update()
127 def create_camera_widget(self, name):
128 # Creates a camera ctrl widget
130 obj = create_widget(self, name)
131 if obj is not None:
132 verts = [(0.13756819069385529, 1.0706068032106941e-08, -0.13756819069385529),
133 (0.1797415018081665, 5.353034016053471e-09, -0.07445136457681656),
134 (0.19455081224441528, -6.381313819948996e-16, 8.504085435845354e-09),
135 (0.1797415018081665, -5.353034016053471e-09, 0.07445138692855835),
136 (0.13756819069385529, -1.0706068032106941e-08, 0.13756819069385529),
137 (0.07445137947797775, -2.1412136064213882e-08, 0.1797415018081665),
138 (-9.740904971522468e-08, -2.1412136064213882e-08, 0.19455081224441528),
139 (-5.87527146933553e-08, 2.1412136064213882e-08, -0.19455081224441528),
140 (0.0744515135884285, 2.1412136064213882e-08, -0.17974145710468292),
141 (0.3317747414112091, 5.353034016053471e-09, -0.04680081456899643),
142 (0.3317747414112091, -5.353034016053471e-09, 0.04680081456899643),
143 (0.24882805347442627, -5.353034016053471e-09, 0.04680081456899643),
144 (0.24882805347442627, 5.353034016053471e-09, -0.04680084437131882),
145 (0.3317747414112091, -5.353034016053471e-09, 0.08675074577331543),
146 (0.3317747414112091, 5.353034016053471e-09, -0.08675074577331543),
147 (0.43759751319885254, 0.0, 0.0), (-0.07445148378610611, -2.1412136064213882e-08, 0.17974145710468292),
148 (-0.07445141673088074, 2.1412136064213882e-08, -0.1797415018081665),
149 (-0.13756820559501648, 1.0706068032106941e-08, -0.1375681608915329),
150 (-0.1797415018081665, 5.353034016053471e-09, -0.07445136457681656),
151 (-0.19455081224441528, -1.2762627639897992e-15, 2.0872269246297037e-08),
152 (-0.1797415018081665, -5.353034016053471e-09, 0.07445140182971954),
153 (-0.1375681608915329, -1.0706068032106941e-08, 0.13756820559501648),
154 (5.1712785165136665e-08, -4.2824272128427765e-08, 0.43759751319885254),
155 (0.08675077557563782, -2.1412136064213882e-08, 0.3317747414112091),
156 (-0.08675073087215424, -2.1412136064213882e-08, 0.3317747414112091),
157 (0.046800870448350906, -2.1412136064213882e-08, 0.24882805347442627),
158 (-0.04680079594254494, -2.1412136064213882e-08, 0.24882805347442627),
159 (-0.04680079594254494, -2.1412136064213882e-08, 0.3317747414112091),
160 (0.04680084437131882, -2.1412136064213882e-08, 0.3317747414112091),
161 (-0.04680076241493225, 2.1412136064213882e-08, -0.3317747414112091),
162 (0.046800874173641205, 2.1412136064213882e-08, -0.3317747414112091),
163 (0.04680086299777031, 2.1412136064213882e-08, -0.24882805347442627),
164 (-0.046800799667835236, 2.1412136064213882e-08, -0.24882805347442627),
165 (0.0867508053779602, 2.1412136064213882e-08, -0.3317747414112091),
166 (-0.08675070106983185, 2.1412136064213882e-08, -0.3317747414112091),
167 (4.711345980012993e-08, 4.2824272128427765e-08, -0.43759751319885254),
168 (-0.43759751319885254, 1.0210102111918393e-14, -9.882624141255292e-08),
169 (-0.3317747414112091, -5.353034016053471e-09, 0.08675065636634827),
170 (-0.3317747414112091, 5.353034016053471e-09, -0.08675083518028259),
171 (-0.24882805347442627, -5.353034016053471e-09, 0.04680076986551285),
172 (-0.24882805347442627, 5.353034016053471e-09, -0.0468008853495121),
173 (-0.3317747414112091, 5.353034016053471e-09, -0.046800896525382996),
174 (-0.3317747414112091, -5.353034016053471e-09, 0.04680073633790016),
175 (-0.08263588696718216, -7.0564780685344886e-09, 0.08263592422008514),
176 (-0.10796899348497391, -3.5282390342672443e-09, 0.04472224414348602),
177 (-0.11686481535434723, -8.411977372806655e-16, 1.2537773486087644e-08),
178 (-0.10796899348497391, 3.5282390342672443e-09, -0.04472222551703453),
179 (-0.08263592422008514, 7.0564780685344886e-09, -0.08263588696718216),
180 (-0.04472225159406662, 7.0564780685344886e-09, -0.10796899348497391),
181 (-0.0447222925722599, -7.0564780685344886e-09, 0.10796897858381271),
182 (0.0447223074734211, 7.0564780685344886e-09, -0.10796897858381271),
183 (-3.529219583242593e-08, 7.0564780685344886e-09, -0.11686481535434723),
184 (-5.8512675593647145e-08, -7.0564780685344886e-09, 0.11686481535434723),
185 (0.04472222924232483, -7.0564780685344886e-09, 0.10796899348497391),
186 (0.08263590186834335, -7.0564780685344886e-09, 0.08263590186834335),
187 (0.10796899348497391, -3.5282390342672443e-09, 0.04472223296761513),
188 (0.11686481535434723, -4.2059886864033273e-16, 5.108323541946902e-09),
189 (0.10796899348497391, 3.5282390342672443e-09, -0.04472222924232483),
190 (0.08263590186834335, 7.0564780685344886e-09, -0.08263590186834335),
191 (3.725290298461914e-08, -2.1412136064213882e-08, 0.24882805347442627)]
192 edges = [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (7, 8), (0, 8),
193 (10, 11), (9, 12), (11, 12), (10, 13), (9, 14), (13, 15), (14, 15), (16, 22),
194 (17, 18), (18, 19), (19, 20), (20, 21), (21, 22), (7, 17), (6, 16), (23, 24),
195 (23, 25), (24, 29), (25, 28), (26, 29), (27, 28), (31, 32), (30, 33), (32, 33),
196 (31, 34), (30, 35), (34, 36), (35, 36), (37, 38), (37, 39), (38, 43), (39, 42),
197 (40, 41), (40, 43), (41, 42), (50, 53), (49, 52), (44, 45), (45, 46), (46, 47),
198 (47, 48), (48, 49), (44, 50), (51, 59), (51, 52), (53, 54), (54, 55), (55, 56),
199 (56, 57), (57, 58), (58, 59), (26, 60), (27, 60), (23, 60)]
200 mesh = obj.data
201 mesh.from_pydata(verts, edges, [])
202 mesh.update()
205 def create_aim_widget(self, name):
206 """ Creates a camera aim widget."""
208 obj = create_widget(self, name)
209 if obj is not None:
210 verts = [(0.15504144132137299, 1.4901161193847656e-08, 0.15504144132137299),
211 (0.20257140696048737, 7.450580596923828e-09, 0.0839078277349472),
212 (0.21926172077655792, -8.881784197001252e-16, -9.584233851001045e-09),
213 (0.20257140696048737, -7.450580596923828e-09, -0.0839078426361084),
214 (0.15504144132137299, -1.4901161193847656e-08, -0.15504144132137299),
215 (0.0839078351855278, -1.4901161193847656e-08, -0.20257140696048737),
216 (-1.0978147457763043e-07, -1.4901161193847656e-08, -0.21926172077655792),
217 (-6.621520043381679e-08, 1.4901161193847656e-08, 0.21926172077655792),
218 (0.08390798419713974, 1.4901161193847656e-08, 0.2025713473558426),
219 (0.39969685673713684, 3.725290298461914e-09, 0.05274524539709091),
220 (0.39969685673713684, -3.725290298461914e-09, -0.05274524167180061),
221 (0.4931790232658386, -3.725290298461914e-09, -0.05274524167180061),
222 (0.4931790232658386, 3.725290298461914e-09, 0.052745271474123),
223 (0.39969685673713684, -7.450580596923828e-09, -0.09776943176984787),
224 (0.39969685673713684, 7.450580596923828e-09, 0.09776943176984787),
225 (0.28043296933174133, 6.226862126577502e-17, -6.226862788321993e-17),
226 (-0.08390796184539795, -1.4901161193847656e-08, -0.2025713473558426),
227 (-0.08390787988901138, 1.4901161193847656e-08, 0.20257140696048737),
228 (-0.15504147112369537, 1.4901161193847656e-08, 0.1550414115190506),
229 (-0.20257140696048737, 7.450580596923828e-09, 0.08390782028436661),
230 (-0.21926172077655792, -1.7763568394002505e-15, -2.352336458955051e-08),
231 (-0.20257140696048737, -7.450580596923828e-09, -0.08390786498785019),
232 (-0.1550414115190506, -1.4901161193847656e-08, -0.15504147112369537),
233 (2.9140544199890428e-08, 2.9802322387695312e-08, 0.2804329991340637),
234 (-0.09776944667100906, 2.9802322387695312e-08, 0.3996969163417816),
235 (0.09776947647333145, 2.9802322387695312e-08, 0.3996969163417816),
236 (-0.052745264023542404, 2.9802322387695312e-08, 0.4931790828704834),
237 (0.05274529010057449, 2.9802322387695312e-08, 0.4931790828704834),
238 (0.052745264023542404, 2.9802322387695312e-08, 0.3996969163417816),
239 (-0.052745234221220016, 2.9802322387695312e-08, 0.3996969163417816),
240 (0.05274517461657524, -2.9802322387695312e-08, -0.3996969759464264),
241 (-0.052745334804058075, -2.9802322387695312e-08, -0.3996969759464264),
242 (-0.05274537205696106, -2.9802322387695312e-08, -0.49317920207977295),
243 (0.05274519696831703, -2.9802322387695312e-08, -0.49317920207977295),
244 (-0.09776955097913742, -2.9802322387695312e-08, -0.3996969163417816),
245 (0.09776940196752548, -2.9802322387695312e-08, -0.39969703555107117),
246 (-7.148475589247028e-08, -2.9802322387695312e-08, -0.2804329991340637),
247 (-0.2804330289363861, 3.552713678800501e-15, 4.234420103443881e-08),
248 (-0.3996969759464264, -7.450580596923828e-09, -0.09776938706636429),
249 (-0.39969685673713684, 7.450580596923828e-09, 0.09776950627565384),
250 (-0.4931790232658386, -3.725290298461914e-09, -0.05274520441889763),
251 (-0.4931790232658386, 3.725290298461914e-09, 0.05274531990289688),
252 (-0.3996969163417816, 3.725290298461914e-09, 0.052745312452316284),
253 (-0.3996969163417816, -3.725290298461914e-09, -0.05274519324302673),
254 (-0.06401804089546204, -7.450580596923828e-09, -0.06401806324720383),
255 (-0.0836436077952385, -3.725290298461914e-09, -0.03464633598923683),
256 (-0.09053517132997513, -8.881784197001252e-16, -9.713016169143884e-09),
257 (-0.0836436077952385, 3.725290298461914e-09, 0.03464631363749504),
258 (-0.06401806324720383, 7.450580596923828e-09, 0.06401804089546204),
259 (-0.03464633598923683, 7.450580596923828e-09, 0.0836436077952385),
260 (-0.034646373242139816, -7.450580596923828e-09, -0.0836435854434967),
261 (0.03464638441801071, 7.450580596923828e-09, 0.0836435854434967),
262 (-2.734086912425937e-08, 7.450580596923828e-09, 0.09053517132997513),
263 (-4.532979147597871e-08, -7.450580596923828e-09, -0.09053517132997513),
264 (0.034646324813365936, -7.450580596923828e-09, -0.0836436077952385),
265 (0.06401804834604263, -7.450580596923828e-09, -0.06401804834604263),
266 (0.0836436077952385, -3.725290298461914e-09, -0.034646324813365936),
267 (0.09053517132997513, -4.440892098500626e-16, -3.957419281164221e-09),
268 (0.0836436077952385, 3.725290298461914e-09, 0.03464632108807564),
269 (0.06401804834604263, 7.450580596923828e-09, 0.06401804834604263),
270 (1.1175870895385742e-08, 2.9802322387695312e-08, 0.4931790828704834),
271 (-3.3337176574832483e-08, 2.4835267176115394e-09, 0.030178390443325043),
272 (-3.9333485801762436e-08, -2.4835271617007493e-09, -0.030178390443325043),
273 (-0.030178390443325043, -7.40148665436918e-16, -7.794483281031717e-09),
274 (0.030178390443325043, -5.921189111737107e-16, -5.875951281097969e-09)]
275 edges = [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (7, 8), (0, 8),
276 (10, 11), (9, 12), (11, 12), (10, 13), (9, 14), (13, 15), (14, 15), (16, 22),
277 (17, 18), (18, 19), (19, 20), (20, 21), (21, 22), (7, 17), (6, 16), (23, 24),
278 (23, 25), (24, 29), (25, 28), (26, 29), (27, 28), (31, 32), (30, 33), (32, 33),
279 (31, 34), (30, 35), (34, 36), (35, 36), (37, 38), (37, 39), (38, 43), (39, 42),
280 (40, 41), (40, 43), (41, 42), (50, 53), (49, 52), (44, 45), (45, 46), (46, 47),
281 (47, 48), (48, 49), (44, 50), (51, 59), (51, 52), (53, 54), (54, 55), (55, 56),
282 (56, 57), (57, 58), (58, 59), (26, 60), (27, 60), (23, 60), (61, 62), (63, 64)]
283 mesh = obj.data
284 mesh.from_pydata(verts, edges, [])
285 mesh.update()
288 # =========================================================================
289 # Define the fuction to make the camera active
290 # =========================================================================
291 def sceneCamera():
292 ob = bpy.context.active_object
293 # find the children on the rig (the camera name)
294 active_cam = ob.children[0].name
295 # cam = bpy.data.cameras[bpy.data.objects[active_cam]]
296 scene_cam = bpy.context.scene.camera
298 if active_cam != scene_cam.name:
299 bpy.context.scene.camera = bpy.data.objects[active_cam]
300 else:
301 return None
304 class MakeCameraActive(Operator):
305 bl_idname = "scene.make_camera_active"
306 bl_label = "Make Camera Active"
307 bl_description = "Makes the camera parented to this rig the active scene camera"
309 @classmethod
310 def poll(cls, context):
311 return context.active_object is not None
313 def execute(self, context):
314 sceneCamera()
316 return {'FINISHED'}
319 # =========================================================================
320 # Define function to add marker to timeline and bind camera
321 # =========================================================================
322 def markerBind():
323 ob = bpy.context.active_object # rig object
324 active_cam = ob.children[0] # camera object
326 # switch area to timeline to add marker
327 bpy.context.area.type = 'TIMELINE'
328 # add marker
329 bpy.ops.marker.add()
330 bpy.ops.marker.rename(name="cam_" + str(bpy.context.scene.frame_current))
331 # select rig camera
332 bpy.context.scene.objects.active = active_cam
333 # bind marker to selected camera
334 bpy.ops.marker.camera_bind()
335 # switch selected object back to the rig
336 bpy.context.scene.objects.active = ob
337 # switch back to 3d view
338 bpy.context.area.type = 'VIEW_3D'
341 class AddMarkerBind(Operator):
342 bl_idname = "add.marker_bind"
343 bl_label = "Add marker and Bind Camera"
344 bl_description = ("Add marker to current frame then bind "
345 "rig camera to it (for camera switching)")
347 @classmethod
348 def poll(cls, context):
349 return context.active_object is not None
351 def execute(self, context):
352 markerBind()
354 return {'FINISHED'}
357 # =========================================================================
358 # Define the function to add an Empty as DOF object
359 # =========================================================================
360 def add_DOF_Empty():
361 smode = bpy.context.mode
362 rig = bpy.context.active_object
363 bone = rig.data.bones['AIM_child']
364 active_cam = rig.children[0].name
365 cam = bpy.data.cameras[bpy.data.objects[active_cam].data.name]
367 bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
368 # Add Empty
369 bpy.ops.object.empty_add()
370 obj = bpy.context.active_object
372 obj.name = "Empty_DOF"
373 # parent to AIM_Child
374 obj.parent = rig
375 obj.parent_type = "BONE"
376 obj.parent_bone = "AIM_child"
377 # clear loc and rot
378 bpy.ops.object.location_clear()
379 bpy.ops.object.rotation_clear()
380 # move to bone head
381 obj.location = bone.head
383 # make this new empty the dof_object
384 cam.dof_object = obj
385 # reselect the rig
386 bpy.context.scene.objects.active = rig
387 obj.select = False
388 rig.select = True
390 bpy.ops.object.mode_set(mode=smode, toggle=False)
393 class AddDofEmpty(Operator):
394 bl_idname = "add.dof_empty"
395 bl_label = "Add DOF Empty"
396 bl_description = "Create empty and add as DOF Object"
398 @classmethod
399 def poll(cls, context):
400 return context.active_object is not None
402 def execute(self, context):
403 add_DOF_Empty()
405 return {'FINISHED'}
408 # =========================================================================
409 # Define the function to build the Dolly Rig
410 # =========================================================================
411 def build_dolly_rig(context):
412 # Define some useful variables:
413 boneLayer = (False, True, False, False, False, False, False, False,
414 False, False, False, False, False, False, False, False,
415 False, False, False, False, False, False, False, False,
416 False, False, False, False, False, False, False, False)
418 # Add the new armature object:
419 bpy.ops.object.armature_add()
420 rig = context.active_object
422 # it will try to name the rig "Dolly_Rig" but if that name exists it will
423 # add 000 to the name
424 if "Dolly_Rig" not in context.scene.objects:
425 rig.name = "Dolly_Rig"
426 else:
427 rig.name = "Dolly_Rig.000"
428 rig["rig_id"] = "Dolly_Rig"
430 bpy.ops.object.mode_set(mode='EDIT')
432 # Remove default bone:
433 bones = rig.data.edit_bones
434 bones.remove(bones[0])
436 # Add new bones:
437 root = bones.new("Root")
438 root.tail = (0.0, 0.0, -5.0)
439 root.roll = radians(90)
441 bpy.ops.object.mode_set(mode='EDIT')
442 ctrlAimChild = bones.new("AIM_child")
443 ctrlAimChild.head = (0.0, 5.0, 3.0)
444 ctrlAimChild.tail = (0.0, 7.0, 3.0)
445 ctrlAimChild.layers = boneLayer
447 ctrlAim = bones.new("AIM")
448 ctrlAim.head = (0.0, 5.0, 3.0)
449 ctrlAim.tail = (0.0, 7.0, 3.0)
451 ctrl = bones.new("CTRL")
452 ctrl.head = (0.0, 0.0, 3.0)
453 ctrl.tail = (0.0, 2.0, 3.0)
455 # Setup hierarchy:
456 ctrl.parent = root
457 ctrlAim.parent = root
458 ctrlAimChild.parent = ctrlAim
460 # jump into pose mode and change bones to euler
461 bpy.ops.object.mode_set(mode='POSE')
462 for x in bpy.context.object.pose.bones:
463 x.rotation_mode = 'XYZ'
465 # jump into pose mode and add the custom bone shapes
466 bpy.ops.object.mode_set(mode='POSE')
467 bpy.context.object.pose.bones["Root"].custom_shape = \
468 bpy.data.objects["WDGT_Camera_Root"] # add the widget as custom shape
469 # set the wireframe checkbox to true
470 bpy.context.object.data.bones["Root"].show_wire = True
471 bpy.context.object.pose.bones["AIM"].custom_shape = \
472 bpy.data.objects["WDGT_AIM"]
473 bpy.context.object.data.bones["AIM"].show_wire = True
474 bpy.context.object.pose.bones["AIM"].custom_shape_transform = \
475 bpy.data.objects[rig.name].pose.bones["AIM_child"] # sets the "At" field to the child
476 bpy.context.object.pose.bones["CTRL"].custom_shape = \
477 bpy.data.objects["WDGT_CTRL"]
478 bpy.context.object.data.bones["CTRL"].show_wire = True
480 # jump into object mode
481 bpy.ops.object.mode_set(mode='OBJECT')
483 # Add constraints to bones:
484 con = rig.pose.bones['AIM_child'].constraints.new('COPY_ROTATION')
485 con.target = rig
486 con.subtarget = "CTRL"
488 con = rig.pose.bones['CTRL'].constraints.new('TRACK_TO')
489 con.target = rig
490 con.subtarget = "AIM"
491 con.use_target_z = True
493 # Add custom Bone property to CTRL bone
494 ob = bpy.context.object.pose.bones['CTRL']
495 prop = rna_idprop_ui_prop_get(ob, "Lock", create=True)
496 ob["Lock"] = 1.0
497 prop["soft_min"] = prop["min"] = 0.0
498 prop["soft_max"] = prop["max"] = 1.0
500 # Add Driver to Lock/Unlock Camera from Aim Target
501 rig = bpy.context.scene.objects.active
502 pose_bone = bpy.data.objects[rig.name].pose.bones['CTRL']
504 constraint = pose_bone.constraints["Track To"]
505 inf_driver = constraint.driver_add('influence')
506 inf_driver.driver.type = 'SCRIPTED'
507 var = inf_driver.driver.variables.new()
508 var.name = 'var'
509 var.type = 'SINGLE_PROP'
511 # Target the Custom bone property
512 var.targets[0].id = bpy.data.objects[rig.name]
513 var.targets[0].data_path = 'pose.bones["CTRL"]["Lock"]'
514 inf_driver.driver.expression = 'var'
516 # Add the camera object:
517 bpy.ops.object.mode_set(mode='OBJECT')
519 bpy.ops.object.camera_add(
520 view_align=False, enter_editmode=False, location=(0, 0, 0), rotation=(0, 0, 0))
521 cam = bpy.context.active_object
523 # this will name the Camera Object
524 if 'Dolly_Camera' not in context.scene.objects:
525 cam.name = "Dolly_Camera"
526 else:
527 cam.name = "Dolly_Camera.000"
529 # this will name the camera Data Object
530 if "Dolly_Camera" not in bpy.context.scene.objects.data.camera:
531 cam.data.name = "Dolly_Camera"
532 else:
533 cam.data.name = "Dolly_Camera.000"
535 cam_data_name = bpy.context.object.data.name
536 bpy.data.cameras[cam_data_name].display_size = 1.0
537 cam.rotation_euler[0] = 1.5708 # rotate the camera 90 degrees in x
538 cam.location = (0.0, -2.0, 0.0) # move the camera to the correct postion
539 cam.parent = rig
540 cam.parent_type = "BONE"
541 cam.parent_bone = "CTRL"
543 # Add blank drivers to lock the camera loc, rot scale
544 cam.driver_add('location', 0)
545 cam.driver_add('location', 1)
546 cam.driver_add('location', 2)
547 cam.driver_add('rotation_euler', 0)
548 cam.driver_add('rotation_euler', 1)
549 cam.driver_add('rotation_euler', 2)
550 cam.driver_add('scale', 0)
551 cam.driver_add('scale', 1)
552 cam.driver_add('scale', 2)
554 # Set new camera as active camera
555 bpy.context.scene.camera = cam
557 # make sure the camera is selectable by default (this can be locked in the UI)
558 bpy.context.object.hide_select = False
560 # make the rig the active object before finishing
561 bpy.context.scene.objects.active = rig
562 cam.select = False
563 rig.select = True
565 return rig
568 # =========================================================================
569 # Define the function to build the Crane Rig
570 # =========================================================================
571 def build_crane_rig(context):
572 # Define some useful variables:
573 boneLayer = (False, True, False, False, False, False, False, False,
574 False, False, False, False, False, False, False, False,
575 False, False, False, False, False, False, False, False,
576 False, False, False, False, False, False, False, False)
578 # Add the new armature object:
579 bpy.ops.object.armature_add()
580 rig = context.active_object
582 # it will try to name the rig "Dolly_Rig" but if that name exists it will
583 # add .000 to the name
584 if "Crane_Rig" not in context.scene.objects:
585 rig.name = "Crane_Rig"
586 else:
587 rig.name = "Crane_Rig.000"
588 rig["rig_id"] = "Crane_Rig"
590 bpy.ops.object.mode_set(mode='EDIT')
592 # Remove default bone:
593 bones = rig.data.edit_bones
594 bones.remove(bones[0])
596 # Add new bones:
597 root = bones.new("Root")
598 root.tail = (0.0, 0.0, -5.0)
600 ctrlAimChild = bones.new("AIM_child")
601 ctrlAimChild.head = (0.0, 10.0, 1.0)
602 ctrlAimChild.tail = (0.0, 12.0, 1.0)
603 ctrlAimChild.layers = boneLayer
605 ctrlAim = bones.new("AIM")
606 ctrlAim.head = (0.0, 10.0, 1.0)
607 ctrlAim.tail = (0.0, 12.0, 1.0)
609 ctrl = bones.new("CTRL")
610 ctrl.head = (0.0, 1.0, 1.0)
611 ctrl.tail = (0.0, 3.0, 1.0)
613 arm = bones.new("Crane_Arm")
614 arm.head = (0.0, 0.0, 1.0)
615 arm.tail = (0.0, 1.0, 1.0)
617 height = bones.new("Height")
618 height.head = (0.0, 0.0, 0.0)
619 height.tail = (0.0, 0.0, 1.0)
621 # Setup hierarchy:
622 ctrl.parent = arm
623 ctrl.use_inherit_rotation = False
624 ctrl.use_inherit_scale = False
626 arm.parent = height
627 arm.use_inherit_scale = False
629 height.parent = root
630 ctrlAim.parent = root
631 ctrlAimChild.parent = ctrlAim
633 # change display to BBone: it just looks nicer
634 bpy.context.object.data.display_type = 'BBONE'
635 # change display to wire for object
636 bpy.context.object.display_type = 'WIRE'
638 # jump into pose mode and change bones to euler
639 bpy.ops.object.mode_set(mode='POSE')
640 for x in bpy.context.object.pose.bones:
641 x.rotation_mode = 'XYZ'
643 # lock the relevant loc, rot and scale
644 bpy.context.object.pose.bones[
645 "Crane_Arm"].lock_rotation = [False, True, False]
646 bpy.context.object.pose.bones["Crane_Arm"].lock_scale = [True, False, True]
647 bpy.context.object.pose.bones["Height"].lock_location = [True, True, True]
648 bpy.context.object.pose.bones["Height"].lock_rotation = [True, True, True]
649 bpy.context.object.pose.bones["Height"].lock_scale = [True, False, True]
651 # add the custom bone shapes
652 bpy.context.object.pose.bones["Root"].custom_shape = bpy.data.objects[
653 "WDGT_Camera_Root"] # add the widget as custom shape
654 # set the wireframe checkbox to true
655 bpy.context.object.data.bones["Root"].show_wire = True
656 bpy.context.object.pose.bones[
657 "AIM"].custom_shape = bpy.data.objects["WDGT_AIM"]
658 bpy.context.object.data.bones["AIM"].show_wire = True
659 bpy.context.object.pose.bones["AIM"].custom_shape_transform = bpy.data.objects[
660 rig.name].pose.bones["AIM_child"] # sets the "At" field to the child
661 bpy.context.object.pose.bones[
662 "CTRL"].custom_shape = bpy.data.objects["WDGT_CTRL"]
663 bpy.context.object.data.bones["CTRL"].show_wire = True
665 # jump into object mode
666 bpy.ops.object.mode_set(mode='OBJECT')
668 # Add constraints to bones:
669 con = rig.pose.bones['AIM_child'].constraints.new('COPY_ROTATION')
670 con.target = rig
671 con.subtarget = "CTRL"
673 con = rig.pose.bones['CTRL'].constraints.new('TRACK_TO')
674 con.target = rig
675 con.subtarget = "AIM"
676 con.use_target_z = True
678 # Add custom Bone property to CTRL bone
679 ob = bpy.context.object.pose.bones['CTRL']
680 prop = rna_idprop_ui_prop_get(ob, "Lock", create=True)
681 ob["Lock"] = 1.0
682 prop["soft_min"] = prop["min"] = 0.0
683 prop["soft_max"] = prop["max"] = 1.0
685 # Add Driver to Lock/Unlock Camera from Aim Target
686 rig = bpy.context.scene.objects.active
687 pose_bone = bpy.data.objects[rig.name].pose.bones['CTRL']
689 constraint = pose_bone.constraints["Track To"]
690 inf_driver = constraint.driver_add('influence')
691 inf_driver.driver.type = 'SCRIPTED'
692 var = inf_driver.driver.variables.new()
693 var.name = 'var'
694 var.type = 'SINGLE_PROP'
696 # Target the Custom bone property
697 var.targets[0].id = bpy.data.objects[rig.name]
698 var.targets[0].data_path = 'pose.bones["CTRL"]["Lock"]'
699 inf_driver.driver.expression = 'var'
701 # Add the camera object:
702 bpy.ops.object.mode_set(mode='OBJECT')
704 bpy.ops.object.camera_add(
705 view_align=False, enter_editmode=False, location=(0, 0, 0), rotation=(0, 0, 0))
706 cam = bpy.context.active_object
708 # this will name the Camera Object
709 if 'Crane_Camera' not in context.scene.objects:
710 cam.name = "Crane_Camera"
711 else:
712 cam.name = "Crane_Camera.000"
714 # this will name the camera Data Object
715 if "Crane_Camera" not in bpy.context.scene.objects.data.camera:
716 cam.data.name = "Crane_Camera"
717 else:
718 cam.data.name = "Crane_Camera.000"
720 cam_data_name = bpy.context.object.data.name
721 bpy.data.cameras[cam_data_name].display_size = 1.0
722 cam.rotation_euler[0] = 1.5708 # rotate the camera 90 degrees in x
723 cam.location = (0.0, -2.0, 0.0) # move the camera to the correct postion
724 cam.parent = rig
725 cam.parent_type = "BONE"
726 cam.parent_bone = "CTRL"
728 # Add blank drivers to lock the camera loc, rot scale
729 cam.driver_add('location', 0)
730 cam.driver_add('location', 1)
731 cam.driver_add('location', 2)
732 cam.driver_add('rotation_euler', 0)
733 cam.driver_add('rotation_euler', 1)
734 cam.driver_add('rotation_euler', 2)
735 cam.driver_add('scale', 0)
736 cam.driver_add('scale', 1)
737 cam.driver_add('scale', 2)
739 # Set new camera as active camera
740 bpy.context.scene.camera = cam
742 # make sure the camera is selectable by default (this can be locked in the UI)
743 bpy.context.object.hide_select = False
745 # make the rig the active object before finishing
746 bpy.context.scene.objects.active = rig
747 cam.select = False
748 rig.select = True
750 return rig
753 # =========================================================================
754 # This is the UI for the Dolly Camera Rig
755 # =========================================================================
756 class DollyCameraUI(Panel):
757 bl_idname = "CAMERA_DOLLY_PT_ui"
758 bl_space_type = 'VIEW_3D'
759 bl_region_type = 'UI'
760 bl_label = "Dolly Camera UI"
762 @classmethod
763 def poll(self, context):
764 try:
765 ob = bpy.context.active_object
766 return (ob["rig_id"] == "Dolly_Rig")
767 except (AttributeError, KeyError, TypeError):
768 return False
770 def draw(self, context):
771 layout = self.layout
772 ob = bpy.context.active_object
773 pose_bones = context.active_object.pose.bones
774 # find the children on the rig (the camera name)
775 active_cam = ob.children[0].name
777 cam = bpy.data.cameras[bpy.data.objects[active_cam].data.name]
778 box = layout.box()
779 col = box.column()
780 col.separator()
782 # Display Camera Properties
783 col.label(text="Clipping:")
784 col.prop(cam, "clip_start", text="Start")
785 col.prop(cam, "clip_end", text="End")
786 col.prop(cam, "type")
787 col.prop(cam, "dof_object")
789 if cam.dof_object is None:
790 col.operator("add.dof_empty", text="Add DOF Empty")
791 col.prop(cam, "dof_distance")
792 # added the comp guides here
793 col.prop_menu_enum(cam, "show_guide", text="Compostion Guides")
794 col.prop(bpy.data.objects[active_cam],
795 "hide_select", text="Make Camera Unselectable")
797 col.operator("add.marker_bind", text="Add Marker and Bind")
799 if bpy.context.scene.camera.name != active_cam:
800 col.operator("scene.make_camera_active",
801 text="Make Active Camera", icon='CAMERA_DATA')
803 col.prop(context.active_object,
804 'show_in_front', toggle=False, text='X Ray')
805 col.prop(cam, "show_limits")
806 col.prop(cam, "show_safe_areas")
807 col.prop(cam, "show_passepartout")
808 col.prop(cam, "passepartout_alpha")
810 # Camera Lens
811 col.label(text="Focal Length:")
812 col.prop(cam, "lens", text="Angle")
814 # Track to Constraint
815 col.label(text="Tracking:")
816 col.prop(pose_bones["CTRL"], '["Lock"]', text="Aim Lock", slider=True)
819 # =========================================================================
820 # This is the UI for the Crane Rig Camera
821 # =========================================================================
822 class CraneCameraUI(Panel):
823 bl_idname = "CAMERA_CRANE_PT_ui"
824 bl_space_type = 'VIEW_3D'
825 bl_region_type = 'UI'
826 bl_label = "Crane Camera UI"
828 @classmethod
829 def poll(self, context):
830 try:
831 ob = bpy.context.active_object
832 return (ob["rig_id"] == "Crane_Rig")
833 except (AttributeError, KeyError, TypeError):
834 return False
836 def draw(self, context):
837 layout = self.layout
838 ob = bpy.context.active_object
839 pose_bones = context.active_object.pose.bones
840 # find the children on the rig (camera)
841 active_cam = ob.children[0].name
842 cam = bpy.data.cameras[bpy.data.objects[active_cam].data.name]
844 box = layout.box()
845 col = box.column()
846 col.separator()
848 # Display Camera Properties
849 col.label(text="Clipping:")
850 col.prop(cam, "clip_start", text="Start")
851 col.prop(cam, "clip_end", text="End")
852 col.prop(cam, "type")
853 col.prop(cam, "dof_object")
855 if cam.dof_object is None:
856 col.operator("add.dof_empty", text="Add DOF object")
857 col.prop(cam, "dof_distance")
858 # added the comp guides here
859 col.prop_menu_enum(cam, "show_guide", text="Compostion Guides")
860 col.prop(bpy.data.objects[active_cam],
861 "hide_select", text="Make Camera Unselectable")
862 col.operator("add.marker_bind", text="Add Marker and Bind")
864 if bpy.context.scene.camera.name != active_cam:
865 col.operator(
866 "scene.make_camera_active", text="Make Active Camera", icon='CAMERA_DATA')
867 col.prop(
868 context.active_object, 'show_in_front', toggle=False, text='X Ray')
869 col.prop(cam, "show_limits")
870 col.prop(cam, "show_safe_areas")
871 col.prop(cam, "show_passepartout")
872 col.prop(cam, "passepartout_alpha")
874 # Camera Lens
875 col.label(text="Focal Length:")
876 col.prop(cam, "lens", text="Angle")
878 # Track to Constraint
879 col.label(text="Tracking:")
880 col.prop(pose_bones["CTRL"], '["Lock"]', text="Aim Lock", slider=True)
882 # make this camera active if more than one camera exists
884 if cam != bpy.context.scene.camera:
885 col.op(, text="Make Active Camera", toggle=True)
888 box = layout.box()
889 col = box.column()
890 col.separator()
892 # Crane arm stuff
893 col.label(text="Crane Arm:")
894 col.prop(pose_bones["Height"], 'scale', index=1, text="Arm Height")
895 col.prop(pose_bones["Crane_Arm"], 'scale', index=1, text="Arm Length")
898 # =========================================================================
899 # This is the operator that will call all the functions and build the dolly rig
900 # =========================================================================
901 class BuildDollyRig(Operator):
902 bl_idname = "object.build_dolly_rig"
903 bl_label = "Build Dolly Camera Rig"
904 bl_description = "Build a Camera Dolly Rig"
905 bl_options = {'REGISTER', 'UNDO'}
907 def execute(self, context):
909 # build the Widgets
910 create_root_widget(self, "Camera_Root")
911 create_camera_widget(self, "CTRL")
912 create_aim_widget(self, "AIM")
914 # call the function to build the rig
915 build_dolly_rig(context)
917 return {'FINISHED'}
920 # =========================================================================
921 # This is the operator that will call all the functions and build the crane rig
922 # =========================================================================
923 class BuildCraneRig(Operator):
924 bl_idname = "object.build_crane_rig"
925 bl_label = "Build Crane Camera Rig"
926 bl_description = "Build a Camera Crane Rig"
927 bl_options = {'REGISTER', 'UNDO'}
929 def execute(self, context):
931 # build the Widgets
932 create_root_widget(self, "Camera_Root")
933 create_camera_widget(self, "CTRL")
934 create_aim_widget(self, "AIM")
936 # call the function to build the rig
937 build_crane_rig(context)
939 return {'FINISHED'}
942 # =========================================================================
943 # Registration:
944 # =========================================================================
946 # dolly and crane entries in the Add Object > Camera Menu
947 def add_dolly_crane_buttons(self, context):
948 if context.mode == 'OBJECT':
949 self.layout.operator(
950 BuildDollyRig.bl_idname,
951 text="Dolly Camera Rig",
952 icon='CAMERA_DATA'
954 self.layout.operator(
955 BuildCraneRig.bl_idname,
956 text="Crane Camera Rig",
957 icon='CAMERA_DATA'
961 def register():
962 bpy.utils.register_class(BuildDollyRig)
963 bpy.utils.register_class(BuildCraneRig)
964 bpy.utils.register_class(DollyCameraUI)
965 bpy.utils.register_class(CraneCameraUI)
966 bpy.utils.register_class(MakeCameraActive)
967 bpy.utils.register_class(AddMarkerBind)
968 bpy.utils.register_class(AddDofEmpty)
969 bpy.types.VIEW3D_MT_camera_add.append(add_dolly_crane_buttons)
972 def unregister():
973 bpy.utils.unregister_class(BuildDollyRig)
974 bpy.utils.unregister_class(BuildCraneRig)
975 bpy.utils.unregister_class(DollyCameraUI)
976 bpy.utils.unregister_class(CraneCameraUI)
977 bpy.utils.unregister_class(MakeCameraActive)
978 bpy.utils.unregister_class(AddMarkerBind)
979 bpy.utils.unregister_class(AddDofEmpty)
980 bpy.types.VIEW3D_MT_camera_add.remove(add_dolly_crane_buttons)
983 if __name__ == "__main__":
984 register()