class MapOperations(object): """ class that contains operations applied to the entire mesh """ def __init__(self): self.mll = MllInterface() self.selection_name = [] self.ngs_layer_id = -1 self.ngs_influence = None self.ngs_weight_list = [] self.ngs_vert_count = -1 self.max_value = -1.0 self.min_value = -1.0 def get_data(self): self.selection_name = cmds.ls(selection=True) self.ngs_layer_id = self.mll.getCurrentLayer() self.ngs_influence = self.mll.getCurrentPaintTarget() self.ngs_weight_list = self.mll.getInfluenceWeights( self.ngs_layer_id, self.ngs_influence) self.ngs_vert_count = self.mll.getVertCount() self.max_value = max(self.ngs_weight_list) self.min_value = min(self.ngs_weight_list) def grow_map(self, intensity): """ pushes the border of the active weight map outwards """ self.get_data() new_weight_list = [] for i in range(self.ngs_vert_count): vertex_weight = self.ngs_weight_list[i] if vertex_weight >= self.max_value: new_weight_list.append(vertex_weight) continue vertex_name = '.'.join([self.selection_name[0], 'vtx[%d]' % i]) area_vertices = get_surrounding_verts(vertex_name) weight_list = [self.ngs_weight_list[int(x)] for x in area_vertices] max_avg = max(weight_list) if max_avg <= self.min_value: new_weight_list.append(vertex_weight) continue grow_weight = vertex_weight + (abs(vertex_weight - max_avg) * intensity) grow_weight = min(grow_weight, self.max_value) new_weight_list.append(grow_weight) self.mll.setInfluenceWeights(self.ngs_layer_id, self.ngs_influence, new_weight_list) def shrink_map(self, intensity): """ pulls the border of the active weight map inwards """ self.get_data() new_weight_list = [] for i in range(self.ngs_vert_count): vertex_weight = self.ngs_weight_list[i] if vertex_weight <= self.min_value: new_weight_list.append(vertex_weight) continue vertex_name = '.'.join([self.selection_name[0], 'vtx[%d]' % i]) area_vertices = get_surrounding_verts(vertex_name) weight_list = [self.ngs_weight_list[int(x)] for x in area_vertices] min_avg = min(weight_list) if min_avg >= self.max_value: new_weight_list.append(vertex_weight) continue shrink_weight = vertex_weight - (abs(vertex_weight - min_avg) * intensity) shrink_weight = max(shrink_weight, self.min_value) new_weight_list.append(shrink_weight) self.mll.setInfluenceWeights(self.ngs_layer_id, self.ngs_influence, new_weight_list) def conceal_map(self, intensity): """ smooth operation for the active map by only lowering values """ self.get_data() new_weight_list = [] threshold = 0.01 / (intensity / 0.1) for i in range(self.ngs_vert_count): vertex_weight = self.ngs_weight_list[i] if vertex_weight <= self.min_value: new_weight_list.append(vertex_weight) continue vertex_name = '.'.join([self.selection_name[0], 'vtx[%d]' % i]) area_vertices = get_surrounding_verts(vertex_name) weight_list = [self.ngs_weight_list[int(x)] for x in area_vertices] weight_avg = sum(weight_list) / float(len(weight_list)) min_avg = min(weight_list) if weight_avg >= self.max_value and abs(weight_avg - vertex_weight) < threshold: new_weight_list.append(vertex_weight) continue weight_diff = abs(weight_avg - vertex_weight) conceal_weight = vertex_weight * (1 - (weight_diff * intensity)) conceal_weight = max(conceal_weight, min_avg) new_weight_list.append(conceal_weight) self.mll.setInfluenceWeights(self.ngs_layer_id, self.ngs_influence, new_weight_list) def spread_map(self, intensity): """ smooth operation for the active map by only increasing values """ self.get_data() new_weight_list = [] threshold = 0.01 / (intensity / 0.1) for i in range(self.ngs_vert_count): vertex_weight = self.ngs_weight_list[i] if vertex_weight >= self.max_value: new_weight_list.append(vertex_weight) continue vertex_name = '.'.join([self.selection_name[0], 'vtx[%d]' % i]) area_vertices = get_surrounding_verts(vertex_name) weight_list = [self.ngs_weight_list[int(x)] for x in area_vertices] weight_avg = sum(weight_list) / float(len(weight_list)) max_avg = max(weight_list) if weight_avg <= self.min_value and abs(weight_avg - vertex_weight) < threshold: new_weight_list.append(vertex_weight) continue weight_diff = abs(weight_avg - vertex_weight) spread_weight = vertex_weight + weight_diff * intensity spread_weight = min(spread_weight, max_avg) new_weight_list.append(spread_weight) self.mll.setInfluenceWeights(self.ngs_layer_id, self.ngs_influence, new_weight_list) def gain_map(self, intensity): """ 'reverse scale' tool that only increases weight values above 0 """ self.get_data() new_weight_list = [] for i in range(self.ngs_vert_count): vertex_weight = self.ngs_weight_list[i] if vertex_weight == 0: new_weight_list.append(vertex_weight) continue gain_weight = vertex_weight + (vertex_weight * intensity) gain_weight = min(gain_weight, 1) new_weight_list.append(gain_weight) self.mll.setInfluenceWeights(self.ngs_layer_id, self.ngs_influence, new_weight_list) def contrast_map(self, intensity): """ sharpens the edge of the active weight map """ self.get_data() new_weight_list = [] avg_value = (self.max_value + self.min_value) / 2 normalized_range = self.max_value - self.min_value for i in range(self.ngs_vert_count): vertex_weight = self.ngs_weight_list[i] if not self.max_value > vertex_weight > self.min_value: new_weight_list.append(vertex_weight) continue dist_value = vertex_weight - avg_value modifier = norm.cdf(dist_value, loc=0, scale=(0.1 * normalized_range)) - vertex_weight contrast_weight = vertex_weight + modifier * intensity contrast_weight = max(self.min_value, min(contrast_weight, self.max_value)) new_weight_list.append(contrast_weight) self.mll.setInfluenceWeights(self.ngs_layer_id, self.ngs_influence, new_weight_list)
class UseNgBrush(object): """ setup for custom brush operations, a new instance is created on every brush stroke """ def __init__(self, surface_name): self.surface = surface_name self.stroke_id = None self.mode = 1 self.value = 1 self.volumeThreshold = -0.1 self.mll = MllInterface() self.selection_name = cmds.ls(selection=True) self.mesh = cmds.listRelatives(self.selection_name[0], shapes=True) self.ngs_layer_id = self.mll.getCurrentLayer() self.ngs_influence = self.mll.getCurrentPaintTarget() self.ngs_weight_list = self.mll.getInfluenceWeights( self.ngs_layer_id, self.ngs_influence) self.max_value = max(self.ngs_weight_list) self.min_value = min(self.ngs_weight_list) def stroke_initialize(self): """ this function is executed before each brush stroke """ cmds.undoInfo(openChunk=True, undoName="paint stroke") get_stroke_id = ngLayerPaintCtxInitialize(self.mesh[0]) self.stroke_id = int(get_stroke_id.split(" ")[1]) cmds.ngSkinLayer(paintOperation=self.mode, paintIntensity=self.value) self.stroke_update() return self.surface, self.stroke_id def stroke_finalize(self): """ this function is executed after each brush stroke """ if self.stroke_id: cmds.ngLayerPaintCtxFinalize(self.stroke_id) self.stroke_id = None cmds.undoInfo(closeChunk=True) def stroke_update(self): """ updates certain attributes for the brush instance """ # self.mll = MllInterface() # self.selection_name = cmds.ls(selection=True) # self.mesh = cmds.listRelatives(self.selection_name[0], shapes=True) # self.ngs_layer_id = self.mll.getCurrentLayer() # self.ngs_influence = self.mll.getCurrentPaintTarget() # self.ngs_weight_list = self.mll.getInfluenceWeights(self.ngs_layer_id, self.ngs_influence) # self.max_value = max(self.ngs_weight_list) # self.min_value = min(self.ngs_weight_list) self.volumeThreshold = cmds.floatSlider("volume_slider", q=True, value=True) def contrast_paint(self, vert_id, value): """ sharpens the edge of the active weight map """ vertex_weight = self.ngs_weight_list[vert_id] if not self.max_value > vertex_weight > self.min_value: return avg_value = (self.max_value + self.min_value) / 2 normalized_range = self.max_value - self.min_value dist_value = vertex_weight - avg_value modifier = norm.cdf(dist_value, loc=0, scale=(0.1 * normalized_range)) - vertex_weight contrast_weight = vertex_weight + (modifier * value) contrast_weight = max(self.min_value, min(contrast_weight, self.max_value)) cmds.ngSkinLayer(paintIntensity=contrast_weight) cmds.ngLayerPaintCtxSetValue(self.stroke_id, vert_id, 1) def conceal_paint(self, vert_id, value): """ smooth operation that only lowers weight values """ vertex_weight = self.ngs_weight_list[vert_id] if vertex_weight <= self.min_value: return vertex_name = '{}.vtx[{}]'.format(self.selection_name[0], vert_id) area_vertices = get_surrounding_verts(vertex_name) weight_list = [self.ngs_weight_list[int(x)] for x in area_vertices] weight_avg = sum(weight_list) / float(len(weight_list)) min_avg = min(weight_list) threshold = 0.01 / (value / 0.1) if weight_avg >= self.max_value and abs(weight_avg - vertex_weight) <= threshold: return weight_diff = abs(weight_avg - vertex_weight) conceal_weight = vertex_weight * (1 - (weight_diff * value)) conceal_weight = max(conceal_weight, min_avg) cmds.ngSkinLayer(paintIntensity=conceal_weight) cmds.ngLayerPaintCtxSetValue(self.stroke_id, vert_id, 1) def spread_paint(self, vert_id, value): """ smooth operation that only increases weight values """ vertex_weight = self.ngs_weight_list[vert_id] if vertex_weight >= self.max_value: return vertex_name = '.'.join([self.selection_name[0], 'vtx[%d]' % vert_id]) area_vertices = get_surrounding_verts(vertex_name) weight_list = [self.ngs_weight_list[int(x)] for x in area_vertices] weight_avg = sum(weight_list) / float(len(weight_list)) max_avg = max(weight_list) threshold = 0.01 / (value / 0.1) if weight_avg <= self.min_value and abs(weight_avg - vertex_weight) <= threshold: return weight_diff = abs(weight_avg - vertex_weight) spread_weight = vertex_weight + (weight_diff * value) spread_weight = min(spread_weight, max_avg) cmds.ngSkinLayer(paintIntensity=spread_weight) cmds.ngLayerPaintCtxSetValue(self.stroke_id, vert_id, 1) def gain_paint(self, vert_id, value): """ increases existing weight values but preserves empty weights """ vertex_weight = self.ngs_weight_list[vert_id] if vertex_weight == 0: return gain_weight = vertex_weight + (vertex_weight * value) gain_weight = min(gain_weight, 1) cmds.ngSkinLayer(paintIntensity=gain_weight) cmds.ngLayerPaintCtxSetValue(self.stroke_id, vert_id, 1) def volume_equalize(self, vert_id, value): """ i.e a volumetric match operation with a falloff. applies weight values inside the brush radius onto other vertices inside a spherical volume """ origin_vertex = '.'.join([self.selection_name[0], 'vtx[%s]']) % vert_id vertex_weight = self.ngs_weight_list[vert_id] v1 = cmds.pointPosition(origin_vertex) for i in range(len(self.ngs_weight_list)): target_weight = self.ngs_weight_list[i] if target_weight == vertex_weight: continue if i == vert_id: continue target_vertex = '.'.join([self.selection_name[0], 'vtx[%s]']) % i v2 = cmds.pointPosition(target_vertex) target_distance = sqrt((pow((v1[0] - v2[0]), 2)) + (pow((v1[1] - v2[1]), 2)) + (pow((v1[2] - v2[2]), 2))) if target_distance > (self.volumeThreshold * value): continue falloff = (self.volumeThreshold - target_distance) / self.volumeThreshold eq_weight = target_weight - (( (target_weight - vertex_weight) * value) * falloff) cmds.ngSkinLayer(paintIntensity=eq_weight) cmds.ngLayerPaintCtxSetValue(self.stroke_id, i, 1)
class Equalize(object): def __init__(self): self.mll = MllInterface() self.ngs_vert_count = -1 self.ngs_layer_id = -1 self.intensity = -1 self.ngs_influence = None self.vert_weight_dict = {} self.vert_weight_list = [] self.ngs_weight_dict = {} self.ngs_weight_list = [] self.new_weight_list = [] self.selection_vert = [] self.vertex_list = [] self.id_list = [] self.modes = { "max": self.vert_max, "min": self.vert_min, "avg": self.vert_avg, "first": self.vert_first, "last": self.vert_last } def get_data(self, check): self.ngs_weight_dict = {} self.vert_weight_dict = {} self.selection_vert = cmds.ls(os=True) if not self.selection_vert: return False if not check: self.ngs_influence = [("selected influence:", self.mll.getCurrentPaintTarget())] else: self.ngs_influence = self.mll.listLayerInfluences( layerId=None, activeInfluences=True) self.mll = MllInterface() self.ngs_layer_id = self.mll.getCurrentLayer() self.ngs_vert_count = self.mll.getVertCount() self.vertex_list = cmds.ls(self.selection_vert, flatten=True) self.id_list = list( map(lambda x: x[x.find("[") + 1:x.find("]")], self.vertex_list)) for influences in self.ngs_influence: influence_weights = self.mll.getInfluenceWeights( self.ngs_layer_id, influences[1]) vert_weights = [influence_weights[int(i)] for i in self.id_list] self.ngs_weight_dict[influences] = influence_weights self.vert_weight_dict[influences] = vert_weights return True def set_vert(self, mode, intensity): self.intensity = intensity for influences in self.ngs_influence: self.new_weight_list = [] self.ngs_weight_list = self.ngs_weight_dict[influences] self.vert_weight_list = self.vert_weight_dict[influences] self.modes[mode]() self.mll.setInfluenceWeights(self.ngs_layer_id, influences[1], self.new_weight_list) def vert_max(self): for i in range(self.ngs_vert_count): vertex_weight = self.ngs_weight_list[i] if str(i) not in self.id_list or vertex_weight == max( self.vert_weight_list): self.new_weight_list.append(vertex_weight) continue new_weight = vertex_weight + ( (max(self.vert_weight_list) - vertex_weight) * self.intensity) self.new_weight_list.append(new_weight) def vert_min(self): for i in range(self.ngs_vert_count): vertex_weight = self.ngs_weight_list[i] if str(i) not in self.id_list or vertex_weight == min( self.vert_weight_list): self.new_weight_list.append(vertex_weight) continue new_weight = vertex_weight - ( (vertex_weight - min(self.vert_weight_list)) * self.intensity) self.new_weight_list.append(new_weight) def vert_avg(self): average = sum(self.vert_weight_list) / float(len( self.vert_weight_list)) for i in range(self.ngs_vert_count): vertex_weight = self.ngs_weight_list[i] if str(i) not in self.id_list or vertex_weight == average: self.new_weight_list.append(vertex_weight) continue new_weight = vertex_weight - ( (vertex_weight - average) * self.intensity) self.new_weight_list.append(new_weight) def vert_first(self): first = self.vert_weight_list[0] for i in range(self.ngs_vert_count): vertex_weight = self.ngs_weight_list[i] if str(i) not in self.id_list or vertex_weight == first: self.new_weight_list.append(vertex_weight) continue new_weight = vertex_weight - ( (vertex_weight - first) * self.intensity) self.new_weight_list.append(new_weight) def vert_last(self): last = self.vert_weight_list[-1] for i in range(self.ngs_vert_count): vertex_weight = self.ngs_weight_list[i] if str(i) not in self.id_list or vertex_weight == last: self.new_weight_list.append(vertex_weight) continue new_weight = vertex_weight - ( (vertex_weight - last) * self.intensity) self.new_weight_list.append(new_weight)