PDA

Voir la version complète : WIP Apprendre le Python



Seb-bbl
09/06/2011, 13h06
Salut la French.

Bon, j'ai décidé de me lancer dans l'apprentissage du Python, et je peux vous dire que ça va pas être de la tarte, vu que mes compétences au niveau de la programmation sont proches du zéro absolu.
J'ai commencé à éplucher la doc, et c'est pas gagné, j'y comprends pas grand-chose, aussi j'aurai besoin de quelques pistes pour me mettre le pied à l'étrier.

Voici mon tout premier code, et j'en suis pas peu fier :


import c4d
mat = c4d.BaseMaterial(c4d.Mmaterial)
doc.InsertMaterial(mat)
c4d.EventAdd()

Je me sens comme à la création de ma première sphère réfléchissant un damier !

Le but de la suite de l'exercice, c'est d'activer la transparence, de désactiver la couleur et de régler la réfraction à 1.5. Et déjà les choses se gâtent !
Peut-être que le Material.SetChannelState me serait d'une quelconque utilité, mais je n'arrive pas à le positionner correctement ou à avoir la syntaxe correcte, en bref, je nage pas, je coule !

Donc si de généreux codeurs pouvaient me tendre la main, ce serait bien cool !

tarlack
09/06/2011, 13h18
avant de vouloir utiliser l'api de c4d pour python, je ne peux que recommander d'apprendre au moins les bases de python. Des tutoriaux sont disponibles en nombre sur internet, tel que par exemple http://docs.python.org/tutorial/. C'est sans recommandation particuliere, je ne l'ai pas suivi mais c'est le tutorial du site officiel de python, donc il doit pas etre trop mal. Bon courage et bienvenu dans le monde de la programmation ;)

Seb-bbl
09/06/2011, 13h25
Merci, j'y jetterai un globe oculaire.

En attendant, j'ai réussi à obtenir ce que je voulais, ayant enfin pigé le principe des ID :


import c4d

Mat = c4d.BaseMaterial(c4d.Mmaterial)
Mat[c4d.MATERIAL_USE_TRANSPARENCY] = 1
Mat[c4d.MATERIAL_USE_COLOR] = 0
Mat[c4d.MATERIAL_TRANSPARENCY_REFRACTION] = 1.5
doc.InsertMaterial(Mat)
c4d.EventAdd()

C'est jouissif !

Bon, ok, script créé, avec sa petite icône, ajouté dans l'interface, tout va bien. Maintenant, une petite question d'ordre esthétique : lorsque je survole l'icône, l'infobulle et le message d'aide utilisateur me disent : exécuter xxxxxxx.py. Comment mettre une petite description à la place ?

Ouais, bon, je fais mon débutant de base, avec des questions con, mais c'est vraiment pas évident au départ, on ne sait pas où chercher et surtout QUOI chercher ! Y'a pas un bac à sable pour les développeurs en herbe ? :icon_mrgreen:

xs_yann
09/06/2011, 14h39
Salut Seb,

Je ne sais pas si c'est possible de changer la BubbleHelp d'un script (je n'y connais pas grand chose aux scripts), mais tu peux le faire en transformant ton script en plugin comme ceci :

import os
import c4d
from c4d import plugins

# be sure to use a unique ID obtained from www.plugincafe.com
PLUGIN_ID = 1000007

class MyScript(c4d.plugins.CommandData):

def Execute(self, doc):
mat = c4d.BaseMaterial(c4d.Mmaterial)
mat[c4d.MATERIAL_USE_TRANSPARENCY] = True
mat[c4d.MATERIAL_USE_COLOR] = False
mat[c4d.MATERIAL_TRANSPARENCY_REFRACTION] = 1.5
doc.InsertMaterial(mat)
c4d.EventAdd(c4d.EVENT_0)
return True

if __name__ == "__main__":
bmp = c4d.bitmaps.BaseBitmap()
dir, file = os.path.split(__file__)
fn = os.path.join(dir, "res", "icon.tif")
bmp.InitWith(fn)
c4d.plugins.RegisterCommandPlugin(id=PLUGIN_ID, str="MyScript",
info=0, icon=bmp, help="Create a preset Material", dat=MyScript())

Une seule petite critique sur ton code : évite de nommer tes variables avec une majuscule au début c'est réservé aux noms de classes.
Un petit article qui a l'air pas mal : http://all4dev.libre-entreprise.org/index.php/Conventions_de_syntaxe_en_python

Bon courage. ;)

Seb-bbl
09/06/2011, 15h10
Merci pour ta réponse Yann. Pour le moment, j'en suis à l'étape du script, celle du plugin comporte quelques notions que je n'ai pas encore découvertes.

Et comme je n'arrive à mémoriser que par l'exemple, peut-être aurais-tu la gentillesse de compléter mon explication de texte...


import os
import c4d
from c4d import plugins
Ici on importe les libraries générales de C4D ainsi que celles liées aux plugins, j'ai bon ?


# be sure to use a unique ID obtained from www.plugincafe.com
PLUGIN_ID = 1000007
On renseigne l'ID du plugin, obtenue sur C4D Café. Les ID entre 1000000 et 1000010 sont réservées au développement.


