Example #1
0
def createRawObject(name, faces, verts, uvFaces, uvs):
    mm = mxs.mesh(numverts=len(verts))
    oldUndo = mxs.execute("set undo off")
    try:
        mm.name = name
        for i in xrange(len(verts)):
            mxs.meshop.setvert(
                mm, i + 1,
                mxs.Point3(float(verts[i][0]), float(verts[i][1]),
                           float(verts[i][2])))

        mxs.convertTo(mm, mxs.PolyMeshObject)
        for face in faces:
            fPlus = [i + 1 for i in face]
            mxs.polyop.createPolygon(mm, fPlus)

        if uvs is not None:
            mxs.polyop.defaultMapFaces(mm, 1)
            mxs.polyop.setNumMapVerts(mm, 1, len(uvs), keep=False)
            mxs.polyop.setNumMapFaces(mm, 1, len(uvFaces), keep=False)

            for i in xrange(len(uvs)):
                mxs.polyop.setMapVert(
                    mm, 1, i + 1,
                    mxs.Point3(float(uvs[i][0]), float(uvs[i][1]), 0.0))

            mxs.convertTo(mm, mxs.PolyMeshObject)
            for f, face in enumerate(uvFaces):
                fPlus = [i + 1 for i in face]
                mxs.polyop.setMapFace(mm, 1, f + 1, fPlus)
    finally:
        mxs.execute("set undo {}".format('on' if oldUndo else 'off'))
    return mm
Example #2
0
    def _addNativeController(self, name, group='', tpe=float, default=0.0):

        if not group:
            group = 'Custom_Attributes'

        types = {float: 'float', int: 'integer'}

        if tpe in [float, int] and isinstance(default, tpe):

            maxScript = """fn addAttributeToObject obj = (
				attribute = attributes {group} (
					parameters main (
						{name} type:#{tpe} default:{default}
					)
				)
				CustAttributes.add obj attribute #Unique
				return obj.{name}.controller
			)"""

            mxs.execute(
                maxScript.format(name=name,
                                 group=group,
                                 tpe=types[tpe],
                                 default=default))
            return mxs.addAttributeToObject(self._nativePointer)

        else:
            raise Exception('This method only support ints ')
            return None
Example #3
0
    def addProceduralShake(self):

        listController = mxs.getPropertyController(
            self._nativePointer.controller, 'rotation')
        print mxs.classOf(listController)
        if not mxs.classOf(listController) == mxs.rotation_list:
            listController = mxs.rotation_list()
            mxs.setPropertyController(self._nativePointer.controller,
                                      'rotation', listController)

        noise = mxs.Noise_rotation()
        noise.frequency = 0.05
        noise.fractal = False
        noise.seed = random.randint(0, 10000000)

        # Got lazy here, did not have time to find the Python way to do it.
        maxScript = """fn setNoiseControllerStrength noiseController x y z = (
            noiseController.noise_strength = [x, y, z]
        )"""

        mxs.execute(maxScript)
        weirdFactor = 57.296
        mxs.setNoiseControllerStrength(noise, 0.4 / weirdFactor,
                                       0.4 / weirdFactor, 0.1 / weirdFactor)
        mxs.setPropertyController(listController, 'Available', noise)

        return True
