PDA

Voir la version complète : Py4D : le language python dans C4D



oli_d
16/01/2010, 05h09
EDIT : en cours de modification pour adaptation au python de la r12, les captures d'écran ne sont pas encore à jour

Attention vous devez avoir au moins la version 12 de Cinema4D

Python : kesako ?

La version 12 de c4d vous permet de programmer des scripts et plugins en langage Python. Le python est déjà utilisé dans de nombreux autres logiciels tels que Blender, Vue, etc.. Le python est également utilisé pour créer des programmes autonomes.

Dans Cinema4D il y a en gros cinq possibilités d'utilisation différentes :

les scripts
les tags ou propriété Py4D
les noeuds Xpresso
les génerateurs
les plugins


Les scripts sont comparables aux scripts C4D en COFFEE. Vous pouvez les écrire directement dans le Gestionnaire de script (Script Manager) du menu Python ou dans un autre programme et les enregistrer au format texte dans un fichier .py. On les utilisera pour des programmes simples dont l'action se fera sur demande (en cliquant sur exécuter ou en appelant le script via un menu)

Le tag Py4D est tout à fait comparable au tag COFFEE, le code s'exécute chaque fois qu'il y a un "évènement" dans C4D.

Le noeud Xpresso permettra d'inclure un bout de code personnalisé au milieu de chaines Xpresso.

Les générateurs servent à créer des objets similaires aux objets paramétriques, mais sans avoir besoin de créer un plugin

Pour les plugins c'est un tout petit peu plus compliqué, mais vous pourrez a peu près tout créer (objets paramétriques, déformateurs, tags, matières, etc...) et vous prendre pour les développeurs de Cinema4d. Ils sont chargés au lancement de c4D et toute modification nécessite de relancer cinema4d (pour l'instant).

Bon le mieux c'est de comprendre par l'exemple, donc au boulot

Premier Script en python


Ouvrez la console du menu Python
Ouvrez le Gestionnaire de script du menu Python
Tapez : print "Hello world" à la place du texte existant (attention de bien écrire print en minuscule)
Cliquez sur le bouton Exécuter


http://campus.hesge.ch/eil/e-eil/od/tuto_py4d/002_hello.jpg

Si tout se passe bien vous devriez voir s'afficher "Hello world" dans la Console (je sais ça impressionne pas encore les filles (ou les garçons pour les filles), mais ça viendra...).

Le Gestionnaire de scripts sert à saisir le code, le bouton Exécuter je vous le donne en mille ...l'exécute.
Notre super programme comprend une ligne avec une fonction print . Cette fonction "imprime"le texte qui suit dans la console. Pour du texte il faut le mettre entre guillemets double ou simple
print 'Salut la French' fonctionne également.
Vous pouvez également envoyer des nombres et là pas besoin de guillemets : print 12345

Cette fonction print sera très utile pour faire des tests au milieu d'un programme. Vous pouvez effacer le texte existant dans la console en cliquant sur le menu Fichier/Effacer

Bon maintenant je vous apprend à faire faux, tapez Print 12345 (majuscule au début de print)
http://campus.hesge.ch/eil/e-eil/od/tuto_py4d/003_erreur.jpg

Eh beh ouais, ça marche pas à tout les coups, il faudra vous y habituer!
Il nous a mis un message d'erreur dans la cosole qui dit en gros qu'on a fait une connerie à la ligne 1, c'est une erreur de nom il connait pas ce Print. Donc première leçon le python est sensible à la casse, print n 'est pas la même chose que Print et encore moins que PRINT


la suite au prochain épisode ....

Jean-Laurent
16/01/2010, 09h37
Ah, c'est malin. :roll: Comme si les journée était pas déjà assez courtes. :cry2:
J'en suis à la page 122 d' "apprendre le python" du coup. :wink:

Les deux premières questions:

- L'installation de Py4D est je présume obligatoire pour l'utilisation d'un plugin python, contrairement au coffee qui est directement rattaché au logiciel? Pas de conversion possible d'un plug réalisé en python en fichier binaire directement utilisable dans le menu plugin ? On peut rêver. :mrgreen:

- C'est quoi la différence entre 'hello' et "hello" ?
De mémoire en C++ c'était un caractère et une chaine de caractère, mais en python ça semble identique, c'est le cas ?

Très belle initiative en tout cas. :poucehaut:

oli_d
16/01/2010, 10h03
Ah, c'est malin. :roll: Comme si les journée était pas déjà assez courtes. :cry2:
J'en suis à la page 122 d' "apprendre le python" du coup. :wink:

C'est pas perdu, je n'ai pas l'intention de réécrire le bouquin mais juste donner des pistes pour l'utilisation spécifique du python dans C4D



- L'installation de Py4D est je présume obligatoire pour l'utilisation d'un plugin python, contrairement au coffee qui est directement rattaché au logiciel? Pas de conversion possible d'un plug réalisé en python en fichier binaire directement utilisable dans le menu plugin ?

Oui pour l'instant il faudra installer le plugin pour faire tourner les plug en python, mais à mon avis vu tous les avantages du python Maxon va sûrement intégrer ça dans une prochaine version et à mon avis il vont progressivement laisser tomber le COFFEE (ce ne sont que des suppositions).



- C'est quoi la différence entre 'hello' et "hello" ?

Il y en a un qui a des guillemets doubles :mrgreen:
Plus sérieusement il y a une bonne explication page 46 du livre de Swinnen qui est cité ci-dessous (5.2.1) en gros si tu veux inclure des apostrophes dans ton texte utilise les guillemets doubles et vice et versa, exemple


print 'la"sandbox" de Py4D'#affiche : la"sandbox" de Py4D
print "l'olivier'" #affiche : l'olivier

BerTiN03
16/01/2010, 11h32
:poucehaut:

Bon pareil, journée trop courtes pour apprendre ça pour ma part, mais ceci dit, je suis avec intérêt ! :bounce:

clemz
16/01/2010, 12h18
super Oli_D merci :)

oli_d
16/01/2010, 12h20
Le language Python

