mardi 29 octobre 2013

NUKE list all callbacks

   Hey,
It's been a long time i searched how to list all callbacks present in a nuke script...
And now i get it !

We can list them by type like knobChanged or onCreate and so on.

We acces by the callbacks module in .nuke :

 

nukeCallbacks = nuke.callbacks


And then use its variables by the type :

 

nukeCallbacks = nuke.callbacks
allKnobChanged = nukeCallbacks.knobChangeds



Nuke list callbacks in a big dictionary with the node Class as key and its value as a list who contains the function to call and its arguments.
 

nukeCallbacks = nuke.callbacks
allKnobChanged = nukeCallbacks.knobChangeds

# Result: 
{'Read': [(<function readFn at 0x00000000047A3EB8>, (101,), {}, None)], 'Write': [(<function writeFn at 0x00000000047A3D68>, (), {}, None)], '*': [(<function readFn at 0x00000000047A3EB8>, (101,), {}, 'Read1')], 'Roto': [(<function rotoFn at 0x00000000047A3DD8>, (), {}, None)]}

Here some types examples :


 
autolabels = {}
beforeFrameRenders = {}
beforeRenders = {}
filenameFilters = {}
knobChangeds = {}
onCreates = {}
onDestroys = {}
onScriptCloses = {}
onScriptLoads = {}
onScriptSaves = {}
onUserCreates = {}
updateUIs = {}

lundi 22 juillet 2013

PyQt QGraphicsView la base pour un node graph

   
Evolution de la chose : http://unblogdecolin.blogspot.fr/2016/11/le-retour-du-node-graph-en-pyside.html

Ici je vais vous présenter une base pour faire un "node graph" ou viewport 2D... mon exemple est très simple il y a seulement deux éllipses en guise de "nodes",pour l'instant on regarde juste le paramétrage de base de notre QGraphicsView qui est notre support de base, peut être un jour je vous représenterai un ticket pour les nodes et leurs connections.


Un QGraphicsView avec une grille, deux items sélectionnable et bougeable, un lasso de sélection et un alt-drag pour bouger dans la vue.


 
from PyQt4 import QtGui, QtCore


class View(QtGui.QGraphicsView):
    def __init__(self):
        QtGui.QGraphicsView.__init__(self)
        self.resize(500, 500)

#on place le point de pivot des transformation au niveau du pointeur
       self.setTransformationAnchor(QtGui.QGraphicsView.AnchorUnderMouse)
       self.setResizeAnchor(QtGui.QGraphicsView.AnchorViewCenter)
#on cache les scrollBar
       self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
       self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)  
        
#active l’antialiasing
        self.setRenderHint(QtGui.QPainter.Antialiasing)
        
#creation du scene qui contient les items et sera dans la QView
        self.scene = QtGui.QGraphicsScene()
        self.scene.setSceneRect(-50000, -50000, 100000, 100000)

        
#Ajout d'une grille en fond
        self.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(60,60,60), QtCore.Qt.CrossPattern))
  
#creation de deux elipse simple a la scene, selectable et movable
        ep = self.scene.addEllipse (20, 40, 50, 50)
        ep.setFlag(QtGui.QGraphicsItem.ItemIsMovable, True)
        ep.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)
 
        epS = self.scene.addEllipse (20, 120, 50, 50)
        epS.setFlag(QtGui.QGraphicsItem.ItemIsMovable, True)
        epS.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)
        
#parametrage du drag mode  rubber …. permet davoir un lasso rectangulaire de selection
        self.setDragMode(QtGui.QGraphicsView.RubberBandDrag)
        self.setRubberBandSelectionMode(QtCore.Qt.IntersectsItemShape)
        self.setScene(self.scene)
        
        
#alt drag scroll bar, permet de se deplacer dans le graph grace a la touche alt.       
    def keyPressEvent(self, event):
        if event.key() == QtCore.Qt.Key_Alt:
            self.setDragMode(QtGui.QGraphicsView.ScrollHandDrag)
    def keyReleaseEvent(self, event):
        if event.key() == QtCore.Qt.Key_Alt:
            self.setDragMode(QtGui.QGraphicsView.RubberBandDrag)
            
        
d = View()
d.show()




vendredi 7 juin 2013