Example #4
0
    def _connectStudiomaxSignal(self, connDef, cross3dSignal):
        """
			\remarks	Responsible for connecting a signal to studiomax
		"""
        # store the maxscript methods needed
        if connDef.callbackType == _ConnectionType.Viewport:
            signal = _STUDIOMAX_VIEWPORT_TEMPLATE % {
                'cls': 'dispatch',
                'function': connDef.function,
                'signal': cross3dSignal
            }
            # Ensure that if the old signal existed it is removed before redefining it.
            # If function is undefined it will do nothing
            mxs.unregisterRedrawViewsCallback(
                getattr(mxs, 'blurfn_%s' % cross3dSignal))
            mxs.execute(signal)
            mxs.registerRedrawViewsCallback(
                getattr(mxs, 'blurfn_%s' % cross3dSignal))
        else:
            # Connect the callback
            self._addCallback(connDef, cross3dSignal)
            # Connect any associated callbacks using a diffrent ID name allows us to disconnect
            # this signal without affecting any direct connections to the associated callbacks
            for reqDef in connDef.associated:
                self._addCallback(
                    reqDef, reqDef.signal,
                    'cross3dcallbacks_{}'.format(connDef.callback))
	def _addNativeController(self, name, group='', tpe=float, default=0.0):

		if not group:
			group = 'Custom_Attributes'

		types = {float: 'float', int:'integer'}

		if tpe in [float, int] and isinstance(default, tpe):

			maxScript = """fn addAttributeToObject obj = (
				attribute = attributes {group} (
					parameters main (
						{name} type:#{tpe} default:{default}
					)
				)
				CustAttributes.add obj attribute #Unique
				return obj.{name}.controller
			)"""

			mxs.execute(maxScript.format(name=name, group=group, tpe=types[tpe], default=default))
			return mxs.addAttributeToObject(self._nativePointer)

		else:
			raise Exception('This method only support ints ')
			return None
    def applyCache(self, path, transformIdentifier, propertiesIdentifier):

        # Applying the controller for transform.
        self._nativePointer.controller = mxs.Alembic_Xform(path=path, identifier=transformIdentifier)
    
        # Creating our own little MAXScript function for things unsupported in Py3dsMax.
        mxs.execute('fn setTimeController obj controller = (obj.controller.time.controller = controller)')

        # Creating the time controller.
        timeController = mxs.Float_Script(script='S')

        # Adding a script controller to alembic time.
        mxs.setTimeController(self._nativePointer, timeController)

        # Creating our own little MAXScript function things unsupported in Py3dsMax.
        maxScript = """fn setAlembicFloatController cam timeController = (
            cam.{prop}.controller = Alembic_Float_Controller()
            cam.{prop}.controller.path = @"{path}"
            cam.{prop}.controller.identifier = @"{identifier}"
            cam.{prop}.controller.property = @"{propertyName}"
            cam.{prop}.controller.time.controller = timeController
            return cam.{prop}.controller.time.controller
        )"""

        # These are the properties we are going to want to load alembic data on.
        cameraType = self.cameraType()
        if cameraType == CameraType.Physical:

            # We need to create a dedicated radians FOV contoller as the regular FOV controller expects degrees.
            self._addNativeController('RadianFOV', group='Alembic')
            properties = {'Alembic.RadianFOV': 'horizontalFOV', 'clip_near': 'NearClippingPlane', 'clip_far': 'FarClippingPlane', 'focus_distance': 'FocusDistance'}

        else:
            properties = {'fov': 'horizontalFOV', 'nearclip': 'NearClippingPlane', 'farclip': 'FarClippingPlane', 'mpassEffect.focalDepth': 'FocusDistance'}

        for prop in properties:
            mxs.execute(maxScript.format(prop=prop, path=path, identifier=propertiesIdentifier, propertyName=properties[prop]))
            mxs.setAlembicFloatController(self._nativePointer, timeController)

        # FOV is going to be special for V-Ray camera.
        if cameraType == CameraType.Physical:
    
            # Building a script controller for the FOV in degrees.
            scriptController = mxs.float_script()
            scriptController.addtarget('RadianFOV', mxs.getPropertyController(self._nativePointer, "RadianFOV"))

            # Using the radians FOV controller reading the Alembic and converting to degrees.
            scriptController.script = 'radToDeg(RadianFOV)'
            mxs.setPropertyController(self._nativePointer, 'fov', scriptController)

        return True
	def _nativeController( self, name ):

		# Checking inputs.
		if not isinstance(name, basestring):
			return None
			
		# Handling nested attributes. The try is here to avoid crashes. 
		# If you do not believe it, try for yourself.
		maxScript = """fn attributeValue obj = (
			value = undefined
			try value = obj.{path}
			catch()
			value
		)"""
		mxs.execute(maxScript.format(path=name))
		if mxs.attributeValue(self._nativePointer) is not None:	
			maxScript = """fn controller obj = (
				obj.{path}.controller
			)"""
			mxs.execute(maxScript.format(path=name))
			controller = mxs.controller(self._nativePointer)
			if controller is not None:
				return controller

		# Strip out controller references.
		name = name.replace('.controller', '')
		parent = self._nativePointer
		
		# look up the parent
		splt = name.split('.')
		controller = None
		parent = self._nativePointer
		
		# Start with the transform controller if necessary.
		if (splt[0] == 'transform'):
			parent = parent.controller
			controller = parent
			splt = splt[1:]
		
		for section in splt:
			controller = mxs.getPropertyController( parent, section )
			if ( not controller ):
				return None
			parent = controller
		
		return controller
