[PYTHON] Obtenez et créez des nœuds ajoutés et mis à jour dans la nouvelle version

introduction

Cet article est l'article du 10ème jour du ** Houdini Advent Calender 2019 **.

** Houdini 18.0 ** est sorti à la fin du mois dernier!

Beaucoup de gens l'utilisent déjà, mais le nœud introduit dans ** New Feature Movie ** En outre, il semble que des mises à jour mineures aient été apportées.

Donc, dans cet article, je vais vous montrer comment obtenir et créer des nœuds ajoutés et mis à jour dans Houdini 18.0.

Définition des nœuds ajoutés et mis à jour

Considérez la définition des ajouts et des mises à jour pour le découvrir. Les deux suivants sont définis.

Sur la base de cette condition, je voudrais créer tous les nœuds ajoutés et mis à jour en Python comme un éditeur de réseau. À propos, les versions à comparer sont ** 17.5.391 ** et ** 18.0.287 **.

Résultat de l'exécution du script

Tout d'abord, voyez le résultat de l'exécution du script. Get New Nodes

Lorsque vous exécutez le script, une fenêtre apparaît dans laquelle vous pouvez sélectionner la version à comparer, et lorsque vous la sélectionnez, le processus de comparaison de nœuds s'exécute. Lorsque le traitement est terminé, ** NewNodes ** sera créé pour le nœud avec le nœud ajouté lui-même, et ** Subnet ** sera créé pour le nœud avec le paramètre ajouté ** NewParmNodes **, et les catégories telles que ** Sop ** seront créées. Il y a un nœud pour chacun.

** Nœud Sop ajouté dans 18.0 ** New Sop

En passant, le paramètre ajouté contient une expression appelée ** constant () **, donc si vous sélectionnez ** Paramètres avec des valeurs non par défaut ** dans le filtre de paramètres, seul le paramètre ajouté peut être affiché. Je vais. Parameter Filter

Le script peut être téléchargé et utilisé à partir du référentiel ** GitHub ** ci-dessous.

Liste des nœuds ajoutés et mis à jour

Au début, j'ai pensé à lister tous les nœuds ajoutés et mis à jour, mais il y en avait trop, j'ai donc résumé le nombre de nœuds ajoutés et mis à jour par catégorie.

Nombre de nœuds qui n'existent que dans Houdini 18.0

Category Node Count
Shop 1
Chop 2
Top 12
Object 3
Driver 6
Cop2 1
Sop 62
Lop 51
Dop 12
TopNet 2

Un total de ** 152 ** nœuds ont été ajoutés et mis à jour.

Non seulement le ** LOP ** nouvellement ajouté, mais aussi ** SOP ** à lui seul a ajouté et mis à jour ** 62 ** nœuds.

Regardons maintenant le nombre de nœuds avec des paramètres ajoutés.

Nœuds avec paramètres ajoutés et nombre de paramètres ajoutés

Category Node Count Parameter Count
Top 44 175
Object 1 3
Driver 1 3
Chop 1 4
Sop 43 226
Lop 24 241
Vop 10 41
Dop 63 361

Ici, des paramètres ont été ajoutés à ** 187 ** nœuds au total, et ** 1054 ** paramètres ont été ajoutés en termes de nombre de paramètres.

En regardant cela, ** Lop ** était à partir de ** Houdini 17,5 **. Et il semble que non seulement ** LOP ** et ** Sop ** mais aussi ** Top ** et ** Dop ** ont été considérablement mis à jour.

Je n'ai plus envie de courir après.

Données CSV

Pour ceux qui souhaitent voir la liste des noms de nœuds et des noms de paramètres, nous avons téléchargé le fichier CSV ci-dessous.

Nœuds qui n'existent que dans Houdini 18.0

Nœud avec des paramètres ajoutés

Comment obtenir des nœuds ajoutés et mis à jour

