def testNewSlider(): simp = Simplex.buildEmptySystem(None, 'Face') model = SimplexModel(simp, None) smodel = SliderModel(model) fmodel = SliderFilterModel(smodel) fmodel.doFilter = True app = QApplication(sys.argv) topWid = QWidget() lay = QVBoxLayout(topWid) tv = QTreeView(topWid) btn = QPushButton('NEW', topWid) lay.addWidget(tv) lay.addWidget(btn) tv.setModel(fmodel) expandRecursive(tv, fmodel) topWid.show() newSlider = lambda: Slider.createSlider('NewSlider', simp) btn.clicked.connect(newSlider) sys.exit(app.exec_())
def testDeleteBase(path): simp = buildDummySystem(path) model = SimplexModel(simp, None) model = SliderModel(model) model = SliderFilterModel(model) app = QApplication(sys.argv) topWid = QWidget() lay = QVBoxLayout(topWid) tv = QTreeView(topWid) btn = QPushButton('DELETE', topWid) lay.addWidget(tv) lay.addWidget(btn) tv.setModel(model) topWid.show() expandRecursive(tv, model) tv.resizeColumnToContents(0) def delCallback(): sel = tv.selectedIndexes() sel = [i for i in sel if i.column() == 0] items = [s.model().itemFromIndex(s) for s in sel] items[0].delete() tv.model().invalidateFilter() btn.clicked.connect(delCallback) sys.exit(app.exec_())
def _writeSimplex(oarch, name, jsString, faces, counts, newShapes, pBar=None): ''' Separate the writer from oarch creation so garbage collection *hopefully* works as expected ''' par = OXform(oarch.getTop(), name) props = par.getSchema().getUserProperties() prop = OStringProperty(props, "simplex") prop.setValue(str(jsString)) abcMesh = OPolyMesh(par, name) schema = abcMesh.getSchema() if pBar is not None: pBar.setLabelText('Writing Corrected Simplex') pBar.setMaximum(len(newShapes)) for i, newShape in enumerate(newShapes): if pBar is not None: pBar.setValue(i) QApplication.processEvents() else: print "Writing {0: 3d} of {1}\r".format(i, len(newShapes)), verts = mkSampleVertexPoints(newShape) abcSample = OPolyMeshSchemaSample(verts, faces, counts) schema.set(abcSample) if pBar is None: print "Writing {0: 3d} of {1}".format(len(newShapes), len(newShapes))
def outputCorrectiveReferences(outNames, outRefs, simplex, mesh, poses, sliders, pBar=None): ''' Output the proper files for an external corrective application Arguments: outNames: The filepath for the output shape and reference indices outRefs: The filepath for the deformation references simplex: A simplex system mesh: The mesh object to deform poses: Lists of parameter/value pairs. Each list corresponds to a slider sliders: The simplex sliders that correspond to the poses ''' refs, shapes, refIdxs = buildCorrectiveReferences(mesh, simplex, poses, sliders, pBar) if pBar is not None: pBar.setLabelText('Writing Names') QApplication.processEvents() nameWrite = ['{};{}'.format(s.name, r) for s, r, in zip(shapes, refIdxs)] with open(outNames, 'w') as f: f.write('\n'.join(nameWrite)) if pBar is not None: pBar.setLabelText('Writing References') QApplication.processEvents() refs.dump(outRefs)
def readAndApplyCorrectives(inPath, namePath, refPath, outPath, pBar=None): ''' Read the provided files, apply the correctives, then output a new file Arguments: inPath: The input .smpx file namePath: A file correlating the shape names, and the reference indices. Separated by ; with one entry per line refPath: The reference matrices per point of deformation. Created by npArray.dump(refPath) outPath: The output .smpx filepath ''' if pBar is not None: pBar.setLabelText("Reading reference data") QApplication.processEvents() jsString, simplex, solver, allShapePts, restPts = loadSimplex(inPath) with open(namePath, 'r') as f: nr = f.read() nr = [i.split(';') for i in nr.split('\n') if i] names, refIdxs = zip(*nr) refIdxs = map(int, refIdxs) refs = np.load(refPath) shapeByName = {i.name: i for i in simplex.shapes} shapes = [shapeByName[n] for n in names] newPts = applyCorrectives(simplex, allShapePts, restPts, solver, shapes, refIdxs, refs, pBar) writeSimplex(inPath, outPath, newPts, pBar=pBar) print "DONE"
def shapeMatchIndexes(self, indexes): # make a dict of name:object sel = DCC.getSelectedObjects() if not sel: return mesh = sel[0] pairs = coerceIndexToChildType(indexes, ProgPair) pairs = [i.model().itemFromIndex(i) for i in pairs] pairs = makeUnique([i for i in pairs if not i.shape.isRest]) # Set up the progress bar pBar = QProgressDialog("Matching Shapes", "Cancel", 0, 100, self) pBar.setMaximum(len(pairs)) # Do the extractions for pair in pairs: c = pair.prog.controller c.connectShape(pair.shape, mesh=mesh) # ProgressBar pBar.setValue(pBar.value() + 1) pBar.setLabelText("Matching:\n{0}".format(pair.shape.name)) QApplication.processEvents() if pBar.wasCanceled(): return pBar.close()
def shapeIndexExtract(self, indexes, live=None): # Create meshes that are possibly live-connected to the shapes if live is None: live = self.uiLiveShapeConnectionACT.isChecked() pairs = coerceIndexToChildType(indexes, ProgPair) pairs = [i.model().itemFromIndex(i) for i in pairs] pairs = makeUnique([i for i in pairs if not i.shape.isRest]) pairs.sort(key=lambda x: naturalSortKey(x.shape.name)) # Set up the progress bar pBar = QProgressDialog("Extracting Shapes", "Cancel", 0, 100, self) pBar.setMaximum(len(pairs)) # Do the extractions offset = 10 for pair in pairs: c = pair.prog.controller c.extractShape(pair.shape, live=live, offset=offset) offset += 5 # ProgressBar pBar.setValue(pBar.value() + 1) pBar.setLabelText("Extracting:\n{0}".format(pair.shape.name)) QApplication.processEvents() if pBar.wasCanceled(): return pBar.close()
def exportAbc(self, dccMesh, abcMesh, js, world=False, pBar=None): # export the data to alembic if dccMesh is None: dccMesh = self.mesh shapeDict = {i.name:i for i in self.simplex.shapes} shapeNames = js['shapes'] if js['encodingVersion'] > 1: shapeNames = [i['name'] for i in shapeNames] shapes = [shapeDict[i] for i in shapeNames] schema = abcMesh.getSchema() if pBar is not None: pBar.show() pBar.setMaximum(len(shapes)) spacerName = '_' * max(map(len, shapeNames)) pBar.setLabelText('Exporting:\n{0}'.format(spacerName)) QApplication.processEvents() for i, shape in enumerate(shapes): if pBar is not None: pBar.setLabelText('Exporting:\n{0}'.format(shape.name)) pBar.setValue(i) QApplication.processEvents() if pBar.wasCanceled(): return verts = mkSampleVertexPoints(self._shapes[shape.name]) if self._uvs is not None: # Alembic doesn't allow for self._uvs=None for some reason abcSample = OPolyMeshSchemaSample(verts, self._faces, self._counts, self._uvs) else: abcSample = OPolyMeshSchemaSample(verts, self._faces, self._counts) schema.set(abcSample)
def startDrag(self, o, e): if self._dragStart is None: self._dragStart = e.pos() dtop = QApplication.desktop() sn = dtop.screenNumber(o.mapToGlobal(e.pos())) self._screen = dtop.availableGeometry(sn) if abs(e.x() - self._dragStart.x()) > self.startSensitivity: self._dragType = self.DRAG_HORIZONTAL elif abs(e.y() - self._dragStart.y()) > self.startSensitivity: self._dragType = self.DRAG_VERTICAL if self._dragType: self._leftover = 0 self._lastPos = e.pos() self._firstDrag = True self.dragPressed.emit() self.doOverrideCursor() if self.isSpinbox: if e.buttons() & self.dragButton: # Send mouseRelease to spin buttons when dragging # otherwise the spinbox will keep ticking. @longClickFix # There's gotta be a better way to do this :-/ mouseup = QMouseEvent(QEvent.MouseButtonRelease, e.pos(), self.dragButton, e.buttons(), e.modifiers()) QApplication.sendEvent(o, mouseup)
def testSliderTreeDisplay(smpxPath): simp = Simplex.buildSystemFromSmpx(smpxPath) redAttrs = set([ u'lowerLipDepressor_X', u'stretcher_X', u'platysmaFlex_X', u'cheekRaiser_X', u'jawOpen', u'lidTightener_X', u'outerBrowRaiser_X', u'eyesClosed_X', u'cornerPuller_X', u'noseWrinkler_X', u'lipsBlow_X', u'cornerDepressor_X', u'funneler', u'browLateral_X', u'innerBrowRaiser_X', u'upperLipRaiser_X', u'chinRaiser', u'cheek_SuckBlow_X', u'pucker', u'eyeGaze_DownUp_X', u'eyeGaze_RightLeft_X', u'upperLidTweak_X', u'lowerLidTweak_X' ]) greenAttrs = set([ u'nasolabialDeepener_X', u'neckStretcher_X', u'lipsPressed_T', u'lipsPressed_B', u'throatCompress', u'lipsRolled_InOut_B', u'lipsRolled_InOut_T', u'sharpCornerPuller_X', u'dimpler_X', u'eyeBlink_X', u'scalpSlide_BackFwd', u'browDown_X', u'mouthSwing_RightLeft', u'sternoFlex_X', u'throatOpen' ]) blueAttrs = set([ u'adamsApple', u'noseSwing_RightLeft', u'nostrilCompress_X', u'jawThrust_BackFwd', u'eyesWide_X', u'lipsVerticalT_X', u'lipsVerticalB_X', u'earPull_X', u'lipsTighten_T', u'lipsTighten_B', u'lipsCompress_T', u'lipsCompress_B', u'lipsShift_RightLeft_B', u'lipsShift_RightLeft_T', u'lipsNarrowT_X', u'lipsNarrowB_X', u'jawSwing_RightLeft', u'nostril_SuckFlare_X', u'lipsCorner_DownUp_X', u'jawClench' ]) greyAttrs = set([u'lipsTogether']) app = QApplication(sys.argv) #tv = ChannelTree() tv = QTreeView() model = ChannelTreeModel(simp, None) #delegate = ChannelBoxDelegate() #slideFilter = SlideFilter(tv.viewport()) #slideFilter.slideButton = Qt.LeftButton #tv.viewport().installEventFilter(slideFilter) #slideFilter.slidePressed.connect(tv.slideStart) #slideFilter.slideReleased.connect(tv.slideStop) #slideFilter.slideTick.connect(tv.slideTick) #for g in simp.sliderGroups: #for item in g.items: #if item.name in redAttrs: #item.color = QColor(178, 103, 103) #elif item.name in greenAttrs: #item.color = QColor(90, 161, 27) #elif item.name in blueAttrs: #item.color = QColor(103, 141, 178) #elif item.name in greyAttrs: #item.color = QColor(130, 130, 130) tv.setModel(model) #tv.setItemDelegate(delegate) tv.show() sys.exit(app.exec_())
def exportUnsub(inPath, outPath, newFaces, kept, shapePrefix=None, pBar=None): ''' Export the unsubdivided simplex ''' iarch = IArchive(str(inPath)) # because alembic hates unicode top = iarch.getTop() ixfo = IXform(top, top.children[0].getName()) iprops = ixfo.getSchema().getUserProperties() iprop = iprops.getProperty("simplex") jsString = iprop.getValue() if shapePrefix is not None: d = json.loads(jsString) if d['encodingVersion'] > 1: for shape in d['shapes']: shape['name'] = shapePrefix + shape['name'] else: d['shapes'] = [shapePrefix + i for i in d['shapes']] jsString = json.dumps(d) imesh = IPolyMesh(ixfo, ixfo.children[0].getName()) verts = getSampleArray(imesh) verts = verts[:, kept] indices = [] counts = [] for f in newFaces: indices.extend(f) counts.append(len(f)) abcCounts = mkArray(IntArray, counts) abcIndices = mkArray(IntArray, indices) # `False` for HDF5 `True` for Ogawa oarch = OArchive(str(outPath), False) oxfo = OXform(oarch.getTop(), ixfo.getName()) oprops = oxfo.getSchema().getUserProperties() oprop = OStringProperty(oprops, "simplex") oprop.setValue(str(jsString)) omesh = OPolyMesh(oxfo, imesh.getName()) osch = omesh.getSchema() if pBar is not None: pBar.setValue(0) pBar.setMaximum(len(verts)) pBar.setLabelText("Exporting Unsubdivided Shapes") QApplication.processEvents() for i, v in enumerate(verts): if pBar is not None: pBar.setValue(i) QApplication.processEvents() else: print "Exporting Unsubdivided Shape {0: <4}\r".format(i + 1), sample = OPolyMeshSchemaSample(mkSampleVertexPoints(v), abcIndices, abcCounts) osch.set(sample) if pBar is None: print "Exporting Unsubdivided Shape {0: <4}".format(len(verts))
def showTree(model): app = QApplication(sys.argv) tv = QTreeView() tv.setModel(model) expandRecursive(tv, model) tv.resizeColumnToContents(0) tv.show() sys.exit(app.exec_())
def _test(): app = QApplication(sys.argv) path = r'C:\Users\tfox\Documents\GitHub\Simplex\scripts\SimplexUI\build\HeadMaleStandard_High_Unsplit.smpx' d = SimplexDialog() newSystem = Simplex.buildSystemFromSmpx(path, d.getCurrentObject(), sliderMul=1.0) d.setSystem(newSystem) d.show() sys.exit(app.exec_())
def buildFullShapes(simplex, shapeObjs, shapes, solver, restPts, pBar=None): ''' Given shape inputs, build the full output shape from the deltas We use shapes here because a shape implies both the progression and the value of the inputs (with a little figuring) ''' ########################################### # Manipulate all the input lists and caches indexBySlider = {s: i for i, s in enumerate(simplex.sliders)} indexByShape = {s: i for i, s in enumerate(simplex.shapes)} floaters = set(simplex.getFloatingShapes()) floatIdxs = set([indexByShape[s] for s in floaters]) shapeDict = {} for item in itertools.chain(simplex.sliders, simplex.combos): for pair in item.prog.pairs: if not pair.shape.isRest: shapeDict[pair.shape] = (item, pair.value) ###################### # Actually do the work vecByShape = {} # store this for later use ptsByShape = {} if pBar is not None: pBar.setMaximum(len(shapeObjs)) pBar.setValue(0) QApplication.processEvents() flatShapes = shapes.reshape((len(shapes), -1)) for i, shape in enumerate(shapeObjs): if pBar is not None: pBar.setValue(i) QApplication.processEvents() else: print "Building {0} of {1}\r".format(i+1, len(shapeObjs)), item, value = shapeDict[shape] inVec = _buildSolverInputs(simplex, item, value, indexBySlider) outVec = solver.solve(inVec) if shape not in floaters: for fi in floatIdxs: outVec[fi] = 0.0 outVec = np.array(outVec) outVec[np.where(np.isclose(outVec, 0))] = 0 outVec[np.where(np.isclose(outVec, 1))] = 1 vecByShape[shape] = outVec pts = np.dot(outVec, flatShapes) pts = pts.reshape((-1, 3)) ptsByShape[shape] = pts + restPts if pBar is None: print return ptsByShape, vecByShape
def toggleTree(self, index, expand): ''' Expand or collapse an entire sub-tree of an index ''' # Separate function to deal with filtering capability if not index.isValid(): return model = self.model() mods = QApplication.keyboardModifiers() thing = model.itemFromIndex(index) thing.expanded[id(self)] = expand if mods & (self.expandModifier | self.depthModifier): queue = [index] self.blockSignals(True) try: while queue: idx = queue.pop() thing = model.itemFromIndex(idx) thing.expanded[id(self)] = expand self.setExpanded(idx, expand) if mods & self.depthModifier: if isinstance(thing, Group): continue for i in xrange(model.rowCount(idx)): child = model.index(i, 0, idx) if child and child.isValid(): queue.append(child) finally: self.blockSignals(False) if expand: self.resizeColumns()
def importSystemFromFile(self): if self._currentObject is None: impTypes = ['smpx'] else: impTypes = ['smpx', 'json'] if blurdev is None: pref = QSettings("Blur", "Simplex3") defaultPath = str(toPyObject(pref.value('systemImport', os.path.join(os.path.expanduser('~'))))) path = self.fileDialog("Import Template", defaultPath, impTypes, save=False) if not path: return pref.setValue('systemImport', os.path.dirname(path)) pref.sync() else: # Blur Prefs pref = blurdev.prefs.find('tools/simplex3') defaultPath = pref.restoreProperty('systemImport', os.path.join(os.path.expanduser('~'))) path = self.fileDialog("Import Template", defaultPath, impTypes, save=False) if not path: return pref.recordProperty('systemImport', os.path.dirname(path)) pref.save() pBar = QProgressDialog("Loading Shapes", "Cancel", 0, 100, self) pBar.show() QApplication.processEvents() # TODO: Come up with a better list of possibilites for loading # simplex files, and make the appropriate methods on the Simplex if path.endswith('.smpx'): newSystem = Simplex.buildSystemFromSmpx(path, self._currentObject, sliderMul=self._sliderMul, pBar=pBar) elif path.endswith('.json'): newSystem = Simplex.buildSystemFromJson(path, self._currentObject, sliderMul=self._sliderMul, pBar=pBar) with signalsBlocked(self.uiCurrentSystemCBOX): self.loadObject(newSystem.DCC.mesh) idx = self.uiCurrentSystemCBOX.findText(self._currentObjectName) if idx >= 0: self.uiCurrentSystemCBOX.setCurrentIndex(idx) else: self.uiCurrentSystemCBOX.addItem(newSystem.name) self.uiCurrentSystemCBOX.setCurrentIndex(self.uiCurrentSystemCBOX.count()-1) self.setSystem(newSystem) pBar.close()
def applyCorrectives(simplex, allShapePts, restPts, solver, shapes, refIdxs, references, pBar=None): ''' Loop over the shapes and references, apply them, and return a new np.array of shape points simplex: Simplex system allShapePts: deltas per shape restPts: The rest point positions solver: The Python Simplex solver object shapes: The simplex shape objects we care about refIdxs: The reference index per shape references: A list of matrix-per-points ''' # The rule of thumb is "THE SHAPE IS ALWAYS A DELTA" if pBar is not None: pBar.setLabelText("Inverting References") pBar.setValue(0) pBar.setMaximum(len(references)) QApplication.processEvents() else: print "Inverting References" inverses = [] for i, r in enumerate(references): if pBar is not None: pBar.setValue(i) QApplication.processEvents() inverses.append(invertAll(r)) if pBar is not None: pBar.setLabelText("Extracting Uncorrected Shapes") QApplication.processEvents() else: print "Building Full Shapes" ptsByShape, vecByShape = buildFullShapes(simplex, shapes, allShapePts, solver, restPts, pBar) if pBar is not None: pBar.setLabelText("Correcting") QApplication.processEvents() else: print "Correcting" newPtsByShape = {} for shape, refIdx in zip(shapes, refIdxs): inv = inverses[refIdx] pts = ptsByShape[shape] newPts = applyReference(pts, inv) newPtsByShape[shape] = newPts newShapePts = collapseFullShapes(simplex, allShapePts, newPtsByShape, vecByShape, pBar) newShapePts = newShapePts + restPts[None, ...] return newShapePts
def shapeConnectFromSelection(self): if self.simplex is None: return # make a dict of name:object sel = DCC.getSelectedObjects() selDict = {} for s in sel: name = DCC.getObjectName(s) if name.endswith("_Extract"): nn = name.rsplit("_Extract", 1)[0] selDict[nn] = s pairDict = {} for p in self.simplex.progs: for pp in p.pairs: pairDict[pp.shape.name] = pp # get all common names selKeys = set(selDict.iterkeys()) pairKeys = set(pairDict.iterkeys()) common = selKeys & pairKeys # get those items pairs = [pairDict[i] for i in common] # Set up the progress bar pBar = QProgressDialog("Connecting Shapes", "Cancel", 0, 100, self) pBar.setMaximum(len(pairs)) # Do the extractions for pair in pairs: c = pair.prog.controller c.connectShape(pair.shape, delete=True) # ProgressBar pBar.setValue(pBar.value() + 1) pBar.setLabelText("Connecting:\n{0}".format(pair.shape.name)) QApplication.processEvents() if pBar.wasCanceled(): return pBar.close()
def unifySelection(self): ''' Clear the selection if no modifiers are being held ''' mods = QApplication.keyboardModifiers() if not mods & (Qt.ControlModifier | Qt.ShiftModifier): selModel = self.selectionModel() selModel.blockSignals(True) try: selModel.clearSelection() finally: selModel.blockSignals(False) self.viewport().update()
def unifyComboSelection(self): ''' Clear the selection of the slider tree when an item on the combo tree is selected ''' mods = QApplication.keyboardModifiers() if not mods & (Qt.ControlModifier | Qt.ShiftModifier): sliderSelModel = self.uiSliderTREE.selectionModel() if not sliderSelModel: return with signalsBlocked(sliderSelModel): sliderSelModel.clearSelection() self.uiSliderTREE.viewport().update()
def shapeConnectIndexes(self, indexes): pairs = coerceIndexToChildType(indexes, ProgPair) pairs = [i.model().itemFromIndex(i) for i in pairs] pairs = makeUnique([i for i in pairs if not i.shape.isRest]) # Set up the progress bar pBar = QProgressDialog("Connecting Shapes", "Cancel", 0, 100, self) pBar.setMaximum(len(pairs)) # Do the extractions for pair in pairs: c = pair.prog.controller c.connectShape(pair.shape, delete=True) # ProgressBar pBar.setValue(pBar.value() + 1) pBar.setLabelText("Extracting:\n{0}".format(pair.shape.name)) QApplication.processEvents() if pBar.wasCanceled(): return pBar.close()
def testNewChild(path): simp = buildDummySystem(path) model = SimplexModel(simp, None) model = SliderModel(model) model = SliderFilterModel(model) app = QApplication(sys.argv) topWid = QWidget() lay = QVBoxLayout(topWid) tv = QTreeView(topWid) btn = QPushButton('NEW', topWid) lay.addWidget(tv) lay.addWidget(btn) tv.setModel(model) topWid.show() expandRecursive(tv, model) tv.resizeColumnToContents(0) def newCallback(): sel = tv.selectedIndexes() sel = [i for i in sel if i.column() == 0] items = [s.model().itemFromIndex(s) for s in sel] item = items[0] # TODO # find the child type of item # make a new one of those tv.model().invalidateFilter() btn.clicked.connect(newCallback) sys.exit(app.exec_())
def doOverrideCursor(self): if self._overridden: return if self.dragCursor == self.CURSOR_BLANK: QApplication.setOverrideCursor(Qt.BlankCursor) elif self.dragCursor == self.CURSOR_ARROWS: if self._dragType == self.DRAG_VERTICAL: QApplication.setOverrideCursor(Qt.SizeVerCursor) elif self._dragType == self.DRAG_HORIZONTAL: QApplication.setOverrideCursor(Qt.SizeHorCursor) self._overridden = True
def restoreOverrideCursor(self): if not self._overridden: return QApplication.restoreOverrideCursor() self._overridden = False
def doOverrideCursor(self): if self._overridden: return QApplication.setOverrideCursor(self.slideCursor) self._overridden = True
def collapseFullShapes(simplex, allPts, ptsByShape, vecByShape, pBar=None): ''' Given a set of shapes that are full-on shapes (not just deltas) Collapse them back into deltas in the simplex shape list ''' ####################### # Manipulate all the input lists and caches #indexBySlider = {s: i for i, s in enumerate(simplex.sliders)} indexByShape = {s: i for i, s in enumerate(simplex.shapes)} floaters = set(simplex.getFloatingShapes()) #floatIdxs = set([indexByShape[s] for s in floaters]) newPts = np.copy(allPts) # Order the combos by depth, and split out the floaters allDFirst = sorted(simplex.combos[:], key=lambda x: len(x.pairs)) dFirst, dFloat = [], [] for c in allDFirst: app = dFloat if c.isFloating() else dFirst app.append(c) # first do the sliders for item in simplex.sliders: for pair in item.prog.pairs: if pair.shape in ptsByShape: idx = indexByShape[pair.shape] newPts[idx] = ptsByShape[pair.shape] # Get the max number of iterations mxcount = 0 for c in itertools.chain(dFirst, dFloat): for pair in c.prog.pairs: if pair.shape in ptsByShape: mxcount += 1 if pBar is not None: pBar.setValue(0) pBar.setMaximum(mxcount) pBar.setLabelText("Building Corrected Deltas") QApplication.processEvents() # Then go through all the combos in order vcount = 0 for c in itertools.chain(dFirst, dFloat): for pair in c.prog.pairs: if pair.shape in ptsByShape: if pBar is not None: pBar.setValue(vcount) QApplication.processEvents() else: print "Collapsing {0} of {1}\r".format(vcount + 1, mxcount), vcount += 1 idx = indexByShape[pair.shape] outVec = vecByShape[pair.shape] outVec[idx] = 0.0 # turn off the influence of the current shape comboBase = np.dot(outVec, newPts.transpose((1, 0, 2))) comboSculpt = ptsByShape[pair.shape] newPts[idx] = comboSculpt - comboBase if pBar is None: print return newPts
def buildCorrectiveReferences(mesh, simplex, poses, sliders, pBar=None): ''' Take correlated poses and sliders, and expand down the simplex combo tree, building references for each required shape Inputs: simplex <SimplexSystem> : A simplex system solver <PySimplex> : An instantiated simplex value solver poses <Prop/Value pair lists> : Different rig poses shapes <SimplexShapes> : Shape objects correlated to the poses ''' # cache the pose search # Pre-cache the combo search allCombosBySliderValue = {} for c in simplex.combos: for p in c.pairs: allCombosBySliderValue.setdefault((p.slider, p.value), []).append(c) # This is only my subset set of downstreams # Get the downstreams by slider and value sliderValuesByCombo = {} for slider in sliders: for p in slider.prog.pairs: combos = allCombosBySliderValue.get((slider, p.value), []) for combo in combos: sliderValuesByCombo.setdefault(combo, []).append((slider, p.value)) #out = [] refCache = {} refs, shapes, refIdxs = [], [], [] # get the slider outputs if pBar is not None: pBar.setLabelText("Building Shape References") pBar.setValue(0) mv = 0 for slider in sliders: for p in slider.prog.pairs: if not p.shape.isRest: mv += 1 pBar.setMaximum(mv) QApplication.processEvents() poseBySlider = {} for slider, pose in zip(sliders, poses): poseBySlider[slider] = pose for p in slider.prog.pairs: if not p.shape.isRest: if pBar is not None: pBar.setValue(pBar.value()) QApplication.processEvents() cacheKey = frozenset([(slider, p.value)]) if cacheKey in refCache: idx = refCache[cacheKey] refIdxs.append(idx) else: ref = getRefForPoses(mesh, [pose], p.value) refIdxs.append(len(refs)) refCache[cacheKey] = len(refs) refs.append(ref) shapes.append(p.shape) # Get the combo outputs if pBar is not None: pBar.setLabelText("Building Combo References") pBar.setValue(0) mv = 0 for combo in sliderValuesByCombo.iterkeys(): for p in combo.prog.pairs: if not p.shape.isRest: mv += 1 pBar.setMaximum(mv) QApplication.processEvents() for combo, sliderVals in sliderValuesByCombo.iteritems(): #components = frozenset(sliderVals) poses = [poseBySlider[s] for s, _ in sliderVals] for p in combo.prog.pairs: if not p.shape.isRest: if pBar is not None: pBar.setValue(pBar.value()) QApplication.processEvents() cacheKey = frozenset(sliderVals) if cacheKey in refCache: idx = refCache[cacheKey] refIdxs.append(idx) else: ref = getRefForPoses(mesh, poses, p.value) refIdxs.append(len(refs)) refCache[cacheKey] = len(refs) refs.append(ref) shapes.append(p.shape) return np.array(refs), shapes, refIdxs
def importObjFolder(self, folder): ''' Import all objs from a user selected folder ''' if not os.path.isdir(folder): QMessageBox.warning(self, 'Warning', 'Folder does not exist') return paths = os.listdir(folder) paths = [i for i in paths if i.endswith('.obj')] if not paths: QMessageBox.warning(self, 'Warning', 'Folder does not contain any .obj files') return shapeDict = {shape.name: shape for shape in self.simplex.shapes} inPairs = {} for path in paths: shapeName = os.path.splitext(os.path.basename(path))[0] shape = shapeDict.get(shapeName) if shape is not None: inPairs[shapeName] = path else: sfx = "_Extract" if shapeName.endswith(sfx): shapeName = shapeName[:-len(sfx)] shape = shapeDict.get(shapeName) if shape is not None: inPairs[shapeName] = path sliderMasters, comboMasters = {}, {} for masters in [self.simplex.sliders, self.simplex.combos]: for master in masters: for pp in master.prog.pairs: shape = shapeDict.get(pp.shape.name) if shape is not None: if shape.name in inPairs: if isinstance(master, Slider): sliderMasters[shape.name] = master if isinstance(master, Combo): comboMasters[shape.name] = master comboDepth = {} for k, v in comboMasters.iteritems(): depth = len(v.pairs) comboDepth.setdefault(depth, {})[k] = v pBar = QProgressDialog("Loading from Mesh", "Cancel", 0, len(comboMasters) + len(sliderMasters), self) pBar.show() for shapeName, slider in sliderMasters.iteritems(): pBar.setValue(pBar.value() + 1) pBar.setLabelText("Loading Obj :\n{0}".format(shapeName)) QApplication.processEvents() if pBar.wasCanceled(): return path = inPairs[shapeName] mesh = self.simplex.DCC.importObj(os.path.join(folder, path)) shape = shapeDict[shapeName] self.simplex.DCC.connectShape(shape, mesh=mesh, live=False, delete=True) for depth in sorted(comboDepth.keys()): for shapeName, combo in comboDepth[depth].iteritems(): pBar.setValue(pBar.value() + 1) pBar.setLabelText("Loading Obj :\n{0}".format(shapeName)) QApplication.processEvents() if pBar.wasCanceled(): return path = inPairs[shapeName] mesh = self.simplex.DCC.importObj(os.path.join(folder, path)) shape = shapeDict[shapeName] self.simplex.DCC.connectComboShape(combo, shape, mesh=mesh, live=False, delete=True) pBar.close()