Blender
Python: 
Exploding a mesh
french version
    Main   Index
Previous Text2uvbaker Script 
LOD Script  : Next

 
  1. v04 Motion pict (avi divx)
  2. zipped file v04
  3. Introduction
  4. Short tutorial
  5. The "explode4.py" script
  6.      +materiasl and  textures
  7. The "Scriptlink.py" script
  8. A few explosion's patterns

The short  film of the 0.4v (avi format)
The zipped blend file of the 0.4 version
v0.4B Fichier Blender 7zippé: offers materials and textures management 

The short  film of the 0.3v (avi format)
The zipped blend file of the 0.3 version

The short  film of the 0.1v (avi format)
The zipped blend file of the 0.1 version

Introduction
This script has a little advantage compared to the first version : it creates a reference mesh object to move the exploded mesh vertices instead of storing them in a Registry module dictionary. This method should result in a more efficient work and a reducing in the congestion of the RAM .

For the moment, there is still a minimum of operations to do , you have to go into a frame outside the field of the animation execution to produce the dislocated mesh and the referring mesh. In this example, it is the frame number 252.

Short tutorial

1/ Load this script

2/ Load the script : scriptlink.py

3/ Check that the NAME really is 'explode4.py'

4/ Select a mesh

5/ Go to frame SHATFRAME (252)

6/ Do alt-p on the : scriptlink.py, normally at the loading of the script, the selected mesh is automatically dislocated into separated facets, and renamed 'explode_mesh', at the same time a mesh named 'reference_mesh' is created and will be used as a reference array for the vertices coordinates.

7/ Go back to frame 1

8/ Launch the animation

Optional : 

1 The script need the ground to be located, to do so put an empty and name it "SOL",  if you don't do that, the script will creates it automatically.

 2 TRAJECTORY = 1 marks  positions of each point for each frame. 

 3 ROTATION=1 gives a rotation to each exploded face.

The "explode4.py" script
 

#!BPY
""" Registration info for Blender menus: <- these words are ignored
Name: 'Shattered mesh'
Blender: 233
Group: 'Animation'
Tooltips: 'this script explode the selected mesh'
"""
"""
(c) jm soler Aout 2004/05, released under Blender Artistic Licence 
#----------------------------------------------
#  EXPLODE v0.4
#----------------------------------------------
# Page officielle :
#   http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_meshexplosion.htm
# Communiquer les problemes et erreurs sur:
#   http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender
#---------------------------------------------
# ce script est proposé sous Blender Artistic Licence pour etre associe
#----------------------------------------------
"""

import Blender
from Blender import Object,NMesh,Noise,Scene
from Blender import Registry
from math import sin,cos,pi

EVENT='FrameChanged'
NAME='explode4.py'

FRAME=Blender.Get('curframe')
SHATFRAME=252
TRAJECTORY=0
ROTATION=1
FORCE=1

# ==========================
# Fonction ArbitraryRotate(p0,theta,r,d)
#     Entree :  p0     coordonnees [xyz] d'un sommet/ vertex
#               theta  angle de rotation
#               r      vecteur unitaire [abc] axe de rotation 
#               d      coordonnees [xyz] barycentre de la face
#     Sortie :  q      nouvelle s coordonnees [xyz] du 
#                      sommet/ vertex  P0
#
# FUNCTION ArbitraryRotate(p0,theta,r,d)
#     IN     :  p0     vertex coordinates [xyz] 
#               theta  rotation angle in degrees
#               r      normalized vector [abc], rotation's axe
#               d      [xyz] face center's coordinats 
#     OUT    :  q      P0 vextex' new coordinates [xyz] 

