# ballanim.tcl: demonstration of an animation generating frames # Gordon Kindlmann catch {load vtktcl} # get the interactor ui # "numsteps" determines the number of frames in the animation # I'm using a number as large as 180 in order to make a smooth animation # of what is really a very simple scene set numsteps 180 # "imagebase" is the beginning of the filenames of all the images # If it is "bingo" then the first frame will be saved in "bingo001.ppm" # If the frame images should go in another directory, then that should # be set here by putting the directory name at the beginning of the base # The setting here assumes there is a directory called "frames" set imagebase "frames/" # "setup" arranges all the parameters of the various objects # according to the control variable, which varies smoothly from 0.0 to 1.0 proc setup {t} { # these are variables for the three lights global lt1 lt2 lt3 # convert the control variable to an angle in radians set angle [expr $t*2*3.141592654] # sc controls the distance of the lights to sphere set sc 5 # With each frame we are setting the camera location and the camera # direction. Because the interesting part of the scene is always # a fixed distance away, we don't have to use vtkCamera's # SetClippingRange, but you may need to for more complicated # camera paths # the eyepoint travels in a circle which is slightly above z = 0 set xp [expr 3*cos($angle)] set yp [expr 3*sin($angle)] set zp 1 [ren1 GetActiveCamera] SetPosition $xp $yp $zp # the normalize eye direction set dist [expr sqrt($xp*$xp + $yp*$yp + $zp*$zp)] set xn [expr $xp / $dist] set yn [expr $yp / $dist] set zn [expr $zp / $dist] [ren1 GetActiveCamera] SetViewUp 0 0 1 [ren1 GetActiveCamera] OrthogonalizeViewUp # the lights' position vectors are permuted versions of the eye point # this was done just so the lights had an interesting looking path set l2xp [expr $zp/$sc] set l2yp [expr $xp/$sc] set l2zp [expr $yp/$sc] set l3xp [expr -$l2xp] set l3yp [expr -$l2yp] set l3zp [expr -$l2zp] # the first light is the default light, we set it to track # the eye point so that it acts as a "headlight" $lt1 SetPosition $xp $yp $zp # the second and third light are set to the same position as the balls $lt2 SetPosition $l2xp $l2yp $l2zp $lt3 SetPosition $l3xp $l3yp $l3zp light2Actor SetPosition $l2xp $l2yp $l2zp light3Actor SetPosition $l3xp $l3yp $l3zp } # "animate" contains the mainloop of the animation, calling "setup" for # each time step proc animate {} { global numsteps imagebase for {set i 1} {$i <= $numsteps} {incr i} { # compute the control variable # Note that $t will never actually reach 1.0. I did this so # that the last frame would smoothly precede the very first # frame, if the animation is played in a loop # If this is not desired, use: # set t [expr 1.0*($i-1)/($numsteps-1)] set t [expr 1.0*($i-1)/$numsteps] puts "step $i of $numsteps (t = $t)..." # set up the scene and render setup $t renWin Render # set the image filename using the "format" command set name [format "%s%03d.ppm" $imagebase $i] # uncomment these next three lines to actually save the frames #puts " saving in $name" #renWin SetFileName $name #renWin SaveImageAsPPM } } # basic rendering stuff vtkRenderer ren1 vtkRenderWindow renWin renWin AddRenderer ren1 vtkRenderWindowInteractor iren iren SetRenderWindow renWin iren Initialize # a big sphere in the middle of the image vtkSphereSource sphere sphere SetPhiResolution 10 sphere SetThetaResolution 20 vtkPolyDataMapper sphereMapper sphereMapper SetInput [sphere GetOutput] vtkActor sphereActor sphereActor SetMapper sphereMapper [sphereActor GetProperty] SetColor 1 1 1 [sphereActor GetProperty] SetInterpolationToFlat [sphereActor GetProperty] SetAmbient 0.0 [sphereActor GetProperty] SetDiffuse 0.4 [sphereActor GetProperty] SetSpecular 0.8 [sphereActor GetProperty] SetSpecularPower 30 # little orbiting lights vtkPolyDataMapper light2Mapper light2Mapper SetInput [sphere GetOutput] vtkActor light2Actor light2Actor SetMapper light2Mapper [light2Actor GetProperty] SetColor 0.8 0.0 0.0 light2Actor SetScale 0.2 0.2 0.2 vtkPolyDataMapper light3Mapper light3Mapper SetInput [sphere GetOutput] vtkActor light3Actor light3Actor SetMapper light3Mapper [light3Actor GetProperty] SetColor 0.0 0.8 0.0 light3Actor SetScale 0.2 0.2 0.2 # set up renderer and window ren1 AddActor sphereActor ren1 AddActor light2Actor ren1 AddActor light3Actor ren1 SetBackground 0 0 0 renWin SetSize 256 256 # create two more lights in addition to the single default light # without "ren1 Render", get a core dump, why? ren1 Render ren1 CreateLight ren1 CreateLight set lights [ren1 GetLights] $lights InitTraversal set lt1 [$lights GetNextItem] set lt2 [$lights GetNextItem] set lt3 [$lights GetNextItem] $lt1 SetColor 0.7 0.7 1.0 $lt2 SetColor 0.8 0.0 0.0 $lt3 SetColor 0.0 0.8 0.0 # the very simple interface frame .f button .f.p -text "animate" -command animate button .f.s -text "quit" -command exit pack .f.p .f.s pack .f # make the window show the contents of the first frame setup 0.0