Displacement 32bit

   Un simple post sur la découverte d'un lien qui m'a appris, enfin!, a régler correctement une displace avec zbrush et vray. Finit le tatonage du shift ... place a la précision:

http://www.cggallery.com/tutorials/displacement/

mardi 21 mai 2013

joli print avec .center =)

    Petit poste rapide pour vous présenter une façon de faire des prints ou commentaires de manière cool et visible; grâce  a la fonction .center du module string:


 

>>> print "HELLO".center(50, "-")
----------------------HELLO-----------------------

jeudi 9 mai 2013

reseau to local script nuke

   

    Rien de bien étonnant, nuke demande énormément en appels disques et donc sur notre réseau supinfocom, et bien ça rame pas mal !
La solution la plus simple que j'ai trouvé a un mois de la fin et bien c'est de rapatrier toutes nos séquences de rendu en local, rien de bien fou... sauf que je veux garder exactement les mêmes chemins dans mes reads pour pouvoir passer de la séquence réseau a la séquence local juste en changeant la lettre du root (pour notre cas de D: a W:).
De plus j’avais pas envie de perdre de temps a faire ça manuellement donc j'ai écris un script pour automatiser tout ceci.
Voici le script :


 
import os, nuke
import shutil, glob, threading
from PySide import QtGui, QtCore

#creation de la class progress bar en pyside
class progBar(QtGui.QWidget):
    def __init__(self, parent = None):
        QtGui.QWidget.__init__(self, parent)

        self.pBar = QtGui.QProgressBar(self)
        #je set la taille de la fenetre ainsi que sa position dans l'espace
        self.setGeometry(500,500,10,20)
        #je set un flag tophint pour que la progress bar soit toujours en top
        self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint) 
        #j'affiche le widget progress bar
        self.show()

    #creation d'une simple fonction pour seter la valeur de la progress bar
    def prog(self, p):
        self.pBar.setValue(p)

        

#creation de la class principal derive du module thread    
class readOnLocalClass(threading.Thread):
    def __init__(self, init = True, parent = None):
        threading.Thread.__init__(self, parent)

        self.init = init

        if self.init:
            self.ini()

        else:
            self.notIni()

    #fonction a executer si l'argument init est True
    def ini(self):

            #ouverture d'une fenetre de dialogue pour selectionner une sequences d'image
            files = nuke.getClipname("files sequences : ", multiple = True)
            #remplacement du root W: en D:
            self.newPathLocal = files[0].replace("W:", "D:")
            #split du path pour avoir que le path
            self.newPathLocalSplit = os.path.split(self.newPathLocal)
            #si le dossier local n'existe pas alors on le cree avec makedirs,
            #makedirs cree de maniere recursive tout l'abre du dossier
            if os.path.isdir(self.newPathLocalSplit[0]):
                pass
            else:
                os.makedirs(self.newPathLocalSplit[0])

            #je liste tout les fichiers present dans le dossier reseau
            self.allFiles = glob.glob(os.path.split(files[0])[0] + "\*.*")
      

            #j'appel la class progressbar et je l'affiche
            self.ProgBar = progBar()
            self.ProgBar.show()

    #fonction a executer si l'argument init est False
    #recupere le path du read selectionner et remplace le D: par W:
    #liste les fichiers reseau a partir du path local
    def notIni(self):
        files = nuke.selectedNode().knob("file").value()
        self.newPathLocal = files.replace("D:", "W:")

        self.allFiles = glob.glob(os.path.split(self.newPathLocal)[0] + "\*.*")
        self.newPathLocal = files.replace("W:", "D:")
        self.newPathLocalSplit = os.path.split(self.newPathLocal)

        #j'appel la class progressbar et je l'affiche
        self.ProgBar = progBar()
        self.ProgBar.show()        

    #derive la fonction run du module thread
    def run(self): 
    
        i = 0
        #tant que i est pas egal au nombre de fichier present dans le dossier reseau
        while i != len(self.allFiles):
            #copie le fichier dans le nouveau dossier local
            shutil.copy(self.allFiles[i], self.newPathLocalSplit[0])
            i+=1
            #calcule du pourcentage pour la progression de la bar
            progr = (float(i)/float(len(self.allFiles)))*100
            #progression de la bar
            self.ProgBar.prog(progr)
        
        print "le thread est finit"
       
        self.ProgBar.close()

        self.creaRead()
        

    #fonction pour creer le node read ainsi que le bouton reload   
    def creaRead(self):
        if self.init:
            #creation du node read
            self.read = nuke.createNode('Read', 'file {' + self.newPathLocal + '}', inpanel = False)
            #creation du knob button reload
            bk = nuke.PyScript_Knob("Reload_Copy")
            #set la command du bouton, ici la fonction reload()
            bk.setCommand("reaload()")
            #ajoute le kno au node read
            self.read.addKnob(bk)

        else:
            print "reload"
            nuke.selectedNode().knob("reload").execute()


       