# ==========================
def ArbitraryRotate(p0,theta,r,d):
   q = [0.0,0.0,0.0]
   p = [0.0,0.0,0.0]
   #print r,d
   for n in [0,1,2]: 
     p[n]=p0[n]-d[n]
   costheta = cos(theta*pi/180)
   sintheta = sin(theta*pi/180)
   q[0] += (costheta + (1 - costheta) * r[0] * r[0]) * p[0]
   q[0] += ((1 - costheta) * r[0] * r[1] - r[2] * sintheta) * p[1]
   q[0] += ((1 - costheta) * r[0] * r[2] + r[1] * sintheta) * p[2]
   q[1] += ((1 - costheta) * r[0] * r[1] + r[2] * sintheta) * p[0]
   q[1] += (costheta + (1 - costheta) * r[1] * r[1]) * p[1]
   q[1] += ((1 - costheta) * r[1] * r[2] - r[0] * sintheta) * p[2]
   q[2] += ((1 - costheta) * r[0] * r[2] - r[1] * sintheta) * p[0]
   q[2] += ((1 - costheta) * r[1] * r[2] + r[0] * sintheta) * p[1]
   q[2] += (costheta + (1 - costheta) * r[2] * r[2]) * p[2]
   for n in [0,1,2]: q[n]+=d[n]
   return q

# ==========================
# Fonction taille(c1)
#        Entrée : c1   un vecteur quelconque
#        Sortie : taille de v1
#
# FUNCTION taille(c1)
#        IN  : c1   un vecteur quelconque
#        OUT : v1 size 
# ==========================
def taille(c1):
   return abs(c1[0]**2+c1[1]**2+c1[2]**2)**0.5

# ==========================
# Fonction DimLine(P1,P2)
#        Entrée : c1   un vecteur quelconque
#        Sortie : taille de v1
#
# FUNCTION DimLine(P1,P2)
#        IN  : p1, p2  2 vectors xyz
#        OUT : return size 
# ==========================
def DimLine(P1,P2):
   return abs((P1[0]-P2[0])**2+(P1[1]-P2[1])**2+(P1[2]-P2[2])**2)**0.5

# ==========================
# Fonction normalise(c1)
#        Entrée : c1   un vecteur quelconque
#        Sortie : c1  vecteur unitaire
#
# FUNCTION normalise(c1)
#        IN  : c1   a vector
#        OUT : c1  normalized vector
# ==========================
def normalise(c1):
    v1=taille(c1)
    if v1>0:
      for n in [0,1,2]:
         c1[n]/=v1
    return c1

# ==========================
# Fonction Centroid(f)
#        Entree : f  une face de mesh
#        Sortie : P0 centre de la face
#
# FUNCTION 
#        IN  : f  a mesh face 
#        OUT :  vector xyz face centroid 
# ==========================
def Centroid(f,P0) :
  for v in f.v:
    for n in [0,1,2] :
       P0[n]+=v.co[n]/len(f.v)
  return P0

# ==========================
# Fonction ExtractRotationData(f)
#        Entree : f  une face de mesh
#        Sortie : c1 vecteur unitaire d'un axe de la face
#                 p1 coordonnees xyz du barycentre de la face
#
# FUNCTION 
#        IN  : f  a mesh face 
#        OUT : c1 face's axe normalized vector 
#              p1 coordinates xyz of face's middle 
# ==========================
def ExtractRotationData(f):
  p1=[0.0,0.0,0.0]
  c0=[0.0,0.0,0.0]
  c1=[0.0,0.0,0.0]

  # for v in f.v:
  #  for n in [0,1,2] :
  #     p1[n]+=v.co[n]/len(f.v)
  p1 = Centroid(f,p1)

  for n in [0,1,2] :
    c0[n]=(f.v[0].co[n]+f.v[1].co[n])/2.0
    c1[n]=(f.v[1].co[n]+f.v[2].co[n])/2.0 - c0[n]

  c1=normalise(c1)
  return c1,p1

# ==========================
# Fonction DistancePtoLine(P0,P1,P2)
#        Entrée : P0, un point xyz 
#                 P1,P2   extremite d'un segment
#        Sortie : distance minimale ent P0 et [P1,P2] 
#
# FUNCTION DistancePtoLine(P0,P1,P2)
#        IN  : P0, a xyz point 
#              P1,P2   extremite d'un edge
#              DimLine disance entre P1 et P2
#        OUT : minimal distance  between P0 and [P1,P2] 
# ==========================
def DistancePtoLine(P0,P1,P2, DimLINE):

    if DimLINE>0:
       Ratio=((P0[0]-P1[0])*(P2[0]-P1[0]) +
              (P0[1]-P1[1])*(P2[1]-P1[1]) + 
              (P0[2]-P1[2])*(P2[2]-P1[2]))/DimLINE**2
       P4=[0.0,.0,.0] 
       P4[0] = P1[0] + Ratio*(P2[0]-P1[0])
       P4[1] = P1[1] + Ratio*(P2[1]-P1[1])
       P4[2] = P1[2] + Ratio*(P2[2]-P1[2])
       MinDIST=abs((P4[0]-P0[0])**2+(P4[1]-P0[1])**2+(P4[2]-P0[2])**2)**0.5
    elif  DimLINE==0 :
        MinDIST=abs((P1[0]-P0[0])**2+(P1[1]-P0[1])**2+(P1[2]-P0[2])**2)**0.5
    return MinDIST

