#!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()
|