def findOpacityMap(material): """ \remarks looks for the opacity map for the inputed material based on its type \param material <Py3dsMax.mxs.Material> \return <Py3dsMax.mxs.Map> opacityMap || None """ cls = mxs.classof(material) # return a standard material's opacity map if (cls == mxs.StandardMaterial): if material.opacityMapEnable: return material.opacityMap # return a vray material's opacity map elif (cls in (mxs.VrayMtl, mxs.VRaySkinMtl)): if material.texmap_opacity_on: return material.texmap_opacity # return a vray light material's opacity map elif (cls == mxs.VrayLightMtl): if material.opacity_texmap_on: return material.opacity_texmap # return a matte's opactiy map elif (cls in (mxs.Matte_Shadow_Reflection_mi, mxs.mr_Matte_Shadow_Reflection_Mtl)): if material.opacity_connected: return material.opacity_shader # return an arch design's opacity map elif (cls == mxs.Arch___Design__mi): if material.cutoutmap_on: return material.cutout_map return None
def canDisableCaches( object ): # make sure this is a valid node if ( not mxs.isValidNode( object ) ): return True # make sure this object is not hidden, or a HairFXView object if ( not object.ishidden or mxs.classof( object ) == mxs.HairFXView ): return False # make sure all instances of this object are hidden instances = mxs.pyhelper.getInstances( object ) for inst in instances: if ( not inst.ishidden ): return False # make sure all children of this object can be disabled for child in object.children: if ( not canDisableCaches( child ) ): return False # check all dependent nodes of this object can be disabled for dep in mxs.refs.dependentNodes( object ): if ( not canDisableCaches( object ) ): return False return True
def _nativeSubmaterials(self): """The native submaterials of this material.""" mtl = self._nativePointer # Processing multi/sub materials directly is faster than the getnumsubs # system. if mxs.classof(mtl) == mxs.MultiMaterial: return [mtl[i] for i in range(mtl.numsubs)] else: # Process all other kinds of materials. get_submtl = mxs.getSubMtl return [get_submtl(mtl, i+1) for i in range(mxs.getNumSubMtls(mtl))]
def _nativeSubmaterials(self): """The native submaterials of this material.""" mtl = self._nativePointer # Processing multi/sub materials directly is faster than the getnumsubs # system. if mxs.classof(mtl) == mxs.MultiMaterial: return [mtl[i] for i in range(mtl.numsubs)] else: # Process all other kinds of materials. get_submtl = mxs.getSubMtl return [ get_submtl(mtl, i + 1) for i in range(mxs.getNumSubMtls(mtl)) ]
def cameraType(self): """ \remarks implements the AbstractSceneCamera.cameraType method to determine what type of camera this instance is \return <cross3d.constants.CameraType> """ cls = mxs.classof(self._nativePointer) if cls in (mxs.FreeCamera, mxs.TargetCamera): return CameraType.Standard elif cls == mxs.Physical: return CameraType.Physical elif cls == mxs.VRayPhysicalCamera: return CameraType.Physical return 0
def rendererType( self ): """ \remarks implements AbstractSceneRenderer.rendererType to return the renderer type for this instance \sa setRendererType \return <cross3d.constants.RendererType> """ from cross3d.constants import RendererType classname = str(mxs.classof(self._nativePointer)).lower() if ( classname == 'default_scanline_renderer' ): return RendererType.Scanline elif ( classname == 'mental_ray_renderer' ): return RendererType.MentalRay elif ( 'v_ray' in classname ): return RendererType.VRay return 0
def filmWidth(self): """ \remarks Returns the film_width of the camera. \return film_width (float) """ cls = mxs.classof(self._nativePointer) width = None if cls == mxs.VRayPhysicalCamera: width = self._nativePointer.film_width elif cls == mxs.Physical: width = self._nativePointer.film_width_mm if not width: # If we failed to get a width from a camera, return the scene aperture setting. width = mxs.getRendApertureWidth() return width
def filmHeight(self): """ \remarks Returns the film_height of the camera. \return film_height (float) """ cls = mxs.classof(self._nativePointer) height = None if cls == mxs.VRayPhysicalCamera: # TODO: Why is that wrapped in a try except? try: height = self._nativePointer.film_height except AttributeError: pass elif cls == mxs.Physical: height = self._nativePointer.film_height_mm if not height: # If we failed to get a width from a camera, return the scene aperture setting. height = self.filmWidth() * (mxs.renderPixelAspect / mxs.getRendImageAspect()) return height
def keyframeTimeControllers(self, alembic=True): """ Takes all Alembic, PC and TMC time controllers and keyframe their original time controllers. This is used as a base setup for further time alterations. Returns: SceneAnimationController|boolean: The bezier float keyframed controller used to control time. """ np = self._nativePointer timeController = None frameRate = self._scene.animationFPS() # Processing Alembic controllers. alembicControllers = mxs.getClassInstances( mxs.Alembic_Float_Controller, target=np) alembicControllers += mxs.getClassInstances(mxs.Alembic_Xform, target=np) alembicControllers += mxs.getClassInstances(mxs.Alembic_Mesh_Geometry, target=np) alembicControllers += mxs.getClassInstances(mxs.Alembic_Mesh_Normals, target=np) for alembicController in alembicControllers: # Instantiating if we already computed the time controller. if not timeController: # Unfortunately the start and end frame of the cache data is not stored on the controller so we have to parse the file. import cask archive = cask.Archive(str(alembicController.path)) item = archive.top.children[str(alembicController.identifier)] # Sometimes the identifier will point to a Xform object. # Unfortunately I did not find a way to access the sample count from there. # So instead I am digging through the hierarchy. while item.children: item = item.children[item.children.keys()[0]] properties = item.iobject.getProperties() geometry = properties.getProperty(0) core = geometry.getProperty(0) sampleCount = core.getNumSamples() startTime = core.getTimeSampling().getSampleTime(0) endTime = core.getTimeSampling().getSampleTime( (sampleCount - 1)) # Creating the controller. timeController = mxs.bezier_float() frames = [(round(startTime * frameRate), startTime), (round(endTime * frameRate), endTime)] for frame, value in frames: k = mxs.addNewKey(timeController, frame) k.value = value k.inTangentType = mxs.pyhelper.namify('linear') k.outTangentType = mxs.pyhelper.namify('linear') # Assigning the controller. mxs.setPropertyController(alembicController, 'time', timeController) # Processing TMCs and PCs. nativeCaches = mxs.getClassInstances( mxs.Transform_Cache, target=np) + mxs.getClassInstances( mxs.Point_Cache, target=np) for nativeCache in nativeCaches: # Unfortunately the start and end frame of the cache data is not stored on the controller so we have to parse the file. if mxs.classof(nativeCache) == mxs.Point_Cache: from blur3d.lib.pclib import PointCacheInfo cacheInfo = PointCacheInfo.read(nativeCache.filename, header_only=True) elif mxs.classof(nativeCache) == mxs.Transform_Cache: # Ensure file exists try: from blur3d.lib.tmclib import TMCInfo cacheInfo = TMCInfo.read(nativeCache.CacheFile, header_only=True) except IOError as e: print "Cache file does not exist: {0}".format( nativeCache.CacheFile) continue # Playback type 3 is "Playback Graph". nativeCache.playbackType = 3 # Set the playback frame to a float controller with start and end values pulled from the cache. mxs.setPropertyController(nativeCache, 'playbackFrame', mxs.bezier_float()) timeController = mxs.getPropertyController(nativeCache, 'playbackFrame') # Set keys on the playback frame cache that matches the current frame rate. duration = cacheInfo.end_frame - cacheInfo.start_frame + 1 frames = [(cacheInfo.start_frame, 0), (cacheInfo.end_frame, duration)] for frame, value in frames: key = mxs.addNewKey(timeController, frame) key.value = value key.inTangentType = mxs.pyhelper.namify('linear') key.outTangentType = mxs.pyhelper.namify('linear') # Processing XMeshes. xMeshes = mxs.getClassInstances(mxs.XMeshLoader, target=np) for xMesh in xMeshes: # Enable curve playback. xMesh.enablePlaybackGraph = True # Create a new bezier float controller for the time. mxs.setPropertyController(xMesh, 'playbackGraphTime', mxs.bezier_float()) timeController = mxs.getPropertyController(xMesh, 'playbackGraphTime') # Set keys on the playback in and out frames. frames = (xMesh.rangeFirstFrame, xMesh.rangeLastFrame) for frame in frames: key = mxs.addNewKey(timeController, frame) key.value = frame key.inTangentType = mxs.pyhelper.namify('linear') key.outTangentType = mxs.pyhelper.namify('linear') # Processing Ray Fire caches. rayFireCaches = mxs.getClassInstances(mxs.RF_Cache, target=np) for rayFireCache in rayFireCaches: # Enable curve playback. xMesh.playUseGraph = True # Create a new bezier float controller for the time. mxs.setPropertyController(rayFireCache, 'playFrame', mxs.bezier_float()) timeController = mxs.getPropertyController(rayFireCache, 'playFrame') # Set keys on the playback in and out frames. frames = (xMesh.rangeFirstFrame, xMesh.rangeLastFrame) for frame in frames: key = mxs.addNewKey(timeController, frame) key.value = frame key.inTangentType = mxs.pyhelper.namify('linear') key.outTangentType = mxs.pyhelper.namify('linear') # Returning the time controller if defined. if timeController: # Making the extrapolation linear. linear = mxs.pyhelper.namify('linear') mxs.setBeforeORT(timeController, linear) mxs.setAfterORT(timeController, linear) from cross3d import SceneAnimationController return SceneAnimationController(self._scene, timeController) return None
def keyframeTimeControllers(self, alembic=True): """ Takes all Alembic, PC and TMC time controllers and keyframe their original time controllers. This is used as a base setup for further time alterations. Returns: SceneAnimationController|boolean: The bezier float keyframed controller used to control time. """ np = self._nativePointer timeController = None frameRate = self._scene.animationFPS() # Processing Alembic controllers. alembicControllers = mxs.getClassInstances(mxs.Alembic_Float_Controller, target=np) alembicControllers += mxs.getClassInstances(mxs.Alembic_Xform, target=np) alembicControllers += mxs.getClassInstances(mxs.Alembic_Mesh_Geometry, target=np) alembicControllers += mxs.getClassInstances(mxs.Alembic_Mesh_Normals, target=np) for alembicController in alembicControllers: # Instantiating if we already computed the time controller. if not timeController: # Unfortunately the start and end frame of the cache data is not stored on the controller so we have to parse the file. import cask archive = cask.Archive(str(alembicController.path)) item = archive.top.children[str(alembicController.identifier)] # Sometimes the identifier will point to a Xform object. # Unfortunately I did not find a way to access the sample count from there. # So instead I am digging through the hierarchy. while item.children: item = item.children[item.children.keys()[0]] properties = item.iobject.getProperties() geometry = properties.getProperty(0) core = geometry.getProperty(0) sampleCount = core.getNumSamples() startTime = core.getTimeSampling().getSampleTime(0) endTime = core.getTimeSampling().getSampleTime((sampleCount - 1)) # Creating the controller. timeController = mxs.bezier_float() frames = [(round(startTime * frameRate), startTime), (round(endTime * frameRate), endTime)] for frame, value in frames: k = mxs.addNewKey(timeController, frame) k.value = value k.inTangentType = mxs.pyhelper.namify('linear') k.outTangentType = mxs.pyhelper.namify('linear') # Assigning the controller. mxs.setPropertyController(alembicController, 'time', timeController) # Processing TMCs and PCs. nativeCaches = mxs.getClassInstances(mxs.Transform_Cache, target=np) + mxs.getClassInstances(mxs.Point_Cache, target=np) for nativeCache in nativeCaches: # Unfortunately the start and end frame of the cache data is not stored on the controller so we have to parse the file. if mxs.classof(nativeCache) == mxs.Point_Cache: from blur3d.lib.pclib import PointCacheInfo cacheInfo = PointCacheInfo.read(nativeCache.filename, header_only=True) elif mxs.classof(nativeCache) == mxs.Transform_Cache: # Ensure file exists try: from blur3d.lib.tmclib import TMCInfo cacheInfo = TMCInfo.read(nativeCache.CacheFile, header_only=True) except IOError as e: print "Cache file does not exist: {0}".format(nativeCache.CacheFile) continue # Playback type 3 is "Playback Graph". nativeCache.playbackType = 3 # Set the playback frame to a float controller with start and end values pulled from the cache. mxs.setPropertyController(nativeCache, 'playbackFrame', mxs.bezier_float()) timeController = mxs.getPropertyController(nativeCache, 'playbackFrame') # Set keys on the playback frame cache that matches the current frame rate. duration = cacheInfo.end_frame - cacheInfo.start_frame + 1 frames = [(cacheInfo.start_frame, 0), (cacheInfo.end_frame, duration)] for frame, value in frames: key = mxs.addNewKey(timeController, frame) key.value = value key.inTangentType = mxs.pyhelper.namify('linear') key.outTangentType = mxs.pyhelper.namify('linear') # Processing XMeshes. xMeshes = mxs.getClassInstances(mxs.XMeshLoader, target=np) for xMesh in xMeshes: # Enable curve playback. xMesh.enablePlaybackGraph = True # Create a new bezier float controller for the time. mxs.setPropertyController(xMesh, 'playbackGraphTime', mxs.bezier_float()) timeController = mxs.getPropertyController(xMesh, 'playbackGraphTime') # Set keys on the playback in and out frames. frames = (xMesh.rangeFirstFrame, xMesh.rangeLastFrame) for frame in frames: key = mxs.addNewKey(timeController, frame) key.value = frame key.inTangentType = mxs.pyhelper.namify('linear') key.outTangentType = mxs.pyhelper.namify('linear') # Processing Ray Fire caches. rayFireCaches = mxs.getClassInstances(mxs.RF_Cache, target=np) for rayFireCache in rayFireCaches: # Enable curve playback. xMesh.playUseGraph = True # Create a new bezier float controller for the time. mxs.setPropertyController(rayFireCache, 'playFrame', mxs.bezier_float()) timeController = mxs.getPropertyController(rayFireCache, 'playFrame') # Set keys on the playback in and out frames. frames = (xMesh.rangeFirstFrame, xMesh.rangeLastFrame) for frame in frames: key = mxs.addNewKey(timeController, frame) key.value = frame key.inTangentType = mxs.pyhelper.namify('linear') key.outTangentType = mxs.pyhelper.namify('linear') # Returning the time controller if defined. if timeController: # Making the extrapolation linear. linear = mxs.pyhelper.namify('linear') mxs.setBeforeORT(timeController, linear) mxs.setAfterORT(timeController, linear) from cross3d import SceneAnimationController return SceneAnimationController(self._scene, timeController) return None
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
def findBumpMap(material): """ \remarks looks for the bump map for the inputed material based on its type \param material <Py3dsMax.mxs.Material> \return <Py3dsMax.mxs.Map> opacityMap || None """ cls = mxs.classof(material) # return a standard material's bump map if (cls == mxs.StandardMaterial): if (material.bumpMapEnable): bumpmap = material.bumpMap if (bumpmap and material.bumpMapAmount != 100): bumpTexture = mxs.Output() bumpTexture.map1 = bumpmap bumpTexture.output.bump_amount = (material.bumpMapAmount / 100.0) return bumpTexture return bumpmap return None # return a vray bump map if (cls in (mxs.VrayMtl, mxs.VrayFastSSS2, mxs.VRaySkinMtl)): if (material.texmap_bump_on): bumpmap = material.texmap_bump if (bumpmap and material.texmap_bump_multiplier != 100): bumpTexture = mxs.Output() bumpTexture.map1 = bumpmap bumpTexture.output.bump_amount = ( material.texmap_bump_multiplier / 100.0) return bumpTexture return bumpmap return None # return a matte bump if (cls in (mxs.Matte_Shadow_Reflection__mi, mxs.mr_Matte_Shadow_Reflection_Mtl)): return material.bump # return an arch-design material if (cls == mxs.Arch___Design__mi): if (material.bump_map_on): bumpmap = material.bump_map if (bumpmap and material.bump_map_amt != 1.0): bumpTexture = mxs.Output() bumpTexture.map1 = bumpmap bumpTexture.output.bump_amount = mtl.bump_map_amt return bumpTexture return bumpmap return None # return a skin bump map if (cls in (mxs.SSS_Fast_Skin___w__Disp___mi, mxs.SSS_Fast_Skin___mi, mxs.SSS_Fast_Skin_Material_Displace__mi, mxs.SSS_Fast_Skin_Material__mi, mxs.SSS_Fast_Material__mi)): if (mxs.classof(material.bump) == mxs.Bump__3dsmax): bumpmap = material.bump.map if (bumpmap): bumpTexture = mxs.Output() bumpTexture.map1 = bumpmap bumpTexture.output.bump_amount = material.bump.multiplier return bumpTexture return None else: return material.bump # no bump map found return None
def findDisplacementMap(material): """ \remarks looks for the displacement map for the inputed material based on its type \param material <Py3dsMax.mxs.Material> \return <Py3dsMax.mxs.Map> opacityMap || None """ cls = mxs.classof(material) is_prop = mxs.isproperty # return a standard material's displacement map if (cls == mxs.StandardMaterial): if (material.displacementMap and material.displacementMapEnable): return material.displacementMap elif (is_prop(material, 'mental_ray__material_custom_attribute')): mrattr = material.mental_ray__material_custom_attribute if (mrattr.displacementOn and not mrattr.displacementLocked): return mrattr.displacement return None # return a vray material's displacement map elif (cls in (mxs.VrayMtl, mxs.VRayFastSSS2, mxs.VRaySkinMtl)): if material.texmap_displacement_on: return material.texmap_displacement else: return None # return an arch design's material elif (cls == mxs.Arch___Design__mi): outMap = None # first check for mental ray properties if (is_prop(material, 'mental_ray__material_custom_attribute')): mrattr = material.mental_ray__material_custom_attribute if (mrattr.displacementOn and not mrattr.displacementLocked): outMap = mrattr.displacement else: outMap = None # create a custom output material to match the output amount if (not outMap and material.displacementMap and material.displacement_map_on): if (material.displacement_map_amt): outMap = mxs.Output() outMap.map1 = mtl.displacementMap outMap.map1Enabled = True outMap.output.Output_Amount = material.displacement_map_amt else: outMap = material.displacementMap return outMap # return a blend's displacement elif (cls == mxs.Blend): if (is_prop(material, 'mental_ray__material_custom_attribute')): mrattr = material.mental_ray__material_custom_attribute if (mrattr.displacementOn and not mrattr.displacementLocked): return mrattr.displacement return None # return skin shader displacements elif (cls in (mxs.SSS_Fast_Skin_Material_Displace__mi, mxs.SSS_Fast_Skin___w__Disp___mi)): return material.displace # return a mental ray displacement elif (cls == mxs.mental_ray): if material.displaceOn: return material.displacement return None
def buildMaterialFrom(material, opacityMap=None, displacementMap=None, bumpMap=None): """ \remarks creates a new material using the properties from the inputed material as its base, creating the material with an inputed opacity and displacement map overrides \param material <Py3dsMax.mxs.Material> \param opacityMap <Py3dsMax.mxs.Map> \param displacementMap <Py3dsMax.mxs.Map> \param bumpMap <Py3dsMax.mxs.Map> \return <Py3dsMax.mxs.Material> builtMaterial """ # if there is no opacity of displacement map, then there is no need to modify the inputed material if (not (opacityMap or displacementMap or bumpMap)): return material # store useful methods mcopy = mxs.copy class_of = mxs.classof is_prop = mxs.isproperty cls = class_of(material) #---------------------------------------- # GK 02/05/10 if texture is nested in a "Displacement 3D" or "Height Map" texture, get the root map # and use it in the material's own displacement slot. (trying to maintain some comaptibility between vray and mental ray here.) # if not nested, we must convert to mr connection displacement and put it there anyway since max's displacement spinner # does not correlate correctly to mental ray displacement amounts. displacementTexture = None # extract from a Displacement_3d texture if (class_of(displacementMap) == mxs.Displacement_3D__3dsmax): displacementTexture = displacementMap displacementMap = displacementMap.map # extract from a Height_Map texture elif (class_of(displacementMap) == mxs.Height_Map_Displacement__3dsmax): displacementTexture = displacementMap displacementMap = displacementMap.heightMap #---------------------------------------- # build a matte shadow reflection material if (cls in (mxs.Matte_Shadow_Reflection__mi, mxs.mr_Matte_Shadow_Reflection_Mtl)): matteMtl = mcopy(material) matteMtl.opacity_shader = opacityMap output = mxs.mental_ray() output.surface = mxs.Material_to_Shader() output.surface.material = matteMtl if (displacementTexture): dispTexture = mxs.Displacement_3D__3dsmax() dispTexture.map = displacementMap output.displacement = displacementTexture output.bump = bumpMap return output # build a standard material elif (cls == mxs.StandardMaterial): output = mcopy(material) # use the opacity map if (opacityMap): output.opacityMap = opacityMap # use the bump map if (bumpMap): output.bumpMap = bumpMap output.bumpMapAmount = 100 # use the displacement map if (displacementMap): output.displacementMap = displacementMap output.displacementMapEnable = True if (is_prop(output, 'mental_ray__material_custom_attribute')): if (not displacementTexture): displacementTexture = mxs.Displacement_3D__3dsmax() displacementTexture.map = displacementMap output.mental_ray__material_custom_attribute.displacement = displacementTexture output.mental_ray__material_custom_attribute.displacementLocked = False return output # build a Vray material elif (cls == mxs.VrayMtl): output = mcopy(material) # use the bump map if (bumpMap): output.texmap_bump = bumpMap output.texmap_bump_on = True output.texmap_bump_multiplier = 100 # use the opacity map if (opacityMap): output.texmap_opacity = opacityMap output.texmap_opacity_on = True output.texmap_opacity_multiplier = 100 # use the displacementmap if (displacementMap): output.texmap_displacement = displacementMap output.texmap_displacement_on = True output.texmap_displacement_multiplier = 100 return output # build a Vray Light material elif (cls == mxs.VrayLightMtl): # light materials only need opacity maps if (not opacityMap): return material output = mcopy(material) output.opacity_texmap = opacityMap output.opacity_texmap_on = True return output # build a Arch_Design material elif (cls == mxs.Arch___Design__mi): output = mcopy(material) output.cutout_map = opacityMap # displace the texture if (not displacementTexture): output.displacementMap = displacementMap # use the bump map if (bumpMap): output.bump_map = bumpMap output.bump_map_amt = 1.0 # displace the property elif (is_prop(material, 'mental_ray__material_custom_attribute')): output.mental_ray__material_custom_attribute.displacement = displacementTexture output.mental_ray__material_custom_attribute.displacementLocked = False return output # build a blend material elif (cls == mxs.Blend): if (displacementMap and is_prop('mental_ray__material_custom_attribute')): output = mcopy(material) # create a displacement texture if (not displacementTexture): displacementTexture = mxs.Displacement_3D__3dsmax() displacementTexutre.map = displacementMap output.displace = displacementTexture return output return material # build a fast skin shader elif (cls in (mxs.SSS_Fast_Skin_Material_Displace__mi, mxs.SSS_Fast_Skin___w__Disp___mi)): if (displacementMap): output = mcopy(material) # use the bump map if (bumpMap): if (mxs.classof(bumpMap != mxs.Bump__3dsmax)): bumpTexture = mxs.Bump__3dsmax bumpTexture.map = bumpMap output.bump = bumpTexture else: output.bump = bumpMap # use the displacement texture if (not displacementTexture): displacementTexture = mxs.Displacement_3D__3dsmax() displacementTexture.map = displacementMap output.displace = displacementTexture return output return material # build a mental_ray shader elif (cls == mxs.Mental_Ray): output = mcopy(material) # use displacement if (displacementMap): if (not displacementTexture): displacementTexture = mxs.Displacement_3D__3dsmax() displacementTexture.map = displacementMap output.displacement = displacementTexture # use opacity if (opacityMap): opacityMtl = mxs.Opacity__base() opacityMtl.input_shader = material.surface opacityMtl.opacity_shader = opacityMap output.surface = opacityMtl return output # build a multi/material elif (cls == mxs.MultiMaterial): output = mcopy(material) count = material.numsubs output.numsubs = count for i in range(count): output[i] = buildMaterialFrom(material[i], opacityMap=opacityMap, displacementMap=displacementMap, bumpMap=bumpMap) return output # create a default material else: count = mxs.getNumSubMtls(material) if (count): output = mcopy(material) get_submtl = mxs.getSubMtl set_submtl = mxs.setSubMtl for i in range(output): set_submtl( output, i + 1, buildMaterialFrom(get_submtl(material, i + 1), opacityMap=opacityMap, displacementMap=displacementMap, bumpMap=bumpMap)) return output return material
def setFOVBased(self, fovBased): cls = mxs.classof(self._nativePointer) if cls == mxs.VRayPhysicalCamera: self._nativePointer.specify_fov = fovBased return True return False
def fovBased(self): cls = mxs.classof(self._nativePointer) if cls == mxs.VRayPhysicalCamera: return self._nativePointer.specify_fov return True