home *** CD-ROM | disk | FTP | other *** search
/ Hackers Magazine 57 / CdHackersMagazineNr57.iso / Software / Multimedia / k3d-setup-0.7.11.0.exe / lib / site-packages / cgkit / maimport.py < prev    next >
Encoding:
Python Source  |  2008-02-21  |  25.8 KB  |  659 lines

  1. # ***** BEGIN LICENSE BLOCK *****
  2. # Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3. #
  4. # The contents of this file are subject to the Mozilla Public License Version
  5. # 1.1 (the "License"); you may not use this file except in compliance with
  6. # the License. You may obtain a copy of the License at
  7. # http://www.mozilla.org/MPL/
  8. #
  9. # Software distributed under the License is distributed on an "AS IS" basis,
  10. # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11. # for the specific language governing rights and limitations under the
  12. # License.
  13. #
  14. # The Original Code is the Python Computer Graphics Kit.
  15. #
  16. # The Initial Developer of the Original Code is Matthias Baas.
  17. # Portions created by the Initial Developer are Copyright (C) 2004
  18. # the Initial Developer. All Rights Reserved.
  19. #
  20. # Contributor(s):
  21. #
  22. # Alternatively, the contents of this file may be used under the terms of
  23. # either the GNU General Public License Version 2 or later (the "GPL"), or
  24. # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  25. # in which case the provisions of the GPL or the LGPL are applicable instead
  26. # of those above. If you wish to allow use of your version of this file only
  27. # under the terms of either the GPL or the LGPL, and not to allow others to
  28. # use your version of this file under the terms of the MPL, indicate your
  29. # decision by deleting the provisions above and replace them with the notice
  30. # and other provisions required by the GPL or the LGPL. If you do not delete
  31. # the provisions above, a recipient may use your version of this file under
  32. # the terms of any one of the MPL, the GPL or the LGPL.
  33. #
  34. # ***** END LICENSE BLOCK *****
  35. # $Id: maimport.py,v 1.12 2005/06/15 19:20:29 mbaas Exp $
  36.  
  37. import sys
  38. import mayaascii, cmds
  39. import pluginmanager
  40. import freecamera
  41. import quadrics, box, plane, polyhedron, joint, trimesh, trimeshgeom
  42. import glpointlight, glfreespotlight, glfreedistantlight
  43. import mayaspotlight
  44. from geomobject import *
  45. from cgtypes import *
  46. from worldobject import WorldObject
  47. from sl import *
  48. from math import *
  49.             
  50.                 
  51.  
  52. # MAImporter
  53. class MAImporter(mayaascii.DefaultMAReader):
  54.     """MA import.
  55.     """
  56.  
  57.     _protocols = ["Import"]
  58.  
  59.     def __init__(self):
  60.         mayaascii.DefaultMAReader.__init__(self)
  61.  
  62.     # extension
  63.     def extension():
  64.         """Return the file extensions for this format."""
  65.         return ["ma"]
  66.     extension = staticmethod(extension)
  67.  
  68.     # description
  69.     def description(self):
  70.         """Return a short description for the file dialog."""
  71.         return "Maya ASCII file"
  72.     description = staticmethod(description)
  73.  
  74.     # importFile
  75.     def importFile(self, filename, parent=None):
  76.         """Import a MA file."""
  77.  
  78.         self.root_parent = parent
  79.  
  80.         f = file(filename)
  81.         self.read(f)
  82.  
  83.     # begin
  84.     def begin(self):
  85.         mayaascii.DefaultMAReader.begin(self)
  86.         # A dict with created WorldObjects (key = name)
  87.         self.worldobjects = {}
  88.  
  89.     # end
  90.     def end(self):
  91.         mayaascii.DefaultMAReader.end(self)
  92.         
  93.         issued_warnings = {}
  94.         # Process the nodes by calling an appropriate handler method
  95.         # onNode<Type>(node) for each node type...
  96.         for node in self.nodelist:
  97.             s = node.nodetype
  98.             handlername = "onNode%s%s"%(s[0].upper(), s[1:])
  99.             handler = getattr(self, handlername, None)
  100.             if handler!=None:
  101.                 handler(node)
  102.             else:
  103.                 if node.nodetype not in issued_warnings:
  104.                     print >>sys.stderr, "WARNING: %s nodes are ignored."%node.nodetype
  105.                     issued_warnings[node.nodetype] = 1
  106.  
  107.     #################################################
  108.  
  109.     ### High level callbacks:
  110.     
  111.     # Each node callback takes the current Node object as argument.
  112.     # Whenever a new WorldObject is created, the method has to call
  113.     # the newWorldObject() method to tell the importer about the new object
  114.     # (so that it is known when someone else uses it as parent).
  115.  
  116.     def ignoreWarning(self, node):
  117.         """(this is just a dummy callback so that no warning is issued)"""
  118.         pass
  119.     onNodeTransform = ignoreWarning
  120.     onNodePolySphere = ignoreWarning
  121.     onNodePolyCube = ignoreWarning
  122.     onNodePolyPlane = ignoreWarning
  123.     onNodeRigidBody = ignoreWarning    
  124.  
  125.     def onNodePointLight(self, node):
  126.         """PointLight node.
  127.         """
  128.         args = self.fillWorldObjectArgs(node)
  129.         
  130.         cl = vec3(node.getAttrValue("color", "cl", "float3", 1, vec3(1)))
  131.         intensity = node.getAttrValue("intensity", "in", "float", 1, 1.0)
  132.         de = node.getAttrValue("decayRate", "de", "int", 1, 0)
  133.         if de==0:
  134.             catt = 1.0
  135.             latt = 0.0
  136.             qatt = 0.0
  137.         elif de==1:
  138.             catt = 0.0
  139.             latt = 1.0
  140.             qatt = 0.0
  141.         else:
  142.             catt = 0.0
  143.             latt = 0.0
  144.             qatt = 1.0
  145.  
  146.         lgt = glpointlight.GLPointLight(diffuse = cl,
  147.                                         intensity = intensity,
  148.                                         constant_attenuation = catt,
  149.                                         linear_attenuation = latt,
  150.                                         quadratic_attenuation = qatt,
  151.                                         enabled = args["visible"],
  152.                                         **args)
  153.         self.newWorldObject(lgt, node.getParentName())
  154.  
  155.     def onNodeSpotLight(self, node):
  156.         """SpotLight node.
  157.         """
  158.         args = self.fillWorldObjectArgs(node)
  159.         
  160.         cl = vec3(node.getAttrValue("color", "cl", "float3", 1, vec3(1)))
  161.         intensity = node.getAttrValue("intensity", "in", "float", 1, 1.0)
  162.         de = node.getAttrValue("decayRate", "de", "int", 1, 0)
  163.         ca = node.getAttrValue("coneAngle", "ca", "float", 1, 40.0)
  164.         pa = node.getAttrValue("penumbraAngle", "pa", "float", 1, 0.0)
  165.         dro = node.getAttrValue("dropoff", "dro", "float", 1, 0.0)
  166.  
  167.         dms = node.getAttrValue("useDepthMapShadows", "dms", "bool", 1, False)
  168.         dr = node.getAttrValue("dmapResolution", "dr", "int", 1, 512)
  169.         md = node.getAttrValue("useMidDistDmap", "md", "bool", 1, True)
  170.         af = node.getAttrValue("useDmapAutoFocus", "af", "bool", 1, True)
  171.         df = node.getAttrValue("dmapFocus", "df", "float", 1, 90.0)
  172.         fs = node.getAttrValue("dmapFilterSize", "fs", "int", 1, 1)
  173.         db = node.getAttrValue("dmapBias", "db", "float", 1, 0.001)
  174.  
  175.         args["transform"] = args["transform"]
  176.  
  177.         lgt = mayaspotlight.MayaSpotLight(color = cl,
  178.                                           intensity = intensity,
  179.                                           decayRate = de,
  180.                                           coneAngle = ca,
  181.                                           penumbraAngle = pa,
  182.                                           dropoff = dro,
  183.                                           useDepthMapShadows = dms,
  184.                                           dmapResolution = dr,
  185.                                           useMidDistDmap = md,
  186.                                           useDmapAutoFocus = af,
  187.                                           dmapFocus = df,
  188.                                           dmapFilterSize = fs,
  189.                                           dmapBias = db,
  190.                                           enabled = args["visible"],
  191.                                           **args)
  192.         self.newWorldObject(lgt, node.getParentName())
  193.  
  194.     def onNodeDirectionalLight(self, node):
  195.         """DirectionalLight node.
  196.         """
  197.         args = self.fillWorldObjectArgs(node)
  198.         
  199.         cl = vec3(node.getAttrValue("color", "cl", "float3", 1, vec3(1)))
  200.         intensity = node.getAttrValue("intensity", "in", "float", 1, 1.0)
  201.  
  202.         args["transform"] = args["transform"]*mat4(1).rotation(pi, vec3(1,0,0))
  203.  
  204.         lgt = glfreedistantlight.GLFreeDistantLight(diffuse = cl,
  205.                                         intensity = intensity,
  206.                                         enabled = args["visible"],
  207.                                         **args)
  208.         self.newWorldObject(lgt, node.getParentName())
  209.  
  210.     def onNodeJoint(self, node):
  211.         """Joint node.
  212.         """
  213.         args = self.fillWorldObjectArgs(node)
  214.  
  215.         # Compute transform
  216.         t = vec3(node.getAttrValue("translate", "t", "double3", 1, vec3(0)))
  217.         r = vec3(node.getAttrValue("rotate", "r", "double3", 1, vec3(0)))
  218.         s = vec3(node.getAttrValue("scale", "s", "double3", 1, vec3(1)))
  219.         ra = vec3(node.getAttrValue("rotateAxis", "ra", "double3", 1, vec3(0)))
  220.         roi = node.getAttrValue("rotationInterpolation", "roi", "int", 1, 1)
  221.         ro = node.getAttrValue("rotateOrder", "ro", "int", 1, default=0)
  222.         jo = vec3(node.getAttrValue("jointOrient", "jo", "double3", 1, vec3(0)))
  223.         is_ = vec3(node.getAttrValue("inverseScale", "is", "double3", 1, vec3(1)))
  224.         jot = node.getAttrValue("jointOrientType", "jot", "string", 1, default="xyz")
  225.  
  226.         S = mat4().scaling(s)
  227.         T = mat4(1,0,0,0, 0,1,0,0, 0,0,1,0, t.x,t.y,t.z,1)
  228.         IS = mat4().scaling(is_)
  229.  
  230.         sx = sin(radians(ra.x))
  231.         cx = cos(radians(ra.x))
  232.         sy = sin(radians(ra.y))
  233.         cy = cos(radians(ra.y))
  234.         sz = sin(radians(ra.z))
  235.         cz = cos(radians(ra.z))
  236.         AX = mat4(1,0,0,0, 0,cx,sx,0, 0,-sx,cx,0, 0,0,0,1)
  237.         AY = mat4(cy,0,-sy,0, 0,1,0,0, sy,0,cy,0, 0,0,0,1)
  238.         AZ = mat4(cz,sz,0,0, -sz,cz,0,0, 0,0,1,0, 0,0,0,1)
  239.         RA = AX*AY*AZ
  240.  
  241.         # Euler-angle rotation (todo: quat)
  242.         sx = sin(radians(r.x))
  243.         cx = cos(radians(r.x))
  244.         sy = sin(radians(r.y))
  245.         cy = cos(radians(r.y))
  246.         sz = sin(radians(r.z))
  247.         cz = cos(radians(r.z))
  248.         RX = mat4(1,0,0,0, 0,cx,sx,0, 0,-sx,cx,0, 0,0,0,1)
  249.         RY = mat4(cy,0,-sy,0, 0,1,0,0, sy,0,cy,0, 0,0,0,1)
  250.         RZ = mat4(cz,sz,0,0, -sz,cz,0,0, 0,0,1,0, 0,0,0,1)
  251.         a,b,c = ["XYZ", "YZX", "ZXY", "XZY", "YXZ", "ZYX"][ro]
  252.         exec "R=R%s*R%s*R%s"%(a,b,c)
  253.  
  254.         sx = sin(radians(jo.x))
  255.         cx = cos(radians(jo.x))
  256.         sy = sin(radians(jo.y))
  257.         cy = cos(radians(jo.y))
  258.         sz = sin(radians(jo.z))
  259.         cz = cos(radians(jo.z))
  260.         AX = mat4(1,0,0,0, 0,cx,sx,0, 0,-sx,cx,0, 0,0,0,1)
  261.         AY = mat4(cy,0,-sy,0, 0,1,0,0, sy,0,cy,0, 0,0,0,1)
  262.         AZ = mat4(cz,sz,0,0, -sz,cz,0,0, 0,0,1,0, 0,0,0,1)
  263.         a,b,c = jot.upper()
  264.         exec "JO=A%s*A%s*A%s"%(a,b,c)
  265.  
  266.         WT = S*RA*R*IS*T
  267.            
  268. #        WT = S*RA*R*IS*T
  269. #        WT = T
  270.         WT = WT.transpose()
  271.         args["transform"] = WT
  272.  
  273.         jnt = joint.Joint(radius = 0.5*node.getAttrValue("radius", "radi", "float", 1, 1.0),
  274.                           offsetTransform = JO.inverse(),
  275.                           **args)
  276.         jnt.freezePivot()
  277.         # Reset offset transform (so that pivot frame and local frame coincide)
  278.         jnt.setOffsetTransform(mat4(1))
  279.         self.newWorldObject(jnt, node.getName())
  280.  
  281.  
  282.     def onNodeCamera(self, node):
  283.         """Camera node.
  284.         """
  285.         args = self.fillWorldObjectArgs(node)
  286.         self.getCameraArgs(node, args)
  287.         args["transform"] = args["transform"]*mat4(1).rotation(pi, vec3(0,1,0))
  288.         cam = freecamera.FreeCamera(**args)
  289.         self.newWorldObject(cam, node.getParentName())
  290.  
  291.     def onNodeMesh(self, node):
  292.         args = self.fillWorldObjectArgs(node)
  293.         parentnode = node.getParent()
  294.         
  295.         # Check if the mesh is just a regular mesh or if it's created by
  296.         # a "creator" node (cube, sphere, ...). 
  297.         n,a = node.getInNode("inMesh", "i")
  298.         if n==None:
  299.             meshtype = None
  300.             verts = node.getAttrValue("vrts", "vt", "float3", None, [])
  301.             edges = node.getAttrValue("edge", "ed", "long3", None, [])
  302.             faces = node.getAttrValue("face", "fc", "polyFaces", None, [])
  303.             polyobj = polyhedron.Polyhedron(verts=verts, **args)
  304.             geom = polyobj.geom
  305.             # Initialize the polygons...
  306.             geom.setNumPolys(len(faces))
  307.             valid_st = True
  308.             for i, face in enumerate(faces):
  309.                 valid_st &= face.hasValidTexCoords()
  310.                 poly = []
  311.                 # Iterate over all "loop" (i.e. the outer loop and the holes)
  312.                 # and create the vertex id list for each loop
  313.                 for loop in [face.f]+face.h:
  314.                     p = []
  315.                     for e in loop:
  316.                         if e>=0:
  317.                             p.append(edges[e][0])
  318.                         else:
  319.                             p.append(edges[-e-1][1])
  320.                     poly.append(p)
  321.                 geom.setPoly(i, poly)
  322.  
  323.             # Set texture coordinates...
  324.             uvset = node.getAttrValue("uvSet", "uvst", type=None, n=None)
  325.             if uvset!=None:
  326.                 stlst = list(uvset[0].uvsp)
  327.                 if valid_st and len(stlst)>0:
  328.                     geom.newVariable("st", USER, FLOAT, 2, len(stlst))
  329.                     st = geom.slot("st")
  330.                     for i,stval in enumerate(stlst):
  331.                         st[i] = stval
  332.                     # Set the tex coord faces...
  333.                     geom.newVariable("stfaces", FACEVARYING, INT)
  334.                     stfaces = geom.slot("stfaces")
  335.                     i = 0
  336.                     for face in faces:
  337.                         for mulst in face.mu:
  338.                             for id in mulst[0][1]:
  339.                                 stfaces[i] = id
  340.                                 i+=1
  341.  
  342.             # Set colors...
  343.             colattr = node.getAttrValue("colors", "clr", type="float4", n=None)
  344.             if colattr!=None:
  345.                 collst = list(colattr)
  346.                 geom.newVariable("Cs", USER, COLOR, 1, len(collst))
  347.                 Cs = geom.slot("Cs")
  348.                 for i,Csval in enumerate(collst):
  349.                     Cs[i] = vec3(Csval[:3])
  350.                 # Set the color faces...
  351.                 geom.newVariable("Csfaces", FACEVARYING, INT)
  352.                 Csfaces = geom.slot("Csfaces")
  353.                 i = 0
  354.                 for face in faces:
  355.                     for fclst in face.fc:
  356.                         for id in fclst:
  357.                             Csfaces[i] = id
  358.                             i+=1
  359.  
  360.             # Apply vertex tweaks...
  361.             pnts = node.getAttrValue("pnts", "pt", "float3", None, [])
  362.             pnts = list(pnts)
  363.             for i,v in enumerate(geom.verts):
  364.                 if i>=len(pnts):
  365.                     break
  366.                 p = pnts[i]
  367.                 if p!=None:
  368.                     if type(p)==list:
  369.                         p = p[0]
  370.                     v += vec3(p)
  371.                     geom.verts[i] = v
  372.  
  373.             # Convert the poly to a trimesh if it's a rigid body
  374.             self.getRigidBodyArgs(parentnode, args)
  375.             if args["dynamics"]:
  376.                 tm = trimeshgeom.TriMeshGeom()
  377.                 polyobj.geom.convert(tm)
  378.                 cmds.delete(polyobj)
  379.                 polyobj = trimesh.TriMesh(**args)
  380.                 polyobj.geom = tm
  381.  
  382.             self.newWorldObject(polyobj, node.getParentName())
  383.         else:
  384.             creator = self.findNode(n)
  385.             meshtype = creator.nodetype
  386.             # Sphere?
  387.             if meshtype=="polySphere":
  388.                 self.createSphere(node, creator, args)
  389.             # Cube?
  390.             elif meshtype=="polyCube":
  391.                 self.createBox(node, creator, args)
  392.             # Plane?
  393.             elif meshtype=="polyPlane":
  394.                 self.createPlane(node, creator, args)
  395.  
  396.     def createSphere(self, mesh, creator, args):
  397.         """Creates a true sphere from a polySphere node.
  398.  
  399.         mesh is the mesh node that takes its input from creator.
  400.         creator is an import Node which must be of type polySphere.
  401.         args is a dictionary that already contains the basic WorldObject
  402.         arguments that can be passed to the constructor.
  403.         """
  404.         parentnode = mesh.getParent()
  405.         nod,attr = parentnode.getOutAttr("worldMatrix", "wm", "rigidBody")
  406.         dynamics = (nod!=None)
  407.         r = creator.getAttrValue("radius", "r", "float", 1, 1.0)
  408.         segsu = creator.getAttrValue("subdivisionAxis", "sa", "int", 1, 20)
  409.         segsv = creator.getAttrValue("subdivisionHeight", "sh", "int", 1, 20)
  410.         ax = vec3(creator.getAttrValue("axis", "ax", "double3", 1, vec3(0,1,0)))
  411. #        args["transform"] *= self.axisToTransform(ax)
  412. #        if ax==vec3(1,0,0):
  413. #            args["transform"] *= mat4(1).rotation(pi/4, vec3(0,0,1))
  414.         self.getRigidBodyArgs(parentnode, args)
  415.         s = quadrics.Sphere(radius=r,
  416.                             segmentsu=segsu, segmentsv=segsv,
  417.                             **args)
  418.         self.newWorldObject(s, parentnode.getName())
  419.  
  420.     def createBox(self, mesh, creator, args):
  421.         """Creates a true box from a polyCube node.
  422.  
  423.         mesh is the mesh node that takes its input from creator.
  424.         creator is an import Node which must be of type polyCube.
  425.         args is a dictionary that already contains the basic WorldObject
  426.         arguments that can be passed to the constructor.
  427.         """
  428.         parentnode = mesh.getParent()
  429.         w = creator.getAttrValue("width", "w", "float", 1, 1.0)
  430.         h = creator.getAttrValue("height", "h", "float", 1, 1.0)
  431.         d = creator.getAttrValue("depth", "d", "float", 1, 1.0)
  432.         sw = creator.getAttrValue("subdivisionWidth", "sw", "int", 1, 1)
  433.         sh = creator.getAttrValue("subdivisionHeight", "sh", "int", 1, 1)
  434.         sd = creator.getAttrValue("subdivisionDepth", "sd", "int", 1, 1)
  435.         ax = vec3(creator.getAttrValue("axis", "ax", "double3", 1, vec3(0,1,0)))
  436.  
  437.         # "Rename" width/height/depth to match the axis setting...
  438.         if ax==vec3(1,0,0):
  439.             tmp = d
  440.             d = w
  441.             w = h
  442.             h = tmp
  443.             tmp = sd
  444.             sd = sw
  445.             sw = sh
  446.             sh = tmp
  447.         elif ax==vec3(0,1,0):
  448.             tmp = d
  449.             d = h
  450.             h = tmp
  451.             tmp = sd
  452.             sd = sh
  453.             sh = tmp
  454.             
  455.         self.getRigidBodyArgs(parentnode, args)
  456.         b = box.Box(lx=w, ly=d, lz=h,
  457.                     segmentsx=sw, segmentsy=sd, segmentsz=sh,
  458.                     **args)
  459.         self.newWorldObject(b, parentnode.getName())
  460.  
  461.     def createPlane(self, mesh, creator, args):
  462.         """Creates a true plane from a polyPlane node.
  463.  
  464.         mesh is the mesh node that takes its input from creator.
  465.         creator is an import Node which must be of type polyPlane.
  466.         args is a dictionary that already contains the basic WorldObject
  467.         arguments that can be passed to the constructor.
  468.         """
  469.         parentnode = mesh.getParent()
  470.         w = creator.getAttrValue("width", "w", "float", 1, 1.0)
  471.         h = creator.getAttrValue("height", "h", "float", 1, 1.0)
  472.         sw = creator.getAttrValue("subdivisionWidth", "sw", "int", 1, 1)
  473.         sh = creator.getAttrValue("subdivisionHeight", "sh", "int", 1, 1)
  474.         ax = vec3(creator.getAttrValue("axis", "ax", "double3", 1, vec3(0,1,0)))
  475.  
  476.         if ax!=vec3(0,0,1):
  477.             print "WARNING: Plane %s ignored because axis!=z"%node.getName()
  478.             return
  479.  
  480. #        args["transform"] *= self.axisToTransform(ax)
  481.         self.getRigidBodyArgs(parentnode, args)
  482.         if "static" in args:
  483.             del args["static"]
  484.         p = plane.Plane(lx=w, ly=h,
  485.                 segmentsx=sw, segmentsy=sh,
  486.                 **args)
  487.         self.newWorldObject(p, parentnode.getName())
  488.  
  489.  
  490.     def getRigidBodyArgs(self, transform, res):
  491.         """Retrieve rigid body information.
  492.  
  493.         transform is the transform node as NodeData object.
  494.         """
  495.         rbnode,attr = transform.getOutAttr("worldMatrix", "wm", "rigidBody")
  496.         # No rigid body node? then don't add any arguments
  497.         if rbnode==None:
  498.             res["dynamics"] = False
  499.             return res
  500.  
  501.         res["dynamics"] = True
  502.         res["mass"] = rbnode.getAttrValue("mass", "mas", "float", 1, 1.0)
  503.         res["static"] = not rbnode.getAttrValue("active", "act", "bool", 1, True)
  504.         return res
  505.         
  506.  
  507. #    def axisToTransform(self, axis):
  508. #        if axis==vec3(1,0,0):
  509. #            return mat4(1).rotation(pi/2, vec3(0,1,0))
  510. #        elif axis==vec3(0,1,0):
  511. #            return mat4(1).rotation(pi/2, vec3(1,0,0))
  512. #        else:
  513. #            return mat4(1)
  514.  
  515.     ### Helpers:
  516.  
  517.     def newWorldObject(self, obj, mayanodename):
  518.         """Notify about the creation of a new world object.
  519.  
  520.         This method has to be called whenever a new WorldObject is created.
  521.         This is needed to later find the object when it is used as parent.
  522.         """
  523.         if mayanodename in self.worldobjects:
  524.             print "WARNING: Duplicate node name '%s'"%mayanodename
  525.             
  526.         self.worldobjects[mayanodename] = obj
  527.  
  528.     # getCameraArgs
  529.     def getCameraArgs(self, node, res):
  530.         """Create the argument dict for the WorldObject constructor.
  531.  
  532.         node must contain the data from a Maya transform node. 
  533.         """
  534.  
  535.         fl = node.getAttrValue("focalLength", "fl", "float", 1, 35.0)
  536.         res["focallength"] = fl
  537.         cap = node.getAttrValue("cameraAperture", "cap", "double2", 1, (1.41732, 0.94488))
  538.  
  539.         fov = degrees(2*atan((cap[0]*25.4)/(2*fl)))
  540.         # Convert the FOV from horizontal to vertical direction
  541.         # (Todo: What aspect ratio to use?)
  542.         fov = degrees(atan(480/640.0*tan(radians(fov/2.0))))*2.0
  543.         res["fov"] = fov
  544.         res["fstop"] = node.getAttrValue("fStop", "fs", "float", 1, 5.6)
  545.         return res
  546.  
  547.     # fillWorldObjectArgs
  548.     def fillWorldObjectArgs(self, node, args=None):
  549.         """Fill the argument dict for the WorldObject constructor.
  550.  
  551.         node must be a Node object containing either the transform node
  552.         or the shape node (whose parent must then be a transform node).
  553.         args must be a dictionary which is filled with the arguments
  554.         for a WorldObject constructor. It can also be None in which case
  555.         a new dictionary is created and returned.
  556.         The following attributes are written into args:
  557.  
  558.         - name: The name of the transform node
  559.         - parent: The parent WorldObject (or self.root_parent)
  560.         - transform: The transform matrix (pos rot may come from a rigidBody node)
  561.  
  562.         The return value is the args dictionary or the newly created dict.
  563.         """
  564.         # Obtain the transform node -> tnode
  565.         if node.nodetype in ["transform", "joint"]:
  566.             tnode = node
  567.         else:
  568.             tnode = node.getParent()
  569.             if tnode==None or tnode.nodetype!="transform":
  570.                 raise ValueError, "transform node not found for node %s."%node.getFullName()
  571.  
  572.         if args==None:
  573.             args = {}
  574.  
  575.         # Name
  576.         args["name"] = tnode.getName()
  577.  
  578.         # Parent
  579.         parentnode = tnode.getParent()
  580.         if parentnode!=None:
  581.             parentname = parentnode.getFullName()
  582.             if parentname!=None:
  583.                 parent = self.worldobjects.get(parentname, None)
  584.                 if parent==None:
  585.                     print "WARNING: Parent '%s' not found."%parentname
  586.                     parent = self.root_parent
  587.         else:
  588.             parent = self.root_parent
  589.         args["parent"] = parent
  590.  
  591.         # Check if the world matrix is connected to a rigid body.
  592.         # In this case, the rigid body stores the initial position and
  593.         # orientation
  594.         rbnode,attr = tnode.getOutAttr("worldMatrix", "wm", "rigidBody")
  595.  
  596.         # Compute transform
  597.         if rbnode==None:
  598.             t = vec3(tnode.getAttrValue("translate", "t", "double3", 1, vec3(0)))
  599.             r = vec3(tnode.getAttrValue("rotate", "r", "double3", 1, vec3(0)))
  600.         else:
  601.             t = vec3(rbnode.getAttrValue("initialPosition", "ip", "double3", 1, vec3(0)))
  602.             r = vec3(rbnode.getAttrValue("initialOrientation", "ior", "double3", 1, vec3(0)))
  603.         s = vec3(tnode.getAttrValue("scale", "s", "double3", 1, vec3(1)))
  604.         sp = vec3(tnode.getAttrValue("scalePivot", "sp", "double3", 1, vec3(0)))
  605.         spt = vec3(tnode.getAttrValue("scalePivotTranslate", "spt", "double3", 1, vec3(0)))
  606.         sh = vec3(tnode.getAttrValue("shear", "sh", "double3", 1, vec3(0)))
  607.         rp = vec3(tnode.getAttrValue("rotatePivot", "rp", "double3", 1, vec3(0)))
  608.         rpt = vec3(tnode.getAttrValue("rotatePivotTranslate", "rpt", "double3", 1, vec3(0)))
  609.         ra = vec3(tnode.getAttrValue("rotateAxis", "ra", "double3", 1, vec3(0)))
  610.         roi = tnode.getAttrValue("rotationInterpolation", "roi", "int", 1, 1)
  611.         ro = tnode.getAttrValue("rotateOrder", "ro", "int", 1, default=0)
  612.  
  613.         SP = mat4(1,0,0,0, 0,1,0,0, 0,0,1,0, sp.x,sp.y,sp.z,1)
  614.         ST = mat4(1,0,0,0, 0,1,0,0, 0,0,1,0, spt.x,spt.y,spt.z,1)
  615.         S = mat4().scaling(s)
  616.         SH = mat4(1,0,0,0, sh.x,1,0,0, sh.y,sh.z,1,0, 0,0,0,1)
  617.         RP = mat4(1,0,0,0, 0,1,0,0, 0,0,1,0, rp.x,rp.y,rp.z,1)
  618.         RT = mat4(1,0,0,0, 0,1,0,0, 0,0,1,0, rpt.x,rpt.y,rpt.z,1)
  619.         T = mat4(1,0,0,0, 0,1,0,0, 0,0,1,0, t.x,t.y,t.z,1)
  620.  
  621.         sx = sin(radians(ra.x))
  622.         cx = cos(radians(ra.x))
  623.         sy = sin(radians(ra.y))
  624.         cy = cos(radians(ra.y))
  625.         sz = sin(radians(ra.z))
  626.         cz = cos(radians(ra.z))
  627.         AX = mat4(1,0,0,0, 0,cx,sx,0, 0,-sx,cx,0, 0,0,0,1)
  628.         AY = mat4(cy,0,-sy,0, 0,1,0,0, sy,0,cy,0, 0,0,0,1)
  629.         AZ = mat4(cz,sz,0,0, -sz,cz,0,0, 0,0,1,0, 0,0,0,1)
  630.         RA = AX*AY*AZ
  631.  
  632.         # Euler-angle rotation (todo: quat)
  633.         sx = sin(radians(r.x))
  634.         cx = cos(radians(r.x))
  635.         sy = sin(radians(r.y))
  636.         cy = cos(radians(r.y))
  637.         sz = sin(radians(r.z))
  638.         cz = cos(radians(r.z))
  639.         RX = mat4(1,0,0,0, 0,cx,sx,0, 0,-sx,cx,0, 0,0,0,1)
  640.         RY = mat4(cy,0,-sy,0, 0,1,0,0, sy,0,cy,0, 0,0,0,1)
  641.         RZ = mat4(cz,sz,0,0, -sz,cz,0,0, 0,0,1,0, 0,0,0,1)
  642.         a,b,c = ["XYZ", "YZX", "ZXY", "XZY", "YXZ", "ZYX"][ro]
  643.         exec "R=R%s*R%s*R%s"%(a,b,c)
  644.  
  645.         WT = SP.inverse()*S*SH*SP*ST*RP.inverse()*RA*R*RP*RT*T
  646.         WT = WT.transpose()
  647.         args["transform"] = WT
  648.  
  649.         # Visibility
  650.         args["visible"] = tnode.getAttrValue("visibility", "v", "bool", 1, True)
  651.         
  652.         return args
  653.  
  654.  
  655. ######################################################################
  656.  
  657. # Register the importer class as a plugin class
  658. pluginmanager.register(MAImporter)
  659.