def readOnLocal():
    b = readOnLocalClass(init = True)
    #lance le thread, la fonction run()
    b.start()

def reaload():
    b = readOnLocalClass(init = False)
    #lance le thread, la fonction run()
    b.start() 


Et en bonus :p le script pour changer de root:

import os
import nuke

#remplace la lettre de disque, demande une nouvelle lettre en str et une list de node read
def changeRoot():
    p = nuke.getInput("Change Root Letter")
    allReads = nuke.allNodes("Read")
    for r in allReads:
        n = r.knob("file").value()
        rr = n.split(":/")
        nn = rr[0].replace(rr[0], p )
        nnP = os.path.join(nn + ":", rr[1])
        r.knob("file").setValue(nnP)


lundi 22 avril 2013

python nuke unpremult for all read and shuffle node

    Voici un petit script qui fait gagner du temps, il crée un node unpremult sous tout les nodes read, shuffle et le script recrée les connections des dependences:


 
#permet de recupere un dictionnaire contenant le node connecte ainsi que l'id de son input
def getOutput(node):
    dep = node.dependent()
    id = []
    for d in dep:
        ip = d.inputs()
        for i in range(ip):
            if d.input(i) == node:
                id.append(i)
    dictNodeInput = dict(zip(dep, id))
    return dictNodeInput


#permet de connecter tout les inputs d'un dict cree par la fonction getOutput() a un node
def setOutput(node, dictInput):
    for e, i in dictInput.items():
        e.setInput(i, node)
    return


read = nuke.allNodes("Read")
s = nuke.allNodes("Shuffle")

for p in s:
    read.append(p)

for r in read:
    d = getOutput(r)
    unp = nuke.nodes.Unpremult()
    unp.setInput(0,r)
    setOutput(unp, d)




mardi 16 avril 2013

Petite astuce dict zip python.


    Voici une petite astuce pour simplifier les attributions "keys", "values" d'un dictionnaire.
Lorsque l'on a deux listes et qu'on veut les combiner dans un dictionnaire on peut le faire sans boucle avec la fonction zip de la class dict. Comme ceci:


 

keys = ['A', 'B', 'C']

values = [1, 2, 3]

dic = dict(zip(keys, values))

print(dic)

>>> {'A': 1, 'B': 2, 'C': 3}




mardi 9 avril 2013

PySide/PyQt QDesktopWidget

Petit pense-bête sur le module Qt QDesktopWidget:


 

#module pour les info ecrans
ff = QtGui.QDesktopWidget()

#recupere les dimension des ecrans.
ff = QtGui.QDesktopWidget().screenGeometry(widget)
#recupere l'index de l ecran ou est place le widget
ff = QtGui.QDesktopWidget().screenNumber(widget)
#recupere le nombre d'ecran du system
ff = QtGui.QDesktopWidget().screenCount()


jeudi 28 mars 2013

Slate Material Editor et Py3dsMax (sme)

    Voici quelques fonctions bien utiles pour scripter avec le slate material editor (sme), je vous les présentes a travers un petit script qui permet de stocker tout les matériaux des objets sélectionnés dans une nouvelles vue du sme.


 

from Py3dsMax import mxs

#je recupere la liste des objets selectionnes:
sel = mxs.selection

#je cree une nouvelle vu et recupere son node:
nodeView = mxs.sme.GetView(mxs.sme.CreateView("stock_view"))