Example #8
0
    def _nativeController(self, name):

        # Checking inputs.
        if not isinstance(name, basestring):
            return None

        # Handling nested attributes. The try is here to avoid crashes.
        # If you do not believe it, try for yourself.
        maxScript = """fn attributeValue obj = (
			value = undefined
			try value = obj.{path}
			catch()
			value
		)"""
        mxs.execute(maxScript.format(path=name))
        if mxs.attributeValue(self._nativePointer) is not None:
            maxScript = """fn controller obj = (
				obj.{path}.controller
			)"""
            mxs.execute(maxScript.format(path=name))
            controller = mxs.controller(self._nativePointer)
            if controller is not None:
                return controller

        # Strip out controller references.
        name = name.replace('.controller', '')
        parent = self._nativePointer

        # look up the parent
        splt = name.split('.')
        controller = None
        parent = self._nativePointer

        # Start with the transform controller if necessary.
        if (splt[0] == 'transform'):
            parent = parent.controller
            controller = parent
            splt = splt[1:]

        for section in splt:
            controller = mxs.getPropertyController(parent, section)
            if (not controller):
                return None
            parent = controller

        return controller
Example #9
0
	def register( cls ):
		# clear the old defs
		cls.clear()
		
		# define the class
		cls.define()
		
		# create the maxscript for this class and run it
		data = { 'class': cls.__name__, 'name': cls.attrName(), 'classVersion': cls.__version__, 'parameters': '', 'controls': '' }
			
		# create the parameters
		paramstr = []
		for param in cls._paramDefs.values():
			paramstr.append( param.defString() )
		
		data[ 'parameters' ] = '\n'.join( paramstr )
		
		mscript = maxscript % data
		mxs.execute( mscript )
	def _setNativeController( self, name, nativeController ):

		# strip out controller references
		name = name.replace( '.controller', '' )
		
		# Handling nested attributes.
		try:
			maxScript = """fn attributeValue obj = (
				return obj.{path}
			)"""
			mxs.execute(maxScript.format(path=name))
			if mxs.attributeValue(self._nativePointer) is not None:
				maxScript = """fn setController obj ctrl = (
					obj.{path}.controller = ctrl
				)"""
				mxs.execute(maxScript.format(path=name))
				mxs.setController(self._nativePointer, nativeController)
				return True
		except RuntimeError:
			pass

		# look up the parent
		splt 		= name.split( '.' )
		parent 		= self._nativePointer
		
		# start with the transform controller if necessary
		if ( splt[0] == 'transform' ):
			parent = parent.controller
			splt = splt[1:]
		
		for section in splt:
			parent = mxs.getPropertyController(parent, section)
			if ( not parent ):
				return False
		
		# set the property
		propname 	= splt[-1]
		try:
			mxs.setPropertyController( parent, propname, nativeController )
			return True
		except:
			return False
Example #11
0
    def _setNativeController(self, name, nativeController):

        # strip out controller references
        name = name.replace('.controller', '')

        # Handling nested attributes.
        try:
            maxScript = """fn attributeValue obj = (
				return obj.{path}
			)"""
            mxs.execute(maxScript.format(path=name))
            if mxs.attributeValue(self._nativePointer) is not None:
                maxScript = """fn setController obj ctrl = (
					obj.{path}.controller = ctrl
				)"""
                mxs.execute(maxScript.format(path=name))
                mxs.setController(self._nativePointer, nativeController)
                return True
        except RuntimeError:
            pass

        # look up the parent
        splt = name.split('.')
        parent = self._nativePointer

        # start with the transform controller if necessary
        if (splt[0] == 'transform'):
            parent = parent.controller
            splt = splt[1:]

        for section in splt:
            parent = mxs.getPropertyController(parent, section)
            if (not parent):
                return False

        # set the property
        propname = splt[-1]
        try:
            mxs.setPropertyController(parent, propname, nativeController)
            return True
        except:
            return False
