Package nukescripts :: Module cameratracker
[hide private]
[frames] | no frames]

Source Code for Module nukescripts.cameratracker

  1  """Functions used by the CameraTracker node""" 
  2   
  3  import nuke 
  4  import nukescripts 
  5  import os 
  6   
  7  import camerapresets 
  8   
  9  # 
 10  # Initialisation 
 11  # 
 12   
13 -def populateExportMenu(cameraTracker):
14 """Populate the export menu on a CameraTracker node.""" 15 # These are the entries that will appear in the CameraTracker's export menu. 16 # You can extend this list with your own entries if you like. 17 entries = [ 18 # Label # Script to execute when the bake button is pressed. # Tooltip for this entry. 19 ( 'Camera', 'nukescripts.cameratracker.createCamera(nuke.thisNode())', "Create a Camera linked to the calculated projection."), 20 ( 'Camera rig', 'nukescripts.cameratracker.createCameraRig(nuke.thisNode())', "Create a multi-view rig with a Camera per view."), 21 ( 'Scene', 'nukescripts.cameratracker.createScene(nuke.thisNode())', "Create a Scene with a Camera and PointCloud for the camera solve."), 22 ( 'Scene+', 'nukescripts.cameratracker.createEverything(nuke.thisNode())', "Create a Scene with a Camera, PointCloud, ScanlineRender, and LensDistortion (Undistort) node."), 23 ( 'Point cloud', 'nukescripts.cameratracker.createPointCloud(nuke.thisNode())', "Create a PointCloud for the camera solve."), 24 ( 'Distortion', 'nukescripts.cameratracker.createLensDistortion(nuke.thisNode())', 25 "Create a LensDistortion node preconfigured for distortion using the same settings as the CameraTracker. " + 26 "You can use this node to distort your CG or other elements before comping them back over the input footage."), 27 ( 'Undistortion', 'nukescripts.cameratracker.createUndistortion(nuke.thisNode())', 28 "Create a LensDistortion node preconfigured for undistortion using the same settings as the CameraTracker. " + 29 "You can apply this node to your input footage to make it match CG elements rendered using the calculated camera."), 30 ( 'Cards', 'nukescripts.cameratracker.createCards(nuke.thisNode())', "Create a group of cards.") 31 # Add your own entries here, if desired. 32 ] 33 34 k = cameraTracker['exportMenu'] 35 k.setValues([ "%s\t%s" % (script, label) for label, script, _ in entries ]) 36 37 # Calculate a tooltip which describes all of the available export options. 38 tooltipLines = [ "Create new camera and point cloud nodes based on the results of the solve. The available options are:", "" ] 39 for label, _, tooltip in entries: 40 tooltipLines.append("<b>%s:</b> %s" % (label, tooltip)) 41 42 k.setTooltip(os.linesep.join(tooltipLines))
43 44
45 -def populateFilmBackPresets(cameraTracker):
46 """Populate the film back presets menu on a CameraTracker node.""" 47 # These are the entries that will appear in the CameraTracker's film back presets menu. 48 # You can extend this list with your own entries by modifying camerapresets.py 49 50 k = cameraTracker['filmBackSizePresets'] 51 k.setValues(["%s\t%s" % (idx, label) for idx, label in enumerate(nukescripts.camerapresets.getLabels())])
52 53 # 54 # Export functions 55 # 56
57 -def createCamera(solver):
58 """Create a camera node based on the projection calculated by the solver.""" 59 x = solver.xpos() 60 y = solver.ypos() 61 w = solver.screenWidth() 62 h = solver.screenHeight() 63 m = int(x + w/2) 64 numviews = len( nuke.views() ) 65 link = False 66 linkKnob = solver.knob("linkOutput") 67 if linkKnob: 68 link = bool(linkKnob.getValue()) 69 70 camera = nuke.createNode('Camera', '', False) 71 camera.setInput(0,None) 72 camera.setXYpos(m - int(camera.screenWidth()/2), y + w) 73 if link: 74 camera.knob("focal").setExpression(solver.name() + ".focalLength") 75 camera.knob("haperture").setExpression(solver.name() + ".aperture.x") 76 camera.knob("vaperture").setExpression(solver.name() + ".aperture.y") 77 camera.knob("translate").setExpression(solver.name() + ".camTranslate") 78 camera.knob("rotate").setExpression(solver.name() + ".camRotate") 79 camera.knob("win_translate").setExpression(solver.name() + ".windowTranslate") 80 camera.knob("win_scale").setExpression(solver.name() + ".windowScale") 81 else: 82 camera.knob("focal").fromScript(solver.knob("focalLength").toScript(False)) 83 camera.knob("translate").fromScript(solver.knob("camTranslate").toScript(False)) 84 camera.knob("rotate").fromScript(solver.knob("camRotate").toScript(False)) 85 camera.knob("win_translate").fromScript(solver.knob("windowTranslate").toScript(False)) 86 camera.knob("win_scale").fromScript(solver.knob("windowScale").toScript(False)) 87 for i in xrange(numviews): 88 camera.knob("haperture").setValue(solver.knob("aperture").getValue(0,i+1),0,0,i+1) 89 camera.knob("vaperture").setValue(solver.knob("aperture").getValue(1,i+1),0,0,i+1)
90 91
92 -def createCameraRig(solver):
93 """Create a multi-view rig with a camera per view.""" 94 numviews = len( nuke.views() ) 95 if numviews < 2: 96 nuke.message("Creating a camera rig requires multiple views.\n" + 97 "You can add additional views in your <em>Project Settings</em>, on the <em>Views</em> tab.") 98 return 99 100 x = solver.xpos() 101 y = solver.ypos() 102 w = solver.screenWidth() 103 h = solver.screenHeight() 104 m = int(x + w/2) 105 link = False 106 linkKnob = solver.knob("linkOutput") 107 if linkKnob: 108 link = bool(linkKnob.getValue()) 109 110 join = nuke.nodes.JoinViews() 111 join.setInput(0,None) 112 join.setXYpos(m + int(w*1.5) + int(w * numviews/2), y + w) 113 114 for i in xrange(numviews): 115 viewStr = nuke.views()[i] 116 camera = nuke.nodes.Camera() 117 camera.setInput(0,None) 118 if link: 119 camera.knob("focal").setExpression(solver.name() + ".focalLength." + viewStr) 120 camera.knob("haperture").setExpression(solver.name() + ".aperture." + viewStr + ".x") 121 camera.knob("vaperture").setExpression(solver.name() + ".aperture." + viewStr + ".y") 122 camera.knob("translate").setExpression(solver.name() + ".camTranslate." + viewStr) 123 camera.knob("rotate").setExpression(solver.name() + ".camRotate." + viewStr) 124 camera.knob("win_translate").setExpression(solver.name() + ".windowTranslate." + viewStr) 125 camera.knob("win_scale").setExpression(solver.name() + ".windowScale." + viewStr) 126 else: 127 if solver.knob("focalLength").isAnimated(): 128 camera.knob("focal").copyAnimation(0,solver.knob("focalLength").animation(0,i+1)) 129 else: 130 camera.knob("focal").setValue(solver.knob("focalLength").getValue(0,i+1),0,0,i+1) 131 if solver.knob("camTranslate").isAnimated(): 132 camera.knob("translate").copyAnimation(0,solver.knob("camTranslate").animation(0,i+1)) 133 camera.knob("translate").copyAnimation(1,solver.knob("camTranslate").animation(1,i+1)) 134 camera.knob("translate").copyAnimation(2,solver.knob("camTranslate").animation(2,i+1)) 135 else: 136 camera.knob("translate").setValue(solver.knob("camTranslate").getValue(0,i+1),0,0,i+1) 137 camera.knob("translate").setValue(solver.knob("camTranslate").getValue(1,i+1),1,0,i+1) 138 camera.knob("translate").setValue(solver.knob("camTranslate").getValue(2,i+1),2,0,i+1) 139 if solver.knob("camRotate").isAnimated(): 140 camera.knob("rotate").copyAnimation(0,solver.knob("camRotate").animation(0,i+1)) 141 camera.knob("rotate").copyAnimation(1,solver.knob("camRotate").animation(1,i+1)) 142 camera.knob("rotate").copyAnimation(2,solver.knob("camRotate").animation(2,i+1)) 143 else: 144 camera.knob("rotate").setValue(solver.knob("camRotate").getValue(0,i+1),0,0,i+1) 145 camera.knob("rotate").setValue(solver.knob("camRotate").getValue(1,i+1),1,0,i+1) 146 camera.knob("rotate").setValue(solver.knob("camRotate").getValue(2,i+1),2,0,i+1) 147 camera.knob("win_translate").setValue(solver.knob("windowTranslate").getValue(0,i+1),0,0,i+1) 148 camera.knob("win_scale").setValue(solver.knob("windowScale").getValue(0,i+1),0,0,i+1) 149 camera.knob("haperture").setValue(solver.knob("aperture").getValue(0,i+1),0,0,i+1) 150 camera.knob("vaperture").setValue(solver.knob("aperture").getValue(1,i+1),0,0,i+1) 151 camera.setXYpos(m + 2*w + w*i, y) 152 if numviews==2: 153 if i==0: 154 camera.knob("gl_color").setValue(0xFF0000FF) 155 camera.knob("tile_color").setValue(0xFF0000FF) 156 if i==1: 157 camera.knob("gl_color").setValue(0x00FF00FF) 158 camera.knob("tile_color").setValue(0x00FF00FF) 159 camera.setName( viewStr ) 160 join.setInput(i,camera)
161 162
163 -def createScene(cameraTracker):
164 """Create a Scene with a Camera and PointCloud for the camera solve.""" 165 scene = nuke.createNode('Scene', '', False) 166 camera = nuke.createNode('Camera', '', False) 167 pointCloud = nuke.createNode('CameraTrackerPointCloud', '', False) 168 sw = scene.screenWidth() 169 sh = scene.screenHeight() 170 x = cameraTracker.xpos() 171 y = cameraTracker.ypos() 172 w = cameraTracker.screenWidth() 173 h = cameraTracker.screenHeight() 174 m = int(x + w/2) 175 camera.setXYpos(m + w, y + w + int((h-sh)/2)) 176 pointCloud.setXYpos(m - int(pointCloud.screenWidth()/2), y + w) 177 scene.setXYpos(m - int(sw/2), y + w*2 - int((sh-h)/2)) 178 camera.setInput(0,None) 179 pointCloud.setInput(0,cameraTracker) 180 scene.setInput(0,camera) 181 scene.setInput(1,pointCloud) 182 numviews = len( nuke.views() ) 183 link = False 184 linkKnob = cameraTracker.knob("linkOutput") 185 if linkKnob: 186 link = bool(linkKnob.getValue()) 187 if link: 188 camera.knob("focal").setExpression(cameraTracker.name() + ".focalLength") 189 camera.knob("haperture").setExpression(cameraTracker.name() + ".aperture.x") 190 camera.knob("vaperture").setExpression(cameraTracker.name() + ".aperture.y") 191 camera.knob("translate").setExpression(cameraTracker.name() + ".camTranslate") 192 camera.knob("rotate").setExpression(cameraTracker.name() + ".camRotate") 193 camera.knob("win_translate").setExpression(cameraTracker.name() + ".windowTranslate") 194 camera.knob("win_scale").setExpression(cameraTracker.name() + ".windowScale") 195 else: 196 camera.knob("focal").fromScript(cameraTracker.knob("focalLength").toScript(False)) 197 camera.knob("translate").fromScript(cameraTracker.knob("camTranslate").toScript(False)) 198 camera.knob("rotate").fromScript(cameraTracker.knob("camRotate").toScript(False)) 199 camera.knob("win_translate").fromScript(cameraTracker.knob("windowTranslate").toScript(False)) 200 camera.knob("win_scale").fromScript(cameraTracker.knob("windowScale").toScript(False)) 201 for i in xrange(numviews): 202 camera.knob("haperture").setValue(cameraTracker.knob("aperture").getValue(0,i+1),0,0,i+1) 203 camera.knob("vaperture").setValue(cameraTracker.knob("aperture").getValue(1,i+1),0,0,i+1) 204 return [scene, camera, pointCloud]
205 206
207 -def createEverything(cameraTracker):
208 """Create a Scene with a Camera, PointCloud, ScanlineRender, and LensDistortion (Undistort) node.""" 209 [scene, camera, pointCloud] = createScene(cameraTracker); 210 lensDistort = createUndistortion(cameraTracker) 211 scanline = nuke.createNode('ScanlineRender', '', False) 212 # need to create a dummy camera here, as there seems to be a bug where calling 213 # .screenWidth() on the scene or camera objects always returns 0. 214 dummyCamera = nuke.createNode('Camera', '', False) 215 # creating our 4 dots 216 cameraToSceneDot = nuke.createNode('Dot', '', False) 217 cameraToScanlineRenderDot = nuke.createNode('Dot', '', False) 218 lensToScanlineDot = nuke.createNode('Dot', '', False) 219 # setting up widths & heights 220 sw = dummyCamera.screenWidth() 221 sh = dummyCamera.screenHeight() 222 x = cameraTracker.xpos() 223 y = cameraTracker.ypos() 224 w = cameraTracker.screenWidth() 225 h = cameraTracker.screenHeight() 226 # have to hard-code our dot size because of the the 227 # .screenWidth()/Height() always returning 0 bug. 228 dw = 12 229 dh = 12 230 m = int(x + w/2) 231 hspacing = int(w*1.5) 232 vspacing = w 233 # deleting our dummy camera 234 nuke.delete(dummyCamera); 235 # setting the node positions 236 camera.setXYpos( m - hspacing - int(sw/2), y + vspacing + int((h-sh)/2)) 237 pointCloud.setXYpos( m - int(w/2), y + vspacing) 238 lensDistort.setXYpos( m + hspacing - int(w/2), y + vspacing) 239 scene.setXYpos( m - int(sw/2), y + 2*vspacing + int((h-sh)/2)) 240 scanline.setXYpos( m - int(w/2), y + 3*vspacing) 241 # setting dot positions 242 cameraToSceneDot.setXYpos( m - hspacing - int(dw/2), y + 2*vspacing + int((h-dh)/2) ) 243 cameraToScanlineRenderDot.setXYpos( m - hspacing - int(dw/2), y + 3*vspacing + int((h-dh)/2) ) 244 lensToScanlineDot.setXYpos( m + hspacing - int(dw/2), y + 3*vspacing + int((h-dh)/2) ) 245 # setting dot connections 246 cameraToSceneDot.setInput(0, camera) 247 cameraToScanlineRenderDot.setInput(0, cameraToSceneDot) 248 lensToScanlineDot.setInput(0, lensDistort) 249 # setting node connections 250 camera.setInput(0,None) 251 pointCloud.setInput(0,cameraTracker) 252 # try set the lens distortion input to the CT's input if possible, otherwise ensure it's 253 # disconnected. 254 if cameraTracker.inputs() > 0 and cameraTracker.input(0) != None: 255 lensDistort.setInput(0, cameraTracker.input(0)) 256 else: 257 lensDistort.setInput(0, None) 258 scene.setInput(0,cameraToSceneDot) 259 scene.setInput(1,pointCloud) 260 scanline.setInput(0, lensToScanlineDot) 261 scanline.setInput(1, scene) 262 scanline.setInput(2, cameraToScanlineRenderDot)
263 264
265 -def createPointCloud(cameraTracker):
266 """Create a CameraTrackerPointCloud node.""" 267 _clearSelection() 268 cameraTracker.setSelected(True) 269 pointCloud = nuke.createNode('CameraTrackerPointCloud', '', False)
270 271
272 -def createLensDistortion(cameraTracker):
273 return _createLensDistortionNode(cameraTracker, False)
274 275
276 -def createUndistortion(cameraTracker):
277 return _createLensDistortionNode(cameraTracker, True)
278 279
280 -def _createLensDistortionNode(cameraTracker, invertDistortion):
281 """Create a LensDistortion node which matches the settings calculated by the CameraTracker.""" 282 _clearSelection() 283 284 lensDistort = nuke.createNode('LensDistortion', '', False) 285 lensDistort.setInput(0, cameraTracker.input(0)) 286 link = cameraTracker["linkOutput"].getValue() 287 _copyKnob(cameraTracker, "lensType", lensDistort, "lensType", link) 288 _copyKnob(cameraTracker, "distortion1", lensDistort, "distortion1", link) 289 _copyKnob(cameraTracker, "distortion2", lensDistort, "distortion2", link) 290 _copyKnob(cameraTracker, "distortionCenter", lensDistort, "distortionCenter", link) 291 _copyKnob(cameraTracker, "anamorphicSqueeze", lensDistort, "anamorphicSqueeze", link) 292 _copyKnob(cameraTracker, "asymmetricDistortion", lensDistort, "asymmetricDistortion", link) 293 lensDistort['invertDistortion'].setValue(invertDistortion) 294 _copyKnob(cameraTracker, "filter", lensDistort, "filter", False) 295 _copyKnob(cameraTracker, "cardScale", lensDistort, "cardScale", False) 296 _copyKnob(cameraTracker, "a", lensDistort, "a", False) 297 _copyKnob(cameraTracker, "b", lensDistort, "b", False) 298 _copyKnob(cameraTracker, "c", lensDistort, "c", False) 299 300 lensDistort.selectOnly() 301 302 return lensDistort
303 304
305 -def createCards(solver):
306 numCameras = solver["camTranslate"].getNumKeys() 307 308 if numCameras >= 100: 309 ok = nuke.ask("This will create %d cards, which may take some time.\nAre you sure?" % numCameras) 310 if not ok: 311 return 312 313 if numCameras == 0: 314 nuke.message("You can only create a card set when you have solved cameras.") 315 return 316 317 x = solver.xpos() 318 y = solver.ypos() 319 w = solver.screenWidth() 320 h = solver.screenHeight() 321 m = int(x + w*2) 322 link = False 323 linkKnob = solver.knob("linkOutput") 324 if linkKnob: 325 link = bool(linkKnob.getValue()) 326 exprStr = "[python {nuke.toNode('" + solver.fullName() +"')" 327 328 group = nuke.createNode("Group", '', False) 329 group.begin() 330 group.setName("Cards") 331 group.setXYpos(m + w, y + w) 332 if numCameras>0: 333 scene = nuke.createNode("Scene", '', False) 334 sw = scene.screenWidth() 335 sh = scene.screenHeight() 336 inImg = nuke.createNode("Input", '', False) 337 inImg.setName("img"); 338 inImg.setXYpos(m + int(w*(numCameras-1)/2) - int(sw/2), y) 339 out = nuke.createNode("Output", '', False) 340 out.setXYpos(m + int(w*(numCameras-1)/2) - int(sw/2), y + 5*w) 341 out.setInput(0, scene) 342 group.addKnob(nuke.Tab_Knob('cards','Cards')) 343 zDistKnob = nuke.Double_Knob('z','z') 344 zDistKnob.setRange(0,100) 345 zDistKnob.setTooltip("Cards are placed this far from origin. Use this to make a pan & tile dome of this radius.") 346 zDistKnob.setDefaultValue([1]) 347 group.addKnob(zDistKnob) 348 for i in xrange(numCameras): 349 frame = solver.knob("camTranslate").getKeyTime(i) 350 hold = nuke.createNode("FrameHold", '', False) 351 hold.setInput(0, inImg) 352 hold.knob("first_frame").setValue(frame) 353 hold.setXYpos(m + w*i - int(w/2), y + w) 354 camera = nuke.createNode("Camera", '', False) 355 camera.setInput(0,None) 356 if link: 357 camera.knob("focal").setExpression( exprStr + ".knob('focalLength').getValueAt(" + str(frame) + ")}]" ) 358 camera.knob("haperture").setExpression( exprStr + ".knob('aperture').getValueAt(" + str(frame) + ",0)}]" ) 359 camera.knob("vaperture").setExpression( exprStr + ".knob('aperture').getValueAt(" + str(frame) + ",1)}]" ) 360 camera.knob("translate").setExpression( exprStr + ".knob('camTranslate').getValueAt(" + str(frame) + ",0)}]",0 ) 361 camera.knob("translate").setExpression( exprStr + ".knob('camTranslate').getValueAt(" + str(frame) + ",1)}]",1 ) 362 camera.knob("translate").setExpression( exprStr + ".knob('camTranslate').getValueAt(" + str(frame) + ",2)}]",2 ) 363 camera.knob("rotate").setExpression( exprStr + ".knob('camRotate').getValueAt(" + str(frame) + ",0)}]",0 ) 364 camera.knob("rotate").setExpression( exprStr + ".knob('camRotate').getValueAt(" + str(frame) + ",1)}]",1 ) 365 camera.knob("rotate").setExpression( exprStr + ".knob('camRotate').getValueAt(" + str(frame) + ",2)}]",2 ) 366 else: 367 camera.knob("focal").setValue( solver.knob("focalLength").getValueAt(frame) ) 368 camera.knob("haperture").setValue( solver.knob("aperture").getValueAt(frame,0) ) 369 camera.knob("vaperture").setValue( solver.knob("aperture").getValueAt(frame,1) ) 370 camera.knob("translate").setValue( solver.knob("camTranslate").getValueAt(frame) ) 371 camera.knob("rotate").setValue( solver.knob("camRotate").getValueAt(frame) ) 372 camera.setXYpos(m + w*i - int(sw/2), y + 3*w) 373 card = nuke.createNode("Card", '', False) 374 card.setSelected(False) 375 card.knob("lens_in_focal").setExpression( camera.name() + ".focal" ) 376 card.knob("lens_in_haperture").setExpression( camera.name() + ".haperture" ) 377 card.knob("translate").setExpression( camera.name() + ".translate" ) 378 card.knob("rotate").setExpression( camera.name() + ".rotate" ) 379 card.knob("z").setExpression( "parent.z" ) 380 card.setInput(0, hold) 381 card.setXYpos(m + w*i - int(w/2), y + 2*w) 382 scene.setInput(i*2,camera) 383 scene.setInput(i*2+1,card) 384 scene.setXYpos(m + int(w*(numCameras-1)/2) - int(sw/2), y + 4*w) 385 group.end() 386 group.setInput(0,solver) 387 return group
388 389
390 -def _copyKnob(fromNode, fromKnobName, toNode, toKnobName, link):
391 fromKnob = fromNode[fromKnobName] 392 toKnob = toNode[toKnobName] 393 if link: 394 toKnob.setExpression(fromKnob.fullyQualifiedName()) 395 else: 396 toKnob.fromScript(fromKnob.toScript(False))
397 398
399 -def _clearSelection():
400 nuke.selectAll() 401 nuke.invertSelection()
402 403 404 # 405 # Camera Film Back Preset Functions 406 # 407
408 -def setKnobToPreset(cameraTracker, selectedPresetIdx):
409 """Finds the index of the preset knob and sets the film back size knob accordingly.""" 410 filmbackSizeKnob = cameraTracker['filmBackSize'] 411 selectedFilmbackSize = nukescripts.camerapresets.getFilmBackSize(selectedPresetIdx) 412 filmbackSizeKnob.setValue( selectedFilmbackSize[0], 0 ) 413 filmbackSizeKnob.setValue( selectedFilmbackSize[1], 1 ) 414 415 # Making sure the film back units are set to 'mm' 416 filmBackUnits = cameraTracker['filmBackUnits'] 417 filmBackUnits.setValue(0)
418 419 420 # 421 # Callbacks 422 # 423
424 -def cameratrackerCreateCallback():
425 populateExportMenu(nuke.thisNode()) 426 populateFilmBackPresets(nuke.thisNode())
427 428 429 if not nuke.env['assist']: 430 nuke.addOnCreate(cameratrackerCreateCallback, nodeClass='CameraTracker') 431 nuke.addOnCreate(cameratrackerCreateCallback, nodeClass='CameraTracker1_0') 432 433 # 434 # Track import and export functions 435 # 436
437 -class LinkableImportPanel( nukescripts.PythonPanel ):
438 """ 439 Modal dialog for selecting a Linkable node in the script. 440 441 The following class creates a modal dialog with one UI element: an enum of nodes 442 that derive from the LinkableI class. (The LinkableI interface allows us to easily query and import 443 2D data from a variety of sources, particularly the Tracker node.) The user then selects their source node 444 to import the data from. Once Ok'ed, the code below creates a new user track for each LinkableInfo object 445 returned in the node.linkableKnobs() function with an XY co-ordinate, and then copies each animation curve 446 entry. 447 """ 448
449 - def __init__( self ):
450 nukescripts.PythonPanel.__init__( self, "Select Tracker to Import From", "uk.co.thefoundry.FramePanel" ) 451 # Show a list of trackers in the project. 452 self._trackers = [n.name() for n in nuke.allNodes() if n.linkableKnobs(nuke.KnobType.eXYKnob)] 453 self._tracker = nuke.Enumeration_Knob( "trackers", "tracker node", self._trackers ) 454 self._tracker.setTooltip( "The Tracker node to import from." ) 455 self.addKnob( self._tracker )
456 457
458 - def showModalDialog( self, dstNode ):
459 result = nukescripts.PythonPanel.showModalDialog( self ) 460 if result: 461 srcNode = self._tracker.value() 462 return srcNode 463 return None
464
465 -def _copyLinkableXYAnimCurve(linkableSrc, linkableDst):
466 """Copies the x, y animation curves from one XYKnob linkable object to another.""" 467 linkKnobSrc = linkableSrc.knob() 468 linkKnobDst = linkableDst.knob() 469 linkableSrcIndices = linkableSrc.indices() 470 linkableDstIndices = linkableDst.indices() 471 472 # Setting enabled 473 linkKnobDst.setValue(linkableSrc.enabled(), 0) 474 475 # Clearing the animation curves of the locatior x and y curve 476 linkKnobDst.clearAnimated(int(linkableDstIndices[0])) 477 linkKnobDst.clearAnimated(int(linkableDstIndices[1])) 478 479 # Now setting x and y positions 480 for i in xrange(0, linkKnobSrc.getNumKeys(int(linkableSrcIndices[0]))): 481 t = linkKnobSrc.getKeyTime(i, int(linkableSrcIndices[0])) 482 483 # Because of a bug in the tableknob, before setting the first key/value, we need to re-enable setAnimated. 484 # See below for more details. 485 if i == 0: 486 linkKnobDst.setAnimated(int(linkableDstIndices[0])) 487 linkKnobDst.setAnimated(int(linkableDstIndices[1])) 488 489 # Finally setting the key/values 490 linkKnobDst.setValueAt( linkKnobSrc.getValueAt(t, int(linkableSrcIndices[0])), t, int(linkableDstIndices[0]) ) 491 linkKnobDst.setValueAt( linkKnobSrc.getValueAt(t, int(linkableSrcIndices[1])), t, int(linkableDstIndices[1]) ) 492 493 # Because of the setAnimation bug which always creates a key at 0, we need to explicitly check and remove it. 494 if i == 0 and t != 0: 495 linkKnobDst.removeKeyAt(0, int(linkableDstIndices[0])) 496 linkKnobDst.removeKeyAt(0, int(linkableDstIndices[1]))
497 498
499 -def importTracker(cameraTracker):
500 """Import data from a Tracker node into the CameraTracker node.""" 501 # This is the entry point where we bring up our modal dialog. 502 strSrcNode = LinkableImportPanel().showModalDialog(cameraTracker) 503 if not strSrcNode: 504 return 505 506 # First we start by getting the nodes. 507 srcNode = nuke.toNode(strSrcNode) 508 # And from the nodes, we get our LinkableInfo objects. 509 linkablesSrc = srcNode.linkableKnobs(nuke.KnobType.eXYKnob) 510 linkablesDst = cameraTracker.linkableKnobs(nuke.KnobType.eXYKnob) 511 512 # The following 'startIndex' is used to determine the index of the newly 513 # created user track below. For example, if there are already 10 user tracks, the 514 # next index of the user track we create will be at 10. 515 startIndex = len(linkablesDst) 516 517 # First create new user track for each valid track 518 numValidTracks = 0 519 520 for linkableSrc in linkablesSrc: 521 linkableSrcIndices = linkableSrc.indices() 522 523 # Make sure our source linkable has two indices, one for each co-ordinate. 524 if len(linkableSrcIndices) != 2: 525 continue 526 527 # Here we're manually executing a button, when really 528 # we should be using the 'createLinkable' function in the NDK. 529 # When this code is made into a NukeScript file, we should really just add 530 # 'createLinkable' to PythonObject. 531 cameraTracker['addUserTrack'].execute() 532 533 # We now grab our destination LinkableInfo, our new user track and copy the anims. 534 linkablesDst = cameraTracker.linkableKnobs(nuke.KnobType.eXYKnob) 535 536 if startIndex >= len(linkablesDst): 537 continue; 538 539 linkableDst = linkablesDst[startIndex] 540 541 _copyLinkableXYAnimCurve(linkableSrc, linkableDst) 542 543 # Incrementing the startIndex to say where to find the next user track. 544 startIndex = startIndex + 1
545 546
547 -def exportTracker(cameraTracker):
548 """Export data from the CameraTracker node into a Tracker node.""" 549 tracker = nuke.createNode('Tracker4', '', True) 550 x = cameraTracker.xpos() 551 y = cameraTracker.ypos() 552 w = cameraTracker.screenWidth() 553 h = cameraTracker.screenHeight() 554 m = int(x + w/2) 555 tracker.setXYpos(m - int(tracker.screenWidth()/2), y + w) 556 557 # And from the nodes, we get our LinkableInfo objects. 558 linkablesSrc = cameraTracker.linkableKnobs(nuke.KnobType.eXYKnob) 559 linkablesDst = tracker.linkableKnobs(nuke.KnobType.eXYKnob) 560 561 # The following 'startIndex' is used to determine the index of the newly 562 # created user track below. For example, if there are already 10 user tracks, the 563 # next index of the user track we create will be at 10. 564 startIndex = len(linkablesDst) 565 566 # First create new track for each valid user track 567 numValidTracks = 0 568 569 for linkableSrc in linkablesSrc: 570 linkableSrcIndices = linkableSrc.indices() 571 572 # Make sure our source linkable has two indices, one for each co-ordinate. 573 if len(linkableSrcIndices) < 2: 574 continue 575 576 # Here we're manually executing a button, when really 577 # we should be using the 'createLinkable' function in the NDK. 578 # When this code is made into a NukeScript file, we should really just add 579 # 'createLinkable' to PythonObject. 580 tracker['add_track'].execute() 581 # We now grab our destination LinkableInfo, our new user track and copy the anims. 582 linkablesDst = tracker.linkableKnobs(nuke.KnobType.eXYKnob) 583 584 if startIndex >= len(linkablesDst): 585 continue; 586 587 linkableDst = linkablesDst[startIndex] 588 589 _copyLinkableXYAnimCurve(linkableSrc, linkableDst) 590 591 # Incrementing the startIndex to say where to find the next user track. 592 startIndex = startIndex + 1
593 594
595 -def importTracks(cameraTracker):
596 """Utility function that collects the filename to be used in importing tracks from a Shake formatted file.""" 597 filename = nuke.getClipname("Import File") 598 if filename is None: 599 filename = "" 600 601 cameraTracker.knob("tracksFile").fromScript( filename )
602 603
604 -def exportTracks(cameraTracker):
605 """Utility function that collects the filename to be used in exporting tracks from a Shake formatted file.""" 606 filename = nuke.getClipname("Export File") 607 if filename is None: 608 filename = "" 609 610 cameraTracker.knob("tracksFile").fromScript( filename )
611