SOP, DOP, Wrangle semble être recouvert de matériel: dancer_tone5: Je voudrais donc écrire du matériel Python. La version est à partir de Houdini 15.5. Étant donné que Houdini est un système basé sur des nœuds, en d'autres termes, il permet la programmation visuelle, je pense qu'il y a moins de possibilités de script avec Python qu'avec d'autres logiciels de CG 3D. Alors, où utilisez-vous Python! : punch_tone1: J'en parle, mais après tout, le développement du pipeline est l'essentiel. Par exemple, si HQueue, qui est un répartiteur Houdini standard, est utilisé en standard, le flux consistera à transmettre le travail de rendu à un autre client une fois la simulation de toutes les images terminée, mais si vous utilisez Python, ** 1 simulation d'image Lorsque vous avez terminé, vous pouvez dire ** lancer le travail de rendu à un autre client. De plus, comme vous pouvez spécifier un fichier de script Python avec l'option -P de la commande Mantra, vous pouvez remplacer les ** propriétés de rendu IFD ** (par exemple, les sous-pixels) que vous avez déjà exportés et rendus, donc les sous-pixels. Vous pouvez éviter de changer et de sortir à nouveau l'IFD. : clin d'œil: Vous pouvez également utiliser Python pour lire les informations de ** transformation d'objet ** dans le fichier Alembic lors de sa lecture. HQueue lui-même est gratuit, mais il vérifie les licences Houdini Indie ou supérieures (je n'obtiens pas la licence), et l'exportation IFD n'est possible qu'avec la version commerciale de Houdini / Engine, ce sont donc des informations utiles pour les utilisateurs Apprentice et Indie ** Python Je voudrais vous présenter comment obtenir des informations sur Alembic **. : détendu:
Le Python de Houdini fournit un module appelé ** _alembic_hom_extensions **. Normalement, lorsque vous contrôlez Houdini avec Python, vous commencez avec le module ** hou **, mais ce ** _alembic_hom_extensions ** est indépendant du module ** hou **. En d'autres termes, aucune licence n'est requise si vous utilisez simplement ce module. Mais cela n'a pas beaucoup de sens car la plupart du temps, je transmets les informations d'Alambic à Houdini et les traite: scream_cat: En utilisant ce module, vous pouvez principalement obtenir la hiérarchie d'objets, la transformation d'objet et la visibilité du fichier Almembic spécifié. Vous pouvez également obtenir la valeur de la propriété utilisateur de l'objet (dans le cas d'Alambic de Houdini, c'est-à-dire la résolution définie en plus pour l'objet caméra) et la plage de temps de l'animation de l'objet. Les fonctions de ce module sont: Lisez: zzz: Passons à l'explication suivante.
python
alembicArbGeometry(abcPath, objectPath, name, sampleTime) → (value, isConstant, scope)
Renvoie un taple de None ou (value, isConstant, scope). Le contenu de ce taple est la valeur de l'attribut, la valeur booléenne indiquant si l'attribut est constant sur l'axe du temps et la portée ('variant', 'vertex', 'facevarying', 'uniform', 'constant', 'unknown'. ')est. </ sup>
python
alembicClearArchiveCache()
Effacez le cache interne du fichier Alembic. </ sup>
python
alembicGetArchiveMaxCacheSize()
Renvoie la taille du cache du fichier Alembic. </ sup>
python
alembicGetCameraDict(abcPath, objectPath, sampleTime)
Renvoie un dictionnaire de paramètres de caméra pour l'objet spécifié. </ sup>
python
alembicGetCameraResolution(abcPath, objectPath, sampleTime)
Renvoie un taple contenant Aucun ou deux flottants. La première valeur est la résolution X de la caméra Houdini. La deuxième valeur est la résolution Y de la caméra Houdini. Certaines caméras (par exemple Maya Camera) n'ont pas de résolution, donc Aucune n'est renvoyée dans ce cas. </ sup>
python
alembicGetObjectPathListForMenu(abcPath)
Renvoie un tuple de chaînes au format requis pour les rappels de menu. </ sup>
python
alembicGetSceneHierarchy(abcPath, objectPath) → (object_name, object_type, (children))
Renvoie 3 taples. Chaque taple a la structure suivante: (object_name, object_type, (children)) (children) est un taple contenant des nœuds enfants. object_type contient l'un des éléments suivants (peut inclure d'autres types): --cxform nœud de transformation constante
python
alembicHasUserProperties(abcPath, objectPath)
Renvoie None si l'objet n'a pas de propriétés utilisateur. Si tel est le cas, renvoie si la propriété utilisateur est constante dans le temps. </ sup>
python
alembicSetArchiveMaxCacheSize(size)
Définit le nombre maximum de fichiers Alembic qui seront mis en cache à la fois. </ sup>
python
alembicTimeRange(abcPath, [objectPath=None]) → (start_time, end_time)
Renvoie un taple de None ou (start_time, end_time). Ce taple contient l'heure globale de début / fin de l'archive selon les informations FPS dans l'archive Alembic. Si vous spécifiez objectPath, l'heure de début / fin de cet objet est calculée. Renvoie None si l'archive est constante. </ sup>
python
alembicUserProperty(abcPath, objectPath, name, sampleTime) → (value, isConstant)
Renvoie un taple de None ou (value, isConstant). Ce taple contient la valeur de l'attribut et une valeur booléenne qui indique si l'attribut est constant dans le temps. </ sup>
python
alembicUserPropertyMetadata(abcPath, objectPath, sampleTime)
Renvoie Aucun ou dictionnaire JSON. Ce dictionnaire JSON contient une carte de nom de propriété utilisateur -> métadonnées de propriété utilisateur. </ sup>
python
alembicUserPropertyDictionary(abcPath, objectPath, sampleTime)
Renvoie Aucun ou dictionnaire JSON. Ce dictionnaire JSON contient une carte des noms de propriétés utilisateur-> valeurs des propriétés utilisateur. </ sup>
python
alembicUserPropertyValuesAndMetadata(abcPath, objectPath, sampleTime)
Renvoie None ou Taple. Ce taple contient deux dictionnaires JSON. Le premier dictionnaire contient une carte des propriétés et des valeurs utilisateur. Le deuxième dictionnaire contient une carte des propriétés de l'utilisateur et les métadonnées utilisées pour interpréter le premier dictionnaire. </ sup>
python
alembicVisibility(abcPath, objectPath, sampleTime, [check_ancestor=False]) → (value, isConstant)
Renvoie un taple de None ou (value, isConstant). Ce taple contient la visibilité de l'objet et une valeur booléenne qui indique si la visibilité est constante dans le temps. La valeur de retour de visibilité de 0 signifie masqué, 1 signifie visible et -1 signifie différer (en fonction de la visibilité parentale). </ sup>
python
getLocalXform(abcPath, objectPath, sampleTime) → (xform, isConstant, inherit)
Renvoie un tapple de (xform, isConstant, inherits). Ce tapple est une transformation locale, une valeur booléenne qui indique si la transformation est constante dans le temps et une valeur booléenne qui indique si le nœud hérite (ou est connecté à) la transformation parent. Comprend. </ sup>
python
getWorldXform(abcPath, objectPath, sampleTime) → (xform, isConstant, inherit)
Renvoie un tuple de (xform, isConstant, inherits). Ce tapple est une transformation mondiale, une valeur booléenne qui indique si la transformation est constante dans le temps et une valeur booléenne qui indique si le nœud hérite (ou est connecté à) la transformation parent. Comprend. </ sup>
Je n'utilise pas vraiment toutes les fonctions ci-dessus, donc j'aimerais me concentrer uniquement sur celles qui m'intéressent.
python
alembicGetSceneHierarchy(abcPath, objectPath)
python
alembicTimeRange(abcPath, [objectPath=None])
python
getWorldXform(abcPath, objectPath, sampleTime)
Il a considérablement diminué. Voyons ce que nous pouvons faire avec ces trois fonctions. J'ai créé cam1, Toy, Subnet (Pig, ShaderBall dans ce cas). Autre que ShaderBall, l'animation au niveau de l'objet est définie. Sortez toute cette scène sur Alembic et chargez-la dans une nouvelle scène. Les données sont capturées dans la même hiérarchie d'objets que Houdini et également animées. Mais lorsque je sélectionne l'objet cam1 à animer, l'éditeur d'animation n'affiche aucune courbe d'animation. Si vous connaissez CHOP, vous pouvez utiliser Object CHOP pour afficher la courbe d'animation échantillonnée dans Motion FX View, n'est-ce pas? Je pense que tu peux penser. Si les données d'animation Alembic d'origine sont cuites et interpolées linéairement, c'est très bien, mais si ce n'est pas le cas, vous voudrez également obtenir les valeurs d'image en virgule flottante. Vous voulez donc obtenir la courbe d'animation, non? C'est là que le module ** _alembic_hom_extensions ** entre en jeu. Comme un flux brutal,
Vous pouvez développer divers pipelines avec.
Le code est ci-dessous.
python
import _alembic_hom_extensions as abc
abcPath = "C:/data/alembicFile.abc"
def expandChild(root,child,objectHierarchy,objectType):
objectHierarchy.append(root+child[0])
objectType.append(child[1])
if len(child[2])==0:
return
else:
return expandChild(root+child[0]+"/",child[2][0],objectHierarchy,objectType)
objectHierarchy=[]
objectType=[]
childNodes = abc.alembicGetSceneHierarchy(abcPath, "/")[2]
for eachChildNode in childNodes:
expandChild("/",eachChildNode,objectHierarchy,objectType)
print objectHierarchy
print objectType
python
#Résultat de sortie
['/Toy', '/Toy/testgeometry_rubbertoy1', '/cam1', '/cam1/cameraProperties', '/Subnet', '/Subnet/Pig', '/Subnet/Pig/testgeometry_pighead1', '/Subnet/Pig/testgeometry_pighead1/PigFace']
['xform', 'polymesh', 'xform', 'camera', 'cxform', 'xform', 'polymesh', 'faceset']
Vous pouvez voir que xform a des informations d'animation pour cet objet et cxform n'a aucune information d'animation.
Examinons maintenant la plage d'animation de cam1.
python
import _alembic_hom_extensions as abc
abcPath = "C:/data/alembicFile.abc"
objectPath = "/cam1"
print abc.alembicTimeRange(abcPath, objectPath)
python
#Résultat de sortie
(0.041666666666666664, 2.0)
L'unité de la plage d'animation produite par cette fonction est la seconde. Étant donné que cette caméra capture une plage d'animation de 1 image à 48 images avec FPS = 24 Le résultat de (1.0 / 24.0, 48.0 / 24.0) s'affiche.
Examinons maintenant la transformation de l'objet.
python
import _alembic_hom_extensions as abc
abcPath = "C:/data/alembicFile.abc"
objectPath = "/cam1"
sampleTime = hou.frame()/hou.fps()
#Le premier élément du taple retourné par getWorldXform est 16 tapples float
xform = abc.getWorldXform(abcPath, objectPath, sampleTime)[0]
#Hou convertir au format matriciel.Utiliser Matrix4
xformMatrix = hou.Matrix4(xform)
#Extraire déplacer, faire pivoter, mettre à l'échelle
explodedDictionary = xformMatrix.explode()
print "translate:",explodedDictionary["translate"]
print "rotate",explodedDictionary["rotate"]
print "scale",explodedDictionary["scale"]
python
#Résultat de sortie
translate: [5.75595, 3.34021, 10.2852]
rotate [-11.6801, 28.4249, -1.25354e-06]
scale [1, 1, 1]
```
Vous pouvez l'utiliser dans le script unique ci-dessus, mais ** les expressions Houdini peuvent utiliser Python ainsi que HScript **.
Ensuite, ajoutons un paramètre utilisateur (appelé paramètre Spare dans Houdini) au nœud de caméra importé par Alembic comme suit.
Ici, j'ai ajouté deux Float Vector3 et préparé le paramètre Translate et le paramètre Rotate.
Puis changez le type d'expression en Python.
![UserParms.png](https://qiita-image-store.s3.amazonaws.com/0/154191/3c170758-182d-f349-6414-f89ccfb60957.png)
Dans le nœud Alembic Xform, les paramètres de nom de fichier, chemin d'objet, cadre et cadre sont déjà préparés, je voudrais donc utiliser les valeurs de ces paramètres pour obtenir des informations sur le mouvement et la rotation de la caméra.
Vous pouvez entrer plusieurs lignes de code Python à l'aide de la boîte de dialogue Modifier l'expression affichée en appuyant sur Alt + E sur les paramètres, mais il est difficile de saisir un par un le code fréquemment utilisé.
Il est pratique d'enregistrer le code fréquemment utilisé en tant que fonction personnalisée.
Une façon d'enregistrer une fonction personnalisée est de placer un fichier Python dans un répertoire spécifique et de le placer dans le chemin, mais cela entraînerait un fichier de scène dépendant de l'environnement.
Je veux l'éviter!
Définissons donc une fonction personnalisée dans le fichier de scène.
#### Comment enregistrer une fonction personnalisée dans un fichier de scène
Les fonctions personnalisées peuvent être enregistrées avec l'éditeur de source Python dans le menu Windows.
![PythonSourceEditor.png](https://qiita-image-store.s3.amazonaws.com/0/154191/6022a0b5-fa4d-97ad-e550-6a4fe3141500.png)
Entrez ensuite le code comme indiqué ci-dessous.
![PythonSourceEditorCode.png](https://qiita-image-store.s3.amazonaws.com/0/154191/6285343b-318f-656a-d176-36201529f123.png)
Ce code est une fonction qui fonctionne avec des paramètres sur un nœud Alembic Xform et renvoie des informations de transformation pour ce nœud.
#### **`python`**
```python
#le mode est"translate"Puis les informations de localisation,"rotate"Puis les informations de rotation,"scale"Renvoie les informations d'échelle
#Si l'index est 0, c'est le composant X, s'il vaut 1, c'est le composant Y, et s'il vaut 2, c'est le composant Z.
def getAlembicTransform(mode="translate",index=0):
import _alembic_hom_extensions as abc
currentNode = hou.pwd()
abcPath = currentNode.parm('fileName').eval()
objectPath = currentNode.parm('objectPath').eval()
sampleTime = currentNode.parm('frame').eval()/currentNode.parm('fps').eval()
xform = abc.getWorldXform(abcPath, objectPath, sampleTime)[0]
xformMatrix = hou.Matrix4(xform)
explodedDictionary = xformMatrix.explode()
return explodedDictionary[mode][index]
```
Après avoir enregistré le code dans la fenêtre de l'éditeur de source Python
Vous pourrez appeler la fonction personnalisée "getAlembicTransform" comme suit:
![ParameterExpression.png](https://qiita-image-store.s3.amazonaws.com/0/154191/380f944f-fa7b-6f00-98e3-c6ffd7d9344a.png)
Cliquez avec le bouton gauche sur le nom du paramètre pour voir si la valeur est correcte.
![ParameterExpressionEval.png](https://qiita-image-store.s3.amazonaws.com/0/154191/c8e5cc41-04e2-4412-55ac-3d802a64680b.png)
Vous pouvez maintenant voir la courbe d'animation de l'objet Alembic dans l'éditeur d'animation.
![AnimationCurve.png](https://qiita-image-store.s3.amazonaws.com/0/154191/e4697ace-c750-d3b1-7f2a-64ff75d139f7.png)
Vous avez maintenant inclus les informations de transformation d'Alembic dans les valeurs des paramètres.
C'est tout. : étreindre:
Recommended Posts