Mar 8 2015

Vimeo Mango site!

If you haven’t check it out already….

Mango now has it’s on page, with tons of short demos show that mango pipeline tools set…

check it out!
https://vimeo.com/mangopipeline

also if you’re on facebook like the mango page!
https://www.facebook.com/mangoPipeline


May 16 2014

Resetting Skinwrap Modifiers via maxscript

If you’re reading this right now, you’re probably trying to figure out why the F*&%$@ the built in method for resetting a skin-wrap in max, meshDeformOps.reset(), is doing absolutely nothing for you…
Turns out this method is broken in max.
Here’s a little hack that will allow press the reset button it’s self on any skinwrap via maxscript allowing you to by pass this roadblock.

cheers,

Los.

fn resetSkinWrap md = 
(
	deselect $*
	select (refs.dependentNodes md)[1]
	max modify mode
	modpanel.setcurrentobject md

	maxHWND = windows.getMaxHWND() 
	for c in  (windows.getChildrenHWND maxHWND) do
	(
		if c[4] == "CustButton" and c[5] == "Reset" then
		(
			UIAccessor.PressButton c[1]
			return  True
		)
	)
	false
)
--usage
for m in (getClassInstances skin_wrap) do resetSkinWrap m


May 2 2014

Parenting Qt gui’s to the main 3dsMax window (BlurPython)

I had a chance to break down the blurdev “Dialog” class today. This class is a modified QDialog class that automatically handles parenting the dialog to the max window. The way in which the Blur Developers achieve this is by compiling a Qt4 module (QtWinMigrate) that does not ship with either PySide or PyQt4 that can convert the windows handle id of the main max window into a QObject that we can use as a parent. the process is very simple, here’s a snippet…

from blurdev.gui.winwidget import WinWidget
parent = WinWidget.newInstance(blurdev.core.hwnd()) 

Here’s an example built directly into a class that inherits a QMainWindow…

import blurdev
from blurdev.gui.winwidget import WinWidget
from PyQt4 import QtGui,QtCore, uic

class test(QtGui.QMainWindow):
	def __init__(self,parent=None):
		if not parent:
			parent = WinWidget.newInstance(blurdev.core.hwnd()) 
		super(test,self).__init__(parent)
		self.setAttribute(QtCore.Qt.WA_DeleteOnClose )
		self.setMouseTracking( True )
		self.checkScreenGeo = True
		self.aboutToClearPathsEnabled = True

gui = test()
gui.show()

last but not least here’s the example from my previous uic post using this code to parent the window to Max.

from PyQt4 import QtGui, QtCore, uic  
base,form = uic.loadUiType(r'c:\uifiles\mainUI.ui')
class mainApp(base,form):
    def __init__(self,parent=None):
        super(mainApp,self).__init__(parent)
        self.setupUi(self)
        #----
        self.populateList()
        self.connectWidgets()
    #populate a list box...
    def populateList(self):
        self.scnObjects = mxs.objects
        for o in self.scnObjects:self.listWidget.addItem(o.name)
    #-- connect event handlers
    def connectWidgets(self):
        self.listWidget.itemSelectionChanged.connect(self.selectObjects)
        self.pushButton.clicked.connect(self.pressButton)
    #--list box events
    def selectObjects(self):
        sel = []
        mxs.deselect(mxs.objects)
        for i in self.listWidget.selectedItems():
            obj = self.scnObjects[(self.listWidget.indexFromItem(i).row())]
            sel.append(obj)
        mxs.select(sel)
        mxs.ForceCompleteRedraw()
    #-- button event
    def pressButton(self):
        sel = self.listWidget.selectedItems()
        QtGui.QMessageBox.about(self,'QtMessage',"%i objects selected" % len(mxs.selection))

def open():
	from blurdev.gui.winwidget import WinWidget
	app = mainApp(parent=WinWidget.newInstance(blurdev.core.hwnd()))
	app.show()
	return app

