I was making these couple of doodles and some ideas that were helpful for making this were:
1. staying loose on the initial outline. I found it fun to lower the opacity and redraw another time than to think too much about getting outlines on first try.
2. staying loose on the initial greying of background. Again I really enjoyed trying out different ideas and not really thinking too much about how they would look but more about enjoying drawing the strokes and planes etc.
Also, here are some rough sketches and ideas at a python node plugin I wrote to hold some scene data I may have made some mistakes in my explanations and there may be some bugs in the code.
Hope it is helpful.
#for some error checking import sys #get necessary api functions import maya.OpenMaya as OpenMaya #need this because were making a node import maya.OpenMayaMPx as OpenMayaMPx kPluginNodeTypeName = "camNode" #using a temporary id camNodeId = OpenMaya.MTypeId(0x0000) #build our node off of Maya's our constructor needs to call parent class class camNode(OpenMayaMPx.MPxNode): #in c these are protected, they are the attribute names transform = OpenMaya.MObject() startFrame = OpenMaya.MObject() endFrame = OpenMaya.MObject() output = OpenMaya.MObject() def __init__(self): OpenMayaMPx.MPxNode.__init__(self) ##use inputs of node to generate output #@note in c explicitly give it the type for input parameters, in python types are ommited #@param plug tells us the attributes that need to be recomputed #@param use dataBlock to find all nodes attributes can use ## def compute(self,plug,dataBlock): #in c would have ommited the class part if( plug == camNode.startFrame ): print 'Great An Update in -- startFrame' #in c what is returned from block.inputValue(...) is a reference ex a MFloatVector& #in python forgetting about the type that is returned sframeHandle = dataBlock.inputValue(camNode.startFrame) startFloat = frameHandle.asFloat() print 'Start Frame is >>%d' %startFloat #mark plug as clean dataBlock.setClean(plug) if( plug == camNode.endFrame ): print 'Great An Update in -- endFrame' eframeHandle = dataBlock.inputValue(camNode.endFrame) endFloat = eframeHandle.asFloat() print 'End Frame is >>%d' %endFloat dataBlock.setClean(plug) if( plug == camNode.transform ): print 'Great An Update in -- transform' tfHandle = dataBlock.inputValue(camNode.transform) tfFloat = tfHandle.asFloat() print 'Transform is >>%d' %tfFloat dataBlock.setClean(plug) if( plug == camNode.output ): print 'Great an Update in Ouput' #in c would have passed output and maybe an error checking object outHandle = dataBlock.outputValue( camNode.output ) #mark output value as clean #in c i think would have used the handle to setClean not the dataBlock dataBlock.setClean(plug) ##allow Maya to instantiate an instance of our custom node, its called every time a new instance #of node is made ex: with Maya's createNode command #@note in c this is creator() ## def nodeCreator(): return OpenMayaMPx.asMPxPtr( camNode() ) ##create the node attributes and set their types, keyable status ets #this is called once when Maya loads the plugin ex: pressing load in plugin manager #@note in c this is initialize() ## def nodeInitializer(): #""" #similar in c, this is needed to create numeric attributes for our node #startFrame nAttr = OpenMaya.MFnNumericAttribute(); #This part actually creates the attribute, in c the create would also take a status object #also in c would have set default value separately using setDefault(...) camNode.startFrame = nAttr.create( "startFrame","sf", OpenMaya.MFnNumericData.kFloat, 0.0) #so when file is saved the attribute is written out nAttr.setStorable(1) #so setAttr commands can change this attribute, and attribute can be a connection destination nAttr.setWritable(1) #so cannot be keyframed nAttr.setKeyable(0) #endFrame nAttr = OpenMaya.MFnNumericAttribute(); camNode.endFrame = nAttr.create( "endFrame","ef", OpenMaya.MFnNumericData.kFloat, 0.0) nAttr.setStorable(1) nAttr.setWritable(1) nAttr.setKeyable(0) #transform nAttr = OpenMaya.MFnNumericAttribute(); camNode.transform = nAttr.create( "camTransform","ct", OpenMaya.MFnNumericData.kFloat, 0.0) nAttr.setStorable(1) nAttr.setWritable(1) nAttr.setKeyable(0) #output nAttr = OpenMaya.MFnNumericAttribute(); camNode.output = nAttr.create( "output","out", OpenMaya.MFnNumericData.kFloat, 0.0) nAttr.setStorable(1) nAttr.setWritable(1) nAttr.setKeyable(0) #now we add the attributes to the node, in c I think would ommit the camNode camNode.addAttribute(camNode.startFrame) camNode.addAttribute(camNode.endFrame) camNode.addAttribute(camNode.transform) camNode.addAttribute(camNode.output) #if needed startFrame to affect output attribute would add #camNode.attributeAffects( camNode.startFrame, camNode.output ) #camNode.attributeAffects( camNode.endFrame, camNode.output ) #camNode.attributeAffects( camNode.transform, camNode.output ) #""" ##so when plug in loaded Maya can register the node # ## def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: #in c i think would explicitly tell register node where to find creator, initialize, and id mplugin.registerNode( kPluginNodeTypeName, camNodeId, nodeCreator, nodeInitializer) except: sys.stderr.write("Failed register node: %s" %kPluginNodeTypeName) raise def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: #only need the id to deregister node mplugin.deregisterNode(camNodeId) except: sys.stderr.write("Failed deregister node: %s" %kPluginNodeTypeName) raise
Inspired by Maya included tutorial documentation on API especially lambertShader.cpp and sineNode.py (autodesk dot com).
Cheers,
Nate