if FRAME==SHATFRAME:
  MESH3D = Object.GetSelected()[0]
  scriptlink=MESH3D.getScriptLinks(EVENT)
  if MESH3D.getType() == 'Mesh' and NAME in scriptlink:
        MESH = MESH3D.getData()
        MESH2 = NMesh.GetRaw()
        MESHR = NMesh.GetRaw()
        MESHT =  NMesh.GetRaw() #Marquer la trajectoire
        for f in MESH.faces:
              f1 = Blender.NMesh.Face()
              f2 = Blender.NMesh.Face()
              for v in f.v:
                  co=v[:] 
                  v1 = Blender.NMesh.Vert (co[0],
                                          co[1], 
                                           co[2])

                  v3 = Blender.NMesh.Vert (co[0],
                                          co[1], 
                                           co[2])

                  if TRAJECTORY : v4 = Blender.NMesh.Vert (co[0],
                                          co[1], 
                                           co[2])

                  MESH2.verts.append(v1)
                  MESHR.verts.append(v3)
                  if TRAJECTORY : MESHT.verts.append(v4)

                  f1.v.append(MESH2.verts[len(MESH2.verts) - 1])
                  f2.v.append(MESHR.verts[len(MESHR.verts) - 1])

              f1.sel=f.sel
              f2.sel=f.sel

              MESH2.faces.append(f1)
              MESHR.faces.append(f2)

              #pos[MESH2.faces.index(f1)]=V[:]

        MESH2.name='exploded_mesh' 
        MESH3D.link(MESH2)
        MESHR.name='reference_mesh' 

        try:
            OBJ=Blender.Object.Get('reference')
            OBJ.link(MESHR)
        except: 
           OBJ= Blender.Object.New('Mesh')
           OBJ.setName('reference') 
           SCENE=Blender.Scene.getCurrent()
           SCENE.link(OBJ)
           OBJ.link(MESHR)
        LAYER=Blender.Window.ViewLayer()
        l=19
        if  l in LAYER:
             LAYER.remove(l) 
        OBJ.Layer=1<<19

        if TRAJECTORY :
           try:
              OBJ=Blender.Object.Get('Trajectoire')
              OBJ.link(MESHT)
           except: 
              OBJ= Blender.Object.New('Mesh')
              OBJ.setName('Trajectoire') 
              SCENE=Blender.Scene.getCurrent()
              SCENE.link(OBJ)
              OBJ.link(MESHT)
           LAYER=Blender.Window.ViewLayer()
           l=19
           if  l in LAYER:
             LAYER.remove(l) 
           OBJ.Layer=1<<19
 

