PDA

Voir la version complète : Mon premier script Python. J'ai besoin d'aide pour le tester.



ManuEffect
22/01/2016, 15h50
Bonjour à tous.

Après avoir lu un tweet de Patrick Letourneau : https://twitter.com/PolygonSandwich/status/690237946457239553,
j'ai décidé de me coller à la programmation d'un script pour résoudre ce problème.

Voici donc ce qu'il est censé réaliser:

Pour chaque objet sélectionné :
- Effacer les doublons de tags de texture
- Effacer les tags de sélection vide
- Effacer les tags de texture restreint à des tag de sélection qui n'existe pas

C'est sûrement très mal programmé, je débute totalement en python, mais si vous avez l'occasion de le tester, je suis avide de retours...



import c4d
from c4d import gui


### For selected polygon objects
### - remove empty selection tags
### - remove texture tags restricted to non-existing selection tag
###






def nettoie_polygon_tag(t,anciens_tags):
""" on s'occupe des selections de polygones """

s = t.GetBaseSelect()
if s.GetCount() == 0:
t.Remove()

def nettoie_texture_tag(t,anciens_tags):
""" on s'occupe des textures """

flag_a_garder = False


if t[c4d.TEXTURETAG_RESTRICTION]:
la_restriction = t[c4d.TEXTURETAG_RESTRICTION]

# verifie si restriction existe dans selectiontag
for tt in anciens_tags:
if type(tt) is c4d.SelectionTag:

if tt.GetName() == str (la_restriction):
flag_a_garder = True

else:
flag_a_garder = True


if not flag_a_garder:
t.Remove()


def nettoie_doublon_texture_tag(tag,anciens_tags):
""" on ne garde que la derniere texture """

tags_tex_liste = []
for tt in anciens_tags:
if type(tt) is c4d.TextureTag:
if not tt[c4d.TEXTURETAG_RESTRICTION]:
tags_tex_liste.append(tt)
## tt.Remove()

## remet le dernier
print tags_tex_liste
print (len (tags_tex_liste) )


def nettoie_tags(o):
"""
Nettoyage des Tags
"""




### Passe 1 : virer tag textures doublons
anciens_tags = o.GetTags()
for tag in anciens_tags:
if type(tag) is c4d.TextureTag:
tags_tex_liste = []
for tag in anciens_tags:
if type(tag) is c4d.TextureTag:
if not tag[c4d.TEXTURETAG_RESTRICTION]:
tags_tex_liste.append(tag)
tag.Remove()

c4d.EventAdd()

## Passe 2 : remetre le dernier tag texture
if len (tags_tex_liste) > 0:
le_dernier_tag = tags_tex_liste[len(tags_tex_liste) - 1]
print le_dernier_tag

o.InsertTag(le_dernier_tag)

c4d.EventAdd()


### Passe 3 : virer selection polygones vides
anciens_tags = o.GetTags()
for tag in anciens_tags:
if type(tag) is c4d.SelectionTag:
nettoie_polygon_tag(tag,anciens_tags)
c4d.EventAdd()

### Passe 4 : virer tag textures dont la restriction n'existe pas
anciens_tags = o.GetTags()
for tag in anciens_tags:
if type(tag) is c4d.TextureTag:
nettoie_texture_tag(tag,anciens_tags)
c4d.EventAdd()



def main():
ledoc = c4d.documents.GetActiveDocument() ## type : c4d.documents.BaseDocument
laselection = ledoc.GetActiveObjects(0) ## type : list




ledoc.StartUndo()
for ob in laselection: ## type: c4d.PolygonObject
doc.AddUndo(c4d.UNDOTYPE_CHANGE,ob)
nettoie_tags(ob)

ledoc.EndUndo()
c4d.EventAdd()

if __name__=='__main__':
main()

oli_d
22/01/2016, 21h41
Salut et bienvenue !