Ce qui suit est une explication de Python. Il est difficile de tout écrire, donc je n'expliquerai que les points clés.

Obtenez la version de Houdini que vous avez installée

Tout d'abord, je veux spécifier la version que je veux comparer, donc j'obtiens toutes les versions de Houdini que j'ai installées.

import os
hfs = os.getenv('HFS')
#C:/PROGRA~1/SIDEEF~1/HOUDIN~1.287
root = os.path.dirname(hfs)
versions = os.listdir(root)
#['Houdini 16.5.268', 'Houdini 17.0.376', 'Houdini 17.5.258', 'Houdini 17.5.360','Houdini 17.5.391', 'Houdini 18.0.287']
import hou
current_version = hou.applicationVersionString()
versions.remove('Houdini ' + current_version)
sel_version = hou.ui.selectFromList(
    versions, exclusive=True, title='Select Compare Version',
    column_header='Versions', width=240, height=240
)
if not sel_version:
    return
version = versions[sel_version[0]]
version_path = '{}/{}'.format(root, version)
#C:/PROGRA~1/SIDEEF~1/Houdini 17.5.391

Obtenir tous les types de nœuds

Vous devez obtenir tous les types de nœuds à des fins de comparaison.

Pour obtenir tous les types de nœuds, utilisez ** hou.nodeTypeCategories () ** pour saisir chaque catégorie. Un dictionnaire avec l'objet ** hou.NodeTypeCategory ** dans le nom et la valeur sera renvoyé. Node Categories Et l'objet ** hou.NodeTypeCategory ** [** nodeTypes ](https: // www) En exécutant la fonction .sidefx.com / ja / docs / houdini / hom / hou / NodeTypeCategory.html # nodeTypes), la clé est le nom du type de nœud et la valeur est [ hou.NodeType **](https: // www.sidefx.com/en/docs/houdini/hom/hou/NodeType.html) Un dictionnaire avec des objets sera renvoyé.

Par exemple, pour obtenir tous les noms de type de nœud de SOP, exécutez le code suivant.

import hou
categories = hou.nodeTypeCategories()
sop_category = categories['Sop']
sop_data = sop_category.nodeTypes()
sop_nodes = sop_data.keys()

Obtenir tous les paramètres

Pour obtenir tous les paramètres ** hou.NodeType ** Object ** parmTemplates () ** En exécutant la fonction, essentiellement tous les paramètres ** hou.parmTemplate ** Vous pouvez obtenir l'objet. Cependant, comme les paramètres contenus dans ** Multiparm Block ** ne sont pas inclus, les éléments tels que ** Group Promouvoir ** dont les paramètres sont contenus dans ** Multiparm Block ** ne peuvent pas être obtenus.

Multi Parm

Pour obtenir les paramètres inclus dans ** Multiparm Block **, vous pouvez les obtenir en utilisant la fonction récursive comme indiqué ci-dessous.

def get_all_parm_templates(all_parms, node_type):
    parms = node_type.parmTemplates()
    for parm in parms:
        if parm.type() == hou.parmTemplateType.Folder:
            get_all_parm_templates(all_parms, parm)
        elif parm.type() != hou.parmTemplateType.FolderSet:
            all_parms.append(parm)
    return all_parms

Obtenir tous les types et paramètres de nœuds

Sur la base de ce qui précède, obtenez tous les types et paramètres de nœuds.

# -*- coding: utf-8 -*-
import hou

def get_all_parm_templates(all_parms, node_type):
    parms = node_type.parmTemplates()
    for parm in parms:
        if parm.type() == hou.parmTemplateType.Folder:
            get_all_parm_templates(all_parms, parm)
        elif parm.type() != hou.parmTemplateType.FolderSet:
            all_parms.append(parm)
    return all_parms

def main():
    node_data = {}
    categories = hou.nodeTypeCategories()
    for category_name, category in categories.items():
        category_data = []
        nodes = category.nodeTypes()
        for node_name, node_type in nodes.items():
            node_info = {}
            node_info['node_name'] = node_name
            node_info['node_label'] = node_type.description()
            all_parms = get_all_parm_templates([], node_type)
            node_info['parms'] = [parm.name() for parm in all_parms]
            category_data.append(node_info)
        node_data[category_name] = category_data

    return node_data

Lorsque le code ci-dessus est exécuté, un dictionnaire avec des noms de nœuds, des étiquettes de nœuds et des noms de paramètres sera renvoyé pour chaque catégorie comme indiqué ci-dessous (seule la partie PolySplitSop est affichée).

"Sop": [
    {
        "node_label": "PolySplit", 
        "parms": [
            "splitloc", 
            "pathtype", 
            "override", 
            "newt", 
            "updatenorms", 
            "close", 
            "tolerance"
        ], 
        "node_name": "polysplit"
    }, 

Cependant, même si vous exécutez cela, vous ne pouvez obtenir que les informations de nœud de la version en cours d'exécution, mais pas les informations de nœud de la version spécifiée.

Obtenir des informations de nœud pour la version spécifiée

Utilisez ** Hython ** pour obtenir les informations de nœud pour la version spécifiée. ** Hython ** est un ** shell Python ** situé dans ** $ HFS / bin **, qui existe pour chaque version. Puisque le module ** hou ** est automatiquement chargé au démarrage, vous pouvez exécuter le propre traitement de Houdini sans démarrer ** Houdini. ** **

Pour exécuter le script sur la version spécifiée de ** Hython **, enregistrez le code ci-dessus dans un fichier **. Py ** et utilisez ** sous-processus ** pour le spécifier dans l'argument ** Hython **. Je vais.

import subprocess
from subprocess import PIPE

hython = 'Chemin vers Hython'
script = 'Chemin du script à exécuter'
p = subprocess.Popen([hython, script], shell=True, stdout=PIPE, stderr=PIPE)
#Obtenez la valeur de retour du script
stdout, stderr = p.communicate()
#La valeur renvoyée est une chaîne, alors convertissez-la en dictionnaire avec eval
node_data = eval(stdout)

Cependant, lorsque j'ai fait cela, rien n'a été renvoyé à ** stdout **, et la chaîne suivante a été renvoyée à ** stderr **.

'EnvControl: HOUDINI_USER_PREF_DIR missing __HVER__, ignored.\r\nTraceback (most rec
ent call last):\n  File "<string>", line 8, in <module>\n  File "C:/PROGRA~1/SIDEEF~
1/HOUDIN~1.287/houdini/python2.7libs\\hou.py", line 19, in <module>\n    import _hou
\nImportError: DLL load failed: \x8ew\x92\xe8\x82\xb3\x82\xea\x82\xbd\x83v\x83\x8d\x
83V\x81[\x83W\x83\x83\x82\xaa\x8c\xa9\x82\xc2\x82\xa9\x82\xe8\x82\xdc\x82\xb9\x82\xf
1\x81B\nTraceback (most recent call last):\r\n  File "D:\\create_update_node\\get_node_data.py", lin
e 2, in <module>\r\n    import hou\r\n  File "C:/PROGRA~1/SIDEEF~1/HOUDIN~1.287/houd
ini/python2.7libs\\hou.py", line 19, in <module>\r\n    import _hou\r\nImportError: 
DLL load failed: \x8ew\x92\xe8\x82\xb3\x82\xea\x82\xbd\x83v\x83\x8d\x83V\x81[\x83W\x
83\x83\x82\xaa\x8c\xa9\x82\xc2\x82\xa9\x82\xe8\x82\xdc\x82\xb9\x82\xf1\x81B\r\n'

En regardant l'erreur, il semble que l'importation du module ** hou ** a échoué.

Cause d'erreur

La raison pour laquelle j'obtiens l'erreur est que ** Hython ** va à ** $ HFS ** et ** $ HFS / houdini / python2.7libs ** lors de l'importation du module ** hou **. En d'autres termes, si vous exécutez ** Hython ** à partir de ** 18.0 **, seuls ** HFS ** et ** PYTHONPATH ** pour ** 18.0 ** seront reconnus, vous obtiendrez donc une erreur d'importation.

Solution

Pour résoudre ce problème, vous devez exécuter le code ci-dessous pour modifier les paramètres de cette version avant d'exécuter ** Hython ** (pour des raisons de sécurité, restaurez les paramètres d'origine après avoir exécuté Hython). ..

import sys

#Remplacer par le chemin de la version de comparaison qui a obtenu HFS
os.putenv('HFS') = version_path
#Comme la DLL est également chargée lors de l'importation du module hou, la variable d'environnement PATH est également réécrite.
path = '{}/bin;{}'.format(version_path, os.getenv('PATH'))
os.putenv('PATH', path)

Code entier

Le code entier ressemble à ceci (il est long donc il est plié). L'exécution du script appelle la fonction principale.

Afficher l'intégralité du code

python


# -*- coding: utf-8 -*-
import hou
import os
import subprocess
from subprocess import PIPE

from .get_node_data import get_all_parm_templates

def get_compare_version(hfs):
    version_root = os.path.dirname(hfs)
    versions = os.listdir(version_root)
    current_version = 'Houdini ' + hou.applicationVersionString()
    if current_version in versions:
        versions.remove(current_version)
    #Dictionnaire d'options de l'interface utilisateur
    kwargs = {
        'exclusive': True,
        'title': 'Select Compare Version',
        'column_header': 'Versions',
        'width': 240,
        'height': 240
    }
    #Afficher la vue de liste pour sélectionner la version
    sel_version = hou.ui.selectFromList(versions, **kwargs)
    if not sel_version:
        return
    version = versions[sel_version[0]]
    return version

def get_env_from_version(version, hfs, pref_dir):
    old_hfs = '{}/{}'.format(os.path.dirname(hfs), version)
    old_pref_dir = '{}/{}'.format(
        os.path.dirname(pref_dir),
        '.'.join(version.replace('Houdini ', 'houdini').split('.')[:2])
    )
    return old_hfs, old_pref_dir

def set_base_env(path, hfs, pref_dir):
    #Définir les variables d'environnement et le chemin Python
    os.putenv('PATH', path)
    os.putenv('HFS', hfs)
    os.putenv('HOUDINI_USER_PREF_DIR', pref_dir)

def get_old_node_data(old_hfs, old_pref_dir):
    script_root = os.path.dirname(__file__)
    script = os.path.normpath(script_root + "/get_node_data.py")
    hython = os.path.normpath(old_hfs + '/bin/hython.exe')
    #Passez les variables d'environnement requises et le chemin Python avant de lancer hython
    path = '{}/bin;{}'.format(old_hfs, os.getenv('PATH'))
    set_base_env(path, old_hfs, old_pref_dir)
    #Exécutez le script avec hython
    p = subprocess.Popen([hython, script], shell=True, stdout=PIPE, stderr=PIPE)
    #Récupère la valeur de retour du script
    stdout, stderr = p.communicate()
    if stderr:
        hou.ui.displayMessage('Script Error', severity=hou.severityType.Error)
        return
    #La valeur renvoyée est une chaîne, alors convertissez-la en dictionnaire avec eval
    old_node_data = eval(stdout)
    return old_node_data

def get_node_info(node_name, node_label):
    node_info = {}
    node_info['Node Name'] = node_name
    node_info['Node Label'] = node_label
    return node_info

def compare(old_node_data):
    new_node_data = {}
    new_parm_node_data = {}
    categories = hou.nodeTypeCategories()
    for category, type_category in categories.items():
        new_nodes = []
        new_parm_nodes = []
        nodes = type_category.nodeTypes()
        old_nodes = old_node_data.get(category)
        #Que faire si la catégorie elle-même n'existe pas
        if not old_nodes:
            for node_name, node_type in sorted(nodes.items()):
                node_label = node_type.description()
                node_info = get_node_info(node_name, node_label)
                new_nodes.append(node_info)
            if new_nodes:
                new_node_data[category] = new_nodes
            continue
        #Si la catégorie existe
        old_node_names = [node_info['node_name'] for node_info in old_nodes]
        for node_name, node_type in sorted(nodes.items()):
            node_label = node_type.description()
            node_info = get_node_info(node_name, node_label)
            if node_name in old_node_names:
                all_parms = get_all_parm_templates([], node_type)
                index = old_node_names.index(node_name)
                parm_sets = set(old_nodes[index]['parms'])
                new_parms = [parm.name() for parm in all_parms if not parm.name() in parm_sets]
                if new_parms:
                    node_info['parms'] = new_parms
                    new_parm_nodes.append(node_info)
            else:
                new_nodes.append(node_info)
        if new_nodes:
            new_node_data[category] = new_nodes
        if new_parm_nodes:
            new_parm_node_data[category] = new_parm_nodes
    return new_node_data, new_parm_node_data

def create_nodes(node_data, root_node):
    for category, nodes in node_data.items():
        #Créer un nœud parent selon la catégorie de création d'un nœud
        if category == 'Object':
            parent_node = root_node.createNode('subnet', category)
        elif category == 'Driver':
            parent_node = root_node.createNode('ropnet', category)
        elif category == 'Sop':
            parent_node = root_node.createNode('geo', category)
        elif category == 'Vop':
            parent_node = root_node.createNode('matnet', category)
        elif not 'Net' in category:
            try:
                parent_node = root_node.createNode(
                    category.lower() + 'net', category, run_init_scripts=False)
            except:
                continue
        else:
            parent_node = root_node.createNode(category.lower(), category)
        #Créer un nœud
        for node_info in nodes:
            #Obtenez et créez le nom du nœud
            node_name = node_info['Node Name']
            try:
                new_node = parent_node.createNode(node_name)
            except:
                continue
            #Obtenir les paramètres
            parms = node_info.get('parms')
            if not parms:
                continue
            #Définir l'expression en paramètre
            for parm_name in parms:
                try:
                    if parm_name[-1] == '#':
                        parm_name = parm_name[:-1] + '1'
                    parm_tuple = new_node.parmTuple(parm_name)
                    if not parm_tuple:
                        continue
                    for parm in parm_tuple:
                        parm.setExpression('constant()')
                except:
                    pass
        #Organisation des nœuds
        parent_node.layoutChildren()
    root_node.layoutChildren()

def create_new_nodes(new_node_data):
    root_node = hou.node('/obj').createNode('subnet', 'NewNodes')
    create_nodes(new_node_data, root_node)

def create_new_parm_nodes(new_parm_node_data):
    root_node = hou.node('/obj').createNode('subnet', 'NewParmNodes')
    create_nodes(new_parm_node_data, root_node)

def main():
    hfs = os.getenv('HFS')
    #Obtenez la version à comparer
    version = get_compare_version(hfs)
    if not version:
        return
    pref_dir = os.getenv('HOUDINI_USER_PREF_DIR')
    path = os.getenv('PATH')
    #Obtenir des variables d'environnement pour la version à comparer
    old_hfs, old_pref_dir = get_env_from_version(
        version, hfs, pref_dir)
    #Obtenir des informations sur le nœud pour la version à comparer
    old_node_data = get_old_node_data(old_hfs, old_pref_dir)
    if not old_node_data:
        return
    #Restaurer les variables d'environnement définies pour hython
    set_base_env(path, hfs, pref_dir)
    #Obtenir des informations sur les nœuds par rapport aux nœuds de la version actuelle
    new_node_data, new_parm_node_data = compare(old_node_data)
    #Créer un nœud qui n'existe que dans la version actuelle
    create_new_nodes(new_node_data)
    #Créer un nœud avec des paramètres ajoutés dans la version actuelle
    create_new_parm_nodes(new_parm_node_data)
    #Organiser les nœuds
    hou.node('/obj').layoutChildren()

Résumé

Voici comment vérifier les nœuds ajoutés et mis à jour dans la nouvelle version. En utilisant ce script, vous pouvez vérifier le nœud mis à jour dès qu'une nouvelle version sort!

Si vous avez des erreurs ou des points peu clairs dans l'article, je vous serais reconnaissant de bien vouloir les noter. Jusqu'à la fin Merci d'avoir lu.

Recommended Posts

Obtenez et créez des nœuds ajoutés et mis à jour dans la nouvelle version
Obtenez la version GNOME
Obtenez les cours des actions et créez des graphiques en bougies avec Python
Obtenez le type MIME en Python et déterminez le format de fichier
Recherchez le pandas.DataFrame avec une variable et obtenez la ligne correspondante.
Comment obtenir toutes les clés et valeurs du dictionnaire
Obtenez la date et l'heure actuelles en Python, en tenant compte du décalage horaire
Créer une nouvelle liste en combinant des éléments en double dans la liste
Nouvelle grammaire et fonctionnalités Python non mentionnées dans le livre d'introduction
Accédez à l'API New Relic en Python pour obtenir l'état du serveur
Créez une fonction pour obtenir le contenu de la base de données dans Go
Obtenez le titre et la date de livraison de Yahoo! News en Python
Formatez le journal Git et obtenez le nom du fichier validé au format csv
Obtenez le chemin du bureau en Python
Obtenez le chemin du script en Python
Maya | Obtenir les nœuds parents dans l'ordre
Comment obtenir la version Python
Obtenez le chemin du bureau en Python
Obtenez le nom d'hôte en Python
Récupérer la chaîne de requête (chaîne de requête) avec Django
Créer et lire des paquets de messages en Python
Obtenez, testez et soumettez des cas de test dans le concours AtCoder à partir de la ligne de commande
Comment obtenir la différence de date et d'heure en secondes avec Python
Exemple de code pour obtenir oauth_token et oauth_token_secret de l'API Twitter en Python 2.7
Obtenez et convertissez l'heure actuelle dans le fuseau horaire local du système avec python
[Mémo d'apprentissage] Créer si le répertoire n'existe pas / Récupérer les fichiers dans le répertoire
Si vous obtenez une erreur sans attribut dans boto3, vérifiez la version
Obtenez l'adresse IP du client avec Django
Obtenez les nièmes valeurs les plus importantes dans Pandas
Obtenir la date et l'heure au format spécifié
Créer et exécuter la configuration d'embulk dans Jupyter
Je ne peux pas obtenir l'élément dans Selenium!
Essayez le nouveau chaînage du planificateur dans PyTorch 1.4
Trouvez-le dans la file d'attente et modifiez-le
Obtenir la liste de codes EDINET en Python
Créez et déployez des applications Flask avec PTVS
Obtenez l'adresse à partir de la latitude et de la longitude
Créer en Python sans fichier image factice dans Django et tester le téléchargement de l'image
J'ai comparé la vitesse des expressions régulières en Ruby, Python et Perl (version 2013)
Créez une API REST à l'aide du modèle appris dans Lobe et TensorFlow Serving.
Créer un projet et une application Django dans un environnement virtuel Python et démarrer le serveur
Créez un BOT qui affiche le nombre de personnes infectées dans le nouveau Corona
Je veux obtenir le nom du fichier, le numéro de ligne et le nom de la fonction dans Python 3.4
Obtenez le dernier élément du tableau en fractionnant les chaînes en Python et PHP
Créez un filtre pour obtenir un jeton d'accès avec l'API Graph (Flask)