提交 0a6ce9db 编写于 作者: M Mr.doob

Merge branch 'maya-exporter' of https://github.com/etic/three.js into dev

# Three.js Maya Export
Exports Maya models to Three.js' ASCII JSON format. Currently supports exporting the following:
- Vertices
- Faces
- Normals
- UV sets
- Material indices
- Vertex colors
## Installation
Copy the scripts and plug-ins folders to the appropriate maya folder, where `maya-version` is your current version of Maya (eg. 2013-x64).
- Windows: `C:\Users\username\Documents\maya\maya-version`
- OSX: `~/Library/Preferences/Autodesk/maya/maya-version`
- Linux: `/usr/autodesk/userconfig/maya/maya-version`
After that, you need to activate the plugin. In Maya, open `Window > Settings/Preferences > Plug-in Manager` and enable the checkboxes next to `threeJsFileTranslator.py`.
## Usage
Use the regular Export menus within Maya, select `Three.js`.
\ No newline at end of file
__author__ = 'Chris Lewis'
__version__ = '0.1.0'
__email__ = 'clewis1@c.ringling.edu'
import sys
import json
import maya.cmds as mc
from maya.OpenMaya import *
from maya.OpenMayaMPx import *
kPluginTranslatorTypeName = 'Three.js'
kOptionScript = 'ThreeJsExportScript'
kDefaultOptionsString = '0'
FLOAT_PRECISION = 8
# adds decimal precision to JSON encoding
class DecimalEncoder(json.JSONEncoder):
def _iterencode(self, o, markers=None):
if isinstance(o, float):
s = str(o)
if '.' in s and len(s[s.index('.'):]) > FLOAT_PRECISION - 1:
s = '%.{0}f'.format(FLOAT_PRECISION) % o
while '.' in s and s[-1] == '0':
s = s[-2]
return (s for s in [s])
return super(DecimalEncoder, self)._iterencode(o, markers)
class ThreeJsError(Exception):
pass
class ThreeJsWriter(object):
def __init__(self):
self.componentKeys = ['vertices', 'normals', 'colors', 'uvs', 'materials', 'faces']
def _parseOptions(self, optionsString):
self.options = dict([(x, False) for x in self.componentKeys])
optionsString = optionsString[2:] # trim off the "0;" that Maya adds to the options string
for option in optionsString.split(' '):
self.options[option] = True
def _updateOffsets(self):
for key in self.componentKeys:
if key == 'uvs':
continue
self.offsets[key] = len(getattr(self, key))
for i in range(len(self.uvs)):
self.offsets['uvs'][i] = len(self.uvs[i])
def _getTypeBitmask(self, options):
bitmask = 0
if options['materials']:
bitmask |= 2
if options['uvs']:
bitmask |= 8
if options['normals']:
bitmask |= 32
if options['colors']:
bitmask |= 128
return bitmask
def _exportMesh(self, dagPath, component):
mesh = MFnMesh(dagPath)
options = self.options.copy()
self._updateOffsets()
# export vertex data
if options['vertices']:
try:
iterVerts = MItMeshVertex(dagPath, component)
while not iterVerts.isDone():
point = iterVerts.position(MSpace.kWorld)
self.vertices += [point.x, point.y, point.z]
iterVerts.next()
except:
options['vertices'] = False
# export material data
# TODO: actually parse material data
materialIndices = MIntArray()
if options['materials']:
try:
shaders = MObjectArray()
mesh.getConnectedShaders(0, shaders, materialIndices)
while len(self.materials) < shaders.length():
self.materials.append({}) # placeholder material definition
except:
self.materials = [{}]
# export uv data
if options['uvs']:
try:
uvLayers = []
mesh.getUVSetNames(uvLayers)
while len(uvLayers) > len(self.uvs):
self.uvs.append([])
self.offsets['uvs'].append(0)
for i, layer in enumerate(uvLayers):
uList = MFloatArray()
vList = MFloatArray()
mesh.getUVs(uList, vList, layer)
for j in xrange(uList.length()):
self.uvs[i] += [uList[j], vList[j]]
except:
options['uvs'] = False
# export normal data
if options['normals']:
try:
normals = MFloatVectorArray()
mesh.getNormals(normals, MSpace.kWorld)
for i in xrange(normals.length()):
point = normals[i]
self.normals += [point.x, point.y, point.z]
except:
options['normals'] = False
# export color data
if options['colors']:
try:
colors = MColorArray()
mesh.getColors(colors)
for i in xrange(colors.length()):
color = colors[i]
# uncolored vertices are set to (-1, -1, -1). Clamps colors to (0, 0, 0).
self.colors += [max(color.r, 0), max(color.g, 0), max(color.b, 0)]
except:
options['colors'] = False
# export face data
if not options['vertices']:
return
bitmask = self._getTypeBitmask(options)
iterPolys = MItMeshPolygon(dagPath, component)
while not iterPolys.isDone():
self.faces.append(bitmask)
# export face vertices
verts = MIntArray()
iterPolys.getVertices(verts)
for i in xrange(verts.length()):
self.faces.append(verts[i] + self.offsets['vertices'])
# export face vertex materials
if options['materials']:
if materialIndices.length():
self.faces.append(materialIndices[iterPolys.index()])
# export face vertex uvs
if options['uvs']:
util = MScriptUtil()
uvPtr = util.asIntPtr()
for i, layer in enumerate(uvLayers):
for j in xrange(verts.length()):
iterPolys.getUVIndex(j, uvPtr, layer)
uvIndex = util.getInt(uvPtr)
self.faces.append(uvIndex + self.offsets['uvs'][i])
# export face vertex normals
if options['normals']:
for i in xrange(3):
normalIndex = iterPolys.normalIndex(i)
self.faces.append(normalIndex + self.offsets['normals'])
# export face vertex colors
if options['colors']:
colors = MIntArray()
iterPolys.getColorIndices(colors)
for i in xrange(colors.length()):
self.faces.append(colors[i] + self.offsets['colors'])
iterPolys.next()
def _getMeshes(self, nodes):
meshes = []
for node in nodes:
if mc.nodeType(node) == 'mesh':
meshes.append(node)
else:
for child in mc.listRelatives(node, s=1):
if mc.nodeType(child) == 'mesh':
meshes.append(child)
return meshes
def _exportMeshes(self):
# export all
if self.accessMode == MPxFileTranslator.kExportAccessMode:
mc.select(self._getMeshes(mc.ls(typ='mesh')))
# export selection
elif self.accessMode == MPxFileTranslator.kExportActiveAccessMode:
mc.select(self._getMeshes(mc.ls(sl=1)))
else:
raise ThreeJsError('Unsupported access mode: {0}'.format(self.accessMode))
dups = [mc.duplicate(mesh)[0] for mesh in mc.ls(sl=1)]
combined = mc.polyUnite(dups, mergeUVSets=1, ch=0) if len(dups) > 1 else dups[0]
mc.polyTriangulate(combined)
mc.select(combined)
sel = MSelectionList()
MGlobal.getActiveSelectionList(sel)
mDag = MDagPath()
mComp = MObject()
sel.getDagPath(0, mDag, mComp)
self._exportMesh(mDag, mComp)
mc.delete(combined)
def write(self, path, optionString, accessMode):
self.path = path
self._parseOptions(optionString)
self.accessMode = accessMode
self.root = dict(metadata=dict(formatVersion=3))
self.offsets = dict()
for key in self.componentKeys:
setattr(self, key, [])
self.offsets[key] = 0
self.offsets['uvs'] = []
self.uvs = []
self._exportMeshes()
# add the component buffers to the root JSON object
for key in self.componentKeys:
buffer_ = getattr(self, key)
if buffer_:
self.root[key] = buffer_
# materials are required for parsing
if not self.root.has_key('materials'):
self.root['materials'] = [{}]
# write the file
with file(self.path, 'w') as f:
f.write(json.dumps(self.root, separators=(',',':'), cls=DecimalEncoder))
class ThreeJsTranslator(MPxFileTranslator):
def __init__(self):
MPxFileTranslator.__init__(self)
def haveWriteMethod(self):
return True
def filter(self):
return '*.js'
def defaultExtension(self):
return 'js'
def writer(self, fileObject, optionString, accessMode):
path = fileObject.fullName()
writer = ThreeJsWriter()
writer.write(path, optionString, accessMode)
def translatorCreator():
return asMPxPtr(ThreeJsTranslator())
def initializePlugin(mobject):
mplugin = MFnPlugin(mobject)
try:
mplugin.registerFileTranslator(kPluginTranslatorTypeName, None, translatorCreator, kOptionScript, kDefaultOptionsString)
except:
sys.stderr.write('Failed to register translator: %s' % kPluginTranslatorTypeName)
raise
def uninitializePlugin(mobject):
mplugin = MFnPlugin(mobject)
try:
mplugin.deregisterFileTranslator(kPluginTranslatorTypeName)
except:
sys.stderr.write('Failed to deregister translator: %s' % kPluginTranslatorTypeName)
raise
\ No newline at end of file
// ThreeJsExportScript.mel
// Author: Chris Lewis
// Email: clewis1@c.ringling.edu
global proc int ThreeJsExportScript(string $parent, string $action, string $settings, string $callback)
{
if ($action == "post")
{
setParent $parent;
columnLayout -adj true;
checkBox -v true -l "Vertices" vertsCb;
checkBox -v true -l "Faces" facesCb;
checkBox -v true -l "Normals" normalsCb;
checkBox -v true -l "UVs" uvsCb;
checkBox -v false -l "Material Indices" materialsCb;
checkBox -v false -l "Colors" colorsCb;
}
else if ($action == "query")
{
string $option = "\"";
if (`checkBox -q -v vertsCb`)
$option += "vertices ";
if (`checkBox -q -v facesCb`)
$option += "faces ";
if (`checkBox -q -v normalsCb`)
$option += "normals ";
if (`checkBox -q -v uvsCb`)
$option += "uvs ";
if (`checkBox -q -v materialsCb`)
$option += "materials ";
if (`checkBox -q -v colorsCb`)
$option += "colors ";
$option += "\"";
eval($callback + $option);
}
return 1;
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册