Example #12
0
def getViewData():
    """"
	Gets current viewport transform matrix and returns a list of position and rotation values
	"""
    data = []

    vp = mxs.activeViewport
    viewTM = mxs.viewport.getTM()
    # We need to invert
    inverseViewTM = mxs.Inverse(viewTM)

    # MAKE THIS MORE EFFECTIVE; DONT CONVERT TO STRING AND BACK
    # get rotation data
    rot = inverseViewTM.rotationPart
    ea_rot_str = str(
        mxs.execute(str(rot) +
                    " as EulerAngles"))  # converting to euler angles
    ea_rot_xyz = ea_rot_str.split(" ")[
        1:]  # split by space and skip "eulerAngles"
    ea_rot_xyz[2] = ea_rot_xyz[2][:-1]  # then skip ")" at last element

    # order data to match persp view axes
    # default order of data 0-5 is: posX, posY, posZ, rotX, rotY, rotZ
    # http://forums.epicgames.com/threads/712799-Convert-3dsmax-rotation-to-Unreal-Rotation
    # UDK rotation order: pitch(rotY in Max), yaw(rotZ in Max), roll(rotX in Max)
    # pitch and roll are swapedp, and yaw is inverted
    # this works for PERSPECTIVE and CAMERA views, but only when we subtract 90 degrees from the x rotation later
    # the following order can be used for reordering from the default order (see above),
    # deprecated now as we built up data this way from the start now
    # return [ data[1], data[0], data[2], data[3], -data[5], data[4] ]

    # append position to data list
    # data.append(inverseViewTM.position.y)
    # data.append(inverseViewTM.position.x)
    # data.append(inverseViewTM.position.z)

    data.append(inverseViewTM.position.y)
    data.append(inverseViewTM.position.x)
    data.append(inverseViewTM.position.z)

    # append rotation to data list
    # TEMP CONVERSION TO UDK ROTATION VALUES HERE (MOVE TO UDKTRANSLATOR THEN)

    # data.append( (((float( ea_rot_xyz[0] )) - 90 ) * DegToUnrRot) % 65536 )
    # data.append( (float( ea_rot_xyz[2] ) * -1 * DegToUnrRot) % 65536 )
    # data.append( (float( ea_rot_xyz[1] ) * DegToUnrRot) % 65536 )

    data.append((float(ea_rot_xyz[0])) - 90)
    data.append(float(ea_rot_xyz[2]) * -1)
    data.append(float(ea_rot_xyz[1]))

    # print data
    return data
Example #13
0
def selectAdjacentEdges(obj, centers):
    mxs.execute('''
		function meshCralwer_toBitArray thing = (
			try (
				return (thing as bitArray)
			)
			catch ()
		)
	''')
    selectModifier = mxs.edit_poly()
    mxs.addmodifier(obj, selectModifier)

    mcenters = sorted([i + 1 for i in centers])
    vertBA = mxs.meshCralwer_toBitArray(mcenters)
    edgeBA = mxs.polyop.getEdgesUsingVert(obj, vertBA)
    emptyBA = mxs.meshCralwer_toBitArray([])
    edge = mxs.execute("#edge")

    selectModifier.setEPolySelLevel(edge)
    selectModifier.setSelection(edge, emptyBA)
    selectModifier.select(edge, edgeBA)
