Blender (jusqu'à 2.49)
Python: 
Exploser un mesh
Version Anglaise
    Début   Index
précédentScript Text2uvbaker
Script Mesh2objet : Suivant

 
  1. film v04 (avi divx)
  2. fichier zippé v04
  3. Présentation
  4. Didacticiel court
  5. Le script explode4.py
  6.      +materiaux et textures
  7. Le script Scriptlink.py
  8. Quelques patterns d'explosion

Le court film de la version 0.4v (avi divx format)
v0.4 Fichier Blender zippé 
v0.4B Fichier Blender 7zippé: offre la gestion des matériaux et textures 

Court  film de la version  0.3v (format avi divx5.x)
Fichier Blender zippé du film

Le film de la v0.1
Le fichier Blend zippé de la version 0.1

Présentation
Ce script possède un petit avantage par rapport à la premiere version: il crée un objet mesh de référence pour déplacer les sommets du mesh éclaté au lieu de les stocker dans un dictionnaire du module Registry.  Cette méthode devrait encombrer un peu moins la mémoire vive.

Pour l'instant, il y a encore un minimum de manipulation à effectuer car il faut passer dans une frame en dehors  du champs d'exécution de l'animation pour produire le mesh désarcticulé et le mesh de référence. Dans cet exemple, il s'agit de la frame 252. 

Court tutorial

1/ Charger ce script .

2/ Charger le script : scriptlink.py

3/ Verifier que le NAME est bien 'explode4.py'

4/ Selectionner un mesh

5/ Passer dans la frame SHAFTFRAME (252)

6/ Faire alt-p sur le script : scriptlink.py, normalement en chargeant le script le mesh sélectionné est automatiquement désarticuler en facettes séparées et renommé 'explode_mesh', alors qu'un mesh nommé 'reference_mesh' est créé aussi et servira de tableau de référence pour les corrdonnées des sommets.

7/ revenir  la frame 1

8/ lancer l'animation

Optionnel :

1/  placer le sol sous la forme d'un empty nomme SOL  sinon le script le cree automatiquement.

2/ TRAJECTORY = 1   marque les positions successives de 
    chaque point pour chaque image . 

 3/ ROTATION=1   donne une rotation a chaque face  .

Le script explode45.py

#!BPY

""" Registration info for Blender menus: <- these words are ignored
Name: 'Shattered mesh'
Blender: 236
Group: 'Animation'
Tooltips: 'this script explode the selected mesh'
"""
"""
(c) jm soler Aout 2004, released under Blender Artistic Licence 
#----------------------------------------------
#  EXPLODE v0.4.5
#----------------------------------------------
# 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
#----------------------------------------------

Tutorial:

1/ Charger ce script
2/ Charger le script : scriptlink.py
3/ Verifier que le NAME est bien 'explode2.py'
4/ Selectionner un mesh
5/ Passer dans la frame 102
6/ Faire alt-p sur le sscript : scriptlink.py
7/ revenir  la frame 1
8/ lancer l'animation

Optionnel :   placer le sol
sous la forme d'un empty nomme SOL 
sinon le script le cree automatiquement

Ajouts 0.4.5 : 
    FORCEPOINT 
    SOLPOINT
    SUBSURF
    fonctionne avec les subsurfs enclanchées
"""

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

EVENT='FrameChanged'
NAME='explode45.py'

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

# ==========================
# 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
 

# ==========================
# Fonction CreateObjet(name,MESH)
#        Entrée : name  chaine de caractere
#                 MESH donnees mesh
#        Sortie : rien
#
# FUNCTION 
#        IN  : name  string
#              MESH  mesh data
#        OUT : nothing
# ==========================
def CreateObjet(name,MESH_,OBJ3D):
    try:
            OBJ=Blender.Object.Get(name)
            OBJ.link(MESH_)
            OBJ.setMatrix(OBJ3D.matrix) 
    except: 
           OBJ = Blender.Object.New('Mesh')
           OBJ.setName(name) 
           SCENE=Blender.Scene.getCurrent()
           SCENE.link(OBJ)
           OBJ.link(MESH_)
           OBJ.setMatrix(OBJ3D.matrix) 

    LAYER=Blender.Window.ViewLayer()
    l=19
    if  l in LAYER:
             LAYER.remove(l) 
    OBJ.Layer=1<<19

if FRAME==SHATFRAME:
  MESH3D = Object.GetSelected()[0]
  scriptlink=MESH3D.getScriptLinks(EVENT)
  if MESH3D.getType() == 'Mesh' and NAME in scriptlink:
        MESH = NMesh.GetRawFromObject(MESH3D.getName())
        MESH2 = NMesh.GetRaw()
        MESHR = NMesh.GetRaw()
        MESHT =  NMesh.GetRaw() #Marquer la trajectoire
        F_SEL =[]
        F_NONSEL =[]
        # ----------------------------------
        # tri des faces selectionnees  ou non
        # ----------------------------------
        for f in MESH.faces :
            if f.sel==1:
                 F_SEL.append(f)
            else :
                 F_NONSEL.append(f)
          # ------------------------------------------------
        # tous les sommets sont ajoutes, pas necessaire de 
        # faire un tri
        # -------------------------------------------------
        for f in F_SEL: 
              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)

        # ------------------------------------------------
        # tous les sommets sont ajoutes, pas necessaire de 
        # faire un tri
        # -------------------------------------------------
        VERT_INDEX={} 
        for f in F_NONSEL: 
              f1 = Blender.NMesh.Face()
              f2 = Blender.NMesh.Face()
              for v in f.v:
                    #--------------------------------------
                    # ce vertex est-il dans le dico ?
                    #--------------------------------------
                    if v.index in VERT_INDEX.keys():
                        #--------------------------------------
                          # il y est ...
                        #--------------------------------------
                        f1.v.append(MESH2.verts[VERT_INDEX[v.index]])
                        f2.v.append(MESHR.verts[VERT_INDEX[v.index]])
                    else: 
                        #--------------------------------------
                          # il n'y est pas ...
                        #--------------------------------------
                        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)
                        VERT_INDEX[v.index]=len(MESH2.verts)-1
                        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)

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

        CreateObjet('reference',MESHR,MESH3D)
        if TRAJECTORY :
            CreateObjet('Trajectoire',MESHT,MESH3D) 
        Blender.Set('curframe',1)

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()
      SUBSURF=MESH3D.mode and NMesh.Modes['SUBSURF']
      print  SUBSURF, NMesh.Modes['SUBSURF']
      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()
      if SUBSURF : 
           print 'display'
           MESHS.makeDisplayList() 
 

Exemple de script pour lier automatiquement un script à l'objet actif :

import Blender
EVENT='FrameChanged'
# Le chargement de ce script dans une fenetre texte est 
# obligatoire .
NAME='explode4.py''
MESH3D = Blender.Object.GetSelected()[0]
scriptlink=MESH3D.getScriptLinks(EVENT)
if scriptlink and NAME  in scriptlink:
   pass
else:
   # Erreur si NAME ne se trouve pas dans la liste
   # des fichiers texte.
   MESH3D.addScriptLink(NAME,EVENT)
Blender.Window.RedrawAll()

Quelques patterns d'explosion :
 

       #le film
       t=float(FRAME)/100
        g=[0.0,-9.8,0]
        force=p[1]*9.7
        V=[force]*3
        r=0.5
       #le film
        t=float(FRAME)/100
        g=[0.0,-9.8,0]
        force=-p[1]*9.7
        V=[0,force,0]
        r=0.5
       #le 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

 
 
       #le film
       #le film+sol 
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

 
 
précédentScript Text2uvbaker
 Script Mesh2objet : Suivant
Vers le  Haut de 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

mon site de démos sur youtube