PDA

Voir la version complète : Python Scripts phidek



phidek
12/05/2011, 22h22
Hello la French :icon_wavey:

Etant rookie j'ouvre ce post pour partager mes avancées dans le monde merveilleux de Python, en espérant pouvoir me faire aider et corriger parfois.
J'ai commencé il y a quelques semaines et pour vous donner une idée je vous post mon premier script...

Il renomme chaque enfants de l'objet sélectionné en leur donnant le nom du parent principal + le chiffre correspondant à leur place dans la hiérarchie.
Pratique pour renommer une chaîne de joints par exemple.


import c4d

def main():
pass

counter = 0
end_Counter = 50 #*
const_Selec = doc.GetActiveObject()

while counter<=end_Counter:
selec = doc.GetActiveObject()
new_Selec = selec.GetDown()
le_Nom = const_Selec.GetName()
chiffre = str(counter)
new_Selec.SetName(le_Nom+chiffre)
doc.SetActiveObject(new_Selec)
counter = counter +1


if __name__=='__main__':
main() *J'ai définit la valeur de end_Counter à 50, à défaut d'avoir trouver un moyen de renvoyer le nombre total de sous-objets .GetChildren() ne renvoyant pas les grandchilds. :icon_question:


N'hésitez pas à me corriger.
Merci au post de oli_d qui m'ont permis d'y voir un peu plus clair.

valkaari
12/05/2011, 23h43
il faut revoir ton indentation qui n'est pas bonne à mon sens.

Ton code s'exécutes bien mais pas via la fonction Main. Ce n'est pas forcement un problème (la preuve ça fonctionne) autant prendre de bonnes habitudes.

La fonction Main est au même niveau que ton while. Tu dois virer le pass de ta fonction main et mettre tout ton code en dessous avec une. De la même façon que tout ce qui vas dans le while doit être en dessous avec une tabulation.

Pour ce qui est du "tant qu'il y a un enfant" je ne suis pas certain en python mais normalement tu dois faire un while enfant
et dans la boucle enfant = enfant.GetDown().

Si la fonction GetDown() ne renvoit pas d'objet, elle doit renvoyer none ce qui arrêtera la boucle.

(enfin en c++ c'est comme ça qu'on fait)

Regarde également les fonctions récursive pour ce genre d'exercice, valable dans tous les langages de programmation, c'est diaboliquement puissant et rapide.

edit : j'ai testé ceci et ça fonctionne. J'ai rajouté le c4d.EventAdd() pour que c4d mette à jours l'objet manager après le changement des noms. Par rapport à ton code, pas besoin de récupérer dans la boucle tout ce qui ne change pas.


import c4d

def main():
counter = 0
le_Nom = doc.GetActiveObject().GetName()
enfant = doc.GetActiveObject().GetDown()
while enfant :
chiffre = str(counter)
enfant.SetName(le_Nom + " " + chiffre)
counter += 1
enfant = enfant.GetDown()
c4d.EventAdd()

if __name__=='__main__':
main()


edit 2 :

en générale on préfère écrire counter +=1 plutôt que counter = counter + 1 même si les deux sont identiques.
ça marche également avec les autres opérations.

voir dans d'autres langages tu pourra voir directement counter ++
Ne pas trop abuser quand même, à force ça devient illisible.
un autre abus, c'est les opérations comme j'ai mis genre
enfant = doc. GetActiveObject().GetDown()
si t'as 4km de fonction, autant faire des pointeurs (surtout si tu dois réutiliser d'autre fonction d'un objet ciblé.

phidek
13/05/2011, 02h01
:icon_clap:TOP Val une fois de plus

Parfaites explications.
Comme tjrs.
Je vais revoir ma manière de faire, suite à tes conseils avisés.
En espérant poster quelque chose d'un peu plus propre prochainement.:thumbup1:

oli_d
13/05/2011, 07h26
Bravo pour ton code, ça fait plaisir de voir qu'il y a du monde qui se lance dans le python et ça me motive pour un tuto ...

Je plussoie avec Val qui t'a donné d'excellents conseils.

Pour les bases du python je te conseille 2 excellents outils :