class MyScript(c4d.plugins.CommandData):

def Execute(self, doc):
Là, je sèche, mais au pif, je dirais : exécuter le script dans le doc courant ? (MyScript, c'est le nom de la classe ou bien à remplacer par un nom perso ?)

Bon, ensuite c'est mon script.


return True

if __name__ == "__main__":
bmp = c4d.bitmaps.BaseBitmap()
dir, file = os.path.split(__file__)
fn = os.path.join(dir, "res", "icon.tif")
bmp.InitWith(fn)
c4d.plugins.RegisterCommandPlugin(id=PLUGIN_ID, str="MyScript",
info=0, icon=bmp, help="Create a preset Material", dat=MyScript())
Là, pareil, je pédale. J'y vois quand même la référence à l'icône (qui doit se trouver dans le répertoire res), la référence au plugin ID (j'imagine qu'on devra lui mettre l'ID obtenue sur C4D café), le type d'icône (?) ainsi que le texte d'infobulle. Après, pourquoi c'est agencé ainsi, et ce que ça signifie au final, j'en sais foutre rien. Mais je compte bien le découvrir.

Je rappelle que je suis un total noob en programmation, tous langages confondus. Mes derniers programmes étaient en basic sur un Tandy MC-10 ou un tout petit peu plus récemment sur une Texas Instruments (bref, rien depuis le début des années 90, et encore, c'étaient vraiment des programmes ultra-basiques). J'ai donc tout à apprendre, mais ça a l'air vraiment passionnant.

Edit : 'tain, je me sens comme un petit garçon qui veut tout savoir et qui pose des milliers de questions.

xs_yann
09/06/2011, 16h16
import os
import c4d
from c4d import plugins

Ici on importe les libraries générales de C4D ainsi que celles liées aux plugins, j'ai bon ?

Presque, le module os est un module Python (qui n'est pas propre à c4d) : http://docs.python.org/library/os.html
Ensuite on importe le module c4d ; la ligne 'from c4d import plugins' permet d'importer le module c4d.plugins ce qui permet d'écrire plugins.toto au lieu de c4d.plugins.toto (d'ailleurs ce n'est pas utile pour le plugin que je t'ai présenté étant donné que j'ai écris c4d. avant à chaque fois :sweatdrop:)


# be sure to use a unique ID obtained from www.plugincafe.com
PLUGIN_ID = 1000007

On renseigne l'ID du plugin, obtenue sur C4D Café. Les ID entre 1000000 et 1000010 sont réservées au développement.
Tout à fait.


class MyScript(c4d.plugins.CommandData):

def Execute(self, doc):

MyScript est le nom de ta classe de plugin, en général je l'appelle du même nom que mes plug (sauf que xsFooBar devient XSFooBar pour les mêmes raison évoquées dans mon post précédent).

'(c4d.plugins.CommandData)' signifie que ta classe hérite de la classe CommandData, tu as dans la doc Python les méthodes découlant de cette classe que tu peux surcharger. (Les cours t'expliquerons mieux que moi ce que sont l'héritage et la surcharge (overriding) )

L'idéal étant de trouver des exemples de plugins Python, comme ça tu peux voir ce qui est nécessaire au bon fonctionnement de tel ou tel type de plugin.


return True

if __name__ == "__main__":
bmp = c4d.bitmaps.BaseBitmap()
dir, file = os.path.split(__file__)
fn = os.path.join(dir, "res", "icon.tif")
bmp.InitWith(fn)
c4d.plugins.RegisterCommandPlugin(id=PLUGIN_ID, str="MyScript",
info=0, icon=bmp, help="Create a preset Material", dat=MyScript())

Je ne saurais pas exactement t'expliquer l'utilité du 'if __name__ == "__main__":', tu peux l'enlever, cela fonctionnera toujours. D'après ce que je sais cela est utile si tu veux réutiliser ton fichier en tant que module sans que ce code soit executé à l'import.


dir, file = os.path.split(__file__)


os.path.split(path)
Split the pathname path into a pair, (head, tail) where tail is the last pathname component and head is everything leading up to that. The tail part will never contain a slash; if path ends in a slash, tail will be empty. If there is no slash in path, head will be empty. If path is empty, both head and tail are empty. Trailing slashes are stripped from head unless it is the root (one or more slashes only). In all cases, join(head, tail) returns a path to the same location as path (but the strings may differ).

Tu récupères donc 'dir = /Applications/MAXON/Cinema 4D/plugins' et 'file = MyScript.pyp'


fn = os.path.join(dir, "res", "icon.tif")

Tu peux donc récupérer le filename de ton icone qui sera dans le dossier res (au même niveau que ton fichier .pyp)


c4d.plugins.RegisterCommandPlugin(id=PLUGIN_ID, str="MyScript",
info=0, icon=bmp, help="Create a preset Material", dat=MyScript())

C'est là que tu dis à c4d que ton plugin existe avec son id, son nom, les paramètres du plug (si tu veux le cacher dans le menu et autre, voir la doc), son icône, l'aide affichée dans la status bar et le tool tips, et une instance de ton plugin (que c4d va mémoriser et qui lui servira à intégrer ton plugin, si tu veux en savoir plus regarde du côté des Design Patterns).

Si je n'ai pas été clair sur quelque chose, dis le moi j'essayerais de développer / reformuler. ;)
Il faut aussi que tu saches que je suis également débutant en Python (moins d'un an de pratique non régulière) donc je ne connais pas toutes les subtilités du langages. :icon_artist:

Seb-bbl
09/06/2011, 16h52
Un grand merci pour ces explications qui m'en apprennent déjà un peu plus. Reste à apprendre la langue. Le plus difficile étant la théorie (chose dont j'ai horreur, comme je l'ai dit, j'apprends mieux par l'exemple) et surtout le fait qu'il y ait des choses générales de python et d'autres spécifiques à C4D, du coup on sait pas trop où chercher. Mais ça va venir !

Si vous connaissez des liens vers des tutos (avec des exemples concrets et commentés) je suis preneur. Allez, on va potasser tout ça !

oli_d
09/06/2011, 17h25
Salut Seb,

Je te conseillerais de commencer par les bases du python puis après quand tu commences à comprendre les boucles, les fonctions, les classes de regarder dans cette section les petits scripts qui trainent et de les décortiquer en parallèle avec la doc python. Dans certaines version de la doc (faut que je vérifie laquelle) il y a des exemples de plugins, de scripts et de scènes avec des générateurs ou des tags python.

Pour les bases du python je te conseille vivement ces deux liens :


Le livre en ligne "Programmez avec Python" (http://www.inforef.be/swi/download/python_notes.pdf)de Gérard Swinnen (vraiment très très bien fait et en plus gratuit)



Si tu préfères les vidéos, "les Pythonneries" (http://www.siteduzero.com/tutoriel-3-262842-apprenez-a-programmer-en-python-video.html) (avec une pointe d'humour pas désagréable)

Seb-bbl
09/06/2011, 19h04
Je sens que je vais aimer le second lien.

Sinon, une question me taraude : fondamentalement, quelle est la différence entre un script en un plugin ? Qu'est-ce qui les caractérise ? (oui, je sais, ça fait 2 questions).

oli_d
09/06/2011, 22h18
Là je me sens obligé de mettre à jour mon tuto (http://frenchcinema4d.fr/showthread.php?69711-Py4D-le-language-python-dans-C4D&p=916644#post916644), tu m'as déjà tellement appris de trucs avec les tiens qu'il faut que je te renvoie l'ascenseur.

J'ai mis à jour jusqu'à Créer un objet dans c4d mais sans changer les captures d'écran (il y a plein de trucs que je ne ferai plus la même chose, comme la boucle while que j'utilise très peu je préfère de loin le for , mais bon le principe est là).

Je pars demain pour quelques jours donc il faudra patienter pour la suite, mais bon entre les pythonneries, le livre de Swinnen et le reste tu as largement de quoi occuper tes prochaines nuits :icon_mrgreen:

valkaari
09/06/2011, 23h39
Je ne saurais pas exactement t'expliquer l'utilité du 'if __name__ == "__main__":', tu peux l'enlever, cela fonctionnera toujours. D'après ce que je sais cela est utile si tu veux réutiliser ton fichier en tant que module sans que ce code soit executé à l'import.


ha ben voilà un mystère pour moi de soulevé ^^

voir le 6.1.1. Executing modules as scripts
http://docs.python.org/tutorial/modules.html

ksaa
10/06/2011, 04h37
Hello,
cela fait quelques jours déjà que j'ai touché a Rien! Pas de c4d ni python >>> période de déménagement, mais je vais essayer d'apporter quelques réponses

Pour ce qui est du 'if __name__ == "__main__":, c'est une façon de dire à python " OoHooo je veux exécuter ce module en tant que programme indépendant ... par exemple:
J'importe un module toto.py contenant une méthode qui affiche le message " j'aime python " dans mon script coco.py
J’écris :
import toto au début pour importer… rien de bien compliqué…
Coco.py lui affiche le message " j’aime c4d "…. Maintenant si j'exécute coco.py j’aurai seulement " j’aime c4d ", par contre si j'integre 'if __name__ == "__main__": dans toto.py. J’aurai les deux messages .




Sinon, une question me taraude : fondamentalement, quelle est la différence entre un script en un plugin ? Qu'est-ce qui les caractérise ? (oui, je sais, ça fait 2 questions).


Ben... je pense qu'au début c'est une question de choix ...
Le corps du plugin reste le script lui-même... après.... admettons que je veuille partager ce que j'ai fait sans partager le code source pour autant ... dans ce cas le plugin est plus adapté, car je peux crypter mon code...
Autre cas .... si par exemple j’ai une interface dans mon programme, mon interface sera en français, pour un utilisateur anglais ce n’est pas top, avec un plugin le changement de langue se fait automatiquement, à condition d'avoir réalisé la traduction >> à mettre dans des dossiers portants des noms du style strings_fr ou strings_US etc...

Sinon niveau écriture, le plugin a besoin de deux ou trois choses par exemple un ID, un Type, et une class qui contient notre code

Type >>> dépend de ce que fait le plugin, voir Register Methods (http://www.thirdpartyplugins.com/python/modules/c4d.plugins/index.html)
La classe >>> son argument dépend du type choisi
Y a surement d’autres différences plus "fondamentales", mais c’est tout ce qui me vient à l’esprit maintenant (à 4h du mat :) )…

Bon courage

Seb-bbl
10/06/2011, 09h19
Merci !

J'ai regardé la première vidéo des pythonneries, et au niveau de la méthode explicative, c'est exactement ce qu'il me faut (faut qu'on m'explique comme si j'avais 5 ans sinon je comprends rien).
On va voir la suite. Et merci pour ces explications (mais je continuerai à vous emmerder avec mes questions de gros zéro !) :icon_mrgreen:

Seb-bbl
15/06/2011, 09h07
Je suis à la recherche des valeurs acceptées en fonction de l'attribut choisi.

Par exemple, pour :

[c4d.GI_SETUP_DATA_IR_COUNT_METHOD]

je sais que je peux entrer

=c4d.GI_SETUP_COUNT_LOW

mais ça, c'est parce qu'on me l'a dit.

Je sais qu'en faisant un drag n'drop du paramètre dans l'éditeur, il se retrouve correctement écrit dans le code, mais où trouver les valeurs acceptées ? La doc python relative à C4D n'est pas exhaustive sur ce sujet (je n'ai par exemple pas trouvé les réglages relatifs à l'IG).

Je suis persuadé que j'ai loupé quelque chose, mais si vous pouviez me dire quoi, je me coucherais moins c...

oli_d
15/06/2011, 10h03
Je te conseille de charger aussi la doc du C++, le python utilise les mêmes constantes et il y a plein de trucs qui ne sont pas encore dans la doc python.

Dans le cas que tu cites, la constante n'est pas non plus dans la doc du c++ (je sais c'est pas simple) mais tu peux ruser en faisant une recherche du mot GI_SETUP_DATA_IR_INTERPOLATION_SMOOTHING dans le dossier Maxon et tu verras que dans ce cas il y a un fichier vpgisetup.h dans /Applications/MAXON/CINEMA 4D R12/modules/advanced render/advanced render/res/description et si tu ouvres ce fichier dans un éditeur de texte tu auras la liste de toutes les constantes.

Mais le drag and drop est beaucoup plus simple ...

xs_yann
15/06/2011, 10h12
Salut,

Je vois que oli_d a été plus rapide. :ninja:

Voici ma méthode, qui n'est pas loin de celle de oli_d : Je paste 'GI_SETUP_DATA_IR_COUNT_METHOD' dans le Spotlight et je tombe directement sur le fichier vpgisetup.res, je pense qu'il vaut mieux chercher dans le .res parce que les définitions sont groupées comme dans l'interface (alors qu'elle sont un peu dispersées dans le .h), voire dans le .str avec une recherche du nom affiché dans c4d (exemple : "Custom Sample Count").

Seb-bbl
15/06/2011, 11h07
héhé, ça, c'est bon quand tu es sur mac, qui a une indexation excellente, sur PC, tu peux te brosser pour qu'il te trouve efficacement quelque chose dans le contenu.

Mais je comprends mieux où chercher, en fait, c'est relatif à chaque module. Merci beaucoup !

Focus3D
15/06/2011, 20h17
salut,

allez voir cet excellent tuto sur python pour c4d a [/URL][URL]http://www.smart-page.net/blog/2011/05/09/advanced-python-plugin-coding-for-cinema-4d/ (http://www.smart-page.net/blog/2011/05/09/advanced-python-plugin-coding-for-cinema-4d/)

peit bonus:
dans le script manager de python dans c4d ecrivez : help("modules") vous donne tous les modules python installes;
help("c4d") vous donne l'arborescence des classes et des fonctions de python pour c4d (utiles pour creer fichier xml pour notepad++) mais aussi les elements data de cinema4d et des plugins.

en souhaitant que ceci vous sera utile.

Seb-bbl
15/06/2011, 21h12
Merci !

luistappa
18/11/2011, 16h52
Salut la French.

Bon, j'ai décidé de me lancer dans l'apprentissage du Python, et je peux vous dire que ça va pas être de la tarte, vu que mes compétences au niveau de la programmation sont proches du zéro absolu.
J'ai commencé à éplucher la doc, et c'est pas gagné, j'y comprends pas grand-chose, aussi j'aurai besoin de quelques pistes pour me mettre le pied à l'étrier.
...

Voilà qui est courageux Seb.
Bon je suis dans ton cas si ce n'est que j'ai programmé il y a longtemps en Basic et Pascal et que je pratique toujours un peu pour le boulot en Visual Basic dans Excel. mais comme tu le dis bien, pour le moment c'est obscure dans ma tête et oui je sens que ça va pas être de la tarte :)

Donc je prends ce post en route et je vais suivre ta progression Seb en espérant que cela m'aidera à avancer moi aussi.

Seb-bbl
18/11/2011, 17h47
Oulà, chouette déterrage, Luis, ça fait un moment que j'ai pas touché à Python. Je porterais bien mon RockGen dessus, mais je manque de motivation !

Seb-bbl
09/01/2012, 11h33
Salutations,

Voilà, j'ai ce petit bout de code qui me pose souci :


import c4d

def main():
selec = doc.GetActiveObject()
if selec :
HyperNurbs=c4d.BaseObject(c4d.Osds)
doc.InsertObject(HyperNurbs)
selec.InsertUnder(HyperNurbs)
c4d.EventAdd()

if __name__=='__main__':
main()
Lorsque j'applique le script, pas de souci, l'objet se retrouve bien dans un HN. Mais lorsque j'annule, mon objet disparaît et je me retrouve avec tout un tas de HN... Qu'est-ce que j'ai fait de travers ?

fabrice.sierra
09/01/2012, 15h41
Bonjour à vous tous et une chouette année,

Pour ceux qui comme moi sont franchement nul en programmation,
voici sur le site du zéro qui propose des cours en français sur Python :

http://www.siteduzero.com/tutoriel-3-262844-les-variables-et-les-types-de-donnees.html

valkaari
09/01/2012, 16h07
Lorsque tu programmes des actions, il faut aussi mettre en place le undo. Ce n'est pas logique par contre de se retrouver avec un tas d'HN.

Par exemple :
tu crées un cube via l'interface -> il ajoute un undo dans la liste des undo.
Ton script rajoutes l'HN, mets le cube enfant de l'HN mais tu n'ajoutes pas d'undo à la liste des undo.

Du coup, quand tu annules il annule uniquement le premier élément de la liste qui est la création de ton cube.
En gros, il faut faire un startundo au début, à chaque action que tu veux rajouter dans ton undo, avant ou après suivant les cas, rajouter l'action et finir par un endUndo ou stopundo je sais plus de tête ^^

Je regarderais dans 1h à la louche, faut que je vire le sapin de noël rapidos avant .....

edit : sapin viré script modifié.


import c4d

def main():
selec = doc.GetActiveObject()
if selec :
doc.StartUndo() #start undo

HyperNurbs=c4d.BaseObject(c4d.Osds)
doc.AddUndo(c4d.UNDOTYPE_NEW,HyperNurbs) #add après l'HN puisque l'ajout de l'HN c'est une création

doc.AddUndo(c4d.UNDOTYPE_CHANGE, HyperNurbs) #ajout dans l'undo de la modification de la hiérarchie. Se place avant la modification.
doc.InsertObject(HyperNurbs)

doc.AddUndo(c4d.UNDOTYPE_CHANGE,selec) # ajout de la modification de la hiérarchi pour l'objet selectionné.
selec.InsertUnder(HyperNurbs)

doc.EndUndo() #fin de l'undo.

#un control Z vas annuler 3 actions
c4d.EventAdd()



if __name__=='__main__':
main


Une minuscule précision. En générale, avant de faire le select.InsertUnder(HyperNurbs) on doit faire un select.Remove().
En gros, le supprimer de la hiérarchie (mais il reste en mémoire) et après l'insérer dans le nouvel objet.
En python, ça ne plante pas visiblement, mais il est préférable de prendre l'habitude de le faire au cas où tu passerais en c++

C'est plus propre. D'ailleurs je me demande si la fonction InsertUnder ne le fait pas d'office.

Seb-bbl
09/01/2012, 17h53
Ouch ! Excellent, je n'en demandais pas tant ! Je m'en vais mettre ça en pratique aussi sur mon autre script ! Un gros merci !

Seb-bbl
09/01/2012, 18h27
Je fais face à un nouveau problème, auquel je n'avais pas pensé et qui est lié à ma commande selec.InsertUnder(HyperNurbs) : si mon objet est à l'origine enfant d'un autre, il est sorti de la hiérarchie et placé dans le HN qui est en haut de la hiérarchie. Le script perd de son intérêt donc si l'objet fait partie d'une hiérarchie. La question est donc : comment placer le HN au même niveau hiérarchique que l'objet avant de glisser l'objet dans le HN ?

:icon_wip:

PS : je n'ai pas réussi à mettre en place mon undo sur mon autre script, mais j'y reviendrai plus tard, c'est moins important. ;)

valkaari
09/01/2012, 19h57
là comme ça, je dirais que tu prends l'objet sélectionné, et tu fais un MonParent = select.GetUp() histoire de récupérer l'objet parent. Ensuite tu fais un If MonParent: inserer l'hn enfant de l'objet MonParent Else: insérer l'HN dans le document.

La fonction GetUp() renvoie l'objet ou None s'il n'existe pas.


Accessoirement, tu sais que quand on appuie sur la touche Alt, ça mets l'objet crée (que ça soit un HN ou pas) en parent de l'objet sélectionné ?
(puis shift c'est pour le mettre en enfant)

Seb-bbl
09/01/2012, 20h50
Super ! Je comprends tout à fait une fois que le nom de la commande est énoncé, le souci, c'est justement de trouver le nom de cette commande !

Accessoirement, oui, je sais, mais ça me fait découvrir le scripting ! Pis je suis un gros fainéant : si je peux ne faire qu'un clic en lieu et place d'un alt+clic, je prends !

Edit : ça fonctionne au poil, merci ! Je posterai le script bientôt !

oli_d
09/01/2012, 21h45
Pas grand chose à rajouter, Val a tout dit. Juste un petit truc qui peut faire gagner un peu de temps; dans un script au lieu de selec = doc.GetActiveObject() tu peux simplement utiliser la variable op et commencer par :

if op:au lieu de :


selec = doc.GetActiveObject()
if selec :soit 31 frappages de touche en moins, au prix du frappage de touche actuel c'est toujours ça de pris...

Val toutes mes condoléances pour la perte de ton sapin

Seb-bbl
09/01/2012, 22h13
Si on utilise ce "if : op", comment ensuite dire à l'objet actif de se mettre enfant de l'objet HN ? Où et quand définit-on le nom de l'objet actif ? A moins que ce "op" soit justement l'objet actif ? Auquel cas on pourrait dire :

op.InsertUnder(HyperNurbs) ?

Voilà mon code (qui peut sans doute être amélioré) :


import c4d

def main():
selec = doc.GetActiveObject()
MonParent = selec.GetUp()
if MonParent :
doc.StartUndo()
HyperNurbs=c4d.BaseObject(c4d.Osds)
doc.AddUndo(c4d.UNDOTYPE_NEW,HyperNurbs)
doc.AddUndo(c4d.UNDOTYPE_CHANGE,HyperNurbs)
doc.InsertObject(HyperNurbs)
doc.AddUndo(c4d.UNDOTYPE_CHANGE,HyperNurbs)
HyperNurbs.InsertUnder(MonParent)
doc.AddUndo(c4d.UNDOTYPE_CHANGE,selec)
selec.InsertUnder(HyperNurbs)
doc.EndUndo()
c4d.EventAdd()
else :
if selec :
doc.StartUndo()
HyperNurbs=c4d.BaseObject(c4d.Osds)
doc.AddUndo(c4d.UNDOTYPE_NEW,HyperNurbs)
doc.AddUndo(c4d.UNDOTYPE_CHANGE,HyperNurbs)
doc.InsertObject(HyperNurbs)
doc.AddUndo(c4d.UNDOTYPE_CHANGE,selec)
selec.InsertUnder(HyperNurbs)
doc.EndUndo()
c4d.EventAdd()

if __name__=='__main__':
main()

valkaari
09/01/2012, 22h37
En fait op et doc sont deux variables initialisés lorsque tu lances le script. doc contient le document dans lequel est exécuté le script, op l'objet si tu exécutes les scripts au niveau document, mais le tag si tu exécutes le python depuis un tag python.

Ta fonction selec = doc.GetActiveObject() ne fonctionne que parce que sans le savoir, doc a été initialisé et pointe vers le document.

Par contre, il y a une erreur de logique dans ton script. La fonction If parent ...else ... doit être imbriqué dans ton If select: .... et pas l'inverse.

Là, si tu n'as aucune sélection, ça risque de planter. Donc avant tout, tu vérifies si tu as bien une sélection, ensuite, tu vérifies si tu as un parent.

Etape suivante de ton script, avoir plusieurs objets sélectionné, les mettre dans un objet neutre, et l'objet neutre dans un HN :)

copie à rendre demain sans faute !!!

Seb-bbl
09/01/2012, 22h57
Par contre, il y a une erreur de logique dans ton script. La fonction If parent ...else ... doit être imbriqué dans ton If select: .... et pas l'inverse.
Mais si on fait l'inverse, on fait quoi après le else ? Par contre, je viens d'essayer sans objet sélectionné, ça ne plante pas.

Ma logique (qui vaut ce qu'elle vaut) : si on a un parent, on récupère le parent, on insère le HN en enfant et on met l'objet sélectionné enfant du HN.
Sinon, on insère le HN dans le document et on met l'objet sélectionné dans le HN.
C'est pas comme ça qu'il faut le voir ?

Sinon, l'exercice est intéressant, et je le ferai demain soir, mais je ne l'ajouterai pas à mon script qui est juste comme je le veux !

valkaari
09/01/2012, 23h52
c'est pas ce que tu as fait.

Toi c'est si parent ..... sinon si sélectionné....

faut que tu fasses un


if select:
parent = select.GetUp()
if parent:
ajouter l'HN enfant du parent
else:
ajouter l'HN dans le document
qu'il y ai un parent ou pas, ajouter l'objet sélectionné enfant de l'HN.

else:
afficher un message "merci de sélectionner un objet"

Jissey
10/01/2012, 07h37
si je peu me permettre un question de Super noob, qu'elle est la difference entre python et xpresso dans c4d. les deux servent bien a programmer des actions pour l'animation dans notre logiciel? alors pourquoi deux types de programation différentes?
Bon, cela ne fait pas encore assez longtemps que j'arpente C4D pour en saisir toutes les ressources, mais la programmation m'a toujours attiré, alors je me pose des questions.
merci d'avance

Seb-bbl
10/01/2012, 08h20
Ah oui ok, je voyais pas la chose comme ça, merci, je vais corriger ça. Et puis je m'occupe de la sélection multiple aussi.

Jissey : xpresso est un système qui permet des interactions entre éléments, avec des relations de cause à effet. Python va permettre la création de scripts et de plugins.

Bon, la première partie, c'est ok. Pour la seconde, voici comment je voulais procéder :

Sélectionner les objets actifs
les mettre dans un neutre
mettre le neutre dans le HN.

Avec la fonction GetActiveObject, tant que je n'ai qu'un seul objet sélectionné, tout va bien. Si j'en ai plusieurs, rien ne se passe (enfin si, j'ai mon message d'erreur final "veuillez sélectionner un objet")
J'ai donc essayé GetActiveObjects(), mais pas moyen de l'exploiter, je ne trouve pas comment l'utiliser.

Autre problème : j'ai plusieurs objets, mais répartis dans plusieurs autres objets. Quel comportement pourrait-on attendre ? Un regroupement en tête de hiérarchie ?
Dans ce cas, je pose un if "sélection multiple", alors mettre un neutre puis mettre "sélection multiple" dans HN. Et si pas de sélection multiple, alors si selec blabla else si parent blabla else print "select first". J'ai bon ? Si j'ai bon, ma seule galère est de détecter cette sélection multiple, ce que je n'arrive pas à faire. Un indice ?

Re-edit : bon, j'ai réussi à détecter la sélection multiple, à en faire une condition. Afficher un message en cas de sélection multiple, c'est bon, mais mettre la sélection enfant du neutre, ça coince : "list" object has no attribute InsertUnder. Je creuse.

Seb-bbl
10/01/2012, 10h47
Je pense être dans le vrai :


import c4d
from c4d import gui

def main():
objList = doc.GetActiveObjects(0)
selec = doc.GetActiveObject()
if selec :
MonParent = selec.GetUp()
if MonParent :
doc.StartUndo()
HyperNurbs=c4d.BaseObject(c4d.Osds)
doc.AddUndo(c4d.UNDOTYPE_NEW,HyperNurbs)
doc.AddUndo(c4d.UNDOTYPE_CHANGE,HyperNurbs)
doc.InsertObject(HyperNurbs)
doc.AddUndo(c4d.UNDOTYPE_CHANGE,HyperNurbs)
HyperNurbs.InsertUnder(MonParent)
doc.AddUndo(c4d.UNDOTYPE_CHANGE,selec)
selec.InsertUnder(HyperNurbs)
doc.EndUndo()
c4d.EventAdd()
else :
doc.StartUndo()
HyperNurbs=c4d.BaseObject(c4d.Osds)
doc.AddUndo(c4d.UNDOTYPE_NEW,HyperNurbs)
doc.AddUndo(c4d.UNDOTYPE_CHANGE,HyperNurbs)
doc.InsertObject(HyperNurbs)
doc.AddUndo(c4d.UNDOTYPE_CHANGE,selec)
selec.InsertUnder(HyperNurbs)
doc.EndUndo()
c4d.EventAdd()
else :
if objList :
doc.StartUndo()
HyperNurbs=c4d.BaseObject(c4d.Osds)
MyNull=c4d.BaseObject(c4d.Onull)
doc.AddUndo(c4d.UNDOTYPE_NEW,MyNull)
doc.AddUndo(c4d.UNDOTYPE_CHANGE,MyNull)
doc.InsertObject(MyNull)
doc.AddUndo(c4d.UNDOTYPE_NEW,HyperNurbs)
doc.AddUndo(c4d.UNDOTYPE_CHANGE,HyperNurbs)
doc.InsertObject(HyperNurbs)
doc.AddUndo(c4d.UNDOTYPE_CHANGE,MyNull)
MyNull.InsertUnder(HyperNurbs)
for obj in objList :
doc.AddUndo(c4d.UNDOTYPE_CHANGE,obj)
obj.InsertUnder(MyNull)
doc.EndUndo()
c4d.EventAdd()
else :
gui.MessageDialog("Please select at least an object first !")

if __name__=='__main__':
main()
Des conseils ? Ça marche comme je le souhaite, mais il y a peut-être des choses à ne pas faire ?

valkaari
10/01/2012, 16h33
ben déjà on préfère utiliser False et True quand on parle de booléen. C'est la même chose que 0 ou 1 mais par la même occasion, on sait qu'on parle de bool et pas de numérique.

Ensuite dans ton code, tu as du code en double


doc.AddUndo(c4d.UNDOTYPE_CHANGE,selec)
selec.InsertUnder(HyperNurbs)
doc.EndUndo()


Code qui fait la même chose en fin de condition. Celà veut dire que tu peux sortir ce code de ton if... else....
Si pour des raisons X ou Y tu ne peux pas sortir ce code, en générale : code en double ou réutilisé ----> création d'une fonction.


Pour ce qui est de gérer plusieurs objets sélectionné, il faut le voir d'une autre façon, tu fais un GetActiveObjects, si la longueur de la liste est supérieure à 1 --> plusieurs objets sinon --> un seul objet sélectionné. Si elle est vide -> 0

Seb-bbl
10/01/2012, 17h11
J'ai bien compris pour le code en double, par contre, pour ce qui est de la gestion de la liste, rien du tout ! :icon_mrgreen:
Là j'y suis allé vraiment à tâtons !

valkaari
10/01/2012, 18h27
Une list c'est un tableau d'une ligne mais plusieurs colonnes (cas le plus simple). En tout cas, dans ton cas, il y a plusieurs colonne s'il y a plusieurs objets sélectionnés.
Après le code, y a pas qu'une façon de faire, tout dépends de la logique du développeur. Dans le code en dessous, on peut très bien rapprocher la création de l'HN de son insertion dans le document.

Tu peux aussi trouver dangereux de bouger les différents objets sélectionnés, avant d'insérer l'objet HN dans le document. Si jamais l'insertion ne marche pas comment on fait hein ?

Après vérifier à chaque fois le résultat des fonctions c'est faire de la programmation défensive. Toujours vérifier qu'une opération s'est bien passé avant de passer à la suivante. Bon c'est le truc qu'on fait jamais pour des petits scripts, et encore moins au début de l'apprentissage.

Bref un exemple de ton code plus court. Pas forcement LA façon de faire hein ^^ mais un poil mieux.


import c4d
from c4d import gui

def main():
objList = doc.GetActiveObjects(False)
if objList :
MonParent = None #la variabl parent est déclaré au début
objectForHN = None #cette variable nous permet de ne pas avoir à nous poser de question à la fin du code, c'est cet objet qui vas aller dans l'HN
doc.StartUndo() #on vas faire des modifs, on prévoit le undo

HyperNurbs=c4d.BaseObject(c4d.Osds) #on sait qu'on a un objet donc on vas avoir un HN même si on ne sais pas où le mettre
doc.AddUndo(c4d.UNDOTYPE_NEW,HyperNurbs)

#au moins 1 obj selectionné mais y en a 1 ou plusieurs ?
if (len(objList) > 1):
print "plusieurs objets"
#plusieurs objet, les mettre dans un null
MyNull=c4d.BaseObject(c4d.Onull)
doc.AddUndo(c4d.UNDOTYPE_NEW,MyNull)
doc.AddUndo(c4d.UNDOTYPE_CHANGE,MyNull)
doc.InsertObject(MyNull)
for obj in objList :
doc.AddUndo(c4d.UNDOTYPE_CHANGE,obj)
obj.InsertUnder(MyNull)
objectForHN = MyNull

else:
#il y a bien un objet selectionné et un seul on le mets dans objectForHN
objectForHN = objList[0]
#il a un parent ?
MonParent = objList[0].GetUp()

doc.AddUndo(c4d.UNDOTYPE_CHANGE,HyperNurbs)
if MonParent :
#on est dans le cas un seul objet sélectionné et il a un parent
HyperNurbs.InsertUnder(MonParent)
else:
#soit on a plusieurs objets sélectionné, soit un seul mais qui n'a pas de parent.
doc.InsertObject(HyperNurbs)

#qu'il y ai un ou plusieurs objet, on a mis soit le null soit l'objet seul dans objectForHn donc on le met sous l'HN
doc.AddUndo(c4d.UNDOTYPE_CHANGE,objectForHN)
objectForHN.InsertUnder(HyperNurbs)
doc.EndUndo()
c4d.EventAdd()



else :
gui.MessageDialog("Please select at least an object first !")

if __name__=='__main__':
ma

Seb-bbl
10/01/2012, 18h57
Tu peux aussi trouver dangereux de bouger les différents objets sélectionnés, avant d'insérer l'objet HN dans le document. Si jamais l'insertion ne marche pas comment on fait hein ?
Ben disons que si les objets sélectionnés sont dans des neutres différents, comment savoir automatiquement où les grouper et mettre le HN ? Il faut bien choisir un endroit, non ? Après, si l'insertion ne marche pas, ben ctrl+Z et ajout du HN à l'ancienne. (ou bien j'ai pas compris ce que tu voulais dire, ce qui est possible aussi !)

En tout cas, merci pour ton temps et pour l'exemple !
(je mettrai tout de même mon script à disposition, non pas qu'il ne me plaît pas, mais il n'est pas de moi... ;) )

valkaari
10/01/2012, 20h00
Si en C++ tu essayes d'ajouter dans ta hiérarchie un objet qui n'existe pas, c'est le plantage assuré et un beau vidage mémoire. Je parlais de la prog défensive de manière générale.

Après pour ton script effectivement, mets à dispo le tient, mais ici on est bien dans "Apprendre le Python" donc j'essayes de t'amener sur un code un peu plus simple et facile à modifier. C'est une chose qui est importante quand tu commences à faire des choses plus complexes.

Seb-bbl
10/01/2012, 20h58
Et j'y vois déjà beaucoup plus clair ! Un gros merci !