Tout d'abord pour un premier script je trouve que tu t'en sors vraiment très bien. Plutôt que d'essayer de corriger tout ton code je te montre comment j'aurais abordé le problème, si tu ne comprends pas des trucs n'hésites pas à demander:



import c4d

def main():

doc.StartUndo()

for o in doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_0):
doc.AddUndo(c4d.UNDOTYPE_CHANGE,o)

#################################################
#suppression des tags de sélection de polygones vides
for t in o.GetTags():
if t.CheckType(c4d.Tpolygonselection):
bs = t.GetBaseSelect()
if not bs.GetCount(): t.Remove()

#liste des noms des tags de sélection qui restent par une ompréhension de liste
sel_names = [t.GetName() for t in o.GetTags() if t.CheckType(c4d.Tpolygonselection)]

#################################################
#suppression des tags texture avec restriction qui n'existent pas
for t in o.GetTags():
if t.CheckType(c4d.Ttexture):
restrict = t[c4d.TEXTURETAG_RESTRICTION]
if restrict and restrict not in sel_names: t.Remove()

#################################################
#suppression de tous les tags texture sans restriction sans le dernier

#liste de tous les tags texture qui n'ont pas de restriction
tags_tex = [t for t in o.GetTags() if t.CheckType(c4d.Ttexture) and not t[c4d.TEXTURETAG_RESTRICTION]]

#on supprime tout sauf le dernier
for t in tags_tex[:-1] : t.Remove()

doc.EndUndo()

c4d.EventAdd()

if __name__=='__main__':
main()


Explications dans l'ordre :

