Exporting API issues

Hi all, I have this problem with this exporting…

How it works: Select a camera (animated or not is optional) >> File >> Export Selection >> File Type : .chan (need to load this script as a plugin)

Here’s where the problem starts. It is able to create a .text file, however, it is not ‘exporting’ or writing out the contents into the text file.
The file size is of zero bytes.

I am making use of the current API that it has been coded, modifying the code to add in some maya cmds

Can someone kindly help me out?


import math, sys, string, os

import maya.OpenMaya as OpenMaya
import maya.OpenMayaMPx as OpenMayaMPx
import maya.OpenMayaAnim as OpenMayaAnim

import maya.cmds as cmds
import maya.mel as mel

kPluginTranslatorTypeName = "chan Export/Import"
kVersionNumber = "0.5a"

camSel = []
start = []
end = []
win_name = "chan_window"

class CustomNodeTranslator(OpenMayaMPx.MPxFileTranslator):   
    def __init__(self):
        OpenMayaMPx.MPxFileTranslator.__init__(self)       
    def haveWriteMethod(self):
        return True
    def haveReadMethod(self):
        return True
    def filter(self):
        return " .chan"
    def defaultExtension(self):
        return "chan"
    def writer( self, fileObject, optionString, accessMode ):
        try:
                       
            fullName = fileObject.fullName()
            fileHandle = open(fullName,"w")

            selectList = OpenMaya.MSelectionList()
    
            OpenMaya.MGlobal.getActiveSelectionList(selectList)
            node = OpenMaya.MObject()
            depFn = OpenMaya.MFnDependencyNode()
            path = OpenMaya.MDagPath()
            iterator = OpenMaya.MItSelectionList(selectList)
            
            animationTime = OpenMayaAnim.MAnimControl()
            
            maxTime = int(animationTime.maxTime().value())
            minTime = int(animationTime.minTime().value())
            
            while (iterator.isDone() == 0):
                
                iterator.getDependNode(node)
                
                depFn.setObject(node)
                
                iterator.getDagPath(path, node)
                
                cameraObject = OpenMaya.MFnCamera(path)
                
                transform = OpenMaya.MFnTransform(path)
                    
                chanMe = ChanFileExporter(transform, minTime, maxTime, cameraObject)
            
                for all in chanMe():
                    fileHandle.write(all)
                    
                iterator.next()
            
            fileHandle.close()
            
        except:
            sys.stderr.write( "Failed to write file information
")
            raise
    
    def processLine( self, lineStr ):

        self.importTheChan.writeFrameData(lineStr)
        

class ChanFileExporter():
    """ module for exporting chan files from application. arguments: object, startFrame, endFrame """
    
    def __init__(self, transform, startAnimation, endAnimation, cameraObj):
        self.fileExport = []
        self.transform = transform
        self.cameraObj = cameraObj
        self.start = startAnimation
        self.end = endAnimation
        self.exportWin()

    def exportWin(self):
        self.expWindow = cmds.window(w=150, h=100, title = "Export Selection" )
        cmds.columnLayout( adjustableColumn=True )
        form = cmds.formLayout(numberOfDivisions=100)
        cmds.radioCollection()
        self.chk1 = cmds.radioButton( label='option1', onc = self.opt1On, ofc = self.opt1Off )
        self.chk2 = cmds.radioButton( label='option2', onc = self.opt2On, ofc = self.opt2Off )
        self.okayBtn = cmds.button(label='okay!', command=self.runSel, width=150, height=35)

        cmds.formLayout(form, edit=True, attachForm=[\
        (self.chk1, 'top', 15),\
        (self.chk1, 'left', 15),\
        (self.chk2, 'top', 30),\
        (self.chk2, 'left', 15),\
        (self.okayBtn, 'top', 50),\
        (self.okayBtn, 'left', 15)])

        cmds.showWindow( self.expWindow )
    
    def opt1On(self,  args):
        print "User checked option1"
       
        startAnimation = cmds.playbackOptions(query=True, minTime=True)
        endAnimation = cmds.playbackOptions(query=True, maxTime=True)
        
        self.start = startAnimation
        self.end = endAnimation
   
    def opt1Off(self,  args):
        print "User un-checked option1"
        cmds.radioButton(self.chk2, edit = True, enable = True)
        self.start = ""
        self.end = ""
        
    def opt2On(self,  args):
        print "User checked option2"
        startAnimation = cmds.findKeyframe(which='first')
        endAnimation = cmds.findKeyframe(which='last')

        self.start = startAnimation
        self.end = endAnimation

        #self.start.append(int(startAnimation))
        #self.end.append(int(endAnimation))

    def opt2Off(self,  args):
        print "User un-checked option2"
        self.start = ""
        self.end = ""

    def runSel(self,  args):
        chkVal1 = cmds.radioButton(self.chk1, query=True, sl=1)
        chkVal2 = cmds.radioButton(self.chk2, query=True, sl=1)
       
        if chkVal1 == 1:
            print "opt1 Pressed!"      
            print self.start
            print self.end
            self.test()
            self.closeWindow()
            
        elif chkVal2 == 1:
            print "opt2 Pressed!"
            print self.start
            print self.end
            self.test()
            self.closeWindow()
            
        else:
            cmds.warning("Check an option")

    def closeWindow(self):
        cmds.deleteUI(self.expWindow, window=True)
        
    def test(self):
        self.actualExp(self.transform, self.start, self.end, self.cameraObj)
    
    
    def actualExp(self, transform, startAnimation, endAnimation, cameraObj):
        mayaGlobal = OpenMaya.MGlobal()
        mayaGlobal.viewFrame(OpenMaya.MTime(1))

        # Converts the float arguement into integer
        for i in range(int(startAnimation), int(endAnimation + 1)):

            focalLength = cameraObj.focalLength()
            
            vFilmApp = cameraObj.verticalFilmAperture()

            focalOut = 2  math.degrees(math.atan(vFilmApp   25.4/ (2  focalLength)))

            myEuler = OpenMaya.MEulerRotation()
            spc = OpenMaya.MSpace.kWorld

            trans = transform.getTranslation(spc)

            rotation = transform.getRotation(myEuler)
            rotVector = OpenMaya.MVector(myEuler.asVector())

            self.fileExport.append((str(i) + '	' + str(trans[0]) + "	" + str(trans[1]) + "	" + str(trans[2]) + "	" + str(math.degrees(rotVector[0])) + "	" + str(math.degrees(rotVector[1])) + "	" + str(math.degrees(rotVector[2])) + "	" + str(focalOut) + "
"))

            mayaGlobal.viewFrame(OpenMaya.MTime(i+1))
    
    def __call__(self,  args):
        return self.fileExport

    def radianToDegree(self, radians):
        outDegrees = 0.0
        outDegrees = (float(radians) / (math.pi)) 180
        return outDegrees


# creator
def translatorCreator():
    return OpenMayaMPx.asMPxPtr( CustomNodeTranslator() )

# initialize the script plug-in
def initializePlugin(mobject):
    mplugin = OpenMayaMPx.MFnPlugin(mobject)

    try:
        mplugin.registerFileTranslator(kPluginTranslatorTypeName, None, translatorCreator)
    except:
        sys.stderr.write( "Failed to register translator: %s" % kPluginTranslatorTypeName )
        raise

# uninitialize the script plug-in
def uninitializePlugin(mobject):
    mplugin = OpenMayaMPx.MFnPlugin(mobject)
    try:
        mplugin.deregisterFileTranslator( kPluginTranslatorTypeName )
    except:
        sys.stderr.write( "Failed to deregister translator: %s" % kPluginTranslatorTypeName )
        raise



Really?

A) Please don’t use asterisks to denote indentation. Here’s a non-asterisked version: import math, sys, string, osimport maya.OpenMaya as OpenMayaimport maya.Op - Pastebin.com

B) Just looking at your code I see a potential issue here:

                chanMe = ChanFileExporter(transform, minTime, maxTime, cameraObject)
 
                for all in chanMe():
                    fileHandle.write(all)

The call method of a ChanFileExporter instance returns self.fileExport, which is set as an empty list on init. self.fileExport is not filled with any data until runSel is called. runSel is not called until you press a button in the window created by ChanFileExporter. The thing is the window created by ChanFileExporter does not stop the evaluation of your script, so in the case of your code chanMe() is returning an empty list when that for loop is evaluated, meaning the write method is never called.

[QUOTE=marcuso;25894]Really?[/QUOTE]

I removed the asteriks and I sweared when I posted and previewed it, there isn’t any asteriks… Sorry about that

[QUOTE=capper;25904]A) Please don’t use asterisks to denote indentation. Here’s a non-asterisked version: import math, sys, string, osimport maya.OpenMaya as OpenMayaimport maya.Op - Pastebin.com

