×

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

[section label= »Objectif » anchor= »objectif »]

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.

[section label= »En pratique » anchor= »en-pratique »]

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.

[section label= »Imports nécessaires » anchor= »imports-necessaires »]

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

[section label= »Interface utilisateur » anchor= »interface-utilisateur »]

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)

[section label= »Création des modules » anchor= »creation-modules »]

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

[section label= »Fichier __init__.py » anchor= »init »]

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

[section label= »Création du nouveau module » anchor= »nouveau-module »]

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])

[section label= »Création d’un Channel » anchor= »creation-channel »]

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)

[section label= »Création d’un Paintable Layer » anchor= »creation-paintable-layer »]

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)

[section label= »Création du Procedural Layer » anchor= »creation-procedurak-layer »]

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

[section label= »Création du Adjustment Layer » anchor= »creation-adjustment-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

[section label= »Création de Layer(s) pour le MskChannel » anchor= »creation-mskchannel-layers »]

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)

[section label= »Paramètres et options » anchor= »parametres-options »]

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])

[section label= »Réception du Channel » anchor= »reception-channel »]

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

[section label= »Attribuer une couleur à un Mask » anchor= »couleur-masque »]

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 )

[section label= »Attribuer une couleur à un Layer » anchor= »couleur-layer »]

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 )

[section label= »Vérifier si une couleur existe » anchor= »couleur-existe »]

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.'

[section label= »Trouver l’ID » anchor= »id »]

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

[section label= »TRouver les noms des Channels et Layers » anchor= »objectif »]

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]

Partager sur:

Photographe professionnel, originaire d'Alsace (France), ancien Directeur Technique sur les films d'animation "Minions", "Moi, Moche et Méchant" et "Le Lorax".

Laisser un commentaire