Example #14
0
def addChangeHandler():
	""" Adds changehandler to the current selection in 3ds Max """
	# first, reset list
	from max import objectWatcher
	objectWatcher.removeChangeHandler()
	# # add one changehandler for the whole selection to detect transform changes
	# # changeHandler = mxs.execute( "when transform selection changes handleAt:#redrawViews obj do ( python.exec(\"objectWatcher.onChanged( obj )\"))" )
	if len(mxs.selection) > 0:
		global changeHandler
		changeHandler = mxs.execute( "when transform selection changes handleAt:#redrawViews do ( python.exec(\"objectWatcher.onChanged()\"))" )
		print "OW: Adding change handler to selection"
	else:
		print "OW: Nothing selected, no changehandler added"
Example #15
0
def setAllVerts(obj, newVerts):
    if mxs.classOf(obj) == mxs.XRefObject:
        obj = obj.actualBaseObject
    if mxs.classOf(obj) in [mxs.Editable_Poly, mxs.PolyMeshObject]:
        maxAll = mxs.execute('#all')
        maxPos = [
            mxs.point3(float(i[0]), float(i[1]), float(i[2])) for i in newVerts
        ]
        mxs.polyop.setVert(obj, maxAll, maxPos)
    else:
        for i, v in enumerate(newVerts):
            mxs.setVert(obj, i + 1, *v)
    return True
	def _connectStudiomaxSignal(self, connDef, cross3dSignal):
		"""
			\remarks	Responsible for connecting a signal to studiomax
		"""
		# store the maxscript methods needed
		if connDef.callbackType == _ConnectionType.Viewport:
			signal = _STUDIOMAX_VIEWPORT_TEMPLATE % {
				'cls':'dispatch',
				'function':connDef.function,
				'signal':cross3dSignal
			}
			# Ensure that if the old signal existed it is removed before redefining it.
			# If function is undefined it will do nothing
			mxs.unregisterRedrawViewsCallback(getattr(mxs, 'blurfn_%s' % cross3dSignal))
			mxs.execute(signal)
			mxs.registerRedrawViewsCallback(getattr(mxs, 'blurfn_%s' % cross3dSignal))
		else:
			# Connect the callback
			self._addCallback(connDef, cross3dSignal)
			# Connect any associated callbacks using a diffrent ID name allows us to disconnect
			# this signal without affecting any direct connections to the associated callbacks
			for reqDef in connDef.associated:
				self._addCallback(reqDef, reqDef.signal, 'cross3dcallbacks_{}'.format(connDef.callback))
Example #17
0
def getViewData():
	""""
	Gets current viewport transform matrix and returns a list of position and rotation values
	"""
	data = []
	
	vp = mxs.activeViewport
	viewTM = mxs.viewport.getTM()
	# We need to invert 
	inverseViewTM = mxs.Inverse(viewTM)
	
	# MAKE THIS MORE EFFECTIVE; DONT CONVERT TO STRING AND BACK	
	# get rotation data 
	rot = inverseViewTM.rotationPart
	ea_rot_str = str(mxs.execute(str(rot) + " as EulerAngles")) # converting to euler angles
	ea_rot_xyz = ea_rot_str.split(" ")[1:] # split by space and skip "eulerAngles"
	ea_rot_xyz[2] = ea_rot_xyz[2][:-1] # then skip ")" at last element
		
	# order data to match persp view axes
	# default order of data 0-5 is: posX, posY, posZ, rotX, rotY, rotZ
	# http://forums.epicgames.com/threads/712799-Convert-3dsmax-rotation-to-Unreal-Rotation
	# UDK rotation order: pitch(rotY in Max), yaw(rotZ in Max), roll(rotX in Max)
	# pitch and roll are swapedp, and yaw is inverted
	# this works for PERSPECTIVE and CAMERA views, but only when we subtract 90 degrees from the x rotation later
	# the following order can be used for reordering from the default order (see above), 
	# deprecated now as we built up data this way from the start now
	# return [ data[1], data[0], data[2], data[3], -data[5], data[4] ] 
	
	# append position to data list
	# data.append(inverseViewTM.position.y)
	# data.append(inverseViewTM.position.x)
	# data.append(inverseViewTM.position.z)

	data.append(inverseViewTM.position.y)
	data.append(inverseViewTM.position.x)
	data.append(inverseViewTM.position.z)

	# append rotation to data list 
	# TEMP CONVERSION TO UDK ROTATION VALUES HERE (MOVE TO UDKTRANSLATOR THEN)

	# data.append( (((float( ea_rot_xyz[0] )) - 90 ) * DegToUnrRot) % 65536 ) 
	# data.append( (float( ea_rot_xyz[2] ) * -1 * DegToUnrRot) % 65536 ) 
	# data.append( (float( ea_rot_xyz[1] ) * DegToUnrRot) % 65536 )

	data.append((float(ea_rot_xyz[0]))-90) 
	data.append(float(ea_rot_xyz[2])*-1) 
	data.append(float(ea_rot_xyz[1]))

	# print data
	return data