hors plugin tu peux utiliser la variable doc pour remplacer c4d.documents.GetActiveDocument(), c'est plus court à écrire
j'utilise souvent les compréhensions de liste (http://apprendre-python.com/page-comprehension-list-listes-python-cours-debutants), c'est vachement pratique en python
dans une liste si tu veux le dernier élément tu peux écrire list[-1] si tu veux tous les éléments sauf le dernier list[:-1] (voir d'autres combines ici) (http://apprendre-python.com/page-apprendre-listes-list-tableaux-tableaux-liste-array-python-cours-debutant)


En ce qui concerne les fonctions, je suis toujours un peu partagé. Pour les scripts courts je préfére taper le code à la suite, je trouve ça plus lisible. Mon critère pour utiliser une classe ou une fonction, c'est dès que tu commences à copier/coller des portions de code c'est qu'il faut créer soit une classe soit une fonction. Pour les codes plus long, c'est une autre problématique.

Il y a évidemment toujours 40 manières d'arriver au même résultat. J'ai appris sur le tas et je fais sûrement des trucs pas très catholiques. Il y a des plus pro sur le forum, comme xsYann, Valkaari et César qui me corrigeront si j'ai dit des conneries.

En tous cas bravo, ça fait toujours plaisir de voir pointer des nouveaux codeurs par ici.

PS :Si il y a un modo qui passe, je vote pour qu'on le désensable et que l'on bouge ce sujet dans la section programmation

Aurety
22/01/2016, 21h53
ouaip je fais ça !

oli_d
22/01/2016, 21h56
ça c'est du rapide, merci Aurety !

ManuEffect
23/01/2016, 18h02
Merci beaucoup Oli_d pour ta réponse super détaillée et Aurety pour ta promptitude.
Ca va me prendre un peu de temps de bien comprendre ton code, mais c'est super interessant d'avoir le corrigé !



Bon je vais déjà potasser :

bin le python de base....

les listes

les compréhensions de liste (http://apprendre-python.com/page-comprehension-list-listes-python-cours-debutants), rien que le nom m'intrigue




Et merci pour les conseils.

valkaari
25/01/2016, 18h23
j'avais complètement raté ce post tient.


tags_tex = [t for t in o.GetTags() if t.CheckType(c4d.Ttexture) and not t[c4d.TEXTURETAG_RESTRICTION]]

En plus d'être pratique c'est d'une élégance folle.

Antoka
25/08/2019, 02h20
Bonjour,

Je suis sur c4d r20 et ça fait plus de 6 heures que je cherche désespérément à écrire un script python qui sélectionne tous tags de texture assignés aux objets de scène, puis qui change la valeur de restriction (TEXTURETAG_RESTRICTION) à "0".

Ca désactiverait toutes les textures, également dans le live viewport d'octane.
Pour le moment, je débute et ça m'a donc pris des lustres pour comprendre un peu le language et écrire cela :


import c4dfrom c4d import gui


def main():
c4d.CallCommand(300001025) # Select All
c4d.CallCommand(16370, 16370) # Select Texture Tags/Objects
s = doc.GetActiveTags()

for i in s:
tag(i)[c4d.TEXTURETAG_RESTRICTION] = "off#"

c4d.EventAdd()


if __name__=='__main__':
main()

Quand j’exécute, ça sélectionne tous tags de texture assignés aux objets de scène mais impossible de changer les valeurs de restriction sur tous en même temps.

Auriez-vous une solution ?

Merci d'avance !

Antoka

César Vonc
25/08/2019, 11h08
Salut,

Essaie ça plutôt :



for i in s:
i[c4d.TEXTURETAG_RESTRICTION] = "off#"



Ce serait plus joliment écrit comme ceci :



tags = doc.GetActiveTags()

for tag in tags:
tag[c4d.TEXTURETAG_RESTRICTION] = "off#"

Antoka
25/08/2019, 12h29
Merci BEAUCOUP César Vonc.
J'étais pas si loin, merci encore. Le chemin va être long avant de maîtriser ce langage.

Aussi j'aurais une nouvelle question, je ne sais pas c'est approprier de la poser à la suite.
Je cherche à écrire un script qui sélectionne puis fusionne tous les shaders ayant le même "MATERIAL_COLOR_SHADER"

Pour l'instant j'ai ça qui me permet de fusionner les shaders sélectionnés manuellement :


import c4d

def main():
mats = doc.GetActiveMaterials()
list_tags = list()


for mat in mats:
obj_link = mat[c4d.ID_MATERIALASSIGNMENTS]


for i in xrange(obj_link.GetObjectCount()):
list_tags.append(obj_link.ObjectFromIndex(doc, i))


doc.StartUndo()
for tag in list_tags:
doc.AddUndo(c4d.UNDOTYPE_CHANGE, tag)
tag[c4d.TEXTURETAG_MATERIAL] = mats[0]


for mat in mats[1:]:
doc.AddUndo(c4d.UNDOTYPE_DELETE, mat)
mat.Remove()


doc.EndUndo()
c4d.EventAdd()


if __name__=='__main__':
main()

Maintenant je n'ai aucune idée de ce que je pourrait écrire devant afin de ça trouve et sélectionne les doublons. Ce scripts me serait très utiles quand j'importe des persos en fbx issue de DAZ. Il y a toujours 1000 shaders dupliqué à fusionner ça prend du temps. Peut-être qu'un script existe déjà, mais je n'ai rien trouvé pour l'instant.

Merci encore !
Antoka

César Vonc
25/08/2019, 14h06
Pour ça, il faut regrouper tes matériaux dans un dictionnaire avec comme clef le nom de la texture, par exemple :



mats = doc.GetMaterials()

dico = {}

for mat in mats :
clef = 'vide'
tex = mat[c4d.MATERIAL_COLOR_SHADER]
if mat[c4d.MATERIAL_USE_COLOR] and tex and tex[c4d.BITMAPSHADER_FILENAME] : clef = tex[c4d.BITMAPSHADER_FILENAME]


if clef in dico :
dico[clef].append(mat)
else :
dico[clef] = [mat]

groupes = dico.values()

for mats in groupes :
print mats # Et là tu peux appeler ta fonction de dédoublonnage



Après, est-ce que la fonction de C4D ne ferait pas l'affaire ? Dans le gestionnaire de matériaux : Fonction > Supprimer les matériaux en double.