Vous lisez
Mari : Création automatique de modules (Channels/Layers)

Objectif

Créer un ensemble de Channels et Layers aux caractéristiques et paramètres prédéfinis. J’ai choisi de nommer ces ensembles des « Modules ».

Le but étant de gagner du temps dans la création de ces derniers car les graphistes sont amené à les utiliser quotidiennement.

En pratique

Il va de soit qu’il est nécessaire de créer une interface utilisateur (UI) pour cet outil. C’est pourquoi nous allons séparer notre développement en deux partie et donc deux Class:
  • moduleMakerUI : Création d’une interface indépendante
  • moduleMaker : Ensemble des fonctions et params de création des modules

Important
Par expérience, j’ai volontairement choisi de ne pas optimiser mon code en regroupant dans des fonctions communes la création des 4 types de modules. En effet, ayant souvent besoin d’apporter des modifs à la logique de l’un ou l’autre, j’ai finalement opté pour une séparation quasi totale des process de création.
Je suis ainsi plus sur de pouvoir répondre à de nouvelles demandes improbables sans avoir à revoir toute ma logique initiale.

Imports nécessaires

1
2
3
4
5
6
7
8
# Lib Mari
import mari
# Lib utils
import functools
# PythonQt UserInterface - Attention: Surcouche spécifique Mari
import PythonQt.QtGui as gui
# PythonQt Core - Attention: Surcouche spécifique Mari
import PythonQt.QtCore as core

Interface utilisateur – moduleMakerUI

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class moduleMakerUI(gui.QWidget):
    def __init__(self, model):
        # Initialisation des variables
        self.mm = model    # Init du model
        moduleList = self.mm.moduleList    # Modules a creer d'apres le model
        # Creation de interface en PythonQt (PyQt spécifique Mari)
        gui.QWidget.__init__(self)
        layout = gui.QVBoxLayout(self)
        # Pour chaque module: Creation d'un bouton
        for module in moduleList:
            button = gui.QPushButton(module, self)
            layout.addWidget(button)
            myFct = functools.partial(self.mm.moduleMaker_createModule, module)
            mari.utils.connect(button.clicked, myFct)
        self.setLayout(layout)

Création des modules – moduleMaker

Ci-dessous, la liste des fonctions utilisées.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class moduleMaker(object):

# 1 - Create a new module
    def moduleMaker_createModule(self, mod="", state=False)
        # Processus de creation de chaque module

# 2 - Create a Channel
    def moduleMaker_createChannel(self, name, res, depth)
        # Creation d'un Channel s'il n'existe pas

# 3 - Create an Paintable Layer
    def moduleMaker_createPaintableLayer(self, chan, name)
        # Creation d'un Paintable Layer s'il n'existe pas

# 4 - Create an Procedural Layer
    def moduleMaker_createProceduralLayer(self, mod, chan, type, col, name, file, msk)
        # Creation d'un Procedural Layer s'il n'existe pas

# 5 - Create an Adjustment Layer
    def moduleMaker_createAdjustmentLayer(self, chan, type, col, name, file, msk)
        # Creation d'un Adjustment Layer s'il n'existe pas

# 6 - Create Layer(s) for the MskChannel
    def moduleMaker_createMskChannelLayer(self, mod, chan, name, file)
        # Creation specifique pour les Layers du Channel Msk

# 7 - Set parameters and options for a layer
    def moduleMaker_setLayerOptions(self, layer, group, col, file, msk)
        # Config des options et parametres des Layers

# 8 - Get a Channel or return False
    def moduleMaker_getChannel(self, name)
        # Retourne l'objet Layer demande

# 9 - Set a color to a Mask
    def moduleMaker_setMaskColor(self, msk, col)
        # Assigne une couleur de fond a un Mask

# 10 - Set a color to a Layer
    def moduleMaker_setLayerColor(self, layer, col)
        # Assigne une couleur de fond a un Layer

# 11 - Check if Channel Color exist, else create it
    def moduleMaker_checkColorChan(self)
        # Verifie si le Channel Color existe, sinon on le cree

# 12 - Get the ID to use for names
    def moduleMaker_getId(self, mod)
        # Retourne l'ID a utiliser pour la creation des noms des Channels et Layers

# 13 - Get names for Channels and Layers
    def moduleMaker_getNames(self, mod, id)
        # Retourne les noms a utiliser pour la creation des Channels et Layers

En avant pour le contenu des fonctions listées ci-dessus.

 

__init__