Example #18
0
def addChangeHandler():
    """ Adds changehandler to the current selection in 3ds Max """
    # first, reset list
    from max import objectWatcher
    objectWatcher.removeChangeHandler()
    # # add one changehandler for the whole selection to detect transform changes
    # # changeHandler = mxs.execute( "when transform selection changes handleAt:#redrawViews obj do ( python.exec(\"objectWatcher.onChanged( obj )\"))" )
    if len(mxs.selection) > 0:
        global changeHandler
        changeHandler = mxs.execute(
            "when transform selection changes handleAt:#redrawViews do ( python.exec(\"objectWatcher.onChanged()\"))"
        )
        print "OW: Adding change handler to selection"
    else:
        print "OW: Nothing selected, no changehandler added"
    def addProceduralShake(self):

        listController = mxs.getPropertyController(self._nativePointer.controller, 'rotation')
        print mxs.classOf(listController)
        if not mxs.classOf(listController) == mxs.rotation_list:
            listController = mxs.rotation_list()
            mxs.setPropertyController(self._nativePointer.controller, 'rotation', listController)

        noise = mxs.Noise_rotation()
        noise.frequency = 0.05
        noise.fractal = False
        noise.seed = random.randint(0, 10000000)

        # Got lazy here, did not have time to find the Python way to do it.
        maxScript = """fn setNoiseControllerStrength noiseController x y z = (
            noiseController.noise_strength = [x, y, z]
        )"""
        
        mxs.execute(maxScript)
        weirdFactor = 57.296
        mxs.setNoiseControllerStrength(noise, 0.4/weirdFactor, 0.4/weirdFactor, 0.1/weirdFactor)
        mxs.setPropertyController(listController, 'Available', noise)

        return True
	def valueAtFrame(self, frame):
		mxs.execute("""fn getControllerValueAtFrame controller frame = (
			at time frame
			return controller.value
		)""")
		return mxs.getControllerValueAtFrame(self._nativePointer, frame)
Example #21
0
    def applyCache(self, path, transformIdentifier, propertiesIdentifier):

        # Applying the controller for transform.
        self._nativePointer.controller = mxs.Alembic_Xform(
            path=path, identifier=transformIdentifier)

        # Creating our own little MAXScript function for things unsupported in Py3dsMax.
        mxs.execute(
            'fn setTimeController obj controller = (obj.controller.time.controller = controller)'
        )

        # Creating the time controller.
        timeController = mxs.Float_Script(script='S')

        # Adding a script controller to alembic time.
        mxs.setTimeController(self._nativePointer, timeController)

        # Creating our own little MAXScript function things unsupported in Py3dsMax.
        maxScript = """fn setAlembicFloatController cam timeController = (
            cam.{prop}.controller = Alembic_Float_Controller()
            cam.{prop}.controller.path = @"{path}"
            cam.{prop}.controller.identifier = @"{identifier}"
            cam.{prop}.controller.property = @"{propertyName}"
            cam.{prop}.controller.time.controller = timeController
            return cam.{prop}.controller.time.controller
        )"""

        # These are the properties we are going to want to load alembic data on.
        cameraType = self.cameraType()
        if cameraType == CameraType.Physical:

            # We need to create a dedicated radians FOV contoller as the regular FOV controller expects degrees.
            self._addNativeController('RadianFOV', group='Alembic')
            properties = {
                'Alembic.RadianFOV': 'horizontalFOV',
                'clip_near': 'NearClippingPlane',
                'clip_far': 'FarClippingPlane',
                'focus_distance': 'FocusDistance'
            }

        else:
            properties = {
                'fov': 'horizontalFOV',
                'nearclip': 'NearClippingPlane',
                'farclip': 'FarClippingPlane',
                'mpassEffect.focalDepth': 'FocusDistance'
            }

        for prop in properties:
            mxs.execute(
                maxScript.format(prop=prop,
                                 path=path,
                                 identifier=propertiesIdentifier,
                                 propertyName=properties[prop]))
            mxs.setAlembicFloatController(self._nativePointer, timeController)

        # FOV is going to be special for V-Ray camera.
        if cameraType == CameraType.Physical:

            # Building a script controller for the FOV in degrees.
            scriptController = mxs.float_script()
            scriptController.addtarget(
                'RadianFOV',
                mxs.getPropertyController(self._nativePointer, "RadianFOV"))

            # Using the radians FOV controller reading the Alembic and converting to degrees.
            scriptController.script = 'radToDeg(RadianFOV)'
            mxs.setPropertyController(self._nativePointer, 'fov',
                                      scriptController)

        return True
