Difference between revisions of "IT:HowTo:Use POV-Ray with Blender/Developers"

From POV-Wiki
Jump to navigation Jump to search
 
(21 intermediate revisions by the same user not shown)
Line 113: Line 113:
  
  
Ad esempio, all'inizio del file, il commento
+
Una delle linee guida per la formattazione del testo/stile di codifica da utilizzare è [https://www.python.org/dev/peps/pep-0008/ PEP8] quindi, ad esempio, dovresti fare attenzione a creare righe abbastanza brevi in ​​tutto il testo file di script con meno di 79 caratteri e meno di 72 per le docstring (vedi sotto) o i commenti.
<source lang="py"># <pep8 compliant></source>
+
 
significa che una delle direttive di stile di formattazione/codifica del testo da utilizzare è [https://www.python.org/dev/peps/pep-0008/ PEP8] quindi ad esempio dovresti assicurarti di creare righe sufficientemente brevi in ​​tutto lo script file di meno di 79 caratteri e meno di 72 per ''docstring'' (vedi sotto) o commenti.
+
Periodicamente la Blender Foundation esegue controlli per questa conformità pep8 sugli script di Blender.
Nota che questo commento ha una sintassi speciale: Periodicamente, la Blender Foundation controlla gli script di Blender per la conformità pep8, affinché gli script siano inclusi in questo controllo, aggiungi questa riga come commento all'inizio dello script.
+
La lunghezza della riga tollerata è arrivata a raggiungere i 100 caratteri.
 +
 
 +
Se devi davvero superare questo limite, ad esempio per promemoria temporanei di lavori in corso, aggiungi
 +
<source lang="py"># nopep8</source>
 +
alla fine della riga pertinente
  
 
Altre regole includono:
 
Altre regole includono:
Line 237: Line 241:
 
</source>
 
</source>
  
La funzione ''execute()'' viene passata un riferimento a a a contesto oggetto. Questo oggetto di contesto contiene tra l'altro un attributo ''active_object'' a cui punta, oggetto attivo Blenders. Ogni oggetto in Blender ha un attributo di rotazione che è un vettore con componenti x, y e z. Cambiare la rotazione di un oggetto è semplice come cambiare uno di questi componenti, che è esattamente ciò che facciamo nella riga 2.
+
La funzione ''execute()'' viene passata un riferimento a a a contesto oggetto. Questo oggetto di contesto contiene tra l'altro un attributo ''active_object'' che punta a l'oggetto attivo di Blender. Ogni oggetto in Blender ha un attributo di rotazione che è un vettore con componenti x, y e z. Cambiare la rotazione di un oggetto è semplice come cambiare uno di questi componenti, che è esattamente ciò che facciamo nella riga 2.
  
La fonction ''execute()'' signale une exécution réussie en renvoyant un ensemble d'indicateurs, dans ce cas un ensemble composé uniquement de la chaine de caractères ''"FINISHED"''.
+
La funzione ''execute()'' segnala l'esecuzione riuscita restituendo un set di flag, in questo caso un set costituito solo dalla stringa di caratteri ''"FINISHED"''.
  
===Création et ajout au registre d'une entrée de menu===
+
===Creazione e aggiunta di un menu al registro===
Lorsque nous activons la case à cocher ''Enable add-on'' dans les ''preferences'', Blender recherchera une fonction '''register()''' et l'exécutera. De même, lors de la désactivation d'un module complémentaire, la fonction '''unregister()''' est appelée. Utilisons-les donc à la fois pour enregistrer notre opérateur auprès de Blender et pour insérer une entrée de menu qui fait référence à notre opérateur. la désinscrire et désafficher est également important pour que notre add-on ne soit pas perçu comme invasif ou destructeur d'une configuration précédente sans retour possible.
+
Quando abilitiamo la casella di controllo ''Enable add-on'' nelle ''preferenze'', Blender cercherà una funzione '''register()''' e la eseguirà. Allo stesso modo, quando si disattiva un componente aggiuntivo, viene richiamata la funzione'''unregister()'''. Usiamoli quindi sia per registrare il nostro operatore con Blender sia per inserire una voce di menu che faccia riferimento al nostro operatore. è inoltre importante annullare l'iscrizione e disattivarla affinché il nostro componente aggiuntivo non venga percepito come invasivo o distruttivo di una configurazione precedente senza possibile ritorno.
  
Pour créer une entrée de menu, nous devons faire deux choses :
+
Per creare un menu dobbiamo fare due cose:
*Créer une fonction qui produira une entrée de menu
+
*Crea una funzione che produrrà una voce di menu
*Et ajouter cette fonction à un menu approprié.
+
*E aggiungi questa funzione al menu appropriato.
  
De nos jours, presque tout dans Blender est disponible sous forme d'objet Python et les menus ne font pas exception. Nous voulons ajouter notre entrée au menu Objet dans la vue 3D, nous appelons donc <source lang="py">bpy.types.VIEW3D_MT_object.append()</source> et lui passer une référence à la fonction que nous définissons un peu plus bas. Comment savons-nous le nom de cet objet de menu? Si vous avez coché''File⇒ User preferences ⇒ Interface ⇒ Python Tooltips'' le nom du menu sera affiché dans une info-bulle lorsque vous survolez un menu. À partir de l'image ci-dessus, nous pouvons voir que nous pouvons utiliser ''bpy.types.VIEW3D_MT_object.append()'' pour ajouter quelque chose au menu ''Objet'' car ''VIEW3D_MT_object'' s'affiche alors dans le texte de la bulle apparue au survol de ce menu.  
+
Al giorno d'oggi quasi tutto in Blender è disponibile come oggetto Python e i menu non fanno eccezione. Vogliamo aggiungere la nostra voce al menu Oggetto nella vista 3D, quindi chiamiamo <source lang="py">bpy.types.VIEW3D_MT_object.append()</source> e passargli un riferimento alla funzione che definiamo poco più sotto. Come facciamo a sapere il nome di questo oggetto di menu? Se hai attivato ''File⇒ User preferences ⇒ Interface ⇒ Python Tooltips'' Il nome del menu verrà visualizzato in una descrizione comando quando passi il mouse su un menu. Dall'immagine sopra possiamo vedere che possiamo usare ''bpy.types.VIEW3D_MT_object.append()'' per aggiungere qualcosa al menu ''Oggetto'' perché ''VIEW3D_MT_object'' viene visualizzato nel testo della bolla che appare quando si passa con il mouse su questo menu.  
  
{{NiceTip|La fonction ''menu_func()'' n'implémente pas d'action elle-même (c'est le rôle d'un opérateur)| Mais lorsqu'elle est appelée, ''menu_func()'' ajoutera un élément d'interface utilisateur pointant vers l'objet qui lui est passé dans le paramètre '''self'''. Cet élément d'interface peut être modifié par l'utilisateur et, à son tour, interagira avec l'opérateur.}}<br/>
+
{{NiceTip|La funzione ''menu_func()'' non implementa un'azione stessa (questo è il ruolo di un operatore)| Ma quando viene chiamato, ''menu_func()'' aggiungerà un elemento UI che punta all'oggetto passatogli nel parametro '''self'''. Questo elemento dell'interfaccia potrà essere modificato dall'utente e, a sua volta, interagirà con l'operatore.}}<br/>
  
Ici, nous allons simplement ajouter une entrée d'opérateur (c'est-à-dire un élément qui exécutera notre opérateur lorsqu'il sera cliqué).
+
Qui aggiungeremo semplicemente un input dell'operatore (ovvero un elemento che eseguirà il nostro operatore quando viene cliccato).
  
L'argument ''self'' passé à ''menu_func()'' fait référence au menu.  
+
L'argomento ''self'' passato a ''menu_func()'' si riferisce al menu.  
  
Ce menu possède un attribut ''layout'' avec une fonction ''operator()'' à laquelle nous passons le nom de notre opérateur. Cela garantira qu'à chaque fois qu'un utilisateur survolera le menu '''Object''', notre opérateur sera affiché dans la liste des options.  
+
Questo menu ha un attributo ''layout'' con una funzione ''operator()'' alla quale passiamo il nome del nostro operatore. Ciò garantirà che ogni volta che un utente passa con il mouse sul menu '''Oggetto''', il nostro operatore verrà visualizzato nell'elenco delle opzioni.
  
Le nom de notre nouvel opérateur ''MyTool'' se trouve dans son attribut '''bl_idname''', c'est pourquoi nous passons ''MyTool.bl_idname''.
+
l nome del nostro nuovo operatore ''MyTool'' è nel suo attributo '''bl_idname''', motivo per cui passiamo ''MyTool.bl_idname''.
  
Le nom de l'entrée et son info-bulle sont déterminés en regardant le '''bl_label''' et la ''docstring'' définis dans notre classe ''MyTool'' et l'icône utilisée dans le menu est déterminée en passant un paramètre facultatif '''icon''' à la fonction ''operator()''.
+
Il nome della voce e il suo tooltip sono determinati guardando '''bl_label''' e ''docstring'' definiti nella nostra classe ''MyTool'' e l'icona utilizzata nel menu è determinata passando un comando facoltativo parametro '''icon''' alla funzione ''operator()''.
  
Définir un menu ne suffit pas en soi à rendre ce menu utilisable. Pour que l'utilisateur puisse le trouver et l'utiliser, nous devons ajouter le menu à son parent depuis la fonction '''register()''' à la fin de son fichier python.  
+
Definire un menu non è di per sé sufficiente a renderlo utilizzabile. Affinché l'utente possa trovarlo e utilizzarlo, dobbiamo aggiungere il menu al suo genitore dalla funzione '''register()''' alla fine del suo file python.
  
 
<source lang="py">
 
<source lang="py">
Line 272: Line 276:
 
     bpy.types.VIEW3D_MT_object.remove(menu_func)
 
     bpy.types.VIEW3D_MT_object.remove(menu_func)
 
</source>
 
</source>
Les opérateurs doivent être enregistrés de la même manière, donc ajouter un opérateur enregistré à un menu nécessite deux à trois actions distinctes :
+
Gli operatori devono essere registrati allo stesso modo, quindi aggiungere un operatore registrato a un menu richiede da due a tre azioni separate:
* Enregistrer l'opérateur ;
+
*Registrati operatore;
* puis l'ajouter à un menu existant ;
+
* quindi aggiungilo a un menu esistente;
* Ou enregistrer d'abord le menu nouvellement créé auquel il doit appartenir et ensuite seulement y ajouter l'opérateur.
+
*Oppure salvare prima il menu appena creato a cui dovrebbe appartenere e solo dopo aggiungervi l'operatore.
Ce n'est qu'après tout cela que le nouvel opérateur apparaîtra sur l'interface utilisateur, du moins, si rien d'autre, en appuyant sur F3 dans la fenêtre de vue 3D et en saisissant le libellé de l'opérateur
+
Solo dopo tutto ciò il nuovo operatore apparirà sull'interfaccia utente, almeno, se non altro, premendo F3 nella finestra di visualizzazione 3D e digitando l'etichetta dell'operatore
  
Tout cela pourrait paraître une peu plus compliqué que nécessaire mais cela permet par exemple d'afficher bien d'autres choses qu'uniquement de simples entrées cliquables dans un menu, par exemple de regrouper plusieurs opérateurs dans une même case, par exemple s'ils font partie de modalités disponibles dans une même sous-thématique, etc.
+
Tutto questo potrebbe sembrare un po' più complicato del necessario ma permette ad esempio di visualizzare molte altre cose oltre alle semplici voci cliccabili in un menu, ad esempio di raggruppare più operatori nella stessa casella, ad esempio se fanno parte di modalità disponibili in lo stesso sottotema, ecc.
  
{{NiceTip|Les commandes ''unregister()'' de désinscription au registre doivent apparaître dans l'ordre inverse de leurs lignes ''register()'' correspondantes| Cela garantit que vous n'essayez pas de désinscrire, par exemple, un menu qui a été ajouté en tant qu'enfant d'une classe d'élément d'interface utilisateur que vous pourriez essayer de désinscrire avant cet enfant, désinscrivant ainsi quelque chose qui n'est déjà plus là... Ce qui déclencherait une erreur et l'échec de l'activation/désactivation du module complémentaire.}}<br/>
+
{{NiceTip|I comandi di ''unregister()'' devono apparire in ordine inverso rispetto alle righe ''register()'' corrispondenti| Ciò garantisce che tu non provi ad annullare la registrazione, ad esempio, di un menu che è stato aggiunto come figlio di una classe di elementi dell'interfaccia utente che potresti provare a annullare la registrazione prima di quel figlio, annullando così la registrazione di qualcosa che già non è più presente... Il che genererebbe un errore e la mancata attivazione/disattivazione del componente aggiuntivo.}}<br/>
  
==Optimisation==
+
==Ottimizzazione==
====Gardez vos notations "pointées" minimale====
+
====Mantieni la notazione "puntata" minima====
Comme dans de nombreux langages orientés objet, Python permet la visualisation d'une structure hiérarchique avec ses niveaux séparés par des points (imaginez chaque point comme l'ouverture de la plus grande poupée russe à gauche qui enjambe les plus petites à sa droite).
+
Come in molti linguaggi orientati agli oggetti, Python consente la visualizzazione di una struttura gerarchica con i suoi livelli separati da punti (pensa a ciascun punto come l'apertura della bambola russa più grande a sinistra che porta quelli più piccoli alla sua destra).
{{NiceTip|Remplacez ses parcours inutilement répétés par des alias|
+
{{NiceTip|Sostituisci le sue ricerche inutilmente ripetute con alias|
L'opérateur point est un moyen simple de récupérer une classe, une donnée, une méthode, n'importe quel objet Python inclus dans une hiérarchie plus large... Mais sachez qu'il est coûteux, surtout s'il est utilisé dans une boucle.}}
+
L'operatore punto è un modo semplice per acquisire classe, dati, metodo, qualunque oggetto python incluso in una gerarchia più ampia ... Ma tieni presente che è costoso, specialmente se usato in un ciclo.}}
Loorsque l'on invoque
+
Quando si chiama
 
<source lang="py">
 
<source lang="py">
 
bpy.data.objects["my_obj"]
 
bpy.data.objects["my_obj"]
 
</source>
 
</source>
Chaque point plonge plus profondément d'un niveau et toute la hiérarchie est parcourue jusqu'à lui. Vous devez toujours le faire au moins une fois pour atteindre l'élément souhaité, il est donc acceptable d'utiliser cette syntaxe lorsque cette référence n'est faite qu'une seule fois, mais au-delà, préférez toujours éviter de refaire entièrement tout ce parcours, et donnez lui plutôt une variable d'alias comme
+
Ogni punto si tuffa di un livello più in profondità e l'intera gerarchia viene raggiunta. Devi sempre farlo almeno una volta per raggiungere l'elemento desiderato, quindi va bene usare quella sintassi quando il riferimento viene fatto solo una volta, ma soprattutto, preferisci sempre evitare l'intera ricerca e piuttosto dargli un alias come
 
<source lang="py">
 
<source lang="py">
 
obj = bpy.data.objects["my_obj"]
 
obj = bpy.data.objects["my_obj"]
 
</source>
 
</source>
Ainsi vous pouvez ensuite toujours l'utiliser, en ne gérant plus que les ramifications du parcours vers des attributs occasionnels à usages uniques comme l'exemple ci-dessous:
+
Quindi puoi ancora usarlo, gestendo attributi occasionali come l'esempio seguente:  
  
 
<source lang="py">obj.location.z += 1</source>
 
<source lang="py">obj.location.z += 1</source>
pour tous les autres attributs disponibles à vos opérations de lecture ou d'écriture. Définissez autant de ces alias requis qu'il le faut '''avant''' d'entrer dans une boucle plutôt qu'à l'intérieur de celle-ci.
+
e tutti gli altri attributi disponibili, per le operazioni di lettura o scrittura. Definire molti di questi alias necessari '''prima''' di entrare in un ciclo piuttosto che all'interno di esso.  
Imaginez si votre GPS vous indiquait toujours les directions précédentes prises depuis le point de départ en passant par les suivantes à chaque virage !
+
Immagina se il tuo GPS ti dicesse sempre le indicazioni precedenti prese dal punto di partenza fino a quella successiva ad ogni turno!
  
====Utilisez ''try/except'' avec parcimonie====
+
====Usare ''try/except'' con parsimonia====
  
L'instruction ''try'' est utile pour gagner du temps lors de l'écriture d'un code de vérification d'erreurs.
+
L'istruzione ''try'' è utile per risparmiare tempo per scrivere il codice di controllo degli errori.
  
Cependant, ''try'' est nettement plus lent qu'un ''if'' car une exception doit aussi être définie à chaque fois, évitez donc d'utiliser ''try'' dans les zones de votre code qui s'exécutent en boucle et s'exécutent plusieurs fois.
+
Tuttavia, ''try'' è significativamente più lento di un ''if'' perchè un'eccezione deve essere impostata ogni volta, quindi evita di utilizzare ''try'' nelle aree del codice che vengono eseguite in un ciclo e vengono eseguite molte volte.
  
Il existe des cas où l'utilisation de ''try'' est plus rapide que d'explicitement détecter par un test (''if'' ou autre) la condition complexe qui génèrerait potentiellement une erreur, il vaut donc la peine d'expérimenter.
+
Ci sono casi in cui l'uso di ''try'' è più veloce che rilevare esplicitamente tramite un test (''if'' o altro) la condizione complessa che potrebbe potenzialmente generare un errore, quindi vale la pena sperimentare.
  
  
Une bonne façon de supprimer certains de vos ''try'' ... ''except'' lorsque l'erreur constatée s'avère une '''AttributeError''' est de les remplacer par un test en amont avec la fonction ''hasattr()'' :
+
Un buon modo per rimuovere alcuni dei tuoi ''try'' ... ''except'' quando l'errore trovato risulta essere un '''AttributeError''' è sostituirli con un pre-test con la funzione ' 'hasattr()'':
 
<syntaxhighlight lang="python3">
 
<syntaxhighlight lang="python3">
 
for member in dir(properties_freestyle):
 
for member in dir(properties_freestyle):
Line 319: Line 323:
 
         pass
 
         pass
 
</syntaxhighlight>
 
</syntaxhighlight>
pourrait alors devenir
+
potrebbe diventare
 
   
 
   
 
<syntaxhighlight lang="python3">
 
<syntaxhighlight lang="python3">
Line 327: Line 331:
 
       subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
 
       subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
 
</syntaxhighlight>
 
</syntaxhighlight>
Si vous devez utiliser ''try:''... ''except:''... ne laissez pas le type d'exception non spécifié, cela ne donne absolument aucun retour d'information ni aucune lisibilité du code. Au lieu de cela, si vous n'avez aucune idée de ce que cela pourrait être, remplacez le par quelque chose qui donnerait plus d'informations pendant votre phase de débogage :
+
Se devi usare ''try:''... ''except:''... non lascia il tipo di eccezione non specificato, questo non fornisce assolutamente alcun feedback o leggibilità del codice. Se invece non hai idea di cosa potrebbe essere, sostituiscilo con qualcosa che dia maggiori informazioni durante la fase di debug:
  
(''BaseException'' est au sommet de la hiérarchie des exceptions)
+
(''BaseException'' è al top della gerarchia delle eccezioni)
 
<syntaxhighlight lang="python3">
 
<syntaxhighlight lang="python3">
 
def your_function(b, c):
 
def your_function(b, c):
Line 341: Line 345:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==Séparez vos fichiers Python (*.py)==
+
==Separare i file python (*.py)==
Historiquement, le script a ensuite été agencé en un[https://docs.python.org/3/tutorial/modules.html#packages package] (plusieurs fichiers dans un dossier) en utilisant le moins de fichiers possible pour que le flux de données soit plus facile à comprendre. Il y avait initialement 3 fichiers principaux:
+
Lo script è stato successivamente suddiviso in un[https://docs.python.org/3/tutorial/modules.html#packages package] (diversi file in una cartella) utilizzando il minor numero di file possibile per rendere il flusso di dati più semplice da comprendere. Inizialmente c'erano 3 file principali:
*''__init__.py''
+
* ''__init__.py''
*''ui.py''
+
* ''ui.py''
*''render.py''
+
* ''render.py''
Cependant, certains fichiers dépassaient les 10 000 lignes, ce qui, pour un tel add-on était encore trop volumineux. Il est donc actuellement toléré que le plus gros fichier reste en dessous de 2000 lignes. Il est très probable que les fichiers pourraient perdre un peu de poids, en supprimant le support 32 bits obsolète et en modularisant une partie du code en quelques fonctions plus réutilisables. Voici les fichiers actuels composant l'add-on et leur utilisation respective :
+
Tuttavia, alcuni file superavano le 10.000 righe, che per un componente aggiuntivo di questo tipo erano ancora troppo grandi. Attualmente è quindi tollerato che il file più grande rimanga al di sotto delle 2000 righe. È molto probabile che i file possano perdere peso, rimuovendo l'obsoleto supporto a 32 bit e modularizzando parte del codice in alcune funzioni più riutilizzabili. Ecco i file attuali che compongono il componente aggiuntivo e i rispettivi usi:
  
===Initialisation===
+
===inizializzazione===
 
====__init__.py====
 
====__init__.py====
Création des préférences utilisateur du module complémentaire POV, autorisation de l'utilisateur à mettre à jour le module complémentaire vers la dernière version et chargement de tous les autres modules.
+
Crea le preferenze utente del componente aggiuntivo POV, ordina all'utente di aggiornare il componente aggiuntivo all'ultima versione e carica tutti gli altri moduli. (Nota il doppio sottolinea il nome del file. Questo lo rende il primo file lanciato) la definizione dell'unità "principale" per un pacchetto; fa anche in modo che Python tratti la directory specifica come un pacchetto. È l'unità che verrà utilizzata quando si chiama import render_povray (e render_povray è una directory).
(Notez les doubles traits de soulignement autour du nom du fichier. Cela en fait le premier fichier lancé)
 
définition de l'unité « principale » pour un package ; cela oblige également Python à traiter le répertoire spécifique comme un package. C'est l'unité qui sera utilisée lorsque l'on appele ''import render_povray'' (et ''render_povray'' est un répertoire).
 
  
 
====scenography_properties.py====
 
====scenography_properties.py====
Initialisation des propriétés pour traduire les paramètres de caméra/lumière/environnement de Blender en langage POV.
+
Inizializzazione delle proprietà per tradurre le impostazioni della fotocamera/luce/ambiente di Blender nel linguaggio POV.
  
 
====object_properties.py====
 
====object_properties.py====
Initialisation des propriétés pour traduire les paramètres d'objets de Blender en langage POV.
+
Inizializzazione delle proprietà per tradurre le impostazioni dell'oggetto Blender nel linguaggio POV.
  
 
====shading_properties.py====
 
====shading_properties.py====
Initialisation des propriétés pour traduire les paramètres de matériaux de Blender en langage POV.
+
Inizializzazione delle proprietà per tradurre le impostazioni dei materiali di Blender nel linguaggio POV.
  
 
====texturing_properties.py====
 
====texturing_properties.py====
Initialisation des propriétés pour traduire les paramètres d'influences de textures des matériaux, d'environnement (world)... de Blender en langage POV.
+
Inizializzazione delle proprietà per tradurre i parametri di influenza delle texture dei materiali, dell'ambiente (mondo), ecc. da Blender al linguaggio POV.
 
 
 
====render_properties.py====
 
====render_properties.py====
Initialisation des propriétés pour traduire les paramètres de rendu (de Blender mais surtout les plus spécifiquement natifs de POV).
+
Inizializzazione delle proprietà per tradurre i parametri di rendering (da Blender ma soprattutto quelli più specificatamente nativi di POV).
  
 
====scripting_properties.py====
 
====scripting_properties.py====
Initialisation des propriétés et champs pour renseigner des instructions directement dans le langage de description de scène POV.
+
Inizializzazione di proprietà e campi per popolare le istruzioni direttamente nel linguaggio di descrizione della scena POV.
 
 
  
===Interface===
+
===Interfaccia===
Quelques notes à garder à l’esprit lors de la création d'éléments d’interface utilisateur :
+
Alcune note da tenere a mente durante la creazione di elementi dell'interfaccia utente:
  
Les commandes fournies par Blender pour l'interface utilisateur sont relativement simples. Les déclarations d'interface sont là pour créer facilement une disposition acceptable. Règle générale ici : si vous avez besoin de plus de code pour la disposition de leur interface que pour les propriétés elles-mêmes, alors vous vous y prenez mal.
+
I controlli che Blender fornisce per l'interfaccia utente sono relativamente semplici. Le dichiarazioni di interfaccia servono per creare facilmente un layout accettabile. Regola generale qui: se hai bisogno di più codice per il layout dell'interfaccia rispetto alle proprietà stesse, allora stai sbagliando.
  
Exemples d'interface:
+
Esempi di interfaccia:
  
 
     layout()
 
     layout()
  
La disposition de base est une disposition simple de Haut -> en Bas.
+
Il layout di base è un semplice layout Alto -> Basso.
  
 
     layout.prop()
 
     layout.prop()
Line 389: Line 389:
 
     layout.row()
 
     layout.row()
  
Use row(), when you want more than 1 property in one line.
+
Usa row(), quando vuoi più di 1 proprietà in una riga.
  
 
     row = layout.row()
 
     row = layout.row()
Line 397: Line 397:
 
     layout.column()
 
     layout.column()
  
Use column(), when you want your properties in a column.
+
Usa column(), quando vuoi che le tue proprietà siano in una colonna.
  
 
     col = layout.column()
 
     col = layout.column()
Line 405: Line 405:
 
     layout.split()
 
     layout.split()
  
This can be used to create more complex layouts. For example you can split the layout and create two column() layouts next to each other. Don’t use split, when you simply want two properties in a row. Use row() for that.
+
Questo può essere utilizzato per creare layout più complessi. Ad esempio puoi dividere il layout e creare due layout ''column()'' uno accanto all'altro. Non utilizzare la suddivisione quando desideri semplicemente due proprietà di seguito. Usa ''row()'' per quello.
 +
 
  
 
     split = layout.split()
 
     split = layout.split()
Line 417: Line 418:
 
     col.prop()
 
     col.prop()
  
Declaration names:
+
Nomi delle dichiarazioni:
 
 
Try to only use these variable names for layout declarations:
 
  
    row for a row() layout
+
Prova a utilizzare solo questi nomi di variabili per le dichiarazioni di layout:
  
    col for a column() layout
+
''row'' per un layout row()
  
    split for a split() layout
+
''col'' per un layout column()
  
    flow for a column_flow() layout
+
''split'' per un layout split()
  
    sub for a sub layout (a column inside a column for example)
+
''flow'' per un layout column_flow()
  
 +
''sub'' per un layout sub() (una colonna all'interno di una colonna per esempio)
  
 
====base_ui.py====
 
====base_ui.py====
Provide a Moray like workspace and define some utility functions.
+
Fornisce un workspace simile a Moray e definisce alcune funzioni di utilità. Carica tutti gli altri moduli relativi alla GUI
Load all the other GUI related modules
 
 
 
  
 
====scenography_gui.py)====
 
====scenography_gui.py)====
Display cam/light/environment properties from situation_properties.py for user to change them
+
Visualizza le proprietà camera/luce/ambiente da scenography_properties.py affinché l'utente possa modificarle
 
 
  
 
====object_gui.py :====
 
====object_gui.py :====

Latest revision as of 17:01, 6 January 2025


🌎    🇬🇧 / 🇫🇷 / 🇮🇹 /


▼ Developer's page

POVExporterLogo.png
Go To User's page ►



Il componente aggiuntivo Blender per POV-Ray e viceversa (noto anche come "POV@Ble") è iniziato come un singolo file Python. Per rispettare i criteri per le estensioni disponibili con Blender, questo componente aggiuntivo doveva:

  • fornire alcune informazioni generali sul componente aggiuntivo: nome e versione,
  • definire il codice per eseguire azioni, principalmente tramite "operatori" o "funzioni"
  • e assicurarsi che siano iscritti nel registro affinché possano essere utilizzati.


bpy

Blender dispone di un interprete Python integrato che è incaricato di avviare Blender e resta attivo mentre Blender è in corso di esecuzione. L'interprete esegue script per progettare l'utente dell'interfaccia ed è anche utilizzato per alcuni strumenti interni di Blender. L'interprete integrato di Blender fornisce un ambiente tipico Python, quindi il codice didattico sulla forma di scrittura degli script Python può essere eseguito anche con l'interprete di Blender. Frullatore fornitomoduli Python, come bpy e mathutils, per la console integrata affinché possano essere importati in uno script e accedere ai dati, alle classi e alle funzioni di Blender. Gli script che trattano i dati di Blender devono essere l'oggetto di unimport di moduli per funzionare. Quindi, tra tutti i moduli, se non ce n'è un altro, bpy è generalmente sempre importato negli script di Blender. (eccetto nella console interattiva dove questa importazione viene eseguita automaticamente per maggiore comodità)

La console interattiva di Blender


metadati del componente aggiuntivo

bl_info = {
    "name": "Persistence of Vision",
    "author": "Campbell Barton, "
    "Maurice Raybaud, "
    "Leonid Desyatkov, "
    "Bastien Montagne, "
    "Constantin Rahn, "
    "Silvio Falcinelli",
    "version": (0, 1, 1),
    "blender": (2, 81, 0),
    "location": "Render Properties > Render Engine > Persistence of Vision",
    "description": "Persistence of Vision integration for blender",
    "doc_url": "{BLENDER_MANUAL_URL}/addons/render/povray.html",
    "category": "Render",
    "warning": "Under active development, seeking co-maintainer(s)",
}


Prima di Blender 4.2, le informazioni generali sui componenti aggiuntivi erano definite in un dizionario denominato

bl_info

Ciascuna chiave in questo dizionario forniva a Blender informazioni specifiche sull'add-on, sebbene non tutte fossero ugualmente importanti. La maggior parte delle informazioni sono state utilizzate nella finestra di dialogo delle preferenze dell'utente e hanno aiutato l'utente a trovare e selezionare un componente aggiuntivo.

name

Una sorta di nome in codice per l'add-on, con cui viene indicato nei sorgenti di Blender... (il nome dell'interfaccia utente potrebbe mostrare qualcos'altro)

author

Se contribuisci, ti verrà accreditato qui!

version

Numero di versione del software. Qualsiasi schema di numerazione è valido, purché sia ​​una tupla di tre numeri interi. È preferibile spostare solo l'ultima posizione, ma in seguito potremmo optare per uno schema più strutturato.

blender

La versione minima di Blender richiesta da questo componente aggiuntivo. Un'altra tupla di tre numeri interi. Anche se ti aspetti che le cose funzionino con le versioni più vecchie e quelle più recenti, potrebbe essere una buona idea elencare la versione più vecchia con cui hai effettivamente testato il tuo componente aggiuntivo! È importante sviluppare con qualcosa di abbastanza stabile e poi testare con l'ultima versione appena prima di impegnarsi, ma generalmente non aggiornare il numero di versione compatibile, solo quando qualcosa si rompe a quel punto.

category

La categoria nelle Preferenze utente in cui è raggruppato il nostro componente aggiuntivo. Sfrutta motori compatibili con POV che sono motori di rendering, quindi aveva senso aggiungerlo storicamente alla categoria Render. Sfortunatamente, questo non riflette la natura versatile che ha finito per sviluppare (come la spedizione a un importatore, l'evidenziazione della sintassi dell'editor di testo, ecc...). Se sono possibili più categorie, forse dovremmo aggiungerle.

location

Dove trovare il componente aggiuntivo una volta attivato. Può trattarsi di un riferimento a un pannello specifico o a un caso particolare, una descrizione della sua posizione in un menu.

description

Una descrizione concisa di ciò che fa il componente aggiuntivo.

warning

Se non è una stringa vuota, il componente aggiuntivo verrà visualizzato con un segno di avviso nelle preferenze dell'utente. Puoi usarlo per contrassegnare un componente aggiuntivo come sperimentale, ad esempio.

doc_url

La documentazione pubblica online è un derivato del lavoro svolto qui. Questo sarà un elemento cliccabile nelle preferenze dell'utente.

tracker_url

Dato che il componente aggiuntivo POV è una parte incorporata di Blender, viene fornito con una propria voce di tracciamento dei bug e questa chiave fornirà un puntatore ad esso.

Commenti

I commenti a riga singola iniziano con un carattere cancelletto (#) immediatamente seguito da uno spazio vuoto e il commento inizia con una lettera maiuscola ma non termina con un punto. Possono essere aggiunti dopo una riga di codice sufficientemente breve (lasciare uno spazio vuoto prima del #).


Una delle linee guida per la formattazione del testo/stile di codifica da utilizzare è PEP8 quindi, ad esempio, dovresti fare attenzione a creare righe abbastanza brevi in ​​tutto il testo file di script con meno di 79 caratteri e meno di 72 per le docstring (vedi sotto) o i commenti.

Periodicamente la Blender Foundation esegue controlli per questa conformità pep8 sugli script di Blender. La lunghezza della riga tollerata è arrivata a raggiungere i 100 caratteri.

Se devi davvero superare questo limite, ad esempio per promemoria temporanei di lavori in corso, aggiungi

# nopep8

alla fine della riga pertinente

Altre regole includono:

  • Camel caps per i nomi delle classi: MyClass
  • tutti i nomi dei moduli separati da caratteri di sottolineatura minuscoli: mio_modulo
  • 4 rientri di spazio (nessuna tabulazione)
  • spazi attorno agli operatori matematici: 1 + 1, non 1+1
  • Utilizzare solo importazioni esplicite (non eseguire mai import *)
  • Non utilizzare una sola riga per un test e l'istruzione che dipende da esso: if val : body, invece, separare i blocchi di istruzioni dalle condizioni da cui dipendono di almeno 2 righe.

Mentre i commenti su più righe possono iniziare con virgolette triple. È convenzione che vengano usate tre virgolette doppie per docstrings, un tipo specifico di commento che non fa nulla nel programma ma che appare comunque quando la console viene utilizzata per ottenere aiuto su una funzione.

"""Questa è una spiegazione generale"""

Oltre ad essere una buona pratica inserire una stringa di documento all'inizio di ogni classe per descriverla e anche all'inizio di ogni file per spiegarne l'utilizzo relativo, ciò consente anche alle chiamate da riga di comando di visualizzare questo documento su richiesta. Questa è una delle principali differenze tra i commenti docstrings e inline (solo su parte di una riga).

Funzioni

Le funzioni sono definite con def, seguita dal nome della funzione e da una coppia di parentesi. Quando si fa riferimento alla funzione per spostarla e passarla da un file all'altro, non ha più bisogno delle parentesi, ma quasi ogni altra volta queste seguono il nome della funzione e tra di esse si possono facoltativamente specificare alcuni attributi.

Classi

Le Classi non solo ti consentono di creare definizioni riutilizzabili. Ma questo è l'unico modo per configurare gli elementi dell'interfaccia utente in Blender. La buona notizia è che ciò significa che gli sviluppatori di componenti aggiuntivi hanno effettivamente meno lavoro da fare. L'implementazione hardcoded si occupa di determinare quando e quali parti aggiornare automaticamente per tutti gli elementi dell'interfaccia utente e l'ereditarietà delle classi tra cui scegliere (l'API) garantisce che si possano gestire le situazioni in modo ottimizzato. Alcune funzioni legacy come draw() devono essere sovrascritte dallo sviluppatore del componente aggiuntivo che le riscrive in base alle proprie esigenze.

Per creare nuove classi, utilizzare il consueto schema di definizione delle classi come mostrato nei modelli Python nell'editor di testo interno di Blender... Oppure copiarne e incollarne uno altrove nello script.

Nomenclatura delle classi

Rispettare il più possibile lo stesso modello di denominazione richiesto dalla Blender Foundation: OT significa che è un operatore, MT un menu, PT un pannello: Il nome della classe deve essere composto come segue: NOMEDELLADDON_PT_pannello_principale NOMEDELLADDON - In lettere maiuscole digitiamo il nome del componente aggiuntivo. È possibile utilizzare un carattere di sottolineatura se il nome contiene più di una parola.

_PT_ - viene poi separata da due lettere che designano il tipo di classe (il cui tipo è ereditato).

pannello_principale - utilizzando le lettere minuscole possiamo digitare il nome dell'operatore/pannello/intestazione ecc.

Altri tipi di classi:

   HT – Header
   MT – Menu
   OT – Operator
   PT – Panel
   UL – UI list

Quindi, nel nostro caso il nome del componente aggiuntivo è POV, ecco alcuni esempi di nomi di classi validi e relativi identificatori:

class POV_MATERIAL_PT_replacement_field(bpy.types.Panel):
    bl_idname = 'pov_PT_replacement_field_panel'

	
class POV_OT_add_basic(bpy.types.Operator):
    bl_idname = 'pov.addbasicitem'

	
class POV_VIEW_MT_Basic_Items(bpy.types.Menu):
    bl_idname = 'pov_MT_basic_items_tools'

Notate come l'ID dell'operatore è diverso? Non è necessario aggiungere "OT" ma piuttosto un punto. Inoltre non è necessario aggiungere "_operator" alla fine.


L'API Python di Blender consente l'integrazione di:


   bpy.types.Panel
   bpy.types.Menu
   bpy.types.Operator
   bpy.types.PropertyGroup
   bpy.types.KeyingSet
   bpy.types.RenderEngine

Questo è intenzionalmente limitato. Attualmente, per funzionalità più avanzate come i modificatori di mesh, i tipi di oggetto o i nodi shader, dovrebbe essere utilizzato C/C++.

Per l'integrazione con Python, Blender definisce metodi comuni a tutti i tipi. Funziona creando una sottoclasse Python di una classe Blender che contiene variabili e funzioni specificate dalla classe genitore che sono predefinite per interfacciarsi con Blender.

Nota che stiamo creando una sottoclasse di un membro di bpy.types, questo è comune a tutte le classi che possono essere integrate in Blender e utilizzate, quindi sappiamo se si tratta di un operatore e non di un pannello quando entri nel registro.


Entrambe le proprietà della classe iniziano con il prefisso bl_. Questa è una convenzione usata per distinguere le proprietà di Blender da quelle che aggiungi tu stesso.

Operatori

La maggior parte dei componenti aggiuntivi definisce nuovi operatori, si tratta di classi che implementano funzionalità specifiche. La definizione effettiva dell'operatore prende la forma di una classe derivata da bpy.types.Operator

import bpy
class MyTool(bpy.types.Operator):
    """Fai cose su un oggetto"""    
    bl_idname = "object.fai_cose_su_oggetto"
    bl_label = "Fai cose su un oggetto"
    bl_options = {'REGISTER', 'UNDO'}

La docstring all'inizio della definizione della classe verrà utilizzata come tooltip ovunque questo operatore sia disponibile, ad esempio in un menu, mentre bl_label definisce l'etichetta effettiva utilizzata nella voce di menu stessa. Qui li abbiamo mantenuti entrambi uguali. Gli operatori faranno parte dei dati di Blender e saranno memorizzati nel modulo bpy.ops. Questo bl_idname garantirà che l'input per questo operatore verrà chiamato bpy.ops.object.move_object. Gli operatori vengono normalmente registrati in modo da renderli utilizzabili e questa è infatti l'impostazione predefinita di bl_options. Tuttavia, se vogliamo che il componente aggiuntivo appaia anche nella cronologia in modo che possa essere annullato o ripetuto, dobbiamo aggiungere UNDO all'insieme di flag assegnati a bl_options, come qui.


Gli operatori hanno limitazioni che possono rendere noiosa la loro scrittura.

I limiti principali sono...

Non è possibile trasferire dati come oggetti, mesh o materiali su cui operare (gli operatori utilizzano invece il contesto)

Il valore restituito dalla chiamata di un operatore è successo (indipendentemente dal fatto che sia stato completato o annullato), in alcuni casi avrebbe più senso per l'API restituire il risultato dell'operazione.

La funzione poll() per richiestare gli operatori potrebbe non riuscire quando una funzione API lancia un'eccezione fornendo i dettagli del motivo esatto.

La funzione execute()

Una classe operatore può avere un numero qualsiasi di funzioni membro ma per essere utile normalmente sovrascrive la funzione execute() :

def execute(self, context):
    context.active_object.rotation.z += 33
    return {'FINISHED'}

La funzione execute() viene passata un riferimento a a a contesto oggetto. Questo oggetto di contesto contiene tra l'altro un attributo active_object che punta a l'oggetto attivo di Blender. Ogni oggetto in Blender ha un attributo di rotazione che è un vettore con componenti x, y e z. Cambiare la rotazione di un oggetto è semplice come cambiare uno di questi componenti, che è esattamente ciò che facciamo nella riga 2.

La funzione execute() segnala l'esecuzione riuscita restituendo un set di flag, in questo caso un set costituito solo dalla stringa di caratteri "FINISHED".

Creazione e aggiunta di un menu al registro

Quando abilitiamo la casella di controllo Enable add-on nelle preferenze, Blender cercherà una funzione register() e la eseguirà. Allo stesso modo, quando si disattiva un componente aggiuntivo, viene richiamata la funzioneunregister(). Usiamoli quindi sia per registrare il nostro operatore con Blender sia per inserire una voce di menu che faccia riferimento al nostro operatore. è inoltre importante annullare l'iscrizione e disattivarla affinché il nostro componente aggiuntivo non venga percepito come invasivo o distruttivo di una configurazione precedente senza possibile ritorno.

Per creare un menu dobbiamo fare due cose:

  • Crea una funzione che produrrà una voce di menu
  • E aggiungi questa funzione al menu appropriato.

Al giorno d'oggi quasi tutto in Blender è disponibile come oggetto Python e i menu non fanno eccezione. Vogliamo aggiungere la nostra voce al menu Oggetto nella vista 3D, quindi chiamiamo

bpy.types.VIEW3D_MT_object.append()

e passargli un riferimento alla funzione che definiamo poco più sotto. Come facciamo a sapere il nome di questo oggetto di menu? Se hai attivato File⇒ User preferences ⇒ Interface ⇒ Python Tooltips Il nome del menu verrà visualizzato in una descrizione comando quando passi il mouse su un menu. Dall'immagine sopra possiamo vedere che possiamo usare bpy.types.VIEW3D_MT_object.append() per aggiungere qualcosa al menu Oggetto perché VIEW3D_MT_object viene visualizzato nel testo della bolla che appare quando si passa con il mouse su questo menu.

BlightBulb.png
La funzione menu_func() non implementa un'azione stessa (questo è il ruolo di un operatore)
Ma quando viene chiamato, menu_func() aggiungerà un elemento UI che punta all'oggetto passatogli nel parametro self. Questo elemento dell'interfaccia potrà essere modificato dall'utente e, a sua volta, interagirà con l'operatore.


Qui aggiungeremo semplicemente un input dell'operatore (ovvero un elemento che eseguirà il nostro operatore quando viene cliccato).

L'argomento self passato a menu_func() si riferisce al menu.

Questo menu ha un attributo layout con una funzione operator() alla quale passiamo il nome del nostro operatore. Ciò garantirà che ogni volta che un utente passa con il mouse sul menu Oggetto, il nostro operatore verrà visualizzato nell'elenco delle opzioni.

l nome del nostro nuovo operatore MyTool è nel suo attributo bl_idname, motivo per cui passiamo MyTool.bl_idname.

Il nome della voce e il suo tooltip sono determinati guardando bl_label e docstring definiti nella nostra classe MyTool e l'icona utilizzata nel menu è determinata passando un comando facoltativo parametro icon alla funzione operator().

Definire un menu non è di per sé sufficiente a renderlo utilizzabile. Affinché l'utente possa trovarlo e utilizzarlo, dobbiamo aggiungere il menu al suo genitore dalla funzione register() alla fine del suo file python.

def menu_func(self, context):
    self.layout.operator(MyTool.bl_idname, icon='MESH_CUBE')
def register():    
    bpy.types.VIEW3D_MT_object.append(menu_func)
def unregister():
    bpy.types.VIEW3D_MT_object.remove(menu_func)

Gli operatori devono essere registrati allo stesso modo, quindi aggiungere un operatore registrato a un menu richiede da due a tre azioni separate:

  • Registrati operatore;
  • quindi aggiungilo a un menu esistente;
  • Oppure salvare prima il menu appena creato a cui dovrebbe appartenere e solo dopo aggiungervi l'operatore.

Solo dopo tutto ciò il nuovo operatore apparirà sull'interfaccia utente, almeno, se non altro, premendo F3 nella finestra di visualizzazione 3D e digitando l'etichetta dell'operatore

Tutto questo potrebbe sembrare un po' più complicato del necessario ma permette ad esempio di visualizzare molte altre cose oltre alle semplici voci cliccabili in un menu, ad esempio di raggruppare più operatori nella stessa casella, ad esempio se fanno parte di modalità disponibili in lo stesso sottotema, ecc.

BlightBulb.png
I comandi di unregister() devono apparire in ordine inverso rispetto alle righe register() corrispondenti
Ciò garantisce che tu non provi ad annullare la registrazione, ad esempio, di un menu che è stato aggiunto come figlio di una classe di elementi dell'interfaccia utente che potresti provare a annullare la registrazione prima di quel figlio, annullando così la registrazione di qualcosa che già non è più presente... Il che genererebbe un errore e la mancata attivazione/disattivazione del componente aggiuntivo.


Ottimizzazione

Mantieni la notazione "puntata" minima

Come in molti linguaggi orientati agli oggetti, Python consente la visualizzazione di una struttura gerarchica con i suoi livelli separati da punti (pensa a ciascun punto come l'apertura della bambola russa più grande a sinistra che porta quelli più piccoli alla sua destra).

BlightBulb.png
Sostituisci le sue ricerche inutilmente ripetute con alias
L'operatore punto è un modo semplice per acquisire classe, dati, metodo, qualunque oggetto python incluso in una gerarchia più ampia ... Ma tieni presente che è costoso, specialmente se usato in un ciclo.

Quando si chiama

bpy.data.objects["my_obj"]

Ogni punto si tuffa di un livello più in profondità e l'intera gerarchia viene raggiunta. Devi sempre farlo almeno una volta per raggiungere l'elemento desiderato, quindi va bene usare quella sintassi quando il riferimento viene fatto solo una volta, ma soprattutto, preferisci sempre evitare l'intera ricerca e piuttosto dargli un alias come

obj = bpy.data.objects["my_obj"]

Quindi puoi ancora usarlo, gestendo attributi occasionali come l'esempio seguente:

obj.location.z += 1

e tutti gli altri attributi disponibili, per le operazioni di lettura o scrittura. Definire molti di questi alias necessari prima di entrare in un ciclo piuttosto che all'interno di esso. Immagina se il tuo GPS ti dicesse sempre le indicazioni precedenti prese dal punto di partenza fino a quella successiva ad ogni turno!

Usare try/except con parsimonia

L'istruzione try è utile per risparmiare tempo per scrivere il codice di controllo degli errori.

Tuttavia, try è significativamente più lento di un if perchè un'eccezione deve essere impostata ogni volta, quindi evita di utilizzare try nelle aree del codice che vengono eseguite in un ciclo e vengono eseguite molte volte.

Ci sono casi in cui l'uso di try è più veloce che rilevare esplicitamente tramite un test (if o altro) la condizione complessa che potrebbe potenzialmente generare un errore, quindi vale la pena sperimentare.


Un buon modo per rimuovere alcuni dei tuoi try ... except quando l'errore trovato risulta essere un AttributeError è sostituirli con un pre-test con la funzione ' 'hasattr():

for member in dir(properties_freestyle):
    subclass = getattr(properties_freestyle, member)
    try:
        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
    except:
        pass

potrebbe diventare

for member in dir(properties_freestyle):
   subclass = getattr(properties_freestyle, member)
   if hasattr(subclass, "COMPAT_ENGINES"):
       subclass.COMPAT_ENGINES.add('POVRAY_RENDER')

Se devi usare try:... except:... non lascia il tipo di eccezione non specificato, questo non fornisce assolutamente alcun feedback o leggibilità del codice. Se invece non hai idea di cosa potrebbe essere, sostituiscilo con qualcosa che dia maggiori informazioni durante la fase di debug:

(BaseException è al top della gerarchia delle eccezioni)

def your_function(b, c):
    try:
        a = b + c
        return True
    except BaseException as e:
        print(e.__doc__)
        print('An exception occurred: {}'.format(e))
        return False

Separare i file python (*.py)

Lo script è stato successivamente suddiviso in unpackage (diversi file in una cartella) utilizzando il minor numero di file possibile per rendere il flusso di dati più semplice da comprendere. Inizialmente c'erano 3 file principali:

  • __init__.py
  • ui.py
  • render.py

Tuttavia, alcuni file superavano le 10.000 righe, che per un componente aggiuntivo di questo tipo erano ancora troppo grandi. Attualmente è quindi tollerato che il file più grande rimanga al di sotto delle 2000 righe. È molto probabile che i file possano perdere peso, rimuovendo l'obsoleto supporto a 32 bit e modularizzando parte del codice in alcune funzioni più riutilizzabili. Ecco i file attuali che compongono il componente aggiuntivo e i rispettivi usi:

inizializzazione

__init__.py

Crea le preferenze utente del componente aggiuntivo POV, ordina all'utente di aggiornare il componente aggiuntivo all'ultima versione e carica tutti gli altri moduli. (Nota il doppio sottolinea il nome del file. Questo lo rende il primo file lanciato) la definizione dell'unità "principale" per un pacchetto; fa anche in modo che Python tratti la directory specifica come un pacchetto. È l'unità che verrà utilizzata quando si chiama import render_povray (e render_povray è una directory).

scenography_properties.py

Inizializzazione delle proprietà per tradurre le impostazioni della fotocamera/luce/ambiente di Blender nel linguaggio POV.

object_properties.py

Inizializzazione delle proprietà per tradurre le impostazioni dell'oggetto Blender nel linguaggio POV.

shading_properties.py

Inizializzazione delle proprietà per tradurre le impostazioni dei materiali di Blender nel linguaggio POV.

texturing_properties.py

Inizializzazione delle proprietà per tradurre i parametri di influenza delle texture dei materiali, dell'ambiente (mondo), ecc. da Blender al linguaggio POV.

render_properties.py

Inizializzazione delle proprietà per tradurre i parametri di rendering (da Blender ma soprattutto quelli più specificatamente nativi di POV).

scripting_properties.py

Inizializzazione di proprietà e campi per popolare le istruzioni direttamente nel linguaggio di descrizione della scena POV.

Interfaccia

Alcune note da tenere a mente durante la creazione di elementi dell'interfaccia utente:

I controlli che Blender fornisce per l'interfaccia utente sono relativamente semplici. Le dichiarazioni di interfaccia servono per creare facilmente un layout accettabile. Regola generale qui: se hai bisogno di più codice per il layout dell'interfaccia rispetto alle proprietà stesse, allora stai sbagliando.

Esempi di interfaccia:

   layout()

Il layout di base è un semplice layout Alto -> Basso.

   layout.prop()
   layout.prop()
   layout.row()

Usa row(), quando vuoi più di 1 proprietà in una riga.

   row = layout.row()
   row.prop()
   row.prop()
   layout.column()

Usa column(), quando vuoi che le tue proprietà siano in una colonna.

   col = layout.column()
   col.prop()
   col.prop()
   layout.split()

Questo può essere utilizzato per creare layout più complessi. Ad esempio puoi dividere il layout e creare due layout column() uno accanto all'altro. Non utilizzare la suddivisione quando desideri semplicemente due proprietà di seguito. Usa row() per quello.


   split = layout.split()
   col = split.column()
   col.prop()
   col.prop()
   col = split.column()
   col.prop()
   col.prop()

Nomi delle dichiarazioni:

Prova a utilizzare solo questi nomi di variabili per le dichiarazioni di layout:

row per un layout row()

col per un layout column()

split per un layout split()

flow per un layout column_flow()

sub per un layout sub() (una colonna all'interno di una colonna per esempio)

base_ui.py

Fornisce un workspace simile a Moray e definisce alcune funzioni di utilità. Carica tutti gli altri moduli relativi alla GUI

scenography_gui.py)

Visualizza le proprietà camera/luce/ambiente da scenography_properties.py affinché l'utente possa modificarle

object_gui.py :

Display properties from object_properties.py for user to change them


shading_gui.py

Display properties from shading_properties.py for user to change them


shading_nodes.py

Translate node trees to the pov file


texturing_gui.py

Display properties from texturing_properties.py for user to change them


render_gui.py

Display properties from render_properties.py for user to change them


scripting_gui.py

Display properties from scripting_properties.py for user to add his custom POV code

Render / import / edit

render.py

Translate geometry and UI properties (Blender and POV native) to the POV file


scenography.py

Translate cam/light/environment properties to corresponding pov features


primitives.py

Display some POV native primitives in 3D view for input and output


object_mesh_topology.py

Translate to POV the meshes geometries


object_curve_topology.py

Translate to POV the curve based geometries


object_particles.py

Translate to POV the particle based geometries


shading.py

Translate shading properties to declared textures at the top of a pov file


texturing.py

Translate blender texture influences into POV


df3_library.py

Render smoke to *.df3 files


scripting.py

Insert POV native scene description elements to exported POV file


update_files.py

Update new variables to values from older API. This file needs an update

Presets

Along these essential files also coexist a few additional libraries to help make Blender stand up to other Persistence of Vision compatible frontends such as povwin or QTPOV

Material (sss)

apple.py

chicken.py

cream.py

Ketchup.py

marble.py

potato.py

skim_milk.py

skin1.py

skin2.py

whole_milk.py

Radiosity

01_Debug.py

02_Fast.py

03_Normal.py

04_Two_Bounces.py

05_Final.py

06_Outdoor_Low_Quality.py

07_Outdoor_High_Quality.py

08_Outdoor(Sun)Light.py

09_Indoor_Low_Quality.py

10_Indoor_High_Quality.py

World

01_Clear_Blue_Sky.py

02_Partly_Hazy_Sky.py

03_Overcast_Sky.py

04_Cartoony_Sky.py

05_Under_Water.py

Light

01_(4800K)_Direct_Sun.py

02_(5400K)_High_Noon_Sun.py

03_(6000K)_Daylight_Window.py

04_(6000K)_2500W_HMI_(Halogen_Metal_Iodide).py

05_(4000K)_100W_Metal_Halide.py

06_(3200K)_100W_Quartz_Halogen.py

07_(2850K)_100w_Tungsten.py

08_(2600K)_40w_Tungsten.py

09_(5000K)_75W_Full_Spectrum_Fluorescent_T12.py

10_(4300K)_40W_Vintage_Fluorescent_T12.py

11_(5000K)_18W_Standard_Fluorescent_T8.py

12_(4200K)_18W_Cool_White_Fluorescent_T8.py

13_(3000K)_18W_Warm_Fluorescent_T8.py

14_(6500K)_54W_Grow_Light_Fluorescent_T5-HO.py

15_(3200K)_40W_Induction_Fluorescent.py

16_(2100K)_150W_High_Pressure_Sodium.py

17_(1700K)_135W_Low_Pressure_Sodium.py

18_(6800K)_175W_Mercury_Vapor.py

19_(5200K)_700W_Carbon_Arc.py

20_(6500K)_15W_LED_Spot.py

21_(2700K)_7W_OLED_Panel.py

22_(30000K)_40W_Black_Light_Fluorescent.py

23_(30000K)_40W_Black_Light_Bulb.py

24_(1850K)_Candle.py

templates

abyss.pov

biscuit.pov

bsp_Tango.pov

chess2.pov

cornell.pov

diffract.pov

diffuse_back.pov

float5

gamma_showcase.pov

grenadine.pov

isocacti.pov

mediasky.pov

patio-radio.pov

subsurface.pov

wallstucco.pov

C++

Some areas could only be added POV specific functionality using C++ :

blender/editors/space_text/text_format_pov.c

blender/editors/space_text/text_format_ini.c

Mspace_text.c

Mtext_format.h

Mtext_format_ini.c

Mtext_format_pov.c

and the MCMakelists.txt had to be modified to include added files.


But in Blender, all of the user interface is written in Python, that's why the file scripts/startup/bl_ui/space_text.py also has been updated even though it lies outside the usual addons folder:

# ##### BEGIN GPL LICENSE BLOCK #####
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software Foundation,
#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####

# <pep8-80 compliant>
import bpy
from bpy.types import Header, Menu, Panel
from bpy.app.translations import pgettext_iface as iface_


class TEXT_HT_header(Header):
    bl_space_type = 'TEXT_EDITOR'

    def draw(self, context):
        layout = self.layout

        st = context.space_data
        text = st.text

        row = layout.row(align=True)
        row.template_header()

        TEXT_MT_editor_menus.draw_collapsible(context, layout)

        if text and text.is_modified:
            sub = row.row(align=True)
            sub.alert = True
            sub.operator("text.resolve_conflict", text="", icon='HELP')

        row = layout.row(align=True)
        row.template_ID(st, "text", new="text.new", unlink="text.unlink", open="text.open")

        row = layout.row(align=True)
        row.prop(st, "show_line_numbers", text="")
        row.prop(st, "show_word_wrap", text="")
        row.prop(st, "show_syntax_highlight", text="")

        if text:
            osl = text.name.endswith(".osl") or text.name.endswith(".oso")

            if osl:
                row = layout.row()
                row.operator("node.shader_script_update")
            else:
                row = layout.row()
                row.operator("text.run_script")

                row = layout.row()
                row.active = text.name.endswith(".py")
                row.prop(text, "use_module")

            row = layout.row()
            if text.filepath:
                if text.is_dirty:
                    row.label(text=iface_("File: *%r (unsaved)") %
                              text.filepath, translate=False)
                else:
                    row.label(text=iface_("File: %r") %
                              text.filepath, translate=False)
            else:
                row.label(text="Text: External"
                          if text.library
                          else "Text: Internal")


class TEXT_MT_editor_menus(Menu):
    bl_idname = "TEXT_MT_editor_menus"
    bl_label = ""

    def draw(self, context):
        self.draw_menus(self.layout, context)

    @staticmethod
    def draw_menus(layout, context):
        st = context.space_data
        text = st.text

        layout.menu("TEXT_MT_view")
        layout.menu("TEXT_MT_text")

        if text:
            layout.menu("TEXT_MT_edit")
            layout.menu("TEXT_MT_format")

        layout.menu("TEXT_MT_templates")


class TEXT_PT_properties(Panel):
    bl_space_type = 'TEXT_EDITOR'
    bl_region_type = 'UI'
    bl_label = "Properties"

    def draw(self, context):
        layout = self.layout

        st = context.space_data

        flow = layout.column_flow()
        flow.prop(st, "show_line_numbers")
        flow.prop(st, "show_word_wrap")
        flow.prop(st, "show_syntax_highlight")
        flow.prop(st, "show_line_highlight")
        flow.prop(st, "use_live_edit")

        flow = layout.column_flow()
        flow.prop(st, "font_size")
        flow.prop(st, "tab_width")

        text = st.text
        if text:
            flow.prop(text, "use_tabs_as_spaces")

        flow.prop(st, "show_margin")
        col = flow.column()
        col.active = st.show_margin
        col.prop(st, "margin_column")


class TEXT_PT_find(Panel):
    bl_space_type = 'TEXT_EDITOR'
    bl_region_type = 'UI'
    bl_label = "Find"

    def draw(self, context):
        layout = self.layout

        st = context.space_data

        # find
        col = layout.column(align=True)
        row = col.row(align=True)
        row.prop(st, "find_text", text="")
        row.operator("text.find_set_selected", text="", icon='TEXT')
        col.operator("text.find")

        # replace
        col = layout.column(align=True)
        row = col.row(align=True)
        row.prop(st, "replace_text", text="")
        row.operator("text.replace_set_selected", text="", icon='TEXT')
        col.operator("text.replace")

        # settings
        layout.prop(st, "use_match_case")
        row = layout.row(align=True)
        row.prop(st, "use_find_wrap", text="Wrap")
        row.prop(st, "use_find_all", text="All")


class TEXT_MT_view(Menu):
    bl_label = "View"

    def draw(self, context):
        layout = self.layout

        layout.operator("text.properties", icon='MENU_PANEL')

        layout.separator()

        layout.operator("text.move",
                        text="Top of File",
                        ).type = 'FILE_TOP'
        layout.operator("text.move",
                        text="Bottom of File",
                        ).type = 'FILE_BOTTOM'

        layout.separator()

        layout.operator("screen.area_dupli")
        layout.operator("screen.screen_full_area")
        layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True


class TEXT_MT_text(Menu):
    bl_label = "Text"

    def draw(self, context):
        layout = self.layout

        st = context.space_data
        text = st.text

        layout.operator("text.new")
        layout.operator("text.open")

        if text:
            layout.operator("text.reload")

            layout.column()
            layout.operator("text.save")
            layout.operator("text.save_as")

            if text.filepath:
                layout.operator("text.make_internal")

            layout.column()
            layout.operator("text.run_script")


class TEXT_MT_templates_py(Menu):
    bl_label = "Python"

    def draw(self, context):
        self.path_menu(
            bpy.utils.script_paths("templates_py"),
            "text.open",
            props_default={"internal": True},
        )


class TEXT_MT_templates_osl(Menu):
    bl_label = "Open Shading Language"

    def draw(self, context):
        self.path_menu(
            bpy.utils.script_paths("templates_osl"),
            "text.open",
            props_default={"internal": True},
        )

class TEXT_MT_templates_pov(Menu):
    bl_label = "POV-Ray Scene Description Language"

    def draw(self, context):
        self.path_menu(
            bpy.utils.script_paths("templates_pov"),
            "text.open",
            props_default={"internal": True},
        )

class TEXT_MT_templates(Menu):
    bl_label = "Templates"

    def draw(self, context):
        layout = self.layout
        layout.menu("TEXT_MT_templates_py")
        layout.menu("TEXT_MT_templates_osl")
        layout.menu("TEXT_MT_templates_pov")


class TEXT_MT_edit_select(Menu):
    bl_label = "Select"

    def draw(self, context):
        layout = self.layout

        layout.operator("text.select_all")
        layout.operator("text.select_line")


class TEXT_MT_format(Menu):
    bl_label = "Format"

    def draw(self, context):
        layout = self.layout

        layout.operator("text.indent")
        layout.operator("text.unindent")

        layout.separator()

        layout.operator("text.comment")
        layout.operator("text.uncomment")

        layout.separator()

        layout.operator_menu_enum("text.convert_whitespace", "type")


class TEXT_MT_edit_to3d(Menu):
    bl_label = "Text To 3D Object"

    def draw(self, context):
        layout = self.layout

        layout.operator("text.to_3d_object",
                        text="One Object",
                        ).split_lines = False
        layout.operator("text.to_3d_object",
                        text="One Object Per Line",
                        ).split_lines = True


class TEXT_MT_edit(Menu):
    bl_label = "Edit"

    @classmethod
    def poll(cls, context):
        return (context.space_data.text)

    def draw(self, context):
        layout = self.layout

        layout.operator("ed.undo")
        layout.operator("ed.redo")

        layout.separator()

        layout.operator("text.cut")
        layout.operator("text.copy")
        layout.operator("text.paste")
        layout.operator("text.duplicate_line")

        layout.separator()

        layout.operator("text.move_lines",
                        text="Move line(s) up").direction = 'UP'
        layout.operator("text.move_lines",
                        text="Move line(s) down").direction = 'DOWN'

        layout.separator()

        layout.menu("TEXT_MT_edit_select")

        layout.separator()

        layout.operator("text.jump")
        layout.operator("text.start_find", text="Find...")
        layout.operator("text.autocomplete")

        layout.separator()

        layout.menu("TEXT_MT_edit_to3d")


class TEXT_MT_toolbox(Menu):
    bl_label = ""

    def draw(self, context):
        layout = self.layout

        layout.operator_context = 'INVOKE_DEFAULT'

        layout.operator("text.cut")
        layout.operator("text.copy")
        layout.operator("text.paste")

        layout.separator()

        layout.operator("text.run_script")


classes = (
    TEXT_HT_header,
    TEXT_MT_edit,
    TEXT_MT_editor_menus,
    TEXT_PT_properties,
    TEXT_PT_find,
    TEXT_MT_view,
    TEXT_MT_text,
    TEXT_MT_templates,
    TEXT_MT_templates_py,
    TEXT_MT_templates_osl,
    TEXT_MT_templates_pov,
    TEXT_MT_edit_select,
    TEXT_MT_format,
    TEXT_MT_edit_to3d,
    TEXT_MT_toolbox,
)

if __name__ == "__main__":  # only for live edit.
    from bpy.utils import register_class
    for cls in classes:
        register_class(cls)

Notice that the special command line

   # <pep8-80 compliant>

writes pep-80 rather than pep-8 as getting closer to the native blender program often requires more demanding standards : pep-80 asks for even shorter line lengths and so a file passing the pep-80 automated tests that the Blender Foundation regularly runs might fail passing PEP-80.