B) Just looking at your code I see a potential issue here:

                chanMe = ChanFileExporter(transform, minTime, maxTime, cameraObject)
 
                for all in chanMe():
                    fileHandle.write(all)

The call method of a ChanFileExporter instance returns self.fileExport, which is set as an empty list on init. self.fileExport is not filled with any data until runSel is called. runSel is not called until you press a button in the window created by ChanFileExporter. The thing is the window created by ChanFileExporter does not stop the evaluation of your script, so in the case of your code chanMe() is returning an empty list when that for loop is evaluated, meaning the write method is never called.[/QUOTE]

Hi capper, what you mentioned are making sense to me. However in this case, are there any better ways for me to rectify it?

Cause initially I had thought that by prompting up this window selection in the ChanFileExporter, it may not interferes with the coding/ execution as I am trying to retain the initial coding styles (expecially for portions that I am unsure of) and have it ‘go-along-with-the-flow’…

Separating the main data extraction from the writer method is fine, but you should use the standard export options UI and workflow that maya provides for getting user options prior to exporting. Don’t write your own UI for it, use the file dialog that pops up when you select “Export Selection”

You can customize the “File Type Specific Options” section of the export dialog:


Shown are the options for the FBX exporter.

Basically you create a melscript that does two things.
Firstly it creates the UI that goes into the File Type Specific Options sections. The user will interact with this UI.
Secondly it gathers all the options and passes them to the export process when the user hits export.