Le livre en ligne gratuit "Programmez avec Python" (http://www.inforef.be/swi/download/python_notes.pdf)de Gérard Swinnen



Si tu préfères les vidéos, "les Pythonneries" (http://www.siteduzero.com/tutoriel-3-262842-apprenez-a-programmer-en-python-video.html)

Regarde en tous cas jusqu'au chapitres sur la récursion des pythonneries.

Bon dans ton cas si tu veux réellement que le premier enfant pas forcément besoin de la récursion.

Mais si tu veux par exemple parcourir tous les objets de ta scène :


import c4d

def parcourir_objs(obj,stop = None):
"""fonction recursive pour parcourir tous les objets
si stop = None tous les objets depuis obj
si stop = obj, uniquement les objets en enfants de obj"""

while obj :
print obj.GetName() #mettre ce que l'on a besoin ici
parcourir_objs(obj.GetDown())# recursion : la fonction s'appelle elle-meme
if stop and obj == stop : return
obj = obj.GetNext()

if __name__=='__main__':
obj = doc.GetFirstObject()#on trouve le premier element de notre scene...
if obj : parcourir_objs(obj)#...si il y en a un on parcourt toutAvec la même fonction pour parcourir tous les enfants de l'objet actif :


import c4d

def parcourir_objs(obj,stop = None):
while obj :
print obj.GetName()
parcourir_objs(obj.GetDown())
if stop and obj == stop : return
obj = obj.GetNext()

if __name__=='__main__':
obj = doc.GetActiveObject()#on recupere l'objet actif...
if obj : parcourir_objs(obj,stop=obj)#...si il existe et on parcourt tous les enfants et sous-enfants

Dans ce cas je ne fais qu'imprimer le nom des objets dans la console, mais tu peux remplacer la ligne où il y a le print par ce que tu veux pour interagir avec tes objets

phidek
14/05/2011, 06h12
Super Oli_d :thumbup1::thumbup1:

Merci pour tes liens, j'espère qu'après leur lecture je ne ressentirai plus cette étrange douleur au cerveau en lisant tes scripts :death: ..:sweatdrop:
« Pour moi, la programmation est plus qu'un art appliqué important. C'est aussi une ambitieuse
quête menée dans les tréfonds de la connaissance. »

Ok :icon_eek: ca attaque fort en page 1...

phidek
21/05/2011, 23h25
Hello à tous :icon_wavey: en particulier à Val et Oli_d

Après une semaine intensive de pythonnerie :whistling: je reviens, comme promis, poster mes avancées sur le reptile.
Voici un nouveau script qui m'a couté pas mal de plantage machine et de surchauffe neuronal :P...

Il regroupe chaque objets au sein du même parent en fonction de leur type (cube, plane, sphere, disc etc...)


import c4d
from c4d import *


def main():
obj = doc.GetObjects()
len_obj= len(obj)
n=0
while n<len_obj:
i=0
while i<len_obj:
if i==n: # ne rien faire (évite le plantage machine)
print 'false'
elif obj[i].GetType()==obj[n].GetType():
obj[i].InsertUnder(obj[n])
obj = doc.GetObjects() # Réinforme la machine sur la taille du chutier une fois modifée.
len_obj= len(obj)
i=i-1
i=i+1
n=n+1
c4d.EventAdd()


if __name__=='__main__':
main()Je pense qu'il existe un moyen plus simple d'atteindre le même but (en dehors d'un glisser déposer avec la souris :P).
Si vous en avez une idée je suis impatient de la connaitre...

oli_d
23/05/2011, 10h25
N'hésites pas à utiliser les boucles for in surtout quand tu récupères une liste :

la fonction doc.GetObjects() renvoie une liste avec tous les objets du premier niveau, donc pour les parcourir tu peux simplement faire :



for obj in doc.GetObjects():
print obj.GetName()Les plantages que tu avais était probablement dû à ta fonction InsertUnder() quand tu essaies de mettre un objet en enfant de lui-même (c'est pire que l'inceste !).

Je te mets une variante qui copie tous les objets et les classes dans un null "Regroupement" (à par ça il y a déjà une fonction qui te permet d'isoler tes éléments par type quand tu cliques sur le petit œil dans la palette objets)


import c4d

def liste_obj(obj,stop = None):
"""fonction recursive pour récupérer tous les objets sous forme de liste
si stop = None tous les objets depuis obj (donc si premier objet d'un doc -> tous les objets)
si stop = obj, uniquement les objets en enfants de obj"""
liste = []
while obj :
liste.append(obj) #on ajoute l'objet a la liste
liste +=liste_obj(obj.GetDown())# recursion : la fonction s'appelle elle-meme et on ajoute la liste
if stop and obj == stop : return
obj = obj.GetNext()
return liste



if __name__=='__main__':

obj = doc.GetFirstObject()
objs = liste_obj(obj,stop = None) # fonction en dessus pour récupérer tous les objets sous forme de liste
null = c4d.BaseObject(c4d.Onull)
null.SetName('Regroupement')

dic_type = {} #on crée un dictionnaire pour stocker nos null object par type
for o in objs:
typ = o.GetTypeName() #on récupère le nom du type
nul_obj = dic_type.get(typ,None) #on regarde si on a déjà stocké un null object correspondant au type ...
if not nul_obj: # si il n'existes pas ...
nul_obj=c4d.BaseObject(c4d.Onull) #...on le crée
nul_obj.SetName(typ)
nul_obj.InsertUnder(null)
dic_type[typ]=nul_obj ## et on l'ajoute à notre dictionnaire

o2 = o.GetClone(flags=c4d.COPYFLAGS_NO_HIERARCHY)# on copie chaque objet sans les enfants
o2.InsertUnder(nul_obj) #et on le met dans notre null object

doc.InsertObject(null)
c4d.EventAdd()

phidek
23/05/2011, 22h16
Merci Oli_d.

J'avais fais pas mal d'essais avec les boucles for in.
J'avais eu des plantages à cause d' obj[x].InsertUnder(obj.[x]) et aussi à cause des boucles infinies... Bref

Merci pour ton code Il y à encore des zones que j'ai du mal à comprendre, je vais me pencher dessus :huh:...
Merci
:thumbup1:

phidek
22/06/2011, 19h41
Un autre petit script qui facilite le processus d'animation d'un cycle de marche.
J'essayerai de le develloper un peu plus dans le futur en esperant en sortir un petit plug


import c4d
from c4d import gui

def main():
Objs=doc.GetActiveObjects(False)

a=0
for i in Objs:
a+=1

if a!=3:
gui.MessageDialog("Please select the 3 following elements: \n - L.Foot \n - R.Foot \n - Control Object")
else:
c4d.CallCommand(12410) # Insert KeyFrames
Obj1V=Objs[0].GetRelPos()
Obj2V=Objs[1].GetRelPos()
Obj3V=Objs[2].GetRelPos()

# Fonction definissant quel pied est le pied arriere
def lepiedarriere():
if Obj1V.z<Obj2V.z:
lePiedArr=Objs[1]
else:
lePiedArr=Objs[0]
return lePiedArr

""" Determine la taille du pas a effectuer en fonction
de l'ecart principal"""

Ecart=Obj1V.z-Obj2V.z
if Ecart<0:
Ecart=0-Ecart

PiedsV=lepiedarriere().GetRelPos()
if PiedsV==Obj1V:
PiedsV.z=0+(Obj2V.z-Ecart)
else:
PiedsV.z=0+(Obj1V.z-Ecart)

lepiedarriere().SetRelPos(PiedsV)

#Determine l'amplitude de l'avancement de l'objet controleur
Obj3V.z=Obj3V.z-Ecart
Objs[2].SetRelPos(Obj3V)

#InsertKey toutes les x Frames Message d'erreur "out of timeline"
def nbrsDeFrames(c):
fps = doc.GetFps()
currentFrame = doc.GetTime().GetFrame(fps)
endTime = doc.GetMaxTime().GetFrame(fps)
if currentFrame>=endTime-(c-1):
gui.MessageDialog("Out of timeline")
else:
doc.SetTime(c4d.BaseTime(currentFrame+c ,fps))
c4d.CallCommand(12410) #insert la key

# Modifie l'interpolation de chaque keys
def interpolation(d):
for n in range(len(Objs)):
track = Objs[n].GetCTracks() #List de CTrack
b=0
key_Count= track[1].GetCurve().GetKeyCount()
while b<=key_Count-1:
for i in range(len(track)):
curve = track[i].GetCurve()
lacle=curve.GetKey(b)
test=lacle.SetInterpolation(curve, d)
b+=1

nbrsDeFrames(20)#Soi 20 frames pour un pas
c4d.EventAdd()
interpolation(2) #Type d'interpolation 2 soi lineaire


if __name__=='__main__':
main()
Les 3 objets doivent être sélectionnés dans cet ordre "les 2 pieds puis l'objet contrôleur".
La grandeur des pas est déterminée en fonction de la pose de départ.
Il ne reste plus qu'à placer la valeur "Y" entre chaque pas.


http://vimeo.com/25457347

Vue que je suis débutant les corrections sont tjrs le bienvenues :icon_mrgreen:
Merci pour les retours...:icon_wavey: