Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
//-*****************************************************************************
//
// Copyright (c) 2009-2014,
// Sony Pictures Imageworks Inc. and
// Industrial Light & Magic, a division of Lucasfilm Entertainment Company Ltd.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Sony Pictures Imageworks, nor
// Industrial Light & Magic, nor the names of their contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//-*****************************************************************************
#include "MayaMeshWriter.h"
#include "MayaUtility.h"
#include <maya/MItSelectionList.h>
#include <maya/MFnSingleIndexedComponent.h>
namespace {
void getColorSet(MFnMesh & iMesh, const MString * iColorSet, bool isRGBA,
std::vector<float> & oColors,
std::vector< Alembic::Util::uint32_t > & oColorIndices)
{
MColorArray colorArray;
iMesh.getColors(colorArray, iColorSet);
bool addDefaultColor = true;
int numFaces = iMesh.numPolygons();
for (int faceIndex = 0; faceIndex < numFaces; faceIndex++)
{
MIntArray vertexList;
iMesh.getPolygonVertices(faceIndex, vertexList);
int numVertices = iMesh.polygonVertexCount(faceIndex);
for ( int v = numVertices-1; v >=0; v-- )
{
int colorIndex = 0;
iMesh.getColorIndex(faceIndex, v, colorIndex, iColorSet);
if (colorIndex == -1)
{
if (addDefaultColor)
{
addDefaultColor = false;
colorArray.append(MColor(1.0, 1.0, 1.0, 1.0));
}
colorIndex = colorArray.length() - 1;
}
oColorIndices.push_back(colorIndex);
}
}
int colorLen = colorArray.length();
for (int i = 0; i < colorLen; ++i)
{
MColor color = colorArray[i];
oColors.push_back(color.r);
oColors.push_back(color.g);
oColors.push_back(color.b);
if (isRGBA)
{
oColors.push_back(color.a);
}
}
};
void getUVSet(const MFnMesh & iMesh, const MString & iUVSetName,
std::vector<float> & oUVs, std::vector<Alembic::Util::uint32_t> & oIndices)
{
MFloatArray uArray, vArray;
iMesh.getUVs(uArray, vArray, &iUVSetName);
if ( uArray.length() != vArray.length() )
{
MString msg = "UV Set " + iUVSetName +
" uArray and vArray not the same length";
MGlobal::displayError(msg);
return;
}
unsigned int arLen = uArray.length();
oUVs.clear();
oUVs.reserve(arLen * 2);
for (unsigned int i = 0; i < arLen; ++i)
{
oUVs.push_back(uArray[i]);
oUVs.push_back(vArray[i]);
}
oIndices.clear();
oIndices.reserve(iMesh.numFaceVertices());
int faceCount = iMesh.numPolygons();
int uvId = 0;
for (int j = 0; j < faceCount; ++j)
{
int vc = iMesh.polygonVertexCount(j);
for (int i = vc - 1; i >= 0; i--)
{
iMesh.getPolygonUVid(j, i, uvId, &iUVSetName);
oIndices.push_back(uvId);
}
}
}
}
void MayaMeshWriter::getUVs(std::vector<float> & uvs,
std::vector<Alembic::Util::uint32_t> & indices,
std::string & name)
{
MStatus status = MS::kSuccess;
MFnMesh lMesh( mDagPath, &status );
if ( !status )
{
MGlobal::displayError( "MFnMesh() failed for MayaMeshWriter" );
}
MString uvSetName = lMesh.currentUVSetName(&status);
if (uvSetName.length() != 0)
{
MFloatArray uArray, vArray;
status = lMesh.getUVs(uArray, vArray, &uvSetName);
// convert the raw uv list into vector uvsvec.clear();
if ( uArray.length() != vArray.length() )
{
MString msg = "uv Set" + uvSetName +
"uArray and vArray not the same length";
MGlobal::displayError(msg);
return;
}
if (uvSetName != "map1")
{
name = uvSetName.asChar();
}
unsigned int len = uArray.length();
uvs.clear();
uvs.reserve(len * 2);
for (unsigned int i = 0; i < len; i++)
{
uvs.push_back(uArray[i]);
uvs.push_back(vArray[i]);
}
indices.clear();
indices.reserve(lMesh.numFaceVertices());
int faceCount = lMesh.numPolygons();
int uvId = 0;
for (int f = 0; f < faceCount; f++)
{
int len = lMesh.polygonVertexCount(f);
for (int i = len-1; i >= 0; i--)
{
lMesh.getPolygonUVid(f, i, uvId, &uvSetName);
indices.push_back(uvId);
}
}
}
}
MayaMeshWriter::MayaMeshWriter(MDagPath & iDag,
Alembic::Abc::OObject & iParent, Alembic::Util::uint32_t iTimeIndex,
const JobArgs & iArgs)
: mNoNormals(iArgs.noNormals),
mWriteGeometry(iArgs.writeGeometry),
mWriteUVs(iArgs.writeUVs),
mWriteColorSets(iArgs.writeColorSets),
mWriteUVSets(iArgs.writeUVSets),
mIsGeometryAnimated(false),
mDagPath(iDag)
{
MStatus status = MS::kSuccess;
MFnMesh lMesh( mDagPath, &status );
if ( !status )
{
MGlobal::displayError( "MFnMesh() failed for MayaMeshWriter" );
}
// intermediate objects aren't translated
MObject surface = iDag.node();
if (iTimeIndex != 0 && util::isAnimated(surface))
{
mIsGeometryAnimated = true;
}
else
{
iTimeIndex = 0;
}
std::vector<float> uvs;
std::vector<Alembic::Util::uint32_t> indices;
std::string uvSetName;
MString name = lMesh.name();
name = util::stripNamespaces(name, iArgs.stripNamespace);
// check to see if this poly has been tagged as a SubD
MPlug plug = lMesh.findPlug("SubDivisionMesh", true);
// if there is flag "autoSubd", and NO "SubDivisionMesh" was defined,
// let's check whether the mesh has crease edge, crease vertex or holes
// then the mesh will be treated as SubD
bool hasToWriteSubd = false;
if( plug.isNull() && iArgs.autoSubd )
{
MUintArray edgeIds, vertexIds;
MDoubleArray edgeCreaseData, vertexCreaseData;
lMesh.getCreaseEdges(edgeIds, edgeCreaseData);
lMesh.getCreaseVertices(vertexIds, vertexCreaseData);
hasToWriteSubd = ( (edgeIds.length() > 0) || (vertexIds.length() > 0) );
#if MAYA_API_VERSION >= 201100
if (!hasToWriteSubd)
{
MUintArray invisibleFaceIds = lMesh.getInvisibleFaces();
hasToWriteSubd = ( hasToWriteSubd || (invisibleFaceIds.length() > 0) );
}
#endif
}
Alembic::Abc::SparseFlag sf = Alembic::Abc::kFull;
if ( !mWriteGeometry )
{
sf = Alembic::Abc::kSparse;
}
if ( (!plug.isNull() && plug.asBool()) || hasToWriteSubd )
{
Alembic::AbcGeom::OSubD obj(iParent, name.asChar(), sf, iTimeIndex);
mSubDSchema = obj.getSchema();
Alembic::AbcGeom::OV2fGeomParam::Sample uvSamp;
if (mWriteUVs || mWriteUVSets)
{
getUVs(uvs, indices, uvSetName);
if (!uvs.empty())
{
if (!uvSetName.empty())
{
mSubDSchema.setUVSourceName(uvSetName);
}
uvSamp.setScope( Alembic::AbcGeom::kFacevaryingScope );
uvSamp.setVals(Alembic::AbcGeom::V2fArraySample(
(const Imath::V2f *) &uvs.front(), uvs.size() / 2));
if (!indices.empty())
{
uvSamp.setIndices(Alembic::Abc::UInt32ArraySample(
&indices.front(), indices.size()));
}
}
}
Alembic::Abc::OCompoundProperty cp;
Alembic::Abc::OCompoundProperty up;
if (AttributesWriter::hasAnyAttr(lMesh, iArgs))
{
cp = mSubDSchema.getArbGeomParams();
up = mSubDSchema.getUserProperties();
}
mAttrs = AttributesWriterPtr(new AttributesWriter(cp, up, obj, lMesh,
iTimeIndex, iArgs, true));
if (!mIsGeometryAnimated || iArgs.setFirstAnimShape)
{
writeSubD(uvSamp);
}
}
else
{
Alembic::AbcGeom::OPolyMesh obj(iParent, name.asChar(), sf, iTimeIndex);
mPolySchema = obj.getSchema();
Alembic::AbcGeom::OV2fGeomParam::Sample uvSamp;
if (mWriteUVs || mWriteUVSets)
{
getUVs(uvs, indices, uvSetName);
if (!uvs.empty())
{
if (!uvSetName.empty())
{
mPolySchema.setUVSourceName(uvSetName);
}
uvSamp.setScope( Alembic::AbcGeom::kFacevaryingScope );
uvSamp.setVals(Alembic::AbcGeom::V2fArraySample(
(const Imath::V2f *) &uvs.front(), uvs.size() / 2));
if (!indices.empty())
{
uvSamp.setIndices(Alembic::Abc::UInt32ArraySample(
&indices.front(), indices.size()));
}
}
}
Alembic::Abc::OCompoundProperty cp;
Alembic::Abc::OCompoundProperty up;
if (AttributesWriter::hasAnyAttr(lMesh, iArgs))
{
cp = mPolySchema.getArbGeomParams();
up = mPolySchema.getUserProperties();
}
// set the rest of the props and write to the writer node
mAttrs = AttributesWriterPtr(new AttributesWriter(cp, up, obj, lMesh,
iTimeIndex, iArgs, true));
if (!mIsGeometryAnimated || iArgs.setFirstAnimShape)
{
writePoly(uvSamp);
}
}
if (mWriteColorSets)
{
MStringArray colorSetNames;
lMesh.getColorSetNames(colorSetNames);
if (colorSetNames.length() > 0)
{
// Create the color sets compound prop
Alembic::Abc::OCompoundProperty arbParams;
if (mPolySchema.valid())
{
arbParams = mPolySchema.getArbGeomParams();
}
else
{
arbParams = mSubDSchema.getArbGeomParams();
}
std::string currentColorSet = lMesh.currentColorSetName().asChar();
for (unsigned int i=0; i < colorSetNames.length(); ++i)
{
// Create an array property for each color set
std::string colorSetPropName = colorSetNames[i].asChar();
Alembic::AbcCoreAbstract::MetaData md;
if (currentColorSet == colorSetPropName)
{
md.set("mayaColorSet", "1");
}
else
{
md.set("mayaColorSet", "0");
}
if (lMesh.getColorRepresentation(colorSetNames[i]) ==
MFnMesh::kRGB)
{
Alembic::AbcGeom::OC3fGeomParam colorProp(arbParams,
colorSetPropName, true,
Alembic::AbcGeom::kFacevaryingScope, 1, iTimeIndex, md);
mRGBParams.push_back(colorProp);
}
else
{
Alembic::AbcGeom::OC4fGeomParam colorProp(arbParams,
colorSetPropName, true,
Alembic::AbcGeom::kFacevaryingScope, 1, iTimeIndex, md);
mRGBAParams.push_back(colorProp);
}
}
if (!mIsGeometryAnimated || iArgs.setFirstAnimShape)
{
writeColor();
}
}
}
if (mWriteUVSets)
{
MStringArray uvSetNames;
lMesh.getUVSetNames(uvSetNames);
unsigned int uvSetNamesLen = uvSetNames.length();
if (uvSetNamesLen > 1)
{
// Create the uv sets compound prop
Alembic::Abc::OCompoundProperty arbParams;
if (mPolySchema.valid())
{
arbParams = mPolySchema.getArbGeomParams();
}
else
{
arbParams = mSubDSchema.getArbGeomParams();
}
MString currentUV = lMesh.currentUVSetName();
for (unsigned int i = 0; i < uvSetNamesLen; ++i)
{
// Create an array property for each uv set
MString uvSetPropName = uvSetNames[i];
// the current UV set gets mapped to the primary UVs
if (currentUV == uvSetPropName)
{
continue;
}
if (uvSetPropName.length() > 0 &&
lMesh.numUVs(uvSetPropName) > 0)
{
mUVparams.push_back(Alembic::AbcGeom::OV2fGeomParam(
arbParams, uvSetPropName.asChar(), true,
Alembic::AbcGeom::kFacevaryingScope, 1, iTimeIndex));
}
}
if (!mIsGeometryAnimated || iArgs.setFirstAnimShape)
{
writeUVSets();
}
}
}
// write out facesets
if(!iArgs.writeFaceSets)
return;
MFnDependencyNode meshDep(mDagPath.node());
MPlug iogPlug( meshDep.findPlug("instObjGroups", false, &status) );
if( status == MS::kFailure )
{
return;
}
// we can have multiple connects to the same shading engine
std::map< std::string,
std::pair< MObject, std::vector< MPlug > > > facesetMap;
// mesh.instObjGroups is an array of compounds
for (unsigned int i = 0; i < iogPlug.numElements(); ++i)
{
MPlug compPlug = iogPlug.elementByPhysicalIndex(i);
for (unsigned int j = 0; j < compPlug.numChildren(); ++j)
{
// no elements in the child could mean the whole mesh is shaded
MPlug objGroupPlug = compPlug.child(j);
for (unsigned int k = 0; k < objGroupPlug.numElements(); ++k)
{
// mesh.instObjGroups[i].objectGroups[k]
MPlug objGrpCompPlug = objGroupPlug.elementByPhysicalIndex(k);
if (objGrpCompPlug.isNull())
{
continue;
}
MPlugArray dests;
if (!objGrpCompPlug.destinations(dests))
{
continue;
}
MObject shadingObj;
// look for a shading engine, can we have more than 1?
for (unsigned int p = 0; p < dests.length(); ++p)
{
if (dests[p].isNull())
{
continue;
}
MObject testObj = dests[p].node();
if (!testObj.hasFn(MFn::kShadingEngine))
{
continue;
}
else
{
shadingObj = testObj;
}
}
if (shadingObj.isNull())
{
continue;
}
// mesh.instObjGroups[i].objectGroups[k].objectGrpCompList
for (unsigned int l = 0; l < objGrpCompPlug.numChildren(); ++l)
{
MPlug childPlug = objGrpCompPlug.child(l);
MString plugName = childPlug.name();
plugName = plugName.substringW(plugName.length() - 17, plugName.length() - 1);
if (plugName == "objectGrpCompList")
{
MFnDependencyNode fnDepNode(shadingObj);
std::string faceSetName = fnDepNode.name().asChar();
std::map< std::string, std::pair< MObject,
std::vector< MPlug > > >::iterator it =
facesetMap.find(faceSetName);
if (it == facesetMap.end())
{
std::pair< MObject, std::vector< MPlug > > opPair;
opPair.first = shadingObj;
opPair.second.push_back(childPlug);
facesetMap[faceSetName] = opPair;
}
else
{
it->second.second.push_back(childPlug);
}
// we can move on to the next
// mesh.instObjGroups[i].objectGroups[k]
break;
}
} // for l
} // for k
} // for j
} // for i
Alembic::Abc::OObject parentObj;
if (mPolySchema.valid())
{
parentObj = mPolySchema.getObject();
}
else
{
parentObj = mSubDSchema.getObject();
}
std::map< std::string,
std::pair< MObject, std::vector< MPlug > > >::iterator it;
for (it = facesetMap.begin(); it != facesetMap.end(); ++it)
{
MayaFaceSetWriterPtr facePtr(new MayaFaceSetWriter(
it->second.first, it->second.second, parentObj,
iTimeIndex, iArgs));
mFaceSets.push_back(facePtr);
}
}
bool MayaMeshWriter::isSubD()
{
return mSubDSchema.valid();
}
unsigned int MayaMeshWriter::getNumCVs()
{
MStatus status = MS::kSuccess;
MFnMesh lMesh( mDagPath, &status );
if ( !status )
{
MGlobal::displayError( "MFnMesh() failed for MayaMeshWriter" );
}
return lMesh.numVertices();
}
unsigned int MayaMeshWriter::getNumFaces()
{
MStatus status = MS::kSuccess;
MFnMesh lMesh( mDagPath, &status );
if ( !status )
{
MGlobal::displayError( "MFnMesh() failed for MayaMeshWriter" );
}
return lMesh.numPolygons();
}
void MayaMeshWriter::getPolyNormals(std::vector<float> & oNormals)
{
MStatus status = MS::kSuccess;
MFnMesh lMesh( mDagPath, &status );
if ( !status )
{
MGlobal::displayError( "MFnMesh() failed for MayaMeshWriter" );
}
// no normals bail early
if (mNoNormals)
{
return;
}
MPlug plug = lMesh.findPlug("noNormals", true, &status);
if (status == MS::kSuccess && plug.asBool() == true)
{
return;
}
// we need to check the locked state of the normals
else if ( status != MS::kSuccess )
{
bool userSetNormals = false;
// go through all per face-vertex normals and verify if any of them
// has been tweaked by users
unsigned int numFaces = lMesh.numPolygons();
for (unsigned int faceIndex = 0; faceIndex < numFaces; faceIndex++)
{
MIntArray normals;
lMesh.getFaceNormalIds(faceIndex, normals);
unsigned int numNormals = normals.length();
for (unsigned int n = 0; n < numNormals; n++)
{
if (lMesh.isNormalLocked(normals[n]))
{
userSetNormals = true;
break;
}
}
}
// we looped over all the normals and they were all calculated by Maya
// so we just need to check to see if any of the edges are hard
// before we decide not to write the normals.
if (!userSetNormals)
{
bool hasHardEdges = false;
// go through all edges and verify if any of them is hard edge
unsigned int numEdges = lMesh.numEdges();
for (unsigned int edgeIndex = 0; edgeIndex < numEdges; edgeIndex++)
{
if (!lMesh.isEdgeSmooth(edgeIndex))
{
hasHardEdges = true;
break;
}
}
// all the edges were smooth, we don't need to write the normals
if (!hasHardEdges)
{
return;
}
}
}
bool flipNormals = false;
plug = lMesh.findPlug("flipNormals", true, &status);
if ( status == MS::kSuccess )
flipNormals = plug.asBool();
// get the per vertex per face normals (aka vertex)
unsigned int numFaces = lMesh.numPolygons();
for (unsigned int faceIndex = 0; faceIndex < numFaces; faceIndex++ )
{
MIntArray vertexList;
lMesh.getPolygonVertices(faceIndex, vertexList);
// re-pack the order of normals in this vector before writing into prop
// so that Renderman can also use it
unsigned int numVertices = vertexList.length();
for ( int v = numVertices-1; v >=0; v-- )
{
unsigned int vertexIndex = vertexList[v];
MVector normal;
lMesh.getFaceVertexNormal(faceIndex, vertexIndex, normal);
if (flipNormals)
normal = -normal;
oNormals.push_back(static_cast<float>(normal[0]));
oNormals.push_back(static_cast<float>(normal[1]));
oNormals.push_back(static_cast<float>(normal[2]));
}
}
}
void MayaMeshWriter::writeUVSets()
{
MStatus status = MS::kSuccess;
const MFnMesh lMesh(mDagPath, &status);
if (!status)
{
MGlobal::displayError(
"MFnMesh() failed for MayaMeshWriter::writeUV" );
return;
}
//Write uvs
const UVParamsVec::const_iterator uvItEnd = mUVparams.end();
for (UVParamsVec::iterator uvIt = mUVparams.begin();
uvIt != uvItEnd; ++uvIt)
{
std::vector<float> uvs;
std::vector<Alembic::Util::uint32_t> indices;
MString uvSetName(uvIt->getName().c_str());
getUVSet(lMesh, uvSetName, uvs, indices);
//cast the vector to the sample type
Alembic::AbcGeom::OV2fGeomParam::Sample sample(
Alembic::Abc::V2fArraySample(
(const Imath::V2f *) &uvs.front(), uvs.size() / 2),
Alembic::Abc::UInt32ArraySample(indices),
Alembic::AbcGeom::kFacevaryingScope);
uvIt->set(sample);
}
}
void MayaMeshWriter::writeColor()
{
MStatus status = MS::kSuccess;
MFnMesh lMesh( mDagPath, &status );
if ( !status )
{
MGlobal::displayError(
"MFnMesh() failed for MayaMeshWriter::writeColor" );
return;
}
//Write colors
std::vector<Alembic::AbcGeom::OC4fGeomParam>::iterator rgbaIt;
std::vector<Alembic::AbcGeom::OC4fGeomParam>::iterator rgbaItEnd;
rgbaIt = mRGBAParams.begin();
rgbaItEnd = mRGBAParams.end();
for (; rgbaIt != rgbaItEnd; ++rgbaIt)
{
std::vector<float> colors;
std::vector< Alembic::Util::uint32_t > colorIndices;
MString colorSetName(rgbaIt->getName().c_str());
getColorSet(lMesh, &colorSetName, true, colors, colorIndices);
//cast the vector to the sample type
Alembic::AbcGeom::OC4fGeomParam::Sample samp(
Alembic::Abc::C4fArraySample(
(const Imath::C4f *) &colors.front(), colors.size()/4),
Alembic::Abc::UInt32ArraySample(colorIndices),
Alembic::AbcGeom::kFacevaryingScope );
rgbaIt->set(samp);
}
std::vector<Alembic::AbcGeom::OC3fGeomParam>::iterator rgbIt;
std::vector<Alembic::AbcGeom::OC3fGeomParam>::iterator rgbItEnd;
rgbIt = mRGBParams.begin();
rgbItEnd = mRGBParams.end();
for (; rgbIt != rgbItEnd; ++rgbIt)
{
std::vector<float> colors;
std::vector< Alembic::Util::uint32_t > colorIndices;
MString colorSetName(rgbIt->getName().c_str());
getColorSet(lMesh, &colorSetName, false, colors, colorIndices);
//cast the vector to the sample type
Alembic::AbcGeom::OC3fGeomParam::Sample samp(
Alembic::Abc::C3fArraySample(
(const Imath::C3f *) &colors.front(), colors.size()/3),
Alembic::Abc::UInt32ArraySample(colorIndices),
Alembic::AbcGeom::kFacevaryingScope);
rgbIt->set(samp);
}
}
void MayaMeshWriter::write()
{
MStatus status = MS::kSuccess;
MFnMesh lMesh( mDagPath, &status );
if ( !status )
{
MGlobal::displayError( "MFnMesh() failed for MayaMeshWriter" );
}
Alembic::AbcGeom::OV2fGeomParam::Sample uvSamp;
std::vector<float> uvs;
std::vector<Alembic::Util::uint32_t> indices;
std::string uvSetName;
if (mWriteUVs || mWriteUVSets)
{
getUVs(uvs, indices, uvSetName);
if (!uvs.empty())
{
if (!uvSetName.empty())
{
if (mPolySchema.valid())
{
mPolySchema.setUVSourceName(uvSetName);
}
else if (mSubDSchema.valid())
{
mSubDSchema.setUVSourceName(uvSetName);
}
}
uvSamp.setScope( Alembic::AbcGeom::kFacevaryingScope );
uvSamp.setVals(Alembic::AbcGeom::V2fArraySample(
(const Imath::V2f *) &uvs.front(), uvs.size() / 2));
if (!indices.empty())
{
uvSamp.setIndices(Alembic::Abc::UInt32ArraySample(
&indices.front(), indices.size()));
}
}
}
std::vector<float> points;
std::vector<Alembic::Util::int32_t> facePoints;
std::vector<Alembic::Util::int32_t> faceList;
if (mPolySchema.valid())
{
writePoly(uvSamp);
}
else if (mSubDSchema.valid())
{
writeSubD(uvSamp);
}
std::vector< MayaFaceSetWriterPtr >::iterator it;
for (it = mFaceSets.begin(); it != mFaceSets.end(); ++it)
{
(*it)->write();
}
}
bool MayaMeshWriter::isAnimated() const
{
return mIsGeometryAnimated;
}
void MayaMeshWriter::writePoly(
const Alembic::AbcGeom::OV2fGeomParam::Sample & iUVs)
{
MStatus status = MS::kSuccess;
MFnMesh lMesh( mDagPath, &status );
if ( !status )
{
MGlobal::displayError( "MFnMesh() failed for MayaMeshWriter" );
}
std::vector<float> points;
std::vector<Alembic::Util::int32_t> facePoints;
std::vector<Alembic::Util::int32_t> pointCounts;
if( mWriteGeometry )
{
fillTopology(points, facePoints, pointCounts);
}
Alembic::AbcGeom::ON3fGeomParam::Sample normalsSamp;
std::vector<float> normals;
getPolyNormals(normals);
if (!normals.empty())
{
normalsSamp.setScope( Alembic::AbcGeom::kFacevaryingScope );
normalsSamp.setVals(Alembic::AbcGeom::N3fArraySample(
(const Imath::V3f *) &normals.front(), normals.size() / 3));
}
Alembic::AbcGeom::OPolyMeshSchema::Sample samp;
if ( mWriteGeometry )
{
samp.setPositions(Alembic::Abc::V3fArraySample(
(const Imath::V3f *)&points.front(), points.size() / 3) );
samp.setFaceIndices(Alembic::Abc::Int32ArraySample(facePoints));
samp.setFaceCounts(Alembic::Abc::Int32ArraySample(pointCounts));
}
samp.setUVs( iUVs );
samp.setNormals( normalsSamp );
mPolySchema.set(samp);
writeColor();
writeUVSets();
}
void MayaMeshWriter::writeSubD(
const Alembic::AbcGeom::OV2fGeomParam::Sample & iUVs)
{
MStatus status = MS::kSuccess;
MFnMesh lMesh( mDagPath, &status );
if ( !status )
{
MGlobal::displayError( "MFnMesh() failed for MayaMeshWriter" );
}
std::vector<float> points;
std::vector<Alembic::Util::int32_t> facePoints;
std::vector<Alembic::Util::int32_t> pointCounts;
if( mWriteGeometry )
{
fillTopology(points, facePoints, pointCounts);
}
Alembic::AbcGeom::OSubDSchema::Sample samp;
if ( !mWriteGeometry )
{
samp.setUVs( iUVs );
mSubDSchema.set(samp);
writeColor();
writeUVSets();
return;
}
samp.setPositions(Alembic::AbcGeom::V3fArraySample(
(const Imath::V3f *)&points.front(), points.size() / 3));
samp.setFaceIndices(Alembic::Abc::Int32ArraySample(facePoints));
samp.setFaceCounts(Alembic::Abc::Int32ArraySample(pointCounts));
MPlug plug = lMesh.findPlug("faceVaryingInterpolateBoundary", true);
if (!plug.isNull())
samp.setFaceVaryingInterpolateBoundary(plug.asInt());
plug = lMesh.findPlug("interpolateBoundary", true);
if (!plug.isNull())
samp.setInterpolateBoundary(plug.asInt());
plug = lMesh.findPlug("faceVaryingPropagateCorners", true);
if (!plug.isNull())
samp.setFaceVaryingPropagateCorners(plug.asInt());
std::vector <Alembic::Util::int32_t> creaseIndices;
std::vector <Alembic::Util::int32_t> creaseLengths;
std::vector <float> creaseSharpness;
std::vector <Alembic::Util::int32_t> cornerIndices;
std::vector <float> cornerSharpness;
MUintArray edgeIds;
MDoubleArray creaseData;
if (lMesh.getCreaseEdges(edgeIds, creaseData) == MS::kSuccess)
{
unsigned int numCreases = creaseData.length();
creaseIndices.resize(numCreases * 2);
creaseLengths.resize(numCreases, 2);
creaseSharpness.resize(numCreases);
for (unsigned int i = 0; i < numCreases; ++i)
{
int verts[2];
lMesh.getEdgeVertices(edgeIds[i], verts);
creaseIndices[2 * i] = verts[0];
creaseIndices[2 * i + 1] = verts[1];
creaseSharpness[i] = static_cast<float>(creaseData[i]);
}
samp.setCreaseIndices(Alembic::Abc::Int32ArraySample(creaseIndices));
samp.setCreaseLengths(Alembic::Abc::Int32ArraySample(creaseLengths));
samp.setCreaseSharpnesses(
Alembic::Abc::FloatArraySample(creaseSharpness));
}
MUintArray cornerIds;
MDoubleArray cornerData;
if (lMesh.getCreaseVertices(cornerIds, cornerData) == MS::kSuccess)
{
unsigned int numCorners = cornerIds.length();
cornerIndices.resize(numCorners);
cornerSharpness.resize(numCorners);
for (unsigned int i = 0; i < numCorners; ++i)
{
cornerIndices[i] = cornerIds[i];
cornerSharpness[i] = static_cast<float>(cornerData[i]);
}
samp.setCornerSharpnesses(
Alembic::Abc::FloatArraySample(cornerSharpness));
samp.setCornerIndices(
Alembic::Abc::Int32ArraySample(cornerIndices));
}
#if MAYA_API_VERSION >= 201100
MUintArray holes = lMesh.getInvisibleFaces();
unsigned int numHoles = holes.length();
std::vector <Alembic::Util::int32_t> holeIndices(numHoles);
for (unsigned int i = 0; i < numHoles; ++i)
{
holeIndices[i] = holes[i];
}
if (!holeIndices.empty())
{
samp.setHoles(holeIndices);
}
#endif
samp.setUVs( iUVs );
mSubDSchema.set(samp);
writeColor();
writeUVSets();
}
// the arrays being passed in are assumed to be empty
void MayaMeshWriter::fillTopology(
std::vector<float> & oPoints,
std::vector<Alembic::Util::int32_t> & oFacePoints,
std::vector<Alembic::Util::int32_t> & oPointCounts)
{
MStatus status = MS::kSuccess;
MFnMesh lMesh( mDagPath, &status );
if ( !status )
{
MGlobal::displayError( "MFnMesh() failed for MayaMeshWriter" );
}
MFloatPointArray pts;
lMesh.getPoints(pts);
if (pts.length() < 3 && pts.length() > 0)
{
MString err = lMesh.fullPathName() +
" is not a valid mesh, because it only has ";
err += pts.length();
err += " points.";
MGlobal::displayError(err);
return;
}
unsigned int numPolys = lMesh.numPolygons();
if (numPolys == 0)
{
MGlobal::displayWarning(lMesh.fullPathName() + " has no polygons.");
return;
}
unsigned int i;
int j;
oPoints.resize(pts.length() * 3);
// repack the float
for (i = 0; i < pts.length(); i++)
{
size_t local = i * 3;
oPoints[local] = pts[i].x;
oPoints[local+1] = pts[i].y;
oPoints[local+2] = pts[i].z;
}
/*
oPoints -
oFacePoints - vertex list
oPointCounts - number of points per polygon
*/
MIntArray faceArray;
for (i = 0; i < numPolys; i++)
{
lMesh.getPolygonVertices(i, faceArray);
if (faceArray.length() < 3)
{
MGlobal::displayWarning("Skipping degenerate polygon");
continue;
}
// write backwards cause polygons in Maya are in a different order
// from Renderman (clockwise vs counter-clockwise?)
int faceArrayLength = faceArray.length() - 1;
for (j = faceArrayLength; j > -1; j--)
{
oFacePoints.push_back(faceArray[j]);
}
oPointCounts.push_back(faceArray.length());
}
}