#je cree la boucle qui traitera chaque objets:
for node in sel:
 
    #je recupere le node material:
    mat = node.material
 
    #je creer le node material dans la nouvelle vue, je lui donne une position grace a la fonction point2 vector.
    nodeView.CreateNode(mat, mxs.point2(0,0))
 
    #j'execute une commande maxscript qui permet de mettre en ordre les materiaux dans la nouvelles vue.
    mxs.execute('actionMan.executeAction 369891408 "40060"')



mardi 12 mars 2013

Py3dsMax et les modifiers

Voici les principales fonctions py3dsmax pour travailler avec les modifiers:


 
#import de la library py3dsmax
from Py3dsMax import mxs

#cree une liste des objets selectionne
sel = mxs.selection

#cree un modifier avant l'index 6 (l'index 1 est le modifier le plus haut de la pile) 
#pour avoir un modifier toujour en bas de la pile mettre un grand before (ex: 10000)
mxs.addModifier(sel[0], mxs.Skin_Wrap(), before = 6)

#la liste des modifiers de l'objet
ld = sel[0].modifiers

#recupere un modifier par son nom
sk = sel[0].modifiers["Skin_Wrap"]

#recupere le node d'un objet par le nom
corp = mxs.getNodeByName("name_obj")


jeudi 28 février 2013

Zbrush to Max pourquoi c'est mou ?

    J'ai souvent entendu et eu ce problème, "j'ai sorti une décimation (ou high poly) de zbrush avec mes normales... et quand je rends avec max ma modé est toute mole et je perds beaucoup de détails."

Le problème vient des smooth group, faut savoir que par défaut max import des .obj avec un smooth group commun pour tout les poly. Vous pouvez voir ça dans l'editpoly, face mode, smoothing groups.

Tout les poly on un smooth group a 1.










Donc avant de rendre votre modé sortie de ZBrush pensez bien a "Clear All" les smooth groups.










Voila, c'est bête mais on y pense pas toujours.
En image, un petit comparatif:

 Avec smoothing group a 1.



Sans smoothing group.

La modé reste en peu moche (pas de lighting, shader, texture ..)  mais on peu voir qu'on gagne réellement en dureté et en détails.


vendredi 22 février 2013

la recursivité ou la fonction dans la fonction

Voici mon dernier petit utilitaire écrit en python pour 3ds max (py3dsMax), il s'agit d'une boucle récursive, c'est a dire une boucle infinie qui analyse des "éléments" les un après les autres jusqu’à qu'on lui signal par une "clé" de stopper la boucle.

Par exemple c'est très pratique lorsqu'on a des arbres nodales et qu'on veut effectuer une tache sur chacun de leurs nodes:



 


from Py3dsMax import mxs

#le nouveau nom appliqué a tout les nodes.
newName = "Name"

#je recupere ma selection d'objet.
sel = mxs.selection

#je recupere le nombre de slot du material appilque a ma selection.
idMap = mxs.getNumSubTexmaps(sel[0].material)

#je rename le material
sel[0].material.name = newName + sel[0].material.name 

#Je lance ma fonction recursive.
renameNode(idMap, sel[0].material)


def renameNode(idMap, sel):

 for i in range(1, idMap+1):
  slot = mxs.getSubTexmap(sel, i)
  if slot == None :
   print("empty slot")

  else:
   slot.name = newName + slot.name 
   idMap = mxs.getNumSubTexmaps(slot)
   for i in range(1, idMap+1):
    #je relance ma fonction dans cette meme fonction:
    renameNode(idMap, slot)

lundi 21 janvier 2013

Paroie rocheuses zbrush tuto

    En pleine prod de notre film de fin d'etude "ascension", je laisse de coté le script pour faire du modeling d'environnement avec zbrush.
Vu que notre film se passe en haute montagne il y a donc beaucoup de parois rocheuses, cailloux, roche ... , le meilleur outils que j'ai trouvé c'est  zbrush.

Voici quelques screens de zbrush des modé finals (sans texture, shader basique de zbrush):







Et voici un step by step:

    la modé de base:

    Première passe avec le brush TrimBorder (dans le dossier brush), jouer beaucoup avec le alt:


Puis un passage avec le brush Crumple pour déformer le tout et rendre moins lisse:


On ajoute du détails et de la texture avec le brush Fracture:







Et une dernière passe avec le NoiseMaker, on ajoute un noise et une érosion avec une petite échelle:






Et voila finit ! Plus qu'a faire un shader et texture dans max.