Hello
J''essaye donc de me lancer dans l'ecriture de plug-in, et pour moi en tout cas c'est pas de la tarte.
j'ouvre donc ce fil pour poser mes questions. Et il va y en avoir pas mal je pense.
il faut dire quand même, que autant pour l’écriture de scripts on trouve pas mal d'infos, des tutoriaux etc…
mais sur l'ecriture de plug-ins c'est un peu le désert.
Voici ce que j'ai trouvé (a part la doc bien sur)
deux videos de pim Grooff https://www.youtube.com/watch?v=47VYjmmijHQ et https://www.youtube.com/watch?v=hbeRQDh-Gsc
et une video de Michael Auerswald : http://www.908video.de/lab_project/t...k-and-plugins/
Mais honnêtement et c'est pas pour critiquer, vu qu'ils ont fait l'effort de le faire et je les en remercie, mais t'en apprend pas beaucoup plus qu'en regardant la doc et des examples.
Le site smart-page : http://www.smart-page.net/blog/2011/05/09/advanced-python-plugin-coding-for-cinema-4d/
Mais comme annoncé c'est pas trop pour les débutants.
Il y avait le site de Pim Grooff que j'avais bookmarqué il y a un certain temps http://blog.grooff.eu/ mais apparemment il n'est plus accessible.
Et finalement celui que j'ai trouvé le plus intéressant, le site de microbion
http://www.microbion.co.uk/graphics/...e_plugins1.htm
les exemples sont en C++, mais il y a pas mal d'explications, notamment sur le mécanisme des fichiers de ressources.
Si vous avez d'autre bonnes sources je suis vraiment preneur.
Ma premiere question donc, est la suivante.
Dans l'ecriture d'un fichier res pour un plug-in de type shader, dans les exemple que j'ai vu, le premier Group est presque toujours acompagné d'un ID_SHADERPROPERTIES.
Dans la doc du SDK C++ il y a ecrit :
"groupid is a constant from the descriptionname.h file. It is used for the name of the group in the string table, and as an identifier for the group. If no group ID is specified the group is just used for structuring".
Dans mon Plugin de test la présence de ID_SHADERPROPERTIES generai une erreur, et comme manifestement c'est pas obligatoire je l'ai suprimé. Donc tout va bien. Mais comme dans les différents exemple il n'y en a aucune trace dans les descriptionname.h, en cherchant un peu j'ai trouvé que c'etait en fait une constante prédéfinie dans xbase.h mais j'ai trouvé aucune info sur l'utilisation ou l'utilité de cette constante.
D'ou ma question quand ou pourquoi faut il utilser cet ID prédéfini sur un groupe ?
Je vois bien que xbase semble etre un type de shader au même titre que xbrick ou xcloud, mais est ce que c'est celui qu'on est censé utiliser quand on développe son propre shader ?
[edit] Ah tiens et j'en rajoute une. Les préfixes pour les nom des fichiers de ressources O pour objet, T pour Tag ect...
C'est obligatoire ou c'est juste une convention ?
Dernière modification par Floc ; 30/01/2018 à 19h31.
Ce groupe ID_SHADERPROPERTIES va servir à afficher ton menu Catactéristiques de la Matière, quand tu cliqueras sur ton shader dans C4D.
As-tu inclus Xbase dans ton .res ?
Ajouter un autre GROUP au même niveau que le GROUP ID_SHADERPROPERTIES ajoutera un nouvel onglet, si je dis pas de bêtise.
Les constantes que tu créés dans ton .res doivent être déclarées et énumérées dans ton .h dans le dossier description.Code:CONTAINER MONSHADER { NAME MONSHADER_NOM; INCLUDE Mpreview; INCLUDE Xbase; GROUP ID_SHADERPROPERTIES { // Ici se trouvera le menu de ton shader REAL MONSHADER_POURCENTAGE { UNIT PERCENT; MIN 0.0; MAX 100.0; CUSTOMGUI REALSLIDER; } } GROUP MONSHADER_UNAUTREONGLET { // Ici se trouvera un autre onglet pour ton shader } }
Code:#ifndef monshader_avecunsuffixetotalementarbitrairepourledifferencierdesautresincludespossibles_H__ #define monshader_avecunsuffixetotalementarbitrairepourledifferencierdesautresincludespossibles_H__ int const MONSHADER = 1037432; // Plugin ID unique à créer sur plugincafe.com enum { MONSHADER_NOM = 1000, MONSHADER_UNAUTREONGLET, MONSHADER_POURCENTAGE, __DUMMY_ELEMENT_PEUIMPORTESONNOM__ // Sert juste à pouvoir écrire une virgule à la fin de chaque énumération au-dessus pour copier, ajouter facilement. }; #endif
Ensuite, pour leur associer un nom, tu alimentes ton fichier .str dnas le dossier description :
Code:STRINGTABLE { MONSHADER_NOM "Mon shader"; MONSHADER_UNAUTREONGLET "Un onglet"; MONSHADER_POURCENTAGE "Un champ pourcentage avec curseur"; }
Le Oobjet, Ttag etc. est une convention, tout comme les constantes en majuscules.
Tu peux t'inspirer de mon shader C++ ici aussi, perso je ne suis pas un adepte des tutos vidéos (je ne saurais t'en conseiller) mais plutôt des examples :
https://code.vonc.fr/?a=70
Dernière modification par César Vonc ; 30/01/2018 à 23h12.
Ok Merci pour ces précisions
Je ne suis pas fan non plus des tutos videos, et surtout pour le developement, mais c'est tout ce que j'ai trouvé.
et tes exemple sont evidement deja en haut de mes "sujet d'études"
Pour xbase.h et ID_SHADERPROPERTIES maintenant que je sais a quoi ca sert je vais le réintegrer.
Mais juste pour finir le type shader xbase c'est bien une sorte de "template" vide à remplir ? celui qu'on est censé utiliser, ou est ce qu'on peu partir d'un autre type ?
Dernière modification par Floc ; 30/01/2018 à 23h24.
Est ce qu'un dev charitable pourrait jeter un oeil a ce code et me dire pourquoi
dans la partie recup des donnée j'obtiens systematiquement cette erreur : "TypeError: an integer is required".
Au depart c'etait des bool. Je lui ai donné du Long, car du Int apparement y a pas. Mais marche pas Je comprend pas. l'erreur vient probablement d'ailleurs, mais je trouve pas
Et c'est peut etre evident mais les different init s'execute bien dans cet ordre ?
_Init_ de la classe
init de nodeData
renderInit de shaderData
C'est un peu comme si la case init (du nodeData) etait zappée.
Quelques remarques :
Les méthodes Set/GetLong et Set/GetReal sont dépréciées, utilise Set/GetInt32 et Set/GetFloat.
Je te conseille de mettre toutes tes propriétés dans le groupe ID_SHADERPROPERTIES, il ajoute par défaut par exemple, l'échantillonage et l'échelle du flou de la texture (que tu peux utiliser ou non). Après je n'ai pas la réponse à toutes tes questions concernant ce groupe. ^^
L'erreur ne vient pas du type du champ mais de la déclaration de tes constantes :
Tu as laissé une virgule à la fin de chaque nombre, du coup Python interprète ça comme un tuple avec un second élément vide (1000,) au lieu d'un entier.Code:FPLUGTWO_TEXTURE = 1000, FPLUGTWO_FLIPX = 1010, FPLUGTWO_FLIPY = 1020, FPLUGTWO_WORLD = 1030, FPLUGTWO_LOCAL = 1050
Code:FPLUGTWO_TEXTURE = 1000 FPLUGTWO_FLIPX = 1010 FPLUGTWO_FLIPY = 1020 FPLUGTWO_WORLD = 1030 FPLUGTWO_LOCAL = 1050
Ça marche mieux.
C'est tout à fait ça, pour l'ordre des appels des init.
Dernière modification par César Vonc ; 31/01/2018 à 23h37.
Je comprend pas.
Dans tous les exemple que j'ai vu y compris ceux de la doc et dans ton matiere-python il y a bien des virgule en fin de ligne ?
Et je viens de tenter mais même sans virgule toujours la même erreur
[Edit] ok autant pour moi. tu parles de la declaration qui est dans le pyp, mas dans .h
Effectivement ca devrait aller mieux
Dernière modification par Floc ; 31/01/2018 à 23h46.
C'est dans le fichier Python qu'il faut les enlever les virgules hein, pas le .h !
Code:import os import math import c4d from c4d import plugins, bitmaps, utils PLUGIN_ID = 1040539 FPLUGTWO_TEXTURE = 1000 FPLUGTWO_FLIPX = 1010 FPLUGTWO_FLIPY = 1020 FPLUGTWO_WORLD = 1030 FPLUGTWO_LOCAL = 1050 class FPlugTwo(c4d.plugins.ShaderData): print "FPlugTwo ok" def __init__(self): #debug color self.ape = True self.mode = 0 #self.theTex = 0.0 self.flipx = 0 self.flipy = 0 self.worldSpace = True self.localSpace = False self.SetExceptionColor(c4d.Vector(1,0,0)) def Init(self, node): donnees = node.GetDataInstance() donnees.SetReal(FPLUGTWO_TEXTURE, self.theTex) donnees.SetInt32(FPLUGTWO_FLIPX, self.flipx) donnees.SetInt32(FPLUGTWO_FLIPY, self.flipy) donnees.SetBool(FPLUGTWO_WORLD, self.worldSpace) donnees.SetBool(FPLUGTWO_LOCAL, self.localSpace) return True def recup(self, sh): donnees = sh.GetDataInstance() self.theTex = donnees.GetReal(FPLUGTWO_TEXTURE) self.flipx = donnees.GetInt32(FPLUGTWO_FLIPX) self.flipy = donnees.GetInt32(FPLUGTWO_FLIPY) self.worldSpace = donnees.GetBool(FPLUGTWO_WORLD) self.localSpace = donnees.GetBool(FPLUGTWO_LOCAL) def InitRender(self, sh, irs): self.recup(sh) self.irs = irs return 0 def Output(self, sh, cd): pos = c4d.Vector() nor = c4d.Vector() space = 0 if self.mode == space : # Espace Monde if cd.vd : # 3D pos = cd.vd.p nor = cd.vd.bumpn else : # Aperçu if self.ape : pos = (cd.p - 0.5) * 100.0 else : return pos elif self.mode == space : # Espace UV pos = cd.p elif self.mode == space : # Espace Objet if cd.vd : # 3D pos = cd.vd.p else : # Aperçu if self.ape : pos = (cd.p - 0.5) * 100.0 else : return pos #color = c4d.Vector(cd.p[0], cd.p[1], 0) #color = c4d.Vector(cd.n[0], cd.n[1], cd.n[2]) color = nor return color def FreeRender(self, sh): #Free any resources used for the precalculated data from InitRender(). return def registerThePlug(): #c4d.plugins.RegisterShaderPlugin(id, str, info, g, description[, disklevel][, res]) IDS_FPLUGTWO=10000 name = plugins.GeLoadString(IDS_FPLUGTWO); return plugins.RegisterShaderPlugin(PLUGIN_ID, name, 0, FPlugTwo, "FPlugTwo", 0) if __name__ == "__main__": registerThePlug()
Ah grillé j'ai pas tilté assez vite
[edit] Et oui ca va nettement mieux !
Merci
Dernière modification par Floc ; 31/01/2018 à 23h50.
Hello. La question du soir.
Est ce qu'il y a une condition particulière en python pour transformer un shader via les uv. Les exemple en C++ paraissent évident, mais en python rien ne se passe.
exemple C++ qui est censé flipper l'image.
Ma version python qui ne donne rienCode:if(!shader) return Vector(1.0, 0.0, 0.0); // return red if no bitmap present uv = cd->p; cd->p.x = 1.0 - cd->p.x; res = shader->Sample(cd); cd->p = uv; return res;
[Edit] Bon y a rien a faire. j'ai tourné le truc dans tous les sens, c'est comme si cd.p (la position dans l'espace uv) ne pouvait pas etre modifié. Avec cd.n en revanche pas de souci.Code:def Output(self, sh, cd): ..... uv = c4d.Vector() ..... elif self.mode == FPLUGTWO_UV : # Espace UV if self.shader : uv = cd.p cd.p.x = 1.0 - cd.p.x cd.p.y = cd.p.y * 2.0 color = self.shader.Sample(cd) cd.p = uv else : color = cd.p ...... return color
Dernière modification par Floc ; 03/02/2018 à 01h16.
En regardant vite fait il semblerait que tu n'es pas accès directement aux paramètres du vecteur(x, y, z), du moins tu n'écris pas sur le même vecteur.
Bref en passant directement par une assignation du vecteur et non des membres de celui-ci ça fonctionne
Je verrais lundi si on peux corriger çaCode:if self.shader : uv = cd.p cd.p = c4d.Vector(1.0 - cd.p.x, cd.p.y * 2.0, cd.p.z) color = self.shader.Sample(cd) cd.p = uv else : color = cd.p
Dernière modification par gr4ph0s ; 05/02/2018 à 09h06.
SDK Specialist
MAXON Computer GmbH
Coooool !!
Ca marche.
Je l'aurai pas trouvé tout seul ça.
Merci gr4ph0s
salut Floc,
admiratif je suis...courageuse est la démarche..
::::::::::::::
pxlntwrk.net
merci pxl, oui et semée d'embuche
Bon c'est a peine une version zéro, mais c'est quand même un premier pas vers le shader textureBombing.
Rien d'impressionnant pour le moment (surtout pour les Cesar, Graphos et consors ), et vous allez me dire qu'on peu faire presque pareil avec un simple tilling.
Et moi je je vous répondrai ouaip… mais c'est pas pareil.
C'est au moins 1000 fois plus long a faire .
Disons que la j'ai la base. il me reste a intégrer du blending, de la rotation, et un masque autre que rectangulaire.
Avec une texture ou on voit bien le "zonage".
Avec une texture de roche et étonnement ça marche déjà plutôt pas trop mal.
Alors j'ai évidement quelques questions.
Notement niveau optimisation. parce que la c'est extremement lent, et pourtant le technique utilisé est plutôt légère en terme de cout calcul, mais pour la suite ca risque de se compliquer.
- Aparement il n'y a pas de gestion de Matrices 2D ni en python ni en C4D. Donc je me demande en terme de performance si il vaut mieux utilser les matrices 3D de C4D ou écrire ma propre fonction de rotation.
- en GLSL pratiquement toute les fonction mathematiques (floor, cos, etc… même rand) supporte les vecteur 2d, 3d, ou 4d. Je suis quasi sur que ce n'est pas le cas ni dans c4d, ni en python ( un truc peu m'echaper).
En python on peu ecrirre a, b = 0.2, 1.5.
Est ce qu'il n'y aurai pas une sintaxe pour ecrire genre : x, y = floor(a, b).
Ou quelque chose de plus élégant que de toujours séparer et réassambler les composantes.
- Question plutot a cesar (mais pas que)
Dans ton shader matiere-python il y a un mecanisme pour gerer les preview dans le cas d'appels a volumeData.
if cd.vd : # 3D
UVs = cd.vd.p
else : # Aperçu
if self.ape : UVs = (cd.p - 0.5) * 100.0
else : return UVs
Comment ca fonctionne ? puisque cd.cd.p existe on ne devrait jamais passer par else. Est ce que C4d evalue deux fois
la metode Output une fois avec cd.vd existant et une deuxieme fois cd.vd inexistant ? du coup on passe par la case
else : # Aperçu
Ou alors est ce que c'est magique ?
Dernière modification par Floc ; 05/02/2018 à 19h22.
Effectivement pas de matrices, ni de vecteur 2D.
Mais une matrice/vecteur 2D n'est qu'un matrice/vecteur 3D dont un des axes ne bouge pas (0).
Apres tu as une classe de Vecteur 4D dans C4D.
Pour ce qui est des performances, déjà vire tout les print ceci ralentit fortement, essaye de "baker" le plus de choses possibles lors du InitRender
Pas sur de comprendre ton problème de floor. Mais en tout cas tu as le module math.
map va exécuter une fonction sur une listeCode:import math a, b = 0.2, 1.5x, y = map(math.floor, [a, b])
SDK Specialist
MAXON Computer GmbH