test = open()

Give it a go, i hope it works for you. Until next time, happy coding!


Feb 7 2014

PySide Rendering HTML pages as images via QWebKit

I’m currently working on a small python script to create slates for frame sequences. i figure it would be a nice if the tool could make slates with custom data without the use of 3d party software such as nuke (which is common practice) to build and populate the information…
it then occurred to me, that i could create slate templates via html and css. Giving my clients total control over the design of the slate. My tool would then simply run a search and replace on the html file to populate the key fields that are unique to the slate and then render the html page, as an image to be loaded as the first frame of the sequence….
the over all approach is simple, the only tricky part was figuring out how to use the QWebKit module of PySide to load a local html page and then render it as an image.
Here’s a simple snippet of what i came up with…


from PySide import QtCore,QtGui,QtWebKit
import sys


app = QtGui.QApplication(sys.argv)

view = QtWebKit.QWebPage()
loop = QtCore.QEventLoop()
view.mainFrame().loadFinished.connect(loop.quit)
view.mainFrame().load('http://www.losart3d.com')
loop.exec_()
print 'done loading page proceed to rendering'
size = view.mainFrame().contentsSize()

view.setViewportSize(size)#.viewportSize())
image = QtGui.QImage(size,QtGui.QImage.Format_ARGB32_Premultiplied)
image.fill(QtCore.Qt.transparent)

p = QtGui.QPainter(image)
p.setRenderHint(QtGui.QPainter.Antialiasing,True)
p.setRenderHint(QtGui.QPainter.TextAntialiasing,True)
p.setRenderHint(QtGui.QPainter.SmoothPixmapTransform,True)

view.mainFrame().render(p)
p.end()

image.save(r'c:\temp\renderedPage.jpg')
            

print 'done!'

Feb 5 2014

PySide QThread and Dynamicly updateing ui’s

 

I’ve recently have been diving more in depth into qthread and how it can help make  GUIs  more interactive, specially when dealing with large data sets, where the programer might want to offload the data collection and processing methods to secondary threads as not to lock up the ui.

I’m still kind of new to the subject, so it’s taken me a while to get a clean working example, and how to set this up. I’ve used q thread before to achieve the effect, but it’s always been hard to know if my over understanding and approach to the method is the most optimized. after lot’s of online digging i found this approach to dealing with threading to work pretty well and be relatively easy to setup.

enjoy!

'''
testing thread ui
by Carlos Anguiano
'''
from PySide import QtCore,QtGui
import sys, random

#inherit from Qthread and setup our own thread class
class upateThread(QtCore.QThread):
    progress = QtCore.Signal(str) #create a custom sygnal we can subscribe to to emit update commands
    def __init__(self,parent=None):
        super(upateThread,self).__init__(parent)
        self.exiting = False

    def run(self):
        while True:
            self.msleep(10)
            self.progress.emit(str(random.randint(0,100)))

class myDialog(QtGui.QDialog):
    def __init__(self,parent=None):
        super(myDialog,self).__init__(parent)
        self.resize(200,0)
        self.qlabel = QtGui.QLabel(self)
        self.qlabel.setText('Processor:')
        self.qlabelSt = QtGui.QLabel(self)
        self.btn = QtGui.QToolButton(self)
        l = QtGui.QVBoxLayout(self)

        l.addWidget(self.qlabel)
        l.addWidget(self.qlabelSt)
        l.addWidget(self.btn)

        self.btn.pressed.connect(lambda :self.qlabelSt.setText(str(random.randint(0,100))))

        self.setupUpdateThread()

    def updateText(self,text):
        self.qlabel.setText('random number: '+text)

    def setupUpdateThread(self):
        self.updateThread = upateThread()
        #connect our update functoin to the progress signal of the update thread
        self.updateThread.progress.connect(self.updateText,QtCore.Qt.QueuedConnection) 
        if not self.updateThread.isRunning():#if the thread has not been started let's kick it off
            self.updateThread.start()

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    win = myDialog()
    win.show()
    sys.exit(app.exec_())

