Advertisement
nlw

Rotating cube animation in python (numpy, matplotlib)

nlw
Mar 19th, 2011
7,641
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.77 KB | None | 0 0
  1. #!/usr/bin/python
  2. #####################################################################
  3. ## Cube animation program using python, numpy and matplotlib.  In the
  4. ## spirit of old-school demo programs... This progam can teach you one
  5. ## thing or two about computer graphics, specially how important it is
  6. ## to learn linear algebra.
  7. ##
  8. ## This also shows a way to create animations using matplotlib. Just
  9. ## make a loop that plots each new frame, and save that frame to an
  10. ## image. You can then make a film from these images using mplayer or
  11. ## whatever. Instead of replotting everything you could just change
  12. ## the parameters from the image curves, but in this case it didn't
  13. ## seem much of an advantage to do that.
  14. ##
  15. ## You can see the output on YouTube:
  16. ##   http://www.youtube.com/watch?v=K5qoS781qOw
  17. ##
  18. ## Coded by Nicolau Werneck<nwerneck@gmail.com> in 2011-03-19
  19. ##
  20. #####################################################################
  21.  
  22. from pylab import *
  23. import numpy as np
  24.  
  25.  
  26. #####################################################################
  27. ## Produces a rotation matrix from the 3 last components of a
  28. ## quaternion.
  29. def quaternion_to_matrix(myx):
  30.     # '''converts from a quaternion representation (last 3 values) to rotation matrix.'''
  31.     xb,xc,xd = myx
  32.  
  33.     xnormsq = xb*xb+xc*xc+xd*xd
  34.  
  35.     if xnormsq < 1:
  36.         ## If inside the unit sphere, these are the components
  37.         ## themselves, and we just have to calculate a to normalize
  38.         ## the quaternion.
  39.         b,c,d = xb,xc,xd
  40.         a = np.sqrt(1-xnormsq)
  41.     else:
  42.         ## Just to work gracefully if we have invalid inputs, we
  43.         ## reflect the vectors outside the unit sphere to the other
  44.         ## side, and use the inverse norm and negative values of a.
  45.         b,c,d = -xb/xnormsq,-xc/xnormsq,-xd/xnormsq
  46.         a = -np.sqrt(1-  1.0/xnormsq  )
  47.         ## This should not be used, it defeats the whole concept that
  48.         ## small (b,c,d) vector norms have small rotation angles. It's
  49.         ## really just to let us work near the borders of the
  50.         ## sphere. Any optimization algorithm should work with
  51.         ## initalizations just inside the spere, and avoid wandering
  52.         ## outside of it.
  53.  
  54.     assert a >= -1
  55.     assert a <= 1
  56.  
  57.     ## Notice we return a transpose matrix, because we work with line-vectors
  58.  
  59.     return np.array([ [(a*a+b*b-c*c-d*d), (2*b*c-2*a*d),     (2*b*d+2*a*c)      ],
  60.                          [(2*b*c+2*a*d),     (a*a-b*b+c*c-d*d), (2*c*d-2*a*b)      ],
  61.                          [(2*b*d-2*a*c),     (2*c*d+2*a*b),     (a*a-b*b-c*c+d*d)] ]  ).T  \
  62.                          / (a*a+b*b+c*c+d*d)
  63.                          
  64. ##
  65. #####################################################################
  66.  
  67.  
  68. ## Calculate quaternion values using sinusoids over the frame index
  69. ## number, and get rotation matrix. Notice that the second parameter
  70. ## is the number of frames. That allows us to easily create an
  71. ## animation that can be played as a loop.
  72. def crazy_rotation(ind,Nind):
  73.     return quaternion_to_matrix(0.5*sin(pi*2*ind*Nind**-1.*array([1,2,3])))
  74.  
  75. ## This function calculate the projected image coordinates form the 3D
  76. ## coordinates of the object vertices.
  77. def project(D, vecs):
  78.     return vvs[:,:2]/(vvs[:,[2,2]]-D)
  79.  
  80. ## The cube vertices
  81. vs = reshape(mgrid[-1:2:2,-1:2:2,-1:2:2].T, (8,3))
  82.  
  83. ## Generate the list of connected vertices
  84. ed=[(j,k)
  85.     for j in range(8)
  86.     for k in range(j,8)
  87.     if sum(abs(vs[j]-vs[k]))==2 ]
  88.  
  89.  
  90. ## Camera position
  91. D=-5
  92.  
  93. ## Create the figure. figsize needed to set the image sizes at the end...
  94. figure(1, figsize=(6.4,4.8))
  95.  
  96. ## create/get the axes object.
  97. ax=subplot(1,1,1)
  98.  
  99. ## Set image title.
  100. suptitle('Cube animation')
  101.  
  102. ## Number of frames.
  103. Nind=250
  104.  
  105. ##
  106. ## Now start a loop over the animation frames. The index is used both
  107. ## to name the images and to calculate the rotation matrix. You could
  108. ## use this index to make some physics stuff...
  109. for ind in range(Nind):
  110.     print ind
  111.     ## This is crucial, clears the figure for the new plot.
  112.     ax.clear()
  113.  
  114.     ## Get the rotation matrix for the current frame.
  115.     rotM = crazy_rotation(ind, Nind)
  116.  
  117.     ## Calculate the 3D coordinates of the vertices of the rotated
  118.     ## cube. Just multiply the vectors by the rotation matrix...
  119.     vvs=dot(vs,rotM)
  120.  
  121.     ## Now calculate the image coordinates of the points.
  122.     pt = project(D,vvs)
  123.  
  124.     ## Plot the edges.
  125.     for j,k in ed:
  126.         ax.plot(pt[[j,k],0], pt[[j,k],1], 'g-', lw=3)
  127.  
  128.     ## Plot the vertices.
  129.     ax.plot(pt[:,0], pt[:,1], 'bo')
  130.  
  131.     ## Set axes limits
  132.     ax.axis('equal')
  133.     ax.axis([-0.5,0.5,-0.5,0.5])
  134.  
  135.     ## Save the current frame. We need the dpi (along with the figure
  136.     ## size up there) to set the image size.
  137.     savefig('anim%03d.png'%ind, dpi=100)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement