void XFileLoader::ReadFaceArray(istream& s, vector<unsigned short>& indices) { int nFaces; ReadMember(s, nFaces); indices.reserve(nFaces * 3); for (int i = 0; i < nFaces; ++i) { if (i != 0) SkipToken(s, XFileToken::Comma); int nIndices; ReadMember(s, nIndices); vector<int> faceIndices(nIndices); ReadArray(s, faceIndices.begin(), faceIndices.end()); for (int i = 1; i < nIndices - 1; ++i) { indices.push_back(faceIndices[0]); indices.push_back(faceIndices[i]); indices.push_back(faceIndices[i + 1]); } } SkipToken(s, XFileToken::Semicolon); }
void OsdPtexMeshData::rebuildHbrMeshIfNeeded(OpenSubdivPtexShader *shader) { MStatus status; if (!_meshTopoDirty && !shader->getHbrMeshDirty()) return; MFnMesh meshFn(_meshDagPath, &status); if (status != MS::kSuccess) return; int level = shader->getLevel(); if (level < 1) level =1; SchemeType scheme = shader->getScheme(); if (scheme == kLoop) scheme = kCatmark; // XXX: avoid loop for now // Get Maya vertex topology and crease data MIntArray vertexCount; MIntArray vertexList; meshFn.getVertices(vertexCount, vertexList); MUintArray edgeIds; MDoubleArray edgeCreaseData; meshFn.getCreaseEdges(edgeIds, edgeCreaseData); MUintArray vtxIds; MDoubleArray vtxCreaseData; meshFn.getCreaseVertices(vtxIds, vtxCreaseData); if (vertexCount.length() == 0) return; // Cache attribute values _level = shader->getLevel(); _scheme = shader->getScheme(); _kernel = shader->getKernel(); _adaptive = shader->isAdaptive(); _interpBoundary = shader->getInterpolateBoundary(); // Copy Maya vectors into std::vectors std::vector<int> numIndices(&vertexCount[0], &vertexCount[vertexCount.length()]); std::vector<int> faceIndices(&vertexList[0], &vertexList[vertexList.length()]); std::vector<int> vtxCreaseIndices(&vtxIds[0], &vtxIds[vtxIds.length()]); std::vector<double> vtxCreases(&vtxCreaseData[0], &vtxCreaseData[vtxCreaseData.length()]); std::vector<double> edgeCreases(&edgeCreaseData[0], &edgeCreaseData[edgeCreaseData.length()]); // Edge crease index is stored as pairs of vertex ids int nEdgeIds = edgeIds.length(); std::vector<int> edgeCreaseIndices; edgeCreaseIndices.resize(nEdgeIds*2); for (int i = 0; i < nEdgeIds; ++i) { int2 vertices; status = meshFn.getEdgeVertices(edgeIds[i], vertices); if (status.error()) { status.perror("ERROR can't get creased edge vertices"); continue; } edgeCreaseIndices[i*2] = vertices[0]; edgeCreaseIndices[i*2+1] = vertices[1]; } // Convert attribute enums to HBR enums (this is why the enums need to match) // XXX use some sort of built-in transmorgification avoid assumption? HbrMeshUtil::SchemeType hbrScheme = (HbrMeshUtil::SchemeType) _scheme; OsdHbrMesh::InterpolateBoundaryMethod hbrInterpBoundary = (OsdHbrMesh::InterpolateBoundaryMethod) _interpBoundary; // Convert Maya mesh to internal HBR representation _hbrmesh = ConvertToHBR(meshFn.numVertices(), numIndices, faceIndices, vtxCreaseIndices, vtxCreases, std::vector<int>(), std::vector<float>(), edgeCreaseIndices, edgeCreases, hbrInterpBoundary, hbrScheme, true ); // add ptex indices to HBR // note: GL function can't be used in prepareForDraw API. _needsInitializeMesh = true; // Mesh topology data is up to date _meshTopoDirty = false; shader->setHbrMeshDirty(false); }
// #### rebuildHbrMeshIfNeeded // // If the topology of the mesh changes, or any attributes that affect // how the mesh is computed the original HBR needs to be rebuilt // which will trigger a rebuild of the FAR mesh and subsequent buffers. // void OsdMeshData::rebuildHbrMeshIfNeeded(OpenSubdivShader *shader) { MStatus status = MS::kSuccess; if (!_meshTopoDirty && !shader->getHbrMeshDirty()) return; MFnMesh meshFn(_meshDagPath); // Cache attribute values _level = shader->getLevel(); _kernel = shader->getKernel(); _adaptive = shader->isAdaptive(); _uvSet = shader->getUVSet(); // Get Maya vertex topology and crease data MIntArray vertexCount; MIntArray vertexList; meshFn.getVertices(vertexCount, vertexList); MUintArray edgeIds; MDoubleArray edgeCreaseData; meshFn.getCreaseEdges(edgeIds, edgeCreaseData); MUintArray vtxIds; MDoubleArray vtxCreaseData; meshFn.getCreaseVertices(vtxIds, vtxCreaseData); if (vertexCount.length() == 0) return; // Copy Maya vectors into std::vectors std::vector<int> numIndices(&vertexCount[0], &vertexCount[vertexCount.length()]); std::vector<int> faceIndices(&vertexList[0], &vertexList[vertexList.length()]); std::vector<int> vtxCreaseIndices(&vtxIds[0], &vtxIds[vtxIds.length()]); std::vector<double> vtxCreases(&vtxCreaseData[0], &vtxCreaseData[vtxCreaseData.length()]); std::vector<double> edgeCreases(&edgeCreaseData[0], &edgeCreaseData[edgeCreaseData.length()]); // Edge crease index is stored as pairs of vertex ids int nEdgeIds = edgeIds.length(); std::vector<int> edgeCreaseIndices; edgeCreaseIndices.resize(nEdgeIds*2); for (int i = 0; i < nEdgeIds; ++i) { int2 vertices; status = meshFn.getEdgeVertices(edgeIds[i], vertices); if (status.error()) { MERROR(status, "OpenSubdivShader: Can't get edge vertices"); continue; } edgeCreaseIndices[i*2] = vertices[0]; edgeCreaseIndices[i*2+1] = vertices[1]; } // Convert attribute enums to HBR enums (this is why the enums need to match) HbrMeshUtil::SchemeType hbrScheme = (HbrMeshUtil::SchemeType) shader->getScheme(); OsdHbrMesh::InterpolateBoundaryMethod hbrInterpBoundary = (OsdHbrMesh::InterpolateBoundaryMethod) shader->getInterpolateBoundary(); OsdHbrMesh::InterpolateBoundaryMethod hbrInterpUVBoundary = (OsdHbrMesh::InterpolateBoundaryMethod) shader->getInterpolateUVBoundary(); // clear any existing face-varying descriptor if (_fvarDesc) { delete _fvarDesc; _fvarDesc = NULL; } // read UV data from maya and build per-face per-vert list of UVs for HBR face-varying data std::vector< float > uvList; status = buildUVList( meshFn, uvList ); if (! status.error()) { // Create face-varying data descriptor. The memory required for indices // and widths needs to stay alive as the HBR library only takes in the // pointers and assumes the client will maintain the memory so keep _fvarDesc // around as long as _hbrmesh is around. int fvarIndices[] = { 0, 1 }; int fvarWidths[] = { 1, 1 }; _fvarDesc = new FVarDataDesc( 2, fvarIndices, fvarWidths, 2, hbrInterpUVBoundary ); } if (_fvarDesc && hbrScheme != HbrMeshUtil::kCatmark) { MGlobal::displayWarning("Face-varying not yet supported for Loop/Bilinear, using Catmull-Clark"); hbrScheme = HbrMeshUtil::kCatmark; } // Convert Maya mesh to internal HBR representation _hbrmesh = ConvertToHBR(meshFn.numVertices(), numIndices, faceIndices, vtxCreaseIndices, vtxCreases, std::vector<int>(), std::vector<float>(), edgeCreaseIndices, edgeCreases, hbrInterpBoundary, hbrScheme, false, // no ptex _fvarDesc, _fvarDesc?&uvList:NULL); // yes fvar (if have UVs) // note: GL function can't be used in prepareForDraw API. _needsInitializeMesh = true; // Mesh topology data is up to date _meshTopoDirty = false; shader->setHbrMeshDirty(false); }
MayaMeshWriter::MayaMeshWriter(MDagPath & iDag, Alembic::Abc::OObject & iParent, Alembic::Util::uint32_t iTimeIndex, const JobArgs & iArgs, GetMembersMap& gmMap) : mNoNormals(iArgs.noNormals), 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"); if ( !plug.isNull() && plug.asBool() ) { Alembic::AbcGeom::OSubD obj(iParent, name.asChar(), 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)); writeSubD(uvSamp); } else { Alembic::AbcGeom::OPolyMesh obj(iParent, name.asChar(), 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)); 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); } } 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)); } } writeUVSets(); } } // write out facesets if(!iArgs.writeFaceSets) return; // get the connected shading engines MObjectArray connSGObjs (getOutConnectedSG(mDagPath)); const unsigned int sgCount = connSGObjs.length(); for (unsigned int i = 0; i < sgCount; ++i) { MObject connSGObj, compObj; connSGObj = connSGObjs[i]; MFnDependencyNode fnDepNode(connSGObj); MString connSgObjName = fnDepNode.name(); // retrive the component MObject status = getSetComponents(mDagPath, connSGObj, gmMap, compObj); if (status != MS::kSuccess) { // for some reason the shading group doesn't represent a face set continue; } // retrieve the face indices MIntArray indices; MFnSingleIndexedComponent compFn; compFn.setObject(compObj); compFn.getElements(indices); const unsigned int numData = indices.length(); // encountered the whole object mapping. skip it. if (numData == 0) continue; std::vector<Alembic::Util::int32_t> faceIndices(numData); for (unsigned int j = 0; j < numData; ++j) { faceIndices[j] = indices[j]; } connSgObjName = util::stripNamespaces(connSgObjName, iArgs.stripNamespace); Alembic::AbcGeom::OFaceSet faceSet; std::string faceSetName(connSgObjName.asChar()); MPlug abcFacesetNamePlug = fnDepNode.findPlug("AbcFacesetName", true); if (!abcFacesetNamePlug.isNull()) { faceSetName = abcFacesetNamePlug.asString().asChar(); } if (mPolySchema.valid()) { if (mPolySchema.hasFaceSet(faceSetName)) { faceSet = mPolySchema.getFaceSet(faceSetName); } else { faceSet = mPolySchema.createFaceSet(faceSetName); } } else { if (mSubDSchema.hasFaceSet(faceSetName)) { faceSet = mSubDSchema.getFaceSet(faceSetName); } else { faceSet = mSubDSchema.createFaceSet(faceSetName); } } Alembic::AbcGeom::OFaceSetSchema::Sample samp; samp.setFaces(Alembic::Abc::Int32ArraySample(faceIndices)); Alembic::AbcGeom::OFaceSetSchema faceSetSchema = faceSet.getSchema(); faceSetSchema.set(samp); faceSetSchema.setFaceExclusivity(Alembic::AbcGeom::kFaceSetExclusive); MFnDependencyNode iNode(connSGObj); Alembic::Abc::OCompoundProperty cp; Alembic::Abc::OCompoundProperty up; if (AttributesWriter::hasAnyAttr(iNode, iArgs)) { cp = faceSetSchema.getArbGeomParams(); up = faceSetSchema.getUserProperties(); } AttributesWriter attrWriter(cp, up, faceSet, iNode, iTimeIndex, iArgs); attrWriter.write(); } }
static void export_alembic_xform_by_buffer(AlembicArchive &archive, const RenderedBuffer & renderedBuffer, int renderedBufferIndex) { Alembic::AbcGeom::OObject topObj(*archive.archive, Alembic::AbcGeom::kTop); Alembic::AbcGeom::OXform xform; if (archive.xform_map.find(renderedBufferIndex) != archive.xform_map.end()) { xform = archive.xform_map[renderedBufferIndex]; } else { xform = Alembic::AbcGeom::OXform(topObj, "xform_" + umbase::UMStringUtil::number_to_string(renderedBufferIndex), archive.timesampling); archive.xform_map[renderedBufferIndex] = xform; } bool isFirstMesh = false; Alembic::AbcGeom::OPolyMesh polyMesh; if (archive.mesh_map.find(renderedBufferIndex) != archive.mesh_map.end()) { polyMesh = archive.mesh_map[renderedBufferIndex]; } else { polyMesh = Alembic::AbcGeom::OPolyMesh(xform, "mesh_" + to_string(renderedBufferIndex), archive.timesampling); archive.mesh_map[renderedBufferIndex] = polyMesh; isFirstMesh = true; Alembic::AbcGeom::OPolyMeshSchema &meshSchema = polyMesh.getSchema(); archive.schema_map[renderedBufferIndex] = meshSchema; } Alembic::AbcGeom::OPolyMeshSchema &meshSchema = archive.schema_map[renderedBufferIndex]; meshSchema.setTimeSampling(archive.timesampling); std::vector<Alembic::Util::int32_t> faceList; std::vector<Alembic::Util::int32_t> faceCountList; const RenderedBuffer::UVList &uvList = renderedBuffer.uvs; const RenderedBuffer::VertexList &vertexList = renderedBuffer.vertecies; const RenderedBuffer::NormalList &normalList = renderedBuffer.normals; RenderedBuffer::UVList& temporary_uv = archive.temporary_uv_list; temporary_uv.resize(uvList.size()); RenderedBuffer::NormalList& temporary_normal = archive.temporary_normal_list; temporary_normal.resize(normalList.size()); RenderedBuffer::VertexList& temporary_vertex = archive.temporary_vertex_list; temporary_vertex.resize(vertexList.size()); const int materialSize = static_cast<int>(renderedBuffer.materials.size()); int totalFaceCount = 0; for (int k = 0; k < materialSize; ++k) { RenderedMaterial* material = renderedBuffer.materials.at(k); totalFaceCount += material->surface.faces.size(); } if (archive.surface_size_map.find(renderedBufferIndex) == archive.surface_size_map.end()) { archive.surface_size_map[renderedBufferIndex] = 0; } int& preSurfaceSize = archive.surface_size_map[renderedBufferIndex]; bool isFirstSurface = totalFaceCount != preSurfaceSize; if (!isFirstMesh && isFirstSurface) { return; } preSurfaceSize = totalFaceCount; faceCountList.resize(totalFaceCount); faceList.resize(totalFaceCount * 3); int faceCounter = 0; for (int k = 0; k < materialSize; ++k) { RenderedMaterial* material = renderedBuffer.materials.at(k); const int faceSize = material->surface.faces.size(); for (int n = 0; n < faceSize; ++n) { UMVec3i face = material->surface.faces[n]; faceList[faceCounter * 3 + 0] = (face.x - 1); faceList[faceCounter * 3 + 1] = (face.y - 1); faceList[faceCounter * 3 + 2] = (face.z - 1); faceCountList[faceCounter] = 3; ++faceCounter; } } Alembic::AbcGeom::OPolyMeshSchema::Sample sample; // vertex for (int n = 0, nsize = vertexList.size(); n < nsize; ++n) { temporary_vertex[n].z = -vertexList[n].z; } Alembic::AbcGeom::P3fArraySample positions( (const Imath::V3f *) &temporary_vertex.front(), temporary_vertex.size()); sample.setPositions(positions); // face index if (isFirstMesh) { Alembic::Abc::Int32ArraySample faceIndices(faceList); Alembic::Abc::Int32ArraySample faceCounts(faceCountList); sample.setFaceIndices(faceIndices); sample.setFaceCounts(faceCounts); } // UVs if (!uvList.empty() && archive.is_export_uvs) { for (int n = 0, nsize = uvList.size(); n < nsize; ++n) { temporary_uv[n].y = 1.0f - uvList[n].y; } Alembic::AbcGeom::OV2fGeomParam::Sample uvSample; uvSample.setScope(Alembic::AbcGeom::kVertexScope ); uvSample.setVals(Alembic::AbcGeom::V2fArraySample( ( const Imath::V2f *) &temporary_uv.front(), temporary_uv.size())); sample.setUVs(uvSample); } // Normals if (!normalList.empty() && archive.is_export_normals) { for (int n = 0, nsize = normalList.size(); n < nsize; ++n) { temporary_normal[n].z = -normalList[n].z; } Alembic::AbcGeom::ON3fGeomParam::Sample normalSample; normalSample.setScope(Alembic::AbcGeom::kVertexScope ); normalSample.setVals(Alembic::AbcGeom::N3fArraySample( (const Alembic::AbcGeom::N3f *) &temporary_normal.front(), temporary_normal.size())); sample.setNormals(normalSample); } meshSchema.set(sample); }
static void export_alembic_xform_by_material_direct(AlembicArchive &archive, const RenderedBuffer & renderedBuffer, int renderedBufferIndex) { Alembic::AbcGeom::OObject topObj(*archive.archive, Alembic::AbcGeom::kTop); for (int k = 0, ksize = static_cast<int>(renderedBuffer.materials.size()); k < ksize; ++k) { Alembic::AbcGeom::OPolyMesh polyMesh; const int key = renderedBufferIndex * 10000 + k; Alembic::AbcGeom::OXform xform; if (archive.xform_map.find(key) != archive.xform_map.end()) { xform = archive.xform_map[key]; } else { xform = Alembic::AbcGeom::OXform(topObj, "xform_" + to_string(renderedBufferIndex) + "_material_" + to_string(k) , archive.timesampling); archive.xform_map[key] = xform; } bool isFirstMesh = false; if (archive.mesh_map.find(key) != archive.mesh_map.end()) { polyMesh = archive.mesh_map[key]; } else { polyMesh = Alembic::AbcGeom::OPolyMesh(xform, "mesh_" + to_string(renderedBufferIndex) + "_material_" + to_string(k), archive.timesampling); archive.mesh_map[key] = polyMesh; isFirstMesh = true; Alembic::AbcGeom::OPolyMeshSchema &meshSchema = polyMesh.getSchema(); archive.schema_map[key] = meshSchema; } if (archive.surface_size_map.find(key) == archive.surface_size_map.end()) { archive.surface_size_map[key] = 0; } Alembic::AbcGeom::OPolyMeshSchema &meshSchema = archive.schema_map[key]; meshSchema.setTimeSampling(archive.timesampling); Alembic::AbcGeom::OPolyMeshSchema::Sample empty; std::vector<Alembic::Util::int32_t> faceList; std::vector<Alembic::Util::int32_t> faceCountList; const RenderedBuffer::UVList &uvList = renderedBuffer.uvs; const RenderedBuffer::VertexList &vertexList = renderedBuffer.vertecies; const RenderedBuffer::NormalList &normalList = renderedBuffer.normals; RenderedBuffer::VertexList vertexListByMaterial; RenderedBuffer::UVList uvListByMaterial; RenderedBuffer::NormalList normalListByMaterial; RenderedMaterial* material = renderedBuffer.materials.at(k); const int materialSurfaceSize = static_cast<int>(material->surface.faces.size()); vertexListByMaterial.resize(materialSurfaceSize * 3); faceList.resize(materialSurfaceSize * 3); faceCountList.resize(materialSurfaceSize); if (!uvList.empty()) { uvListByMaterial.resize(materialSurfaceSize * 3); } if (!normalList.empty()) { normalListByMaterial.resize(materialSurfaceSize * 3); } int& preSurfaceSize = archive.surface_size_map[key]; bool isFirstSurface = material->surface.faces.size() != preSurfaceSize; if (!isFirstMesh && isFirstSurface) { continue; } // re assign par material int lastIndex = 0; for (int n = 0; n < materialSurfaceSize; ++n) { UMVec3i face = material->surface.faces[n]; const int f1 = face.x - 1; const int f2 = face.y - 1; const int f3 = face.z - 1; int vi1 = n * 3 + 0; int vi2 = n * 3 + 1; int vi3 = n * 3 + 2; vertexListByMaterial[vi1] = vertexList.at(f1); vertexListByMaterial[vi2] = vertexList.at(f2); vertexListByMaterial[vi3] = vertexList.at(f3); if (!uvList.empty() && archive.is_export_uvs) { uvListByMaterial[vi1] = uvList.at(f1); uvListByMaterial[vi2] = uvList.at(f2); uvListByMaterial[vi3] = uvList.at(f3); } if (!normalList.empty() && archive.is_export_normals) { normalListByMaterial[vi1] = normalList.at(f1); normalListByMaterial[vi2] = normalList.at(f2); normalListByMaterial[vi3] = normalList.at(f3); } faceList[vi1] = vi1; faceList[vi2] = vi2; faceList[vi3] = vi3; faceCountList[n] = 3; } preSurfaceSize = material->surface.faces.size(); for (int n = 0, nsize = vertexListByMaterial.size(); n < nsize; ++n) { vertexListByMaterial[n].z = -vertexListByMaterial[n].z; } Alembic::AbcGeom::OPolyMeshSchema::Sample sample; // vertex Alembic::AbcGeom::P3fArraySample positions( (const Imath::V3f *) &vertexListByMaterial.front(), vertexListByMaterial.size()); sample.setPositions(positions); // face index if (isFirstMesh) { Alembic::Abc::Int32ArraySample faceIndices(faceList); Alembic::Abc::Int32ArraySample faceCounts(faceCountList); sample.setFaceIndices(faceIndices); sample.setFaceCounts(faceCounts); } // UVs if (!uvListByMaterial.empty() && archive.is_export_uvs) { for (int n = 0, nsize = uvListByMaterial.size(); n < nsize; ++n) { uvListByMaterial[n].y = 1.0f - uvListByMaterial[n].y; } Alembic::AbcGeom::OV2fGeomParam::Sample uvSample; uvSample.setScope(Alembic::AbcGeom::kVertexScope ); uvSample.setVals(Alembic::AbcGeom::V2fArraySample( ( const Imath::V2f *) &uvListByMaterial.front(), uvListByMaterial.size())); sample.setUVs(uvSample); } // Normals if (!normalListByMaterial.empty() && archive.is_export_normals) { for (int n = 0, nsize = normalListByMaterial.size(); n < nsize; ++n) { normalListByMaterial[n].z = -normalListByMaterial[n].z; } Alembic::AbcGeom::ON3fGeomParam::Sample normalSample; normalSample.setScope(Alembic::AbcGeom::kVertexScope ); normalSample.setVals(Alembic::AbcGeom::N3fArraySample( (const Alembic::AbcGeom::N3f *) &normalListByMaterial.front(), normalListByMaterial.size())); sample.setNormals(normalSample); } meshSchema.set(sample); } }