Example #22
0
    def valueAtFrame(self, frame):
        mxs.execute("""fn getControllerValueAtFrame controller frame = (
			at time frame
			return controller.value
		)""")
        return mxs.getControllerValueAtFrame(self._nativePointer, frame)
Example #23
0
	def generatePlayblast( self, path, frameRange=None, resolution=None, slate='', effects=None, geometryOnly=True, pathFormat=r'{basePath}\{fileName}.{frame}.{ext}'):
		'''
			/option <bool> effects
		'''
		
		# Treating inputs.
		if isinstance(frameRange, int):
			frameRange = FrameRange([frameRange, frameRange])
			
		# collecting what we need
		scene = self._scene
		basePath, fn = os.path.split(path)
		fileSplit = fn.split( '.' )
		fileName = '.'.join( fileSplit[:-1] )
		initialRange = scene.animationRange()
		fileExtension = fileSplit[-1]
		
		# Creating folder if does not exist.
		dirName = os.path.dirname(path)
		if not os.path.exists(dirName):
			os.makedirs(dirName)

		# Checking inputs.
		if not frameRange:
			frameRange = initialRange
		if not resolution:
			resolution = scene.renderSize()
			
		# Setting slates.
		if slate:
			self.setSlateText(slate)
			self.setSlateIsActive(True)

		# storing infornation
		initialGeometryVisibility = mxs.hideByCategory.geometry
		initialShapesVisibility = mxs.hideByCategory.shapes
		initialLightsVisibility = mxs.hideByCategory.lights
		initialCamerasVisibility = mxs.hideByCategory.cameras
		initialHelpersVisibility = mxs.hideByCategory.helpers
		initialSpaceWarpsVisibility = mxs.hideByCategory.spacewarps
		initialParticleSystemsVisibility = mxs.hideByCategory.particles
		initialBoneObjectsVisibility = mxs.hideByCategory.bones
		initialGridVisibility = mxs.viewport.getGridVisibility( self._name )
		initialFrame = scene.currentFrame()
		initialSelection = scene.selection()
		initialSafeFrame = mxs.displaySafeFrames
		initialViewNumber = mxs.viewport.numViews

		# Getting the camera.
		camera = self.camera()
		
		# setting the scene
		scene.setAnimationRange( frameRange )
		
		# Setting the viewport.
		if geometryOnly:
			mxs.hideByCategory.geometry = False
			mxs.hideByCategory.shapes = True
			mxs.hideByCategory.lights = True
			mxs.hideByCategory.cameras = True
			mxs.hideByCategory.helpers = True
			mxs.hideByCategory.spacewarps = True
			mxs.hideByCategory.particles = False
			mxs.hideByCategory.bones = True
			
		scene.clearSelection()
		mxs.displaySafeFrames = False
		mxs.viewport.setGridVisibility( self._name, False )
		if initialViewNumber > 1:
			mxs.execute( 'max tool maximize' )
			
		# getting the viewport size information
		viewSize = self.size()
		completed = True 
		count = 0
		
		mxs.pyhelper.setViewportQuadSize( resolution.width(), resolution.height() )

		# Should we compute multi-pass effects.
		effects = camera.hasMultiPassEffects() and effects in [None, True]

		# This is my crappy way of figuring out if we are using Nitrous.
		nitrous = not mxs.gw.GetDriverString() and application.version() >= 15

		# We are going to use progressive rendering if the mode is set to Depth of Field (Mental Ray).
		physical = mxs.classof(camera.nativePointer()) in (mxs.VRayPhysicalCamera, mxs.Physical)
		progressive = nitrous and (physical or mxs.classof(camera.nativePointer().mpassEffect) == mxs.Depth_of_Field__mental_ray)

		# If the viewport is using Nitrous.
		if camera and effects and progressive:

			# Storing and setting up Nitrous options.
			nitrousSettings = mxs.NitrousGraphicsManager.GetActiveViewportSetting()
			initialFadingFactor = nitrousSettings.ProgressiveFadingFactor 
			nitrousSettings.ProgressiveFadingFactor = 0
			
		# For each frame.	
		for frame in range( frameRange[0], frameRange[1] + 1 ):
			image = None
			count = count + 1

			# Watching for Esc key.
			if mxs.keyboard.escPressed:
				completed = False
				break
			scene.setCurrentFrame(frame)

			if camera:
				if effects:

					# If we use a Nitrous viewport, we compute the depth of field the new way.
					passes = 0
					if progressive:
						while not mxs.NitrousGraphicsManager.isProgressiveRenderingFinished():
							mxs.NitrousGraphicsManager.progressiveRendering()
							passes += 1
							if passes == 32:
								break

					# Otherwise we compute it the old way by using the API method.
					else:
						camera.renderMultiPassEffects()

					# Text overlays are only supported until Max 2011.
					if slate and application.version() <= 13:
						self.slateDraw()	

				# For Max 2012 and above only the viewport object allows to save the picture with multipass effects.
				if application.version() >= 14 and effects:
					image = mxs.viewport.getViewportDib()

			if not image:
				image = mxs.gw.getViewportDib()

			imagePath = pathFormat.format(basePath=basePath, fileName=fileName, frame=frame, ext=fileExtension)
			image.filename = imagePath
			mxs.save(image)

			# Updating count.
			if count == 100:
				mxs.gc()
				count = 0
		
		# Restoring scene settings.
		scene.setAnimationRange(initialRange)
		
		# Restoring viewport settings.
		self._name = mxs.viewport.activeViewport
		self.slateClear()	
		scene.setSelection( initialSelection )
		scene.setCurrentFrame( initialFrame )
		mxs.displaySafeFrames = initialSafeFrame
		mxs.hideByCategory.geometry = initialGeometryVisibility
		mxs.hideByCategory.shapes =	initialShapesVisibility
		mxs.hideByCategory.lights =	initialLightsVisibility 
		mxs.hideByCategory.cameras = initialCamerasVisibility 
		mxs.hideByCategory.helpers = initialHelpersVisibility
		mxs.hideByCategory.spacewarps =	initialSpaceWarpsVisibility 
		mxs.hideByCategory.particles = initialParticleSystemsVisibility
		mxs.hideByCategory.bones = initialBoneObjectsVisibility
		mxs.viewport.setGridVisibility( self._name, initialGridVisibility )
		mxs.pyhelper.setViewportQuadSize( viewSize[0], viewSize[1] )
		self.setSlateIsActive( False )

		# Restoring Nitrous settings.
		if camera and progressive and camera.hasMultiPassEffects() and effects in [None, True]:

			# Restoring Nitrous settings.
			nitrousSettings.ProgressiveFadingFactor = initialFadingFactor
			
		if initialViewNumber != 1:
			mxs.execute( 'max tool maximize' )

		# After storing all these bitmaps. We make sure to flush Max's memory.
		mxs.gc()
		
		return completed