Oct 4 2013

Python in 3ds Max 2014 first impressions..

Well folks, it’s finally here… just a few days ago Autodesk released it’s 3dsmax 2014 extension to those who are members of the subscription program.

This extension release is something that I’ve been very excited about ,and have been looking forward to  ever since the new features were first announced.

Well thankfully the wait is over. I’ve spent some time today checking out the new implementation trying to figure out what this update will mean to future mango development for 3ds max (which I would rather do in python and PySide so that apps can float between Max, Maya, Nuke).

Anyway here are some of my first impressions along with some snippets from today’s familiarization session, I hope they might be insightful.

This is not Blur Python

While evaluating the new python implementation in max 2014, it becomes very hard not to compare it to Blur python. They are both CPython implementations. But that’s about where the similarities end. If you have experience working with Blur Python this first installment of 3dsmax python by autodesk is going to be somewhat of hard pill to swallow.
Unlike Py3dsMax(blur python), maxPlus (autodesk python) does not really expose the same set of libraries and methods that people familiar with maxscript already know and love. Instead it exposed a very small (it’s actually pretty large) subset of the max SDK, and relies heavily on the idea, that programers will do most of the max interactions by writing python string containing max script code.
This string are then to be evaluated by “maxPlus.Core.EvalMAXScript” python method. In my opinion this will alienate allot of people.

  • Those who are familiar with maxscript but are new to python will have to learn a whole new way of working with the limited set of exposed functions, and a brand new methodology behind creating and manipulating objects and data in max. Everything you know about max-script is now obsolete.
  •  Those who looked at python as a bridge to write tools for max with out having to learn maxscript will still have to learn maxscript to access the majority of functions and methods available via maxscript.

I’m hoping that the awkwardness of MaxPlus is just due to it’s infancy, and that in the next year or so it will be expanded to equal or even best blur python. At first glance it seems Autodesk really did the bare minimum. We can only hope that this was a time limitation, and that they will continue to devote time to growing the max python ecosystem.

No Python.import

One of Blur Python’s coolest features was the ability to import python modules right into maxscript via the “python.import” method.
This was really great for production, since any max scripter could use python libraries straight in maxscript with out knowing anything about python. For anyone that has used this feature to quickly harness the power of python external libraries inside of their native maxscript code, this will more than likely be very sad news. I really hope Autodesk can bring this feature back since it opens up the power of python to a much larger sets of users.

Where is PySide/PyQt?

Well not surprisingly Autodesk has decided not include PySide or PyQt with it’s new implementation of Python. The fact that PySide doesn’t come integrated with this first release of python is incredibly disappointing. Especially since I have been running Blur Python (Without Qt) in 2014 for months now, the Autodesk implementation of Python is a major downgrade when compared to Blur Python. This alone will keep me from upgrading current mango clients to this new extension (mango currently uses blur Python).

I really hope that they will spend sometime integrating PySide by the time 3ds max 2015 comes out. Switching from Py3dsMax (Blur Python) to MaxPlus (Autodesk Python) is going to be painful, but a properly supported PySide module would really make the switch worth it.

DIY PySide?

While Autodesk failed to give us an easy to use PySide implemention similar to the ones natively supported in Nuke and Maya, they were nice enough to include some documentation that the more technically inclined can use to compile PySide (that’s right! you going to compile stuff!!) against the proper builds of qt and python that are now bundled with max (Python 2.7.3, Qt 4.8.2). From the documentation hints, I was able to actually make my own image of PySide that allows me to start using Qt inside of 3dsmax 2014. This process while a bit technical and esoteric, is actually not to difficult and requires zero programing experience, I recommend that anyone interested actually try it. If you are too lazy to do it your self,  you can try using my compiled installer (use it at your own risk) , which can be found here .
After installing my newly compiled PySide build, I set to do some basic testing using the following snippets. My initial test was just a QMessageBox…