If you have access to the maya devkit that ships with maya, you can find an example for the obj export options:
%MAYA_ROOT%\devkit\plug-ins\objExport\objExportOptions.mel

If you don’t, there is another example here (it’s the second section down):
http://nccastaff.bournemouth.ac.uk/jmacey/RobTheBloke/www/research/maya/exp_plugin.htm

Either name it ExporterNameExportScript.mel, or when you call registerFileTranslator, pass in the option script name. You can also pass in default options. Check the MFnPlugin::registerFileTranslator docs for function details.

[QUOTE=capper;25927]Separating the main data extraction from the writer method is fine, but you should use the standard export options UI and workflow that maya provides for getting user options prior to exporting. Don’t write your own UI for it, use the file dialog that pops up when you select “Export Selection”

You can customize the “File Type Specific Options” section of the export dialog:


Shown are the options for the FBX exporter.

Basically you create a melscript that does two things.
Firstly it creates the UI that goes into the File Type Specific Options sections. The user will interact with this UI.
Secondly it gathers all the options and passes them to the export process when the user hits export.

If you have access to the maya devkit that ships with maya, you can find an example for the obj export options:
%MAYA_ROOT%\devkit\plug-ins\objExport\objExportOptions.mel

If you don’t, there is another example here (it’s the second section down):
http://nccastaff.bournemouth.ac.uk/jmacey/RobTheBloke/www/research/maya/exp_plugin.htm

Either name it ExporterNameExportScript.mel, or when you call registerFileTranslator, pass in the option script name. You can also pass in default options. Check the MFnPlugin::registerFileTranslator docs for function details.[/QUOTE]

Hi Capper, I am not exactly writing out my own exporter, rather I am making use and modifying one of the script that I have found.
I know this isn’t a good excuse but I really am no good with API and hence currently, I am getting a lot of issues with the current one I am doing.

Unfortunately, I do not have access to access to the maya devkit. Is it really not possible to tweak the coding within the script to make it work?