1
2
3
4
5
6
7
def __init__(self):
    # Init vars
    self.moduleList = ['Blender','Dirt','Rust','Hue']
    self.moduleDict = { 'Blender' : [ [ ['Color01', 'Procedural', 'Basic/Color', [179,18,18], False, False], ['Color02', 'Procedural', 'Basic/Color', [85,200,30], False, True] ], ['Blender_msk'], ['BlenderMask', ['path', 3]] ], 'Dirt' : [ [ ['DirtColor', 'Procedural', 'Basic/Color', [170,155,135], False, True]], ['Dirt_msk'], ['DirtMask', False] ], 'Rust' : [ [ ['RustColor', 'Procedural', 'Procedural/Pattern/Tiled', False, ['path', 2], True]], ['Rust_msk'], ['RustMask', False] ], 'Hue' : [ [ ['HueColor', 'Adjustment', 'Filter/HSV', False, False, True]], ['Hue_msk'], ['HueMask', False] ] }
    self.geo        = mari.geo.current()
    self.chanRes    = [4096, 4096]
    self.chanDepth  = 8

1 – Create a new module

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
### Create a new module ###
def moduleMaker_createModule(self, module="", state=False):
   
    # Check if Color Channel exist, elese create it
    self.moduleMaker_checkColorChan()
    # Init vars
    id = self.moduleMaker_getId(module)
    moduleDict = self.moduleDict[module]
  
    # Create Layers in Color Channel
    for layerParams in moduleDict[0]:
        name = self.moduleMaker_getName(id, layerParams[0])
        if layerParams[1] == 'Procedural':
            self.moduleMaker_createProceduralLayer(module, self.colorChan, layerParams[2], layerParams[3], name, layerParams[4], layerParams[5])
        elif layerParams[1] == 'Adjustment':
            self.moduleMaker_createAdjustmentLayer(module, self.colorChan, layerParams[2], layerParams[3], name, layerParams[4], layerParams[5])
   
    # Create Msk Channel
    name = self.moduleMaker_getName(id, moduleDict[1][0])
    mskChan = self.moduleMaker_createChannel(name, self.chanRes, self.chanDepth)
    # Create Base Layer and Fill Color in Black
    layerBase = self.moduleMaker_createPaintableLayer(mskChan, 'Base')
    self.moduleMaker_setLayerColor(layerBase, [0.0,0.0,0.0])
    # Create Msk Channel Layer
    name = self.moduleMaker_getName(id, moduleDict[2][0])
    self.moduleMaker_createMskChannelLayer(module, mskChan, name, moduleDict[2][1])

2 – Create a Channel

1
2
3
4
5
6
7
### Create a Channel ###
def moduleMaker_createChannel(self, name, res, depth):
    print '>>> Create Channel "'+str(name)+'"'
    if self.geo.findChannel(name) == None:
        return self.geo.createChannel(name, res[0], res[1], depth)
    else:
        return self.geo.findChannel(name)

3 – Create an Paintable Layer

1
2
3
4
5
6
7
### Create an Paintable Layer ###
 def moduleMaker_createPaintableLayer(self, chan, name):
     print '>>> Create Paintable Layer "'+str(name)+'" in "'+str(chan.name())+'"'
     if chan.findLayer(name) == None:
         return chan.createPaintableLayer(name)
     else:
         return chan.findLayer(name)

4 – Create an Procedural Layer

1
2
3
4
5
6
7
8
9
10
11
12
### Create an Procedural Layer ###
def moduleMaker_createProceduralLayer(self, module, chan, typeKey, color, name, file, mask):
   
    if module == 'Blender': layerName = name    # Exception for Blender module
    else: layerName = name + 'Base'
   
    group = chan.createGroupLayer(name + '_grp')
   
    layer = group.layerStack().createProceduralLayer(layerName, typeKey)
    self.moduleMaker_setLayerOptions(layer, group, color, file, mask)
   
    return layer

5 – Create an Adjustment Layer

1
2
3
4
5
6
7
8
9
10
11
12
### Create an Adjustment Layer ###
def moduleMaker_createAdjustmentLayer(self, chan, typeKey, color, name, file, mask):
   
    layer = chan.createAdjustmentLayer(name + 'Base', typeKey)
    self.moduleMaker_setLayerOptions(layer, layer, color, file, mask)
   
    if typeKey == 'Filter/HSV':
        layer.setPrimaryAdjustmentParameter("Hue", -3)
        layer.setPrimaryAdjustmentParameter("Saturation", 0.88)
        layer.setPrimaryAdjustmentParameter("Value", 0.97)
   
    return layer

6 – Create Layer(s) for the MskChannel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
### Create Layer(s) for the MskChannel ###
def moduleMaker_createMskChannelLayer(self, module, chan, name, file):
   
    group       = chan.createGroupLayer(name + '_grp')
    groupStack  = group.layerStack()
    groupStack.createPaintableLayer(name + 'Base')
       
    if module == 'Blender':
        layerTiled = groupStack.createProceduralLayer('Mask_TILED', 'Procedural/Pattern/Tiled')
        layerTiled.setBlendMode(23)
        layerTiled.setProceduralParameter('TileImage', file[0])
        layerTiled.setProceduralParameter('URepeat', file[1])
        layerTiled.setProceduralParameter('VRepeat', file[1])
   
   sharedLayer = self.layerMask.shareLayer(group)

7 – Set parameters and options for a layer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
### Set parameters and options for a layer ###
def moduleMaker_setLayerOptions(self, layer, group, color, file, mask)

    if color:
        color = mari.Color(color[0]/255.0, color[1]/255.0, color[2]/255.0)
        layer.setProceduralParameter("Color", color)
   
    if file:
        layer.setProceduralParameter('TileImage', file[0])
        layer.setProceduralParameter('URepeat', file[1])
        layer.setProceduralParameter('VRepeat', file[1])
       
    if mask:
        self.layerMask = group.makeMaskStack()
        layerMask = self.layerMask.layerList()[0]
        self.moduleMaker_setLayerColor(layerMask, [0.0,0.0,0.0])

8 – Get a Channel or return False

1
2
3
4
5
6
7
8
9
10
11
12
13
### Get a Channel or return False ###
def moduleMaker_getChannel(self, name):
   
    chanListLower = {}
    chanList = self.geo.channelList()
   
    for chan in chanList:
        chanListLower[chan.name().lower()] = chan.name()
       
    if name.lower() in chanListLower.keys():
        return self.geo.findChannel(chanListLower[name.lower()])
    else:
        return False

9 – Set a color to a Mask

1
2
3
4
5
6
### Set a color to a Mask ###
def moduleMaker_setMaskColor(self, mask, color):
   
    color = mari.Color(color[0]/255.0, color[1]/255.0, color[2]/255.0)
    for image in mask.imageList():
        image.setUniformColor( color )

10 – Set a color to a Layer

1
2
3
4
5
6
7
### Set a color to a Layer ###
def moduleMaker_setLayerColor(self, layer, color):

    color = mari.Color(color[0]/255.0, color[1]/255.0, color[2]/255.0)
    imageSet = layer.imageSet()
    for image in imageSet.imageList():
        image.setUniformColor( color )

11 – Check if Channel Color exist, else create it

1
2
3
4
5
6
7
8
9
### Check if Channel Color exist, else create it ###
def moduleMaker_checkColorChan(self):
   
    # Test if Color Channel exists. If not, create it
    self.colorChan = self.moduleMaker_getChannel('Color')
    if self.colorChan == False:
        self.colorChan = self.moduleMaker_createChannel('Color', self.chanRes, self.chanDepth)
    else:
        print 'Channel "Color" already exist.'

12 – Get the ID to use for names

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
### Get the ID to use for names ###
def moduleMaker_getId(self, module):
   
    chan = self.moduleMaker_getChannel(str(module)+'_msk')
    if chan == False:
        return False
   
    id = 1
    newId = False
    find  = False
    while find == False:
        chan = self.moduleMaker_getChannel(str(module)+'_msk_'+str(id))
        if chan == False:
            newId = id
            find = True
        id = id + 1
      
    return newId

13 – Get names for Channels and Layers

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
### Get names for Channels and Layers ###
def moduleMaker_getNames(self, module, id):
       
    if id:
        if module == 'Blender':
            nameChanLayer = ['Color01_'+str(id), 'Color02_'+str(id)]
        else:
            nameChanLayer = [str(module)+'Color_'+str(id)]
        nameChanMsk     = str(module)+'_msk_'+str(id)
        nameLayerMsk    = str(module)+'Mask_'+str(id)
     else:
        if module == 'Blender':
            nameChanLayer = ['Color01', 'Color02']
        else:
            nameChanLayer = [str(module)+'Color']
        nameChanMsk     = str(module)+'_msk'
        nameLayerMsk    = str(module)+'Mask'
    return [nameChanLayer, nameChanMsk, nameLayerMsk]   # [Array, String, String]

Qu'avez-vous pensé de cet article ?
J'aime
67%
Merci
0%
Pratique
0%
Incomplet
0%
Rien de neuf
33%
A propos de l'auteur
Olivier Schmitt
Photographe professionnel, originaire d'Alsace (France), ancien Directeur Technique sur les films d'animation "Minions", "Moi, Moche et Méchant" et "Le Lorax".
Commentaires
Laisser une réponse

Laisser une réponse