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.
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 **.
Tout d'abord, voyez le résultat de l'exécution du script.
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 **
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.
Le script peut être téléchargé et utilisé à partir du référentiel ** GitHub ** ci-dessous.
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.
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.
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.
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.
Le chiffre ouvert dans Excel. Chaque nœud est divisé par catégorie, nom de nœud et étiquette de nœud.
Le chiffre ouvert dans Excel. Chaque paramètre est divisé en catégorie, nom de nœud, étiquette de nœud, nom de paramètre et étiquette de paramètre.
Ce qui suit est une explication de Python. Il est difficile de tout écrire, donc je n'expliquerai que les points clés.
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']
HOUDIN ~ 1.287
, donc je l'ai omis par la méthode suivante.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
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é. 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()
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.
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
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.
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é.
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.
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)
Le code entier ressemble à ceci (il est long donc il est plié). L'exécution du script appelle la fonction principale.
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()
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