The main code is fine, you just need to get the options from the maya dialog and not from a window created within the export process. You should make sure you have all the user information you need prior to starting the export process. You can get this by using the ExportOptions mel script I described above. The only change you’d need to make to the exporter after that is to pass the optionString argument to the ChanFileExporter, and have that parse the option string for the user options (either that or parse it before you loop through selected objects and pass each option as an argument to ChanFileExporter

Hey, capper thanks for the suggestion sounds and I really appreciate it. However it will be a big feat for me to handle as I am pretty much lost in it already :x

Hi capper, chance upon this interesting thread as I am looking for info on adding in options into the File Specific Type Options.
I have located the objExport.mel location at /apps/Linux64/aw/maya2014/scripts/others (I am using Linux by the way) but I am unable to add in any new scripts etc into that directory as my workplace has banned users from modifying it (I guess it is a precaution measure?)
Likewise, I do not think my workplace have the devkit

So, are any other ways that I can add in options into the File Specific Type Options? I tried the example in the link you have provided, but when I tried adding in the Export Options (MayaFileExportScript.mel) in the ~/maya/scripts as stated for Linux, it is not reading it at all.

Hey salik,

So I couldn’t get it to work just by naming the script a certain name either. That page is pretty old so that method may be legacy. However it does work for me if I pass the name of the script to MFnPlugin::registerFileTranslator. You can also pass default options here:

expOptionsScript = 'MyExporterOptions'
expDefaultOptions = 'opt1=0;opt2=5'

# creator
def translatorCreator():
    return OpenMayaMPx.asMPxPtr( MyExporter() )

# initialize the script plug-in
def initializePlugin(mobject):
    mplugin = OpenMayaMPx.MFnPlugin(mobject)

    try:
        mplugin.registerFileTranslator(kPluginTranslatorTypeName, None,
                                       translatorCreator,
                                       expOptionsScript,
                                       expDefaultOptions)
    except:
        sys.stderr.write( "Failed to register translator: %s" % kPluginTranslatorTypeName )
        raise

The “expOptionsScript” variable contains the name of the mel script (I imagine the internal procedure needs to have the same name as well). So for this to work you’d need a mel script in your MAYA_SCRIPT_PATH with the name “MyExporterOptions.mel”.

I can post the example I tested this out with if you’re having any further issues.

Hey capper, thanks for getting back to me! At least, the mystery of unable to getting the script to work was found out :slight_smile: and here, I thought I may be screwing it up somewhere

Could I trouble you to post the example you have tested? It will serves me as a great reference to look out for in the future, if you do not mind :smiley:

It exports the time, allowing an optional format string

I’m not familiar with writing file translators so I don’t know if this ignores/breaks any conventions. It works though.

plugin: import timeimport sysimport maya.OpenMayaMPx as OpenMayaMPxkPluginTran - Pastebin.com
options script: // $parent - the parent UI layout// $action - "post" or "query"// $initial - Pastebin.com

The options script should be saved as “ExportThatTimeOptions.mel”

[QUOTE=capper;26045]It exports the time, allowing an optional format string

I’m not familiar with writing file translators so I don’t know if this ignores/breaks any conventions. It works though.

plugin: import timeimport sysimport maya.OpenMayaMPx as OpenMayaMPxkPluginTran - Pastebin.com
options script: // $parent - the parent UI layout// $action - "post" or "query"// $initial - Pastebin.com

The options script should be saved as “ExportThatTimeOptions.mel”[/QUOTE]

Hey capper, thanks alot man!

I actually have a couple of questions if you don’t mind…

  1. is it necessary for the options script (ExportThatTimeOptions.mel) to be only in mel-format? Any ideas if this can be workable if it is done in python?

  2. In your plugin, in line 27, the variable timeMode, I am assuming that it is deriving from the radioButtonGrp that was set in the options Script. If instead of integers, I am using strings to replace the “0” and “1” into “use this” and “use that”. I am trying to implement TS example, only the use of the frame/object range

Does this means that I need to set it as timeMode = “use this”?

  1. Prior to my question 2, I am actually pretty confused about the plugin line 31 to 38. Where does optionString comes from etc, as I do not get what it is doing… The reason I asked this is because while I am also referring back to the bournemouth link and there doesn’t seems to be any MStringArray for the optionString in your code. Hence confused
  1. I’m assuming that it needs to be a MEL script with a function of the same name that accepts those four arguments. How you create or query the UI elements from within it is up to you. You could call a python script from it. You just need to be sure that it behaves the same (including the eval of resultCallback, which if you used python would need to be through maya.mel.eval())

optionString
This is all based on my best guess/deduction from what I’ve read and tested out in the past couple days. I have essentially no experience writing file translators so don’t take my word as gospel.

The optionString is just that, a string of options. Convention dictates that it be a semi-colon-separated list of name=value pairs, although I suppose you could structure it however you want, since your plugin is the only one that needs to make sense of it.

When the writer method of the plugin is called, the second argument is a string of options. This string gets set two ways:
Firstly, you can specify default options when you register the file translator. In line 51 of my plugin you’ll see:

timeDefaultOptions = 'm=0;strfrmt=%M'

which is then passed into the registerFileTranslator call on line 62:

mplugin.registerFileTranslator(kPluginTranslatorTypeName, None,
                               translatorCreator,
                               timeOptionsScript,
                               timeDefaultOptions)

At this point if I export something, the optionsString argument will be set to whatever I specified as the default options. (If no default options are given, the optionsString will be empty)

Secondly options can be gotten from the export dialog. This happens when you specify an options mel script. The options script has two modes: query and post. “post” is called after the fileDialog is created and is where you create the UI elements. “query” is called when the user hits “Export Selected” and is where you gather the current settings and pass them along as a string. We pass our options along by evaling a callback function and passing it the options (which you get by querying the UI that you created in the “post” stage) as a string. So in the options script I posted you can see the two options being gathered and append to the $currentOptions variable. This variable is then passed to the callback function on line 62 with:

eval($resultCallback+" \""+$currentOptions+"\"");

The ultimate result of this is that when your writer method is called, it now has this updated optionsString, which you can split apart to read the options. This is what I’m doing on line 31-38 of my plugin. (Note that it doesn’t actually update the default options string, but actually just appends the options string from the OptionsScript.mel callback onto the default options. Meaning that in my options script, if I passed the options “m=1”, the optionsString that gets passed to writer would actually be: “m=0;strfrmt=%M;m=1”. Don’t ask, it’s just what it does).

The best way to test what’s going on with the optionsString, is just add a print statement to the plugin and play around with different things.

MStringArray doesn’t exist in the Maya python API–python lists take its place.


I need to learn to write more concise responses

Hey capper, thanks again for the descriptive information despite you have no experience in writing out a file translator plugin.

I shall try to play around with this API thingy and see if I can get what I am trying to achieve, hopefully.Thanks again!