if FRAME>=1 and  FRAME<SHATFRAME:

  #print FRAME
  MESHS= Object.GetSelected()[0]
  scriptlink=MESHS.getScriptLinks(EVENT)
  if MESHS.getType() == 'Mesh' and scriptlink and NAME in scriptlink:
      MESH3D=MESHS.getData()
      MESHR = Blender.Object.Get('reference').getData()
      if TRAJECTORY : MESHT = Blender.Object.Get('Trajectoire').getData() 

      #--------------
      #  Situer le sol
      # LOCATE GROUND
      #--------------
      LOC=MESHS.LocZ
      try:
        OBJSOL=Blender.Object.Get('SOL')
      except:
        OBJSOL=Blender.Object.New('Empty','SOL')
        OBJSOL.LocZ=0.0
        SCENE=Blender.Scene.getCurrent()
        SCENE.link(OBJSOL)
      SOL=-abs(OBJSOL.LocZ-LOC)
      SOLABSORB=0.3
      #print SOL
      #--------------
      # Fin sol
      # END GROUND
      #--------------

      if FRAME==1:
         #--------------
         # Calcul de la direction de la force
         # FORCE DIRECTION CALCULUS 
         #--------------
         if FORCE:
            try:
               Force=Blender.Object.Get('FORCE').getData().verts
               #--------------
               # necessaire pour calculer la distance 
               # d'un sommet  a l'axe de la force
               # inutile de la recalculer a chaque fois
               #--------------
               P1=Force[0].co
               P2=Force[1].co
               DIMLINE=DimLine(P1,P2)
               print 'DIMLINE',DIMLINE
               #--------------
               #--------------
               force=[0.0,0.0,0.0]
               for v in Force :
                  for n in [0,1,2] :
                    force[n]+=v.co[n]/len(Force)
               puissance=abs(taille(force)) 
               force=normalise(force) 
            except:
               FORCE=0
         #--------------
         # Fin Calcul de la direction de la force
         # END FORCE DIRECTION CALCULUS
         #--------------

         #--------------
         # Velocite initiale
         # INITIAL VELOCITY
         #--------------
         pos={}
         P0=[0.0,0.0,0.0]
         for f in MESHR.faces:
              P5=Noise.random()
              if FORCE:
                 #P0=Centroid(f,P0)
                 #DistancePtoLine(P0,P1,P2, DIMLINE)
                 if Noise.random()<0.2:
                      pos[MESHR.faces.index(f)]=[x*P5*puissance for x in f.no]
                      for n in [0,1,2] :
                         pos[MESHR.faces.index(f)][n]+=force[n]
                 else:
                      pos[MESHR.faces.index(f)]=[x*puissance*P5 for x in force]
              else: 
                 pos[MESHR.faces.index(f)]=[x*P5 for x in f.no]

              if ROTATION :
                 pos[MESHR.faces.index(f)].append(360.0*Noise.random())
                 pos[MESHR.faces.index(f)].append(ExtractRotationData(f))
                 pos[MESHR.faces.index(f)].append([-1])
                 #print pos[MESHR.faces.index(f)]

         Blender.Registry.SetKey('ExPloZ', pos)
         #--------------
         # Fin Velocite initiale
         # END INITIAL VELOCITY
         #-------------- 

         #--------------
         # Remise en etat de la forme originale
         # RESTORE INITIAL SHAPE
         #-------------- 
         FINDEX=0
         for f in MESH3D.faces:
           f2=MESHR.faces[FINDEX]
           for v in f.v:
             for n in [0,1,2] : 
                 v.co[n]=f2.v[f.v.index(v)].co[n]
           FINDEX+=1
         #--------------
         # Remise en etat de la forme originale
         # RESTORE INITIAL SHAPE
         #-------------- 

      #--------------
      # On garde quelques image neutres pour 
      # laisser dans l'oeil un souvenir de la 
      # forme intacte. 
      # A FEW FRAME TO SEE THE ORIGINAL SHAPE 
      #-------------- 
      pos=Blender.Registry.GetKey('ExPloZ')

      if FRAME>10:
         for f in MESH3D.faces:
          if f.sel :
               FINDEX=MESH3D.faces.index(f)
               p=pos[FINDEX]
               #print p 
               if ROTATION :
                  theta=p[3] 
                  r0=p[4][0]
                  d0=p[4][1]
               #print 'theta,r0,d0',theta, r0, d0
               f2=MESHR.faces[FINDEX]
               t=float(FRAME-10)/100
               g=[0.0,0,-30.8]
               #force=p[2]**2*75
               V=[p[0]**2,p[1]**2,p[2]**2]#[force]*3
               r=0.5
               loc={} 
               REBOND=0

               for v in f.v:
                   loc[f.v.index(v)]=[] 
                   vi=f.v.index(v) 
                   if ROTATION :
                            q=ArbitraryRotate(f2.v[vi].co,theta*FRAME,r0,d0)
                   for n in [0,1,2] : 
                       if ROTATION :
                            loc[vi].append(q[n]+(V[n]*t*p[n] + r*g[n]*t*t))
                       else:
                          loc[vi].append(f2.v[vi].co[n]+(V[n]*t*p[n] + r*g[n]*t*t))
                       #print p[-1][0], 
                       if n==2 and loc[vi][2]<SOL and p[-1][0]==-1:
                           p[-1][0]=1
                           p[-1].append(f2.v[vi].co[2]) 
                           p[-1].append(t)
                           REBOND=1
                       elif p[-1][0]==1 :
                           REBOND=1

               for v in f.v:
                 for n in [0,1,2] : 
                    v.co[n]=loc[f.v.index(v)][n]

                 if TRAJECTORY and not REBOND: 
                    if len(MESHT.verts)>= len(MESH3D.verts) :
                          MESHT.verts.append(NMesh.Vert(v.co[0],
                                          v.co[1],
                                          v.co[2]))
               if REBOND:
                   #print 'REBOND' 
                   for v in f.v:
                       vi=f.v.index(v)
                       t0=t-p[-1][-1]
                       V0=V[:]
                       V0[2]=-V0[2]*SOLABSORB
                       g0=[0.0,0,9.8]
                       fz=f2.v[vi].co[2]- p[-1][1]
                       co0=V0[2]*t0*p[2] - r*g0[2]*t0*t0
                       co=fz+co0
                       if SOL+co>SOL:
                          v.co[2]=SOL+co 
                       else:
                          v.co[2]=SOL+fz 
                   if TRAJECTORY : 
                      if len(MESHT.verts)<= len(MESH3D.verts)*SHATFRAME :
                           MESHT.verts.append(NMesh.Vert(v.co[0],
                     v.co[1],
                     v.co[2])) 
      MESH3D.update()
      if TRAJECTORY : MESHT.update()
 

