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 #####
21 "name": "Add Camera Rigs",
22 "author": "Wayne Dixon, Kris Wittig",
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",
34 from bpy
.types
import (
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
:
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
66 def create_root_widget(self
, name
):
67 # Creates a compass-shaped widget.
69 obj
= create_widget(self
, name
)
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)]
123 mesh
.from_pydata(verts
, edges
, [])
127 def create_camera_widget(self
, name
):
128 # Creates a camera ctrl widget
130 obj
= create_widget(self
, name
)
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)]
201 mesh
.from_pydata(verts
, edges
, [])
205 def create_aim_widget(self
, name
):
206 """ Creates a camera aim widget."""
208 obj
= create_widget(self
, name
)
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)]
284 mesh
.from_pydata(verts
, edges
, [])
288 # =========================================================================
289 # Define the fuction to make the camera active
290 # =========================================================================
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
]
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"
310 def poll(cls
, context
):
311 return context
.active_object
is not None
313 def execute(self
, context
):
319 # =========================================================================
320 # Define function to add marker to timeline and bind camera
321 # =========================================================================
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'
330 bpy
.ops
.marker
.rename(name
="cam_" + str(bpy
.context
.scene
.frame_current
))
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)")
348 def poll(cls
, context
):
349 return context
.active_object
is not None
351 def execute(self
, context
):
357 # =========================================================================
358 # Define the function to add an Empty as DOF object
359 # =========================================================================
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)
369 bpy
.ops
.object.empty_add()
370 obj
= bpy
.context
.active_object
372 obj
.name
= "Empty_DOF"
373 # parent to AIM_Child
375 obj
.parent_type
= "BONE"
376 obj
.parent_bone
= "AIM_child"
378 bpy
.ops
.object.location_clear()
379 bpy
.ops
.object.rotation_clear()
381 obj
.location
= bone
.head
383 # make this new empty the dof_object
386 bpy
.context
.scene
.objects
.active
= rig
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"
399 def poll(cls
, context
):
400 return context
.active_object
is not None
402 def execute(self
, context
):
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"
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])
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)
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')
486 con
.subtarget
= "CTRL"
488 con
= rig
.pose
.bones
['CTRL'].constraints
.new('TRACK_TO')
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)
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()
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"
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"
533 cam
.data
.name
= "Dolly_Camera.000"
535 cam_data_name
= bpy
.context
.object.data
.name
536 bpy
.data
.cameras
[cam_data_name
].draw_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
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
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"
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])
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)
623 ctrl
.use_inherit_rotation
= False
624 ctrl
.use_inherit_scale
= False
627 arm
.use_inherit_scale
= False
630 ctrlAim
.parent
= root
631 ctrlAimChild
.parent
= ctrlAim
633 # change display to BBone: it just looks nicer
634 bpy
.context
.object.data
.draw_type
= 'BBONE'
635 # change display to wire for object
636 bpy
.context
.object.draw_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')
671 con
.subtarget
= "CTRL"
673 con
= rig
.pose
.bones
['CTRL'].constraints
.new('TRACK_TO')
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)
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()
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"
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"
718 cam
.data
.name
= "Crane_Camera.000"
720 cam_data_name
= bpy
.context
.object.data
.name
721 bpy
.data
.cameras
[cam_data_name
].draw_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
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
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"
763 def poll(self
, context
):
765 ob
= bpy
.context
.active_object
766 return (ob
["rig_id"] == "Dolly_Rig")
767 except (AttributeError, KeyError, TypeError):
770 def draw(self
, context
):
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
]
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_x_ray', 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")
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"
829 def poll(self
, context
):
831 ob
= bpy
.context
.active_object
832 return (ob
["rig_id"] == "Crane_Rig")
833 except (AttributeError, KeyError, TypeError):
836 def draw(self
, context
):
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
]
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
:
866 "scene.make_camera_active", text
="Make Active Camera", icon
='CAMERA_DATA')
868 context
.active_object
, 'show_x_ray', 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")
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)
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
):
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
)
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
):
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
)
942 # =========================================================================
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",
954 self
.layout
.operator(
955 BuildCraneRig
.bl_idname
,
956 text
="Crane Camera Rig",
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
.INFO_MT_camera_add
.append(add_dolly_crane_buttons
)
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
.INFO_MT_camera_add
.remove(add_dolly_crane_buttons
)
983 if __name__
== "__main__":