st = "
import sys
import MaxPlus
from PySide import QtGui, QtCore
msg = 'hello'

n = MaxPlus.Core.GetRootNode()
msg = 'objects in scene:\\n'
for c in n.Children:
	msg += '%s%s%s' % ('\\t',c.Name,'\\n')

msg = str(msg)

app = QtGui.QApplication.instance()
if app == None:
	app = QtGui.QApplication([])

QtGui.QMessageBox.about(None,'PySide',msg)
"
python.execute st

This messagebox was just a way to test that the PySide was actually being loaded and working in max, and that python could collect some data from max and pass it to Qt.

While I was writing this snippet there were a few things that I noticed that seem strange.

  • Modal windows have no effect on the max session. It’s not really clear to me how to parent Qt windows to the max application it self. So modal windows which would usually freeze max until the user close the dialog are not actually freezing max.
  • Executing a QApplication is not needed, doing so actually really screws up the max environment, the behavior makes seem as if qt and python are not running on the main max thread. But I’m more than likely just missing a step.

Other than those strange oddities PySide seems to actually be working. Even with out executing the QApplication I can launch dialogs add widgets via the .show() and exec_() methods. exec_() seems to have absolutely no effect on the max session itself (same as qmessagebox) which is very strange.

Here’s my second test a simple Dialog snippet example…

st = "
from PySide import QtCore, QtGui

class mApp(QtGui.QDialog):
	def __init__(self,parent=None):
		super(mApp,self).__init__(parent)
		vL = QtGui.QVBoxLayout(self)
		for i in range(5):
			cb = QtGui.QComboBox(self)
			vL.addWidget(cb)
		btn = QtGui.QPushButton(self)
		vL.addWidget(btn)
		btn.setText('press me')
		btn.clicked.connect(lambda:QtGui.QMessageBox.about(self,'Modal Test','is this modal?'))

app = QtGui.QApplication.instance()
if app == None:
	app = QtGui.QApplication([''])

ui = mApp()
ui.show()

"
python.execute st

here’s what it looks like..

 

Conclusion

Even though Autodesk’s first version of Python for max leaves a lot to be desired, I’m vary happy that Autodesk has actually taken on the task of bringing this very important feature to max. Not having to depend on a 3rd party to provided python support will make it much easier for studios to migrate to feature version of 3ds max with out fear of breaking their pipeline. With today’s need for python and Qt in the never ending realm of unified pipelines an awkward implementation of python, and a ghetto home brew of PySide are much better than NO PYTHON and NO PYSIDE.

I’m looking forward to experimenting with Mango and 3ds Max using this setup, and seeing what new knowledge tips and tricks the community will bring forth in the upcoming months…

Until next time..

Stay frosty my friends 🙂


Sep 12 2013

Mango Version Viewer & Dependecy Tracking

I’m happy to share with you guys a screen grab of the dependency viewer for “mango version viewer”.. view the versions associated with any element being reviewed any time any place with out out having to open the work-files them self’s
dependencies are hierarchical so that you can easily view them in a natural way…

 


Sep 1 2013

Mango Phase 1

Some time has passed since my last Mango related post. Thankfully, I have made significant progress. I’m glad to announce that Mango Phase 1 will be completed in the next few weeks. There are three important developments which I will address in this post: resource-tracking, the Software Launcher, and user applications and tools (stand-alone and software-integrated).

 

Mango’s Resource-Tracking

Mango Phase 1 has been about setting up the structure on which the entire pipeline is based. I implemented base APIs that will support all of the core stand-alone applications and software-integrated tools. The two most significant APIs in this stage of development are:

  • versionTracker (API for versioning of resources with database backend)
  • namingAPI (API for generating the folder structure that host the files that make up the files associated with versions made by versionTracker)