Dans ce chapitre nous allons voir les bases du python pour nous permettre de coder dans C4D. Je ne vais pas faire un cours complet sur le python, il en existe d'ailleurs déjà un qui est très bien fait et que je vous conseille vivement (en plus il est gratuit) :
http://www.inforef.be/swi/download/python_notes.pdf Il s'agit de "Apprendre à programmer avec Python" de Gerard Swinnen. Je ferai souvent référence à ce livre

Le langage python est un langage interprété, c'est à dire qu'il n'a pas besoin d'être compilé (contrairement au c++). Il est directement interprétable par la machine (plus d'info p.13 du livre).
C'est un langage portable, c'est à dire que l'on peut le faire tourner sur Mac, PC, Linux ....
Vous m'avez souvent entendu pester contre le c++ parce qu'il faut le compiler une fois en mac, une fois en PC32 bits et une fois en PC64bits, et puis il faut la plupart du temps le recompiler d'une version de C4D à l'autre, avec python on oublie tout ça !


Les opérateurs (cf p19 du livre)
Bon on va faire un peu de calcul :
http://campus.hesge.ch/eil/e-eil/od/tuto_py4d/004_calcul.jpg

Donc on remarque que les opérateurs courants fonctionnent (+,-,*,/), il y en a un particulier "**" ça c'est "puissance" 2**3 signifie 2 3 c'est à dire 2*2*2. On remarque également que l'ordre prioritaire est pris en compte, multiplication avant les additions, etc...

Essayez maintenant print 7 / 2

Fichtre, diantre, saperlipopette ! ça donne 4 !

Rajoutez un point après le 7 : print 7. / 2 et tout rentre dans l'ordre, cela donne bien 3.5. Cela veut dire que dans le python si vous n'avez que des nombres entiers dans un calcul, le résultat sera en entier, si vous voulez un résultat en décimal il faut qu'il y ait au moins un nombre avec une décimale. Notez bien ce point, parce que perdu au milieu de nombreuse lignes de code un petit détail comme ceci peut devenir difficile à corriger (c'est du vécu !)

Parmi les opérateurs citons encore le modulo "%" que l'on utilise quelque fois en programmation et qui sert à retourner le reste d'une division :
6 % 2 = 0 (6 / 2 donne un chiffre entier, il ne reste rien)
7 % 2 = 1 (7 / 2 donne 2 et il y a encore 1 unité à diviser)
18 % 10 = 8 etc...
On peut utiliser ceci pour par exemple savoir si un chiffre est pair ou impair, pour calculer le jour de la semaine d'une date etc...

Les variables(cf p.21 du livre)

Les variables servent à stocker des données de toutes sortes pour les utiliser dans le code. En COFFEE et en C++ il faut mettre un terme particulier pour déclarer une variable, en c++ il faut en plus donner le type de la variable (texte, entier,décimal etc...) En python pas besoin vous pouvez directement utiliser une variable exemple :

base = 5
hauteur = 3
surface = base * hauteur
print surfacece code affichera 15 dans la sandbox. Là aussi attention aux minuscules.
Pour nommer vos variable vous êtes a à peu près libre (à part les mots réservés), mais prenez l'habitude de les commencer par une lettre minuscule pour la lisibilité du code. Je ne veux pas réécrire le chapitre 2.2 du livre de Swinnen. Je vous laisse donc le soin de lire attentivement

Les conditions(cf p.29 du livre)

C'est une des bases de la programmation, pouvoir diriger d'un côté ou d'un autre le code en fonction d'un résultat.
L'instruction principale est le if exemple :


nombre = 2
resultat = nombre % 2
if resultat == 0:
print "c'est un nombre pair"
else :
print "c'est un nombre impair"
Alors deux ou trois petite choses nouvelles :

l'instruction if () est suivie de deux points et la ligne suivante est décalée (on peut choisir mais normalement le tab correspond 4 espaces)
la ligne décalée ne s'effectuera que si la condition entre les parenthèse est vraie
dans la parenthèse on met une condition, notez le "==" qu'il ne faut pas confondre avec le signe égal simple


Si on traduit ce code en français :

On a un nombre qui vaut 2
On a un résultat qui vaut ce nombre modulo de 2
Si résultat est égal à 0 on affiche "c'est un nombre pair"
Sinon on affiche "c'est un nombre impair"


Dans les autres langages on conseille de décaler ce qui suit un if pour rendre le code plus lisible, dans le python on est obligé de le faire mais par contre on ne doit rien mettre d'autre (en COFFEE et C++ il faut mettre des accolades).

On peut encore insérer entre l'instruction if et else un elif, qui signifie "sinon si" exemple :


a = 0
if a > 0 :
print "a est positif"
elif a < 0 :
print "a est négatif"
else:
print "a est nul"Les opérateurs de comparaison(cf p.31 du livre)

x == y x est égal à y
x != y x est différent de y
x > y x est plus grand que y
x < y x est plus petit que y
x >= y x est plus grand que, ou égal à y
x <= y x est plus petit que, ou égal à y

Les boucles(cf p.35 du livre)

C'est sans doute le truc le plus indispensable en programmation, qui va nous permettre de répéter une opération autant de fois que l'on veut.

Un des deux boucles les plus courantes est le while exemple :

nombre = 0
while nombre<5 :
print nombre
nombre = nombre + 1Attention également au deux points après l'instruction while() et au décalage de 4 espaces des deux lignes suivantes.

Si on traduit :

On a un nombre qui vaut 0
Tant que ce nombre est plus petit que 5 on effectue ces deux opérations

on affiche la valeur de nombre
on rajoute à chaque passage 1 à nombre




Mais attention c'est aussi la boucle la plus dangereuse ! L'instruction while va répéter une portion de code tant qu'une condition ne sera pas respectée, donc si le code ne modifie pas une variable contenue dans la condition elle tournera à l'infini et C4D plantera.... Si par exemple vous oubliez de mettre les 4 espaces au début de la dernière ligne, ce code ne s'effectuera qu'à la fin de la boucle et dans ce cas là jamais parce que votre boucle va tourner à l'infini vu que nombre va rester toujours avec la valeur 0

On a aussi la boucle for qui est très utile mais je préfère vous l'expliquer plus tard quand on sera au cœur de C4D