A script example to automatically link a script to the active object  :

import Blender
EVENT='FrameChanged'
NAME='explode4.py'
MESH3D = Blender.Object.GetSelected()[0]
scriptlink=MESH3D.getScriptLinks(EVENT)
if scriptlink and NAME  in scriptlink:
   pass
else:
   MESH3D.addScriptLink(NAME,EVENT)
Blender.Window.RedrawAll()

A few explosion pattern's :
 

       #the film
       t=float(FRAME)/100
       g=[0.0,-9.8,0]
        force=p[1]*9.7
        V=[force]*3
        r=0.5
       #the film
        t=float(FRAME)/100
        g=[0.0,-9.8,0]
        force=-p[1]*9.7
        V=[0,force,0]
        r=0.5
       #the film
        t=float(FRAME)/100
        g=[0.0,-9.8,0]
        force=p[1]*9.7
        V=[0.0,force,0.0]
       r=0.5
       #the film
       #the film+ground 
if FRAME>=1 and  FRAME<SHATFRAME:
  print FRAME
  MESH3D = Object.GetSelected()[0].getData()
  MESHR = OBJ=Blender.Object.Get('reference').getData()
  if FRAME==1:
     pos={}
     for f in MESHR.faces: 
                pos[MESHR.faces.index(f)]=[x*Noise.random() for x in f.no] 
     Blender.Registry.SetKey('ExPloZ', pos)
  pos=Blender.Registry.GetKey('ExPloZ')
  for f in MESH3D.faces:
        FINDEX=MESH3D.faces.index(f)
        p=pos[FINDEX]
        f2=MESHR.faces[FINDEX]
        t=float(FRAME)/100
        g=[0.0,-9.8,0]
        force=p[1]*9.7
        V=[force]*3
        r=0.5

 
 
Previous Text2uvbaker Script 
 LOD Script  : Next
To the  Top of the page

Les questions concernant cette page  peuvent être posées sur  :
 news://news.zoo-logique.org/3D.Blender


 

 

Livre en français
Blender : apprenez, pratiquez, Créez, livre, Ed. Campus Press, coll. Starter Kit
Blender Starter Kit

Forum
FAQ
Lexique
Didacticiels
Compilations
Blender2KT
Débuter
Modelage
Blender python
Materiaux
Lumière
Animation
API python (eng)
Archives nzn
Statistiques
Doc flash Sculptris
Galerie Sculptris

Les Fralibos sur youtube, soutien au personnel de Fralib de Gémenos