These two main components come together to create a resource-tracking system. In Phase 1, the development of the resource-tracking system has been focused on the needs of smaller studios in rapid production environments. This focus allows smaller studios to start using resource-tracking without being overly intrusive or creating a bottleneck for the artist by over-departmentalizing the process. To achieve this implementation, Mango Phase 1 concentrated on establishing the standards and practices necessary for creating and tracking the main resource types that are the most important in the “generalist” environment. In particular, I have focused on artist “work files”, “render elements”, and “shot plates.” In Phase 2, I will move toward more detailed resource-tracking and implement new resource types for “models”, “rigs”, “animation caches”, “cameras,” and “shaders.”

Mango’s Software Launcher

The Software Launcher is the common entrance to the pipeline. It is a stand-alone application that allows supervisors to control the software configuration by creating unique profiles for their projects. These profiles control which software, plug-ins, third party tools, and extensions are used by artists on their projects. Profiles allow artist to jump between projects, while guaranteeing that every artist under the same project has the same set of tools. Moreover, this profile mechanism allows supervisors to adopt new software or plugin versions without unintended negative effects on concurrent projects.  The Software Launcher and its profile mechanisms means that studios no longer have to rely on IT to push plug-in installations over large networks via more traditional time-consuming means that can be unreliable (e.g., MSI, Psexec, manual installations).

The connection between Mango and the artist’s software relies on the modular plug-in distribution system of the Software Launcher. Mango and its tools get attached to the target application via the “LosPipeLine” Software Launcher module which should be part of every Software Launcher profile. The Software Launcher also offers and optional command line mode. This mode is used to apply the profile-based software configuration approach to network rendering solutions, such as Thinkbox’s Deadline.

User Applications ( stand alone and software-integrated)

Additionally, the deployment of Phase 1  focused on the “hand off” of  resources across the different disciplines of the shot creation process (e.g., how a lighter hands off lighting elements to a compositor). Mango is composed of several applications and tools, both stand-alone and software-integrated. These tools are easy-to-use interfaces for artists, supervisors, and managers to facilitate the adoption of the Mango workflow. Here’s a list of the initial set of applications and tools that are bundled with Mango Phase 1:

  • Project Manager (stand-alone)
    • Simple interface for quickly creating the base directory for a new project
    • Allows for adding sequences and shots at anytime to any project

 

  • Workspace Manager (Integrated with 3ds max, maya, and nuke)
    • Simple interface for creating and navigating artists’ work areas, work files, and snap shots

  • Render Element Farm Submission Tool (Integrated with 3ds max via custom render pass manager)
    • Integrated element publishing and dependency tracking

  • Comp Central (Integrated with nuke)
    • Interface for browsing, importing, and updating render elements, plates, and cameras related to a shot directly from nuke

  • Element Publish (Nuke)
    • Publish comp, precomp, paint resources out of nuke
    • Automatically configure and version up your read nodes
    • Local or farm (via Deadline) publishing

  • Version Viewer (stand-alone)
    • Tool for quickly listing, navigating, and filtering all resources and their versions for a particular project, sequence, or shot

  • Plate Ingestion Tool (Integrated with Version Viewer)
    • Quickly publishes plate resources into the pipeline along with any other auxiliary data (e.g., camera information, hdri data, lens distortion, and LUTs)


Apr 26 2013

Modular Asset Pipeline Flow (Standards And Practices)

One of the main interests in my career has been developing a way in which I could optimize the process of creating and revising animated content in 3d through uniform standards and practices. My interest in this topic is rooted in my experience as a Character Technical Director (TD). A Character TD collaborates with many different departments. For example, he is the one that makes sure that models are technically sound for rigging. He also has to collaborate with animators to ensure that the animation set-ups are simple yet powerful enough for the animator to be able to achieve the desired performance. A Character TD interacts with lighting and effects to make sure that the animated performance transfers from animation department to the lighting department without breaking. He is usually in charge of adding more animated detailed to assets via simulations like hair and cloth. These are just a few of the responsibilities of a Character TD,basically, he has his hands in everything. Owing to their work responsibilities, most Character TDs frequently assume some of the responsibilities of pipeline development.