Je m'arrête là pour le moment pour les concepts du python, il y a encore beaucoup de chose à dire mais je sens que vous trépignez d'impatience et que les chiffres ça va un moment et vous aimeriez bien passer à la 3D ...

... mais il faudra patienter jusqu'au prochain épisode...

D'ici là potassez un peu le bouquin, la prochaine fois il y aura interro !

clemz
16/01/2010, 14h28
Oli_D oh nice ! :prie:

diego1968
16/01/2010, 14h44
Clemz :poucehaut: :lol:

Oli_D je suis :shock: de ton savoir !
:prie:

You're the :boss:

base80
16/01/2010, 15h35
Waw super j'ai tout compris!

Les 4 espaces j'aime moins , j'aurais préféré un tab

oli_d
16/01/2010, 15h54
Les 4 espaces j'aime moins , j'aurais préféré un tab


Oui moi aussi surtout qu'il faut les refaire sur chaque ligne, mais si tu prends un autre éditeur comme IDLE ou Notepad ++ là tu peux utiliser le tab et en plus le code est tout beau en couleur ce qui est beaucoup plus lisible

Mais c'est un peu comme pour le COFFEE, si je fais un tout petit code je reste dans l'éditeur C4D, mais dès qu'il y a plus d'une dizaine de lignes, je préfère passer à Notepad++ puis copier-coller dans C4D.

En plus il ne faut pas oublier que c'est une version bêta, donc je pense que tout cela va être amélioré

tarlack
16/01/2010, 16h01
le fait que la mise en page du code ait un sens dans le langage est en soi quelque chose de très risqué quand on a de gros codes, et qu'on commence à mélanger des bouts de code entre eux (et je parle d'expérience, j'ai été confronté au problème quand j'ai écrit un exporteur pour blender à partir d'un exporteur déjà existant pour kerkythea). L'utilisation des espaces a un avantage énorme comparé aux tab : quelque soit l'éditeur, ca fera toujours la meme taille. Et n'importe quel bon éditeur te permet d'inserer N espaces quand tu appuies sur la touche tab, plutot qu'un tab. ah, et en general il y a aussi des commandes pour indenter et desindenter un bloc de code, très pratique aussi :)
bonne exploration en tout cas !

oli_d
16/01/2010, 17h32
Créer un objet dans C4D

Bon rentrons dans le vif du sujet, je vais tout de suite commencer par la création d'un objet. Par rapport au Xpresso, un des grands avantages de la programmation, c'est qu'on peut créer et inclure autant d'objet que l'on veut.



import c4d #on importe la bibliothèque de C4D...

obj = c4d.BaseObject(c4d.Ocube) #on crée un objet de type cube
doc.InsertObject(obj) #on insère notre objet dans le document (doc est une constande de c4d qui renvoie le document
c4d.EventAdd() # et on avertit C4D qu'il y a eu un évènement pour qu'il actualise
Copiez ce code et collez le dans le script manager. Normalement il devrait y avoir un cube qui apparait chaque fois que vous cliquez sur le bouton Exécuter

Dans le chapitre précédent, j'ai oublié de vous parler des commentaires . C'est toujours pratique, surtout lorsque l'on débute, de pouvoir inclure des commentaires dans notre code, histoire de se rappeler d'une fois à l'autre ce que l'on a fait. Dans le python il suffit de précéder le commentaire du signe #

Je vous propose pour l'instant de prendre le code comme il vient, les explications sur les classes viendront par la suite et surtout comment aller chercher des fonctions et classes dans la jungle de l'aide.

Exercice :

Pour mettre en pratique cette première partie, vous allez essayer de créer une boucle qui crée automatiquement 10 cubes. Réutilisez les fonctions du code en début de post.

Corrigé:

import c4d
nbre = 0

while nbre<10: #boucle jusqu'à 10
obj = c4d.BaseObject(c4d.Ocube) #on crée un objet de type cube
doc.InsertObject(obj) #on insère notre objet dans le doc
nbre = nbre+1 #ne pas oublier sinon la boucle tourne à l'infini

c4d.EventAdd() #sans les 4 espaces comme cela il ne le fait qu'une fois à la sortie de la boucle->plus rapide

BerTiN03
16/01/2010, 23h36
Ca ressemble beaucoup à du basic !

En tout cas, ça à l'air super simple !

Merci encore Oli_D

lolofedo
17/01/2010, 00h44
:shock: j'ai tout compris, merci oli :poucehaut:

oli_d
17/01/2010, 09h17
EDIT : PAS ENCORE MODIFIE POUR R12
Modifier un objet dans C4D

Pour bien comprendre ce qui suit je vous conseille de lire attentivement le chapitre 5.3 du livre (p.50) sur les listes. Pour ceux qui connaissent les tableaux COFFEE ou c++, c'est un peu la même chose mais en beaucoup plus simple et donc beaucoup mieux. Dans une même liste on peut stocker n'importe quel type de valeur et d'objet.

Chaque objet de c4d contient une liste avec toute ses spécificités, il faut juste connaître la référence de l'attribut pour y accéder. Pour trouver ce nombre de référence il suffit des cliquer-glisser le nom de l'attribut dans le champ en bas de la sandbox :
http://campus.hesge.ch/eil/e-eil/od/tuto_py4d/006_no_attribut.jpg

Dans cette exemple j'ai drag&droper Taille pour un objet cube, cela me donne [1100]

http://campus.hesge.ch/eil/e-eil/od/tuto_py4d/007_no_attribut.jpg

Dans celui-ci je n'ai pris que la valeur x de la taille cela me donne [1100,1000]

Utilisation dans le code :

import c4d #on importe la bibliothèque de C4D...
from c4d import * # ...de cette bibliothèque on importe tous les modules

obj = c4d.BaseObject(Ocube) #on crée un objet de type cube
obj[1100,1000] = 500 #on modifie la taille en X
doc = c4d.documents.get_active_document() #on récupère le document actif
doc.insert_object(obj) #dans lequel on insère notre objet
c4d.event_add() # et on avertit C4D qu'il y a eu un évènement pour qu'il actualiseOn a juste à rajouter le ce fameux nombre de référence entre crochet après la variable de l'objet. Simple, non ?
Le seul bémol c'est que si vous laissez le numéro sans commentaire à côté, bonjour pour savoir deux semaines après à quoi ça correspond. Donc insérez un commentaire ! (je pense que dans les versions futures de Py4d on pourra rentrer un chaine de caractère plus explicite à la place du nombre, comme en COFFEE. A moins que cela ne soit déjà possible mais j'ai pas trouvé !)

Prenons l'exemple de la taille complète [1100]. En fait ce 1100 contient trois valeurs, dans c4D c'est un Vecteur (Vector())

import c4d #on importe la bibliothèque de C4D...
from c4d import * # ...de cette bibliothèque on importe tous les modules

obj = c4d.BaseObject(Ocube) #on crée un objet de type cube
obj[1100] = c4d.Vector(100,50,500) #on modifie la taille en X,Y,Z
doc = c4d.documents.get_active_document() #on récupère le document actif
doc.insert_object(obj) #dans lequel on insère notre objet
c4d.event_add() # et on avertit C4D qu'il y a eu un évènement pour qu'il actualiseAllez on rajoute un biseau de 5 subdivisé à 3


import c4d #on importe la bibliothèque de C4D...
from c4d import * # ...de cette bibliothèque on importe tous les modules

obj = c4d.BaseObject(Ocube) #on crée un objet de type cube
obj[1100] = c4d.Vector(100,50,500) #on modifie la taille en X,Y,Z
obj[1107] = True #biseau : case à cocher activée (on peut mettre 1 à la place deTrue)
obj[1105] = 5 #rayon du biseau
obj[1105] = 3 #subdivision du biseau

doc = c4d.documents.get_active_document() #on récupère le document actif
doc.insert_object(obj) #dans lequel on insère notre objet
c4d.event_add() # et on avertit C4D qu'il y a eu un évènement pour qu'il actualise
Vous pouvez ainsi changer tout ce qu'il y a dans la palette attributs, testez !

Bon maintenant que vous savez créer des cubes et les modifier, vous êtes mûrs pour me faire un petit générateur d'escaliers. Allez au boulot tas de feignants !

Corrigé :

import c4d
from c4d import *

nb_marches = 10
larg = 200
haut = 15
prof = 35
pos = c4d.Vector(0,0,0)
nb = 0
doc = c4d.documents.get_active_document() #on récupère le document actif

while(nb<nb_marches): #boucle ne pas oublier les deux points
obj = c4d.BaseObject(Ocube) #on crée un objet de type cube
obj[1100] = c4d.Vector(larg,haut,prof) #on règle la taille du cube
obj[903] = pos #on règle la position
doc.insert_object(obj) #on insère notre objet dans le doc
pos = pos + c4d.Vector(0,haut,prof) #on modifie la position pour la suivante...
#...en rajoutant chaque fois la hauteur et la profondeur
nb=nb+1 #on incrémente, sinon la boucle est infinie

c4d.event_add() # et on avertit C4D qu'il y a eu un évènement pour qu'il actualise

oli_d
17/01/2010, 11h37
Créer un générateur d'objet

Py4D permet de créer très facilement un générateur d'objet (ce que l'on a pas en en COFFEE).
Puisque c'est si simple on va se faire notre générateur d'escaliers avec données utilisateurs et tout le tsoin-tsoin.

Pour commencer sélectionnez Python Generator dans le menu Py4D. Un nouvel objet apparait dans le gestionnaire. Double cliquez sur l'icône de l'objet, et là vous devriez avoir un fenêtre avec du code qui s'ouvre : le Py4D::Editor.

Vous devriez avoir le code suivant :

import c4d
#Welcome to the world of Py4D

def main():
return c4d.BaseObject(c4d.Ocube)
La première ligne on connaît c'est pour importer la bibliothèque c4d. Le welcome ça aussi on connaît.

Par contre de def main(): ???
Alors je vous invite à aller lire attentivement le chapitre 7 du bouquin (p. 62) sur les fonctions. Parceque là on à affaire à une fonction qui va renvoyer un truc à la fin grâce à l'instruction return. Notez bien que la fonction main() est suivie de deux points et que la suite est décalé de quatre espaces (là je sens que Base va pas être content):mrgreen:
Et ce truc que cette fonction main() (principale) renvoie, vous le connaissez c'est un objet cube, qu'on a déjà utilisé.
Faite les test appuyer sur la touche "C" dans C4D pour rendre l'objet éditable. Vous verrez que l'objet se transforme en cube, donc le code se confirme !

Mais vous allez me dire que c'est nul mon truc parce que l'on peut renvoyer qu'un seul objet et nous on a plein de marches. Ben y a cas feinter, on va lui renvoyer un neutre avec toutes nos marches en enfant, et youplazou !

Pour que notre générateur soit efficace on va pas aller chaque fois dans le code pour changer la largeur, le nombre de marche et cie. On va créer des données utilisateurs, ça vous devriez savoir faire :
http://campus.hesge.ch/eil/e-eil/od/tuto_py4d/008_du.jpg

Maintenant le problème, c'est pour récupérer tout ça dans notre générateur. Je pense qu'il y a des petits malins qui ont déjà essayé de drag&droper dans la sandbox pour obtenir un no de référence. Bon réflexe, mais je le mets où ce numéro qui en plus n'en est pas un : Python Generator[ID_USERDATA, 1]. Aaah, on fait moins les malins,là !

Je vous donne un tuyau, l'objet sur lequel on est s'appelle toujours "op". Que ce soit dans un tag Py4D ou dans un générateur (pour le tag se sera vraiment l'objet tag, pas l'objet sur lequel il y a le tag).

Avant de faire tout l'escalier on va tester ça sur un cube. Il faut que l'on modifie un peu le code d'origine pour que cela fonctionne (n'oubliez pas de cliquer sur le bouton commit en haut pour enregistrer les changements):

import c4d
#Welcome to the world of Py4D

def main():
obj = c4d.BaseObject(c4d.Ocube) #on crée notre objet
larg = op[ID_USERDATA, 2] #identifiant trouvé par drag &drop
obj[1100,1000]= larg #on donne larg à la taille X

return obj #et on retourne l'objet


et là ça marche po :coup: :
http://campus.hesge.ch/eil/e-eil/od/tuto_py4d/009_erreur.jpg

et c'est dans ces moments là, que je la hais cette sandbox, n'essayez pas de lui taper dessus c'est votre super écran 32 pouces qui va ramasser.

Analysons, elle nous dit que ce ID_USERDATA à la ligne 6 n'est pas défini...

En fait, vous avez vu au début il y a bien import c4d, mais dans mes codes précédents j'avais rajouté ensuite "from c4d import * ". En fait je vous avais raconté n'importe quoi, ce truc ça importe pas tout les modules, ça évite simplement de marquer c4d. devant chaque fonction ou instruction de la bibliothèque. Du coup si vous le rajoutez ça devrait aller mieux (faites également attention aux quatre espaces après main(): !):


import c4d
from c4d import *
#Welcome to the world of Py4D

def main():
obj = c4d.BaseObject(Ocube) #on crée notre objet
larg = op[ID_USERDATA, 2] #identifiant trouvé par drag &drop
obj[1100,1000]= larg #on donne larg à la taille X

return obj #et on retourne l'objet
ou si vous ne voulez pas le rajouter vous pouvez rajouter c4d. devant ID_USERDATA et aussi devant Ocube


import c4d
#Welcome to the world of Py4D

def main():
obj = c4d.BaseObject(c4d.Ocube) #on crée notre objet
larg = op[c4d.ID_USERDATA, 2] #identifiant trouvé par drag &drop
obj[1100,1000]= larg #on donne larg à la taille X

return obj #et on retourne l'objet

Et bien maintenant on a presque tout pour créer nos escaliers paramétriques. Vous avez noté que contrairement à avant on a plus besoin d'insérer l'objet dans le document, c'est directement le générateur qui le fait dès qu'on lui retourne.

On va créé un objet neutre dans lequel on va mettre toutes nos marches en enfant. Pour le neutre on va remplacer Ocube par Onull, et pour insérer l'objet on va utiliser la méthode enfant.insert_under(parent)


import c4d
from c4d import *

def main(): # fonction principale ne pas oublier de décaler de 4 espaces après
nb_marches = op[c4d.ID_USERDATA, 1] #on récupère les DU dans des variables
larg = op[ID_USERDATA, 2]
haut = op[ID_USERDATA, 3]
prof = op[ID_USERDATA, 4]
pos = c4d.Vector(0,0,0) #on initialise la position à 0
nb = 0
neutre = c4d.BaseObject(Onull) #on crée un objet neutre

while(nb<nb_marches): #boucle ne pas oublier les deux points
marche = c4d.BaseObject(Ocube) #on crée un objet de type cube
marche[1100] = c4d.Vector(larg,haut,prof) #on règle la taille du cube
marche[903] = pos #on règle la position
marche.insert_under(neutre) #on insère notre objet en enfant de neutre
pos = pos + c4d.Vector(0,haut,prof) #on modifie la position pour la marche suivante...
#...en rajoutant chaque fois la hauteur et la profondeur
nb=nb+1 #on incrémente, sinon la boucle est infinie

return neutre #on retourne notre objet neutre au générateur

Dans ce cas là vous noterez que sous le while il faut doubler l'indentation, donc il faut 8 espaces, préparez la pommade contre les ampoules à l'index !

N'oubliez pas également de régler vos DU pour qu'elles ne soient pas à 0, sinon ce sera tout de suite moins spectaculaire.

A part ça, elle est pas belle là vie, vous vous êtes fabriqué le générateur d'escaliers paramétrique de vos rêves en trois coups de cuillère à pot !

Allez un p'tit exercice, c'est pas le moment de fléchir, et si vous me faisiez un générateur de mur en brique (avec les briques en quinconces sinon c'est pas drôle !)

A bientôt pour de nouvelles aventures !

[edit] : solution : Générateur de mur en brique (fichier c4d) (http://campus.hesge.ch/eil/e-eil/od/tuto_py4d/generateur_briques.zip)

tarlack
17/01/2010, 12h00
Dans ce cas là vous noterez que sous le while il faut doubler l'indentation, donc il faut 8 espaces, préparez la pommade contre les ampoules à l'index !

encore une fois, n'importe quel éditeur fait pour la prog te permet de configurer ta touche tab pour qu'elle insère 4 espaces directement ;) il n'y a pas plus fainéant que les programmeurs, donc t'en fait pas qu'ils ont prévu un max de trucs pour s'éviter des ampoules ^^ ah, pour éditer du python, il existe un IDE spécifique, qui s'appelle "eric" : http://eric-ide.python-projects.org/index.html

grover
17/01/2010, 12h21
Bien intéressant, tout ça ! :poucehaut:

oli_d
17/01/2010, 12h21
Merci pour les infos tarlack, je vais tester Eric (en tout bien tout honneur :mrgreen:). Pour Notepad ++ je viens de trouver l'option de paramétrage du tab dans paramétrage/préférences onglet MISC.

Jean-Laurent
17/01/2010, 12h55
Pour l'instant j'ai tout suivi. :poucehaut:

valkaari
17/01/2010, 23h41
Vraiment génial oli-D.

Plus je regarde python et plus je suis :bounce:

Par contre la syntaxe :puke:

oli_d
18/01/2010, 06h48
Merci à tous pour les encouragements :odile:



Par contre la syntaxe :puke:

Moi je la trouve géniale, tout est fait pour que ton code soit le plus simple et le plus lisible. Mais c'est vrai que quand on est habitué à d'autres codes, ça semble bizarre.

Ce que je trouve le plus génial et qui me frustrait au plus haut point entre c++ et COFFEE, c'est que tu peux vraiment tester ton code dans le programme. D'abord quelques lignes dans le script manager, puis tu peux le passer en générateur, en tag ou en menu (script) et puis ensuite si vraiment tu veux aller plus loin tu fais un plugin. Mais là tu peux chaque fois récupérer ton code. Entre COFFEE et c++ on était obligé de tout réécrire.

Jean-Laurent
18/01/2010, 09h37
Mais là tu peux chaque fois récupérer ton code. Entre COFFEE et c++ on était obligé de tout réécrire.


C'est surtout vrai en C++. En coffee, si on est dans un tag coffee c'est automatique, et si on réalise un plug il suffit à chaque modification de recharger le plug dans la console coffee de C4D. (Enfin quand tout se passe bien :wink:)

J'aime bien aussi cette syntaxe très proche du C++ mais avec les trucs pénibles en moins (typage dynamique etc ...).
Et si on accède à toutes les fonctions du SDK C++ sans avoir à compiler en permanence. :poucehaut:

Seb-bbl
18/01/2010, 23h44
Jusque-là je suis aussi (enfin, disons que ça va à lire, après, à créer de toutes pièces, c'est encore autre chose). Mais c'est très instructif en tout cas !!!

Aurety
05/03/2010, 09h40
Ouah ! Excellent, j'ai tout suivi, compris, aimé !! :poucehaut: :love:

Gyom
07/03/2010, 13h18
rrhaa ??? pas le temps de suivre ...
je ferai du rattrapage d'ici un mois !
... je pourrai quand meme poser des questions betes ?

oli_d
07/03/2010, 13h41
Les questions avec plaisir, et même des propositions de petits plugs comme exercice ...

Gyom
07/03/2010, 13h43
:bounce:

des propositions ?! ... mais tu ne sais pas a qui tu proposes ca !!!

Machaon
11/04/2010, 11h48
Maxon vient d'annoncer l'acquisition de Py4D, un interpréteur Python pour Cinema4D qui, promet Maxon, devrait permettre d'ajouter des fonctions personnalisées au logiciel très simplement.
http://www.maxon.net/en/news/singleview-default/article/maxon-announces-acquisition-of-py4d.html

oli_d
11/04/2010, 13h06
Yesssss, :bounce:

Donc cela veut dire que le python sera probablement intégré dans la r12 et à mon avis
cela c'est également la mort annoncée du COFFEE, ou en tous cas du développement du COFFEE.

Cela fait maintenant quelques mois que je teste ce Py4D et je confirme que c'est réellement trop d'la balle ! Ce n'est que la beta, il manque encore quelques fonctions du c++ et il y a quelques bugs, mais depuis que j'y ai touché, impossible de me remettre au c++ et au COFFEE ! (edit : le python est même devenu mon avatar, c'est dire si je suis atteint !)

César Vonc
27/04/2010, 22h18
Très bonne initiative, ce tuto !

En revanche, ce serait chouette de corriger les anciens messages qui ne disent pas la même chose que les suivants.

Par exemple :

En fait, vous avez vu au début il y a bien import c4d, mais dans mes codes précédents j'avais rajouté ensuite "from c4d import * ". En fait je vous avais raconté n'importe quoi, ce truc ça importe pas tout les modules, ça évite simplement de marquer c4d. devant chaque fonction ou instruction de la bibliothèque.

C'est bizarre, je n'ai pas les mêmes résultats que toi dans Py4D.
Tu parles de 4 espaces à mettre, mais ça fonctionne tout aussi bien avec un seul.

La fonction pour récupérer le document actif doc = c4d.documents.get_active_document() m'indique une erreur dans la console : « L'objet 'module' n'a pas d'attribut 'get_active_document'. », pourtant j'ai copié coller ton code pour créer un objet dans c4d mot pour mot.


Tout ça vient peut-être d'un problème de version, j'ai téléchargé la dernière en date, la 0.9.9983, et j'ai carrément moins de choses dans le menu de Py4d que toi (ni même l'onglet « Extras » du gestionnaire de script (« Script Manager ») :? (j'ai pourtant bien installé dans le dossier Plugins de c4d et installé le truc de microsoft avant comme c'est indiqué sur le site).

Je suis sous Windows 7 32 bits.

http://img213.imageshack.us/img213/2070/py4dmenu99983.png

oli_d
28/04/2010, 14h31
Je n'ai pas installé la dernière version, car je suis entrain de développer un truc et j'ai pas envie que tout foire. Et en fait j'ai bien fait !

Tout à changé ! Il est passé d'une convention de nommage à une autre !

c4d.documents.get_active_document() est devenu c4d.documents.GetActiveDocument() !!!!

Ce qui fait que l'ensemble du tuto est obsolète, j'ai bien fait de pas aller trop loin !

Je te dis pas comme je suis content car je suis entrain de faire un truc de gestion de flux piétons, voitures et cie, j'ai plus de 1000 lignes de code que je vais pouvoir me retapper mot par mot ! Plus plein de scripts ....

Les joies de travailler avec une version béta.

Moralité je vais attendre la version1.0 pour réécrire et finaliser le tuto.

A part ça j'ai écrit ce truc à mes débuts en python, j'ai du dire plein de petites bêtises que je corrigerais plus tard quand je serai vraiment plus "pro"

Pour les espaces c'est vrai que cela fonctionne avec moins (je l'ai appris il n'y a pas si longtemps), mais on conseille 4 pour que cela soit plus lisible.

Jean-Laurent
01/05/2010, 18h00
De plus visiblement il n'existe plus qu'une version pour C4D 11.5. :poucebas:
Étant resté à la 11 je pense que le coffee pour l'instant fera très bien l'affaire.
Tourne même sur la CE 6. :nono:

xs_yann
26/09/2010, 11h31
Python et la R12

Python est maintenant intégré a la R12. D'après ce que j'ai pu en voir Python offre une très bonne alternative au C++ pour écrire des plugins assez évolués en bénéficiant d'un langage interprété, ce qui évite de recompiler pour chaque OS.
Je vais donc essayer de faire avancer ce thread en postant mes recherches étant donné que je pense m'orienter vers des plugs python en priorité.

Le SDK R12 Python : http://http.maxon.net/pub/sdk/12/PythonDocumentation.zip

Voici donc le code pour créer un Command Plugin (Une commande dans le menu plugin) :


import c4d
from c4d import plugins

class TestPlugin(c4d.plugins.CommandData):

def Execute(self, doc):
print "Hello World"
return True

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

if __name__ == "__main__":
c4d.plugins.RegisterCommandPlugin(PLUGIN_ID, "My First Python Plugin", 0, None, "A Test Plugin", TestPlugin())


Ce code est a placer dans un fichier testplugin.pyp dans le dossier plugins de Cinema 4D.
Au chargement le plugin apparaîtra dans le Menu Python > Plugins.
Lorsqu'il est exécuté le texte "Hello world" est affiché dans la Console Python (Menu Python > Console (Python)...).

oli_d
26/09/2010, 11h52
Super,
Si XS-Yann se met au Python ça va faire mal ! Je posterai prochainement mes avancées, j'ai programmé un système automatique d'animation de circulation de voitures, piétons transport public tout en python (avec la version béta). Je confirme que c'est vraiment génial, j'ai complètement laisssé tomber le C++.

Dès que j'ai un peu de temps il faut que je mette à jour le tuto, pour que ce soit compatible avec la version de la R12

xs_yann
26/09/2010, 12h12
Super,
Je posterai prochainement mes avancées, j'ai programmé un système automatique d'animation de circulation de voitures, piétons transport public tout en python (avec la version béta).
:blink::D Hâte de voir ça.

Voici comment on ajoute un Dialogue non-modal (asynchrone) :


import c4d
from c4d import plugins, gui

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

class TestPluginDialog(gui.GeDialog):

def CreateLayout(self):
self.SetTitle("Test Plugin Dialog")
self.AddStaticText(0, c4d.BFH_CENTER, 0, 0, "Hello", c4d.BORDER_NONE)
return True

class TestPlugin(c4d.plugins.CommandData):
dialog = None

def Execute(self, doc):
if self.dialog is None:
self.dialog = TestPluginDialog()
return self.dialog.Open(c4d.DLG_TYPE_ASYNC, PLUGIN_ID, -1, -1)

if __name__ == "__main__":
c4d.plugins.RegisterCommandPlugin(PLUGIN_ID, "My First Python Plugin", 0, None, "A Test Plugin", TestPlugin())

Pour tout ce qui est des constantes, elles ont changées de place depuis Py4D R11 :

The biggest change: Python in R12 contains no built-in module called c4d.symbols and all constants were moved to the c4d main module.
Il ne faut donc pas oublié le c4d. : 'c4d.CONSTANTE'

xs_yann
26/09/2010, 12h29
La suite :

Un bouton cliquable :


import c4d
from c4d import plugins, gui

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

MY_BUTTON = 1001

class TestPluginDialog(gui.GeDialog):

def CreateLayout(self):
self.SetTitle("Test Plugin Dialog")
self.GroupBegin(0, c4d.BFH_SCALEFIT)
self.AddButton(MY_BUTTON, c4d.BFH_SCALEFIT, 0, 0, "Click me")
self.GroupBorderSpace(4, 4, 4, 4)
self.GroupEnd()
return True

def Command(self, id, msg):
if id == MY_BUTTON:
print "My button clicked"
return True

class TestPlugin(c4d.plugins.CommandData):
dialog = None

def Execute(self, doc):
if self.dialog is None:
self.dialog = TestPluginDialog()
return self.dialog.Open(c4d.DLG_TYPE_ASYNC, PLUGIN_ID, -1, -1)

if __name__ == "__main__":
c4d.plugins.RegisterCommandPlugin(PLUGIN_ID, "My First Python Plugin", 0, None, "A Test Plugin", TestPlugin())

J'ai ajouté un groupe pour pouvoir espacer mon bouton des bords de la fenêtre.

xs_yann
26/09/2010, 13h00
Voici maintenant un exemple qui affiche un bouton 'Add button' qui, lorsqu'il est cliqué, ajoute un nouveau bouton 'Add button'

Créer des boutons dynamiquement


import c4d
from c4d import plugins, gui

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

BUTTON_GROUP = 1001
GADGET_BUTTON = 1002

class TestPluginDialog(gui.GeDialog):

def __init__(self):
self.button_count = 1

def _CreateButtonGroup(self):
i = 0
while i < self.button_count:
self.AddButton(GADGET_BUTTON + i, c4d.BFH_SCALEFIT, 0, 0, "Add Button")
i += 1

def _ReLayout(self):
self.LayoutFlushGroup(BUTTON_GROUP)
self._CreateButtonGroup()
self.LayoutChanged(BUTTON_GROUP)

def CreateLayout(self):
self.SetTitle("Test Plugin Dialog")
self.GroupBegin(BUTTON_GROUP, c4d.BFH_SCALEFIT)
self._CreateButtonGroup()
self.GroupBorderSpace(4, 4, 4, 4)
self.GroupEnd()
return True

def Command(self, id, msg):
i = 0
while i < self.button_count:
if id == GADGET_BUTTON + i:
print "My button clicked"
self.button_count += 1
self._ReLayout()
i += 1
return True

class TestPlugin(c4d.plugins.CommandData):
dialog = None

def Execute(self, doc):
if self.dialog is None:
self.dialog = TestPluginDialog()
return self.dialog.Open(c4d.DLG_TYPE_ASYNC, PLUGIN_ID, -1, -1)

if __name__ == "__main__":
c4d.plugins.RegisterCommandPlugin(PLUGIN_ID, "My First Python Plugin", 0, None, "A Test Plugin", TestPlugin())


Les méthodes possédant le préfix '_' sont des méthode privées :

Like most languages, Python has the concept of private functions, which can not be called from outside their module; private class methods, which can not be called from outside their class; and private attributes, which can not be accessed from outside their class. Unlike most languages, whether a Python function, method, or attribute is private or public is determined entirely by its name.

Je vais m'arrêter la et me documenter un peu plus sur le langage Python avant de donner de mauvais conseils. ;)

Gyom
26/09/2010, 13h21
Super,
Si XS-Yann se met au Python ça va faire mal ! Je posterai prochainement mes avancées, j'ai programmé un système automatique d'animation de circulation de voitures, piétons transport public tout en python

Wow...
Dire que pour la ville je me suis fade ça 'a la main' avec des trajectoires vectorielles et le plugin Drive... Et vu le temps que ça prenait ma circulation est vraiment light ! Pas de bouchon !
... Ton système gere aussi les feux ? Passage au rouge et arrêt des véhicule et démarrage de ceusses qui sont au vert ?
Parce que ça j'ai laisse tomber pour le coup...

Edit : oui je sais c'est hors sujet ;)

xs_yann
26/09/2010, 18h04
Je continue mes recherches :

Les constantes


On a juste à rajouter le ce fameux nombre de référence entre crochet après la variable de l'objet. Simple, non ?
Le seul bémol c'est que si vous laissez le numéro sans commentaire à côté, bonjour pour savoir deux semaines après à quoi ça correspond. Donc insérez un commentaire ! (je pense que dans les versions futures de Py4d on pourra rentrer un chaine de caractère plus explicite à la place du nombre, comme en COFFEE. A moins que cela ne soit déjà possible mais j'ai pas trouvé !)

C'est désormais possible et il faut utiliser les constantes des que possible pour des raisons d'implémentation et de clarté.
Exemple :

op[c4d.ID_BASEOBJECT_USECOLOR] = 3 # mauvais
op[c4d.ID_BASEOBJECT_USECOLOR] = c4d.ID_BASEOBJECT_USECOLOR_LAYER # bon


if tag.GetType() == 5616 # mauvais
if tag.GetType() == c4d.Ttexture # bon

Docstring

En python, il est d'usage de fournir une doc pour les fonctions, cela se présente sous la forme :


def myFunction():
"""Useless function
without parameters
"""
pass


Truc et astuces :

Swap de deux variables :

foo = 42
bar = 1337
foo, bar = bar, foo

Declaration et définition de plusieurs variables :

foo, bar = 42, 1337 # foo = 42 bar = 1337

En python il est possible de passer une valeur au 2e param tout en laissant la valeur par defaut du 1er param :

def myFunction(a = 5, b = 12, c = 15):
pass

myFunction(c = 5) # a = 5, b = 12, c = 5
myFunction(b = 8, c = 5) # a = 5, b = 8, c = 5

Il est possible de passer un nombre négatif a l'operateur [] :

str = "salut" # str[-1] == 't'

Simuler une boucle for type C avec indices


print range(5) # [0, 1, 2, 3, 4]
# on peut donc écrire
for i in range(5):
print i


Les classes

Attribut de classe (static) :

class MaClasse:
cnt = 0
def __init__(self):
MaClasse.cnt += 1
...
MaClasse.cnt

Methode de classe (static) :

class MaClasse:
def maMeth(): #without self param
pass
...
MaClass.maMeth()

Attribut / Methode privés :

class MaClasse:
def _maMeth(): #private
self._mon_attr #private
...
MaClass.maMeth()

Surcharge d'operateurs :
http://docs.python.org/py3k/reference/datamodel.html#special-method-names

oli_d
26/09/2010, 19h37
... Ton système gere aussi les feux ? Passage au rouge et arrêt des véhicule et démarrage de ceusses qui sont au vert ?
Parce que ça j'ai laisse tomber pour le coup...


Oui j'ai un système de feu et tout et tout

Je ne peux pas montrer les vidéos, le projet est encore confidentiel ....

Jean-Laurent
26/09/2010, 19h46
Excellent tout ça.
Bon, c'est juste pour les yeux, car la R12 c'est pour les pros, mais je suis avec intérêt.

Gyom
26/09/2010, 21h43
Oli... Quand ça devient publique fais moi suivre ca par mail :)
... Ave le prix ;)

walien
27/09/2010, 03h19
Donc en fait si jamais on se lance dans le développement d'un plugin en Python, il faut décider si l'on souhaite le faire compatible pour la R12, ou bien pour les versions précédentes ? Ou alors si on veut le faire compatible partout il faut faire dans un autre langage ?

xs_yann
27/09/2010, 09h46
Donc en fait si jamais on se lance dans le développement d'un plugin en Python, il faut décider si l'on souhaite le faire compatible pour la R12, ou bien pour les versions précédentes ? Ou alors si on veut le faire compatible partout il faut faire dans un autre langage ?

Si tu écris un plug en Python il ne sera compatible que R12. En C++ il suffit de compiler ce qui va bien (il faut donc compiler une version mac R12, une version mac >R12, deux versions PC (R12 64bits + R12 32bits) + deux versions PC (>R12 64bits + >R12 32 bits)), cela fait donc : (cdl, cdl64, dylib) x 2.
En COFFEE, pour la plupart des plugs il faudra faire deux versions étant donné qu'il y a eu quelques changements dans le SDK, notamment :

-UNDO_... IDs renamed to UNDOTYPE_...
-Because of the R12 Dual Transformation funcionality, there are new BaseObject members: GetAbsPos, SetAbsPos, GetAbsScale, SetAbsScale, GetAbsRot, GetAbsRot, GetFrozenPos, SetFrozenPos, GetFrozenScale, SetFrozenScale, GetFrozenRot, GetFrozenRot, GetRelPos, SetRelPos, GetRelScale, SetRelScale, GetRelRot, SetRelRot, GetFrozenMln, GetRelMln, GetRelMl, SetRelMl, CopyMatrixTo


R12 Development Transition PDF (http://http.maxon.net/pub/sdk/12/R12Development.3.pdf)

fabrice.sierra
27/09/2010, 09h55
Bonjour à vous tous,

J'invite les nuls comme moi à consulter ce site qui à pour vocation les bases du Python.
Le traitement des cours est en vidéo avec un ton humoristique. :)
http://www.siteduzero.com/tutoriel-3-262839-presentation-et-installation.html#ss_part_1

Gyom
27/09/2010, 10h12
Merci Fabrice !
Ça c'est sympa : j'espère qu'il passe aussi une pré-couche sur le concept de dev objet car je ne suis pas sur d'avoir encore vraiment compris... J'm'en veux !
J'aurais du prendre ça comme module a la fac :-/

clemz
27/09/2010, 11h18
merci XS-Yann de faire partager tes avancées :) . c'est super intéressant !

faut que je m'y mette ! depuis le temps