While I’ve been fortunate enough to work at studios that have had well-designed asset-based pipelines, I have worked at others that have failed to develop the standards and practices necessary to implement such a pipeline. I have drawn on these professional experiences in both kinds of studios to develop a specialization in writing 3D pipelines and developing this, often missing, set of standards and practices. The link below is an image of an up-to-date concept map of how assets should flow and can be developed through a pipeline. There are many benefits to implementing this kind of pipeline. A few of the most notable include:

  • Modeling, rigging, shading, lighting, effects, and animation can evolve parallel to each other rather than being linearly dependent. This monumentally increases the speed with which people can accomplish work by eliminating a known bottleneck.
  • It facilitates the tracking of different versions of a resource that form an asset and even allow roll-back. This ensures that artists always have the correct versions of resources on which their work depends.
  • It eliminates the need of transitioning from previs to postvis work. This avoids a common redundant step in many small studio pipelines.

This standardized asset flow allows for a very simple database model which is able to track and manage the work greatly simplifying the development of a PTS system (mango pts).

Hopefully, I will be able to blog in more detail about this soon.

Until next time!

 

Modular Asset Pipeline Flow

 


Apr 12 2013

Deploying Blur Python and QT for 3ds max in your studio..

So recently i had to figure out how to deploy Blur Python at pixomondo. most of you are probably thinking what’s the big deal?
blur python comes with an nice self contained installer? you just run the installer and “finito” Blur python for max is deployed…
well unfortunately, this type of installation is not ideal in a large studio where hundreds of machines might need python installed deployed and configured. needless to say that if you ever need to remove or upgrade the plugin this method can turn into a nightmare to manage.

Obviously this particular scenario is not unique to blur python, but it’s actually very common when configuring and managing all the 3rd party plugins that a studio might use at any given time along with max. in this situation most places that have the ability and resources to do so you usually setup up a bat file or script that artist can use to launch max.. this script usually copies all the script plugins and thing the artist needs from a network location and then initiates max start-up script copied over during the sync process can then configure max on start-up.. this way we can guarantee that every time the artist launches max his has the latest and greatest plugins every time he start a max session. so by now you are probably like “Blah Blah Blah, what does that have to do with running blur python from the network?”..

well the thing is that, if you ever tried to deploy blur python to a machine by poorly copying files or trying to load things from the network you might brake your max installation all together.. that’s why i figure i put this poorly written article together, and try and document what I’ve had to do to get blur python and blur qt running inside of max.

Ok so for my case test i was installing

BlurOffline_python26_2013-01-28_install_13200_64.exe on to 3dsmax 2012 sp10

it’s important to note this seance things might be different in previous or feature releases..

So the first thing we need to do to get the whole thing going, is to actually run the installer so that we can pull all the files from the installer and move them to our network location.

once you have ran the installer and made sure that blur python properly running in the test machine inside of max,  we need to find all the difference components that are needed  to run blur python, so that we can  move them to the network.

the main sections we want to concern our self with are…

  • the main python directory
    • c:\python26
  •  the folder containing all of blur Qt.dll’s
    • C:\Windows\System32\blur64
  • python26.dll
    • C:\Windows\SysWOW64\python26.dll
  • the blur python max plugin
    • c:\3dmax2012\plugins\blur\blurpython26.dlx
  • Blur Dev configuration filder
    • c:\blur
  • Blur Scripts
    • c:\3dsmax2012\scripts\starup
      • init_python.ms
      • init_pyhelper.ms
    • c:\3dsmax2012\scripts\python
  • 3dsmax factory QT dll’s
    • C:\Program Files\Autodesk\3DS Max 2012\bin\qt_bak

 

ideally we want to copy all this different components to a single network location from where to run copy or source them in from, an example of this would b