void AlembicImport_FillInCamera(alembic_fillcamera_options& options) { ESS_CPP_EXCEPTION_REPORTING_START ESS_LOG_INFO("AlembicImport_FillInCamera"); if (options.pCameraObj == NULL || !AbcG::ICamera::matches((*options.pIObj).getMetaData())) { return; } AbcG::ICamera objCamera = AbcG::ICamera(*options.pIObj, Abc::kWrapExisting); if (!objCamera.valid()) { return; } double sampleTime = GetSecondsFromTimeValue(options.dTicks); SampleInfo sampleInfo = getSampleInfo(sampleTime, objCamera.getSchema().getTimeSampling(), objCamera.getSchema().getNumSamples()); AbcG::CameraSample sample; objCamera.getSchema().get(sample, sampleInfo.floorIndex); // Extract the camera values from the sample // double focalLength = sample.getFocalLength(); // double fov = sample.getHorizontalAperture(); // double nearClipping = sample.getNearClippingPlane(); // double farClipping = sample.getFarClippingPlane(); // Blend the camera values, if necessary // if (sampleInfo.alpha != 0.0) //{ // objCamera.getSchema().get(sample, sampleInfo.ceilIndex); // focalLength = (1.0 - sampleInfo.alpha) * focalLength + sampleInfo.alpha // * sample.getFocalLength(); // fov = (1.0 - sampleInfo.alpha) * fov + sampleInfo.alpha * // sample.getHorizontalAperture(); // nearClipping = (1.0 - sampleInfo.alpha) * nearClipping + // sampleInfo.alpha * sample.getNearClippingPlane(); // farClipping = (1.0 - sampleInfo.alpha) * farClipping + sampleInfo.alpha // * sample.getFarClippingPlane(); //} // options.pCameraObj->SetTDist(options.dTicks, // static_cast<float>(focalLength)); // options.pCameraObj->SetFOVType(0); // Width FoV = 0 // options.pCameraObj->SetFOV(options.dTicks, static_cast<float>(fov)); // options.pCameraObj->SetClipDist(options.dTicks, CAM_HITHER_CLIP, // static_cast<float>(nearClipping)); // options.pCameraObj->SetClipDist(options.dTicks, CAM_YON_CLIP, // static_cast<float>(farClipping)); options.pCameraObj->SetManualClip(TRUE); ESS_CPP_EXCEPTION_REPORTING_END }
int createAlembicObject(AbcG::IObject &iObj, INode **pMaxNode, alembic_importoptions &options, std::string &file) { AbcA::MetaData mdata = iObj.getMetaData(); int ret = alembic_success; // if(AbcG::IXform::matches(iObj.getMetaData())) //Transform //{ // ESS_LOG_INFO( "AlembicImport_XForm: " << objects[j].getFullName() ); // int ret = AlembicImport_PolyMesh(file, iObj, options, pMaxNode); //} if (AbcG::IPolyMesh::matches(mdata) || AbcG::ISubD::matches(mdata)) { // PolyMesh / SubD ESS_LOG_INFO("AlembicImport_PolyMesh: " << iObj.getFullName()); ret = AlembicImport_PolyMesh(file, iObj, options, pMaxNode); } else if (AbcG::ICamera::matches(mdata)) { // Camera ESS_LOG_INFO("AlembicImport_Camera: " << iObj.getFullName()); ret = AlembicImport_Camera(file, iObj, options, pMaxNode); } else if (AbcG::IPoints::matches(mdata)) { // Points ESS_LOG_INFO("AlembicImport_Points: " << iObj.getFullName()); ret = AlembicImport_Points(file, iObj, options, pMaxNode); } else if (AbcG::ICurves::matches(mdata)) { // Curves if (options.loadCurvesAsNurbs) { ESS_LOG_INFO("AlembicImport_Nurbs: " << iObj.getFullName()); ret = AlembicImport_NURBS(file, iObj, options, pMaxNode); } else { ESS_LOG_INFO("AlembicImport_Shape: " << iObj.getFullName()); ret = AlembicImport_Shape(file, iObj, options, pMaxNode); } } else if (AbcG::ILight::matches(mdata)) { // Light ESS_LOG_INFO("AlembicImport_Light: " << iObj.getFullName()); ret = AlembicImport_Light(file, iObj, options, pMaxNode); } else if (AbcM::IMaterial::matches(mdata)) { ESS_LOG_WARNING( "Alembic IMaterial not yet supported: " << iObj.getFullName()); } else { // NURBS if (options.failOnUnsupported) { ESS_LOG_ERROR("Alembic data type not supported: " << iObj.getFullName()); return alembic_failure; } else { ESS_LOG_WARNING( "Alembic data type not supported: " << iObj.getFullName()); } } return ret; }
int importAlembicScene(AbcArchiveCache *pArchiveCache, AbcObjectCache *pRootObjectCache, alembic_importoptions &options, std::string &file, progressUpdate &progress, std::map<std::string, bool> &nodeFullPaths) { std::vector<stackElement> sceneStack; sceneStack.reserve(200); for (size_t j = 0; j < pRootObjectCache->childIdentifiers.size(); j++) { sceneStack.push_back(stackElement( &(pArchiveCache->find(pRootObjectCache->childIdentifiers[j])->second))); } while (!sceneStack.empty()) { stackElement sElement = sceneStack.back(); sceneStack.pop_back(); Abc::IObject &iObj = sElement.pObjectCache->obj; INode *pParentMaxNode = sElement.pParentMaxNode; if (!iObj.valid()) { return alembic_failure; } const std::string fullname = iObj.getFullName(); const std::string pname = (pParentMaxNode) ? EC_MCHAR_to_UTF8(pParentMaxNode->GetName()) : std::string(""); const std::string name = iObj.getName(); ESS_LOG_INFO("Importing " << fullname); bool bCreateDummyNode = false; int mergedGeomNodeIndex = -1; AbcObjectCache *pMergedObjectCache = NULL; getMergeInfo(pArchiveCache, sElement.pObjectCache, bCreateDummyNode, mergedGeomNodeIndex, &pMergedObjectCache); INode *pMaxNode = NULL; // the newly create node, which may be a merged node INode *pExistingNode = NULL; int keepTM = 1; // I don't remember why this needed to be set in some // cases. bool bCreateNode = true; if (!nodeFullPaths.empty()) { if (mergedGeomNodeIndex != -1) { AbcG::IObject mergedGeomChild = pMergedObjectCache->obj; bCreateNode = nodeFullPaths.find(mergedGeomChild.getFullName()) != nodeFullPaths.end(); } else { bCreateNode = nodeFullPaths.find(fullname) != nodeFullPaths.end(); } } if (bCreateNode) { // if we are about to merge a camera with its parent transform, force it // to create a dummy node instead if the camera's // transform also has children. This is done to prevent the camera // correction matrix from being applied to the other children if (!bCreateDummyNode && pMergedObjectCache && sElement.pObjectCache->childIdentifiers.size() > 1 && AbcG::ICamera::matches(pMergedObjectCache->obj.getMetaData())) { bCreateDummyNode = true; mergedGeomNodeIndex = -1; } if (bCreateDummyNode) { std::string importName = removeXfoSuffix(iObj.getName()); pExistingNode = GetChildNodeFromName(importName, pParentMaxNode); if (options.attachToExisting && pExistingNode) { pMaxNode = pExistingNode; // see if a controller already exists, and then delete it int ret = AlembicImport_XForm(pParentMaxNode, pMaxNode, iObj, NULL, file, options); if (ret != 0) { return ret; } } // only create node if either attachToExisting is false or it is true // and the object does not already exist else { int ret = AlembicImport_DummyNode(iObj, options, &pMaxNode, importName); if (ret != 0) { return ret; } ret = AlembicImport_XForm(pParentMaxNode, pMaxNode, iObj, NULL, file, options); if (ret != 0) { return ret; } } } else { if (mergedGeomNodeIndex != -1) { // we are merging, so look at the child geometry node AbcG::IObject mergedGeomChild = pMergedObjectCache->obj; std::string importName = removeXfoSuffix(iObj.getName()); // mergedGeomChild.getName()); pExistingNode = GetChildNodeFromName(importName, pParentMaxNode); if (options.attachToExisting && pExistingNode) { pMaxNode = pExistingNode; } // only create node if either attachToExisting is false or it is // true and the object does not already exist int ret = createAlembicObject(mergedGeomChild, &pMaxNode, options, file); if (ret != 0) { return ret; } if (pMaxNode != NULL) { ret = AlembicImport_XForm(pParentMaxNode, pMaxNode, iObj, &mergedGeomChild, file, options); if (ret != 0) { return ret; } } } else { // geometry node(s) under a dummy node (in pParentMaxNode) pExistingNode = GetChildNodeFromName(iObj.getName(), pParentMaxNode); if (options.attachToExisting && pExistingNode) { pMaxNode = pExistingNode; } // only create node if either attachToExisting is false or it is // true and the object does not already exist int ret = createAlembicObject(iObj, &pMaxNode, options, file); if (ret != 0) { return ret; } // since the transform is the identity, should position relative to // parent keepTM = 0; if (AbcG::ICamera::matches(iObj.getMetaData())) { // apply camera adjustment matrix to the identity Matrix3 rotation(TRUE); rotation.RotateX(HALFPI); TimeValue zero(0); pMaxNode->SetNodeTM(zero, rotation); } // import identity matrix, since more than goemetry node share the // same transform // Should we just list MAX put a default position/scale/rotation // controller on? // int ret = AlembicImport_XForm(pMaxNode, *piParentObj, file, // options); } if (options.failOnUnsupported) { if (!pMaxNode) { return alembic_failure; } } } } if (pMaxNode && pParentMaxNode && !pExistingNode) { pParentMaxNode->AttachChild(pMaxNode, keepTM); } progress.increment(); progress.update(); if (pMaxNode) { for (size_t j = 0; j < sElement.pObjectCache->childIdentifiers.size(); j++) { AbcObjectCache *pChildObjectCache = &(pArchiveCache->find(sElement.pObjectCache->childIdentifiers[j]) ->second); if (NodeCategory::get(pChildObjectCache->obj) == NodeCategory::UNSUPPORTED) { continue; // skip over unsupported types } // I assume that geometry nodes are always leaf nodes. Thus, if we // merged a geometry node will its parent transform, we don't // need to push it to the stack. // A geometry node can't be combined with its transform node, the // transform node has other tranform nodes as children. These // nodes must be pushed. if (mergedGeomNodeIndex != j) { sceneStack.push_back(stackElement(pChildObjectCache, pMaxNode)); } } } } return alembic_success; }
void AlembicPoints::GetShapeType(IParticleObjectExt *pExt, int particleId, TimeValue ticks, ShapeType &type, Abc::uint16_t &instanceId, float &animationTime) { // Set up initial values type = ShapeType_Point; instanceId = 0; animationTime = 0.0f; // Go into the particle's action list INode *particleGroupNode = pExt->GetParticleGroup(particleId); Object *particleGroupObj = (particleGroupNode != NULL) ? particleGroupNode->EvalWorldState(ticks).obj : NULL; if (!particleGroupObj){ return; } IParticleGroup *particleGroup = GetParticleGroupInterface(particleGroupObj); INode *particleActionListNode = particleGroup->GetActionList(); Object *particleActionObj = (particleActionListNode != NULL ? particleActionListNode->EvalWorldState(ticks).obj : NULL); if (!particleActionObj){ return; } PFSimpleOperator *pSimpleOperator = NULL; //In the case of multiple shape operators in an action list, the one furthest down the list seems to be the one that applies IPFActionList *particleActionList = GetPFActionListInterface(particleActionObj); for (int p = particleActionList->NumActions()-1; p >= 0; p -= 1) { INode *pActionNode = particleActionList->GetAction(p); Object *pActionObj = (pActionNode != NULL ? pActionNode->EvalWorldState(ticks).obj : NULL); if (pActionObj == NULL){ continue; } if (pActionObj->ClassID() == PFOperatorSimpleShape_Class_ID){ pSimpleOperator = static_cast<PFSimpleOperator*>(pActionObj); break; }else if(pActionObj->ClassID() == PFOperatorShapeLib_Class_ID){ pSimpleOperator = static_cast<PFSimpleOperator*>(pActionObj); break; }else if(pActionObj->ClassID() == PFOperatorInstanceShape_Class_ID){ pSimpleOperator = static_cast<PFSimpleOperator*>(pActionObj); break; }else if(pActionObj->ClassID() == PFOperatorMarkShape_Class_ID){ pSimpleOperator = static_cast<PFSimpleOperator*>(pActionObj); break; }else if(pActionObj->ClassID() == PFOperatorFacingShape_Class_ID){ pSimpleOperator = static_cast<PFSimpleOperator*>(pActionObj); break; } } for (int p = particleActionList->NumActions()-1; p >= 0; p -= 1) { INode *pActionNode = particleActionList->GetAction(p); Object *pActionObj = (pActionNode != NULL ? pActionNode->EvalWorldState(ticks).obj : NULL); if (pActionObj == NULL){ continue; } IPFTest* pTestAction = GetPFTestInterface(pActionObj); if (pTestAction){ INode* childActionListNode = pTestAction->GetNextActionList(pActionNode, NULL); if(childActionListNode){ AlembicPoints::perActionListShapeMap_it actionListIt = mPerActionListShapeMap.find(childActionListNode); //create a cache entry if necessary if(actionListIt == mPerActionListShapeMap.end()){ mPerActionListShapeMap[childActionListNode] = AlembicPoints::shapeInfo(); } AlembicPoints::shapeInfo& sInfo = mPerActionListShapeMap[childActionListNode]; if(!sInfo.pParentActionList){ sInfo.pParentActionList = particleActionListNode; } } } } ReadShapeFromOperator(particleGroup, pSimpleOperator, particleId, ticks, type, instanceId, animationTime); if(type != ShapeType_NbElements){//write the shape to the cache // create cache entry for the current action list node, and then fill in the shape info // we will fill in the parent later AlembicPoints::perActionListShapeMap_it actionListIt = mPerActionListShapeMap.find(particleActionListNode); //create a cache entry if necessary if(actionListIt == mPerActionListShapeMap.end()){ mPerActionListShapeMap[particleActionListNode] = AlembicPoints::shapeInfo(); } AlembicPoints::shapeInfo& sInfo = mPerActionListShapeMap[particleActionListNode]; //if(sInfo.type == ShapeType_NbElements){ // sInfo.type = type; // sInfo.animationTime = animationTime; // if(sInfo.type == ShapeType_Instance){ // sInfo.instanceName = mInstanceNames[instanceId]; // } //} } else{ //read the shape from the cache AlembicPoints::shapeInfo sInfo; INode* currActionNode = particleActionListNode; //search for shape along path from this node to the root node const int MAX_DEPTH = 10; //just in case there is an infinite loop due a bug int i = 0; while(currActionNode && sInfo.type == ShapeType_NbElements && i<MAX_DEPTH){ AlembicPoints::perActionListShapeMap_it actionListIt = mPerActionListShapeMap.find(currActionNode); if(actionListIt != mPerActionListShapeMap.end()){ sInfo = actionListIt->second; } currActionNode = sInfo.pParentActionList; i++; } if(sInfo.type != ShapeType_NbElements){//We have found shape, so add it to the list if necessary // Find if the name is alerady registered, otherwise add it to the list //instanceId = FindInstanceName(sInfo.instanceName); //if (instanceId == USHRT_MAX) //{ // mInstanceNames.push_back(sInfo.instanceName); // instanceId = (Abc::uint16_t)mInstanceNames.size()-1; //} //type = sInfo.type; } else{ int nBornIndex = pExt->GetParticleBornIndex(particleId); ESS_LOG_INFO("Could not determine shape type for particle with born index: "<<nBornIndex<<". Defaulting to point."); type = ShapeType_Point; } } }
void AlembicPoints::ReadShapeFromOperator( IParticleGroup *particleGroup, PFSimpleOperator *pSimpleOperator, int particleId, TimeValue ticks, ShapeType &type, Abc::uint16_t &instanceId, float &animationTime) { if(!pSimpleOperator){ return; } if (pSimpleOperator->ClassID() == PFOperatorSimpleShape_Class_ID) { IParamBlock2 *pblock = pSimpleOperator->GetParamBlockByID(0); int nShapeId = pblock->GetInt(PFlow_kSimpleShape_shape, ticks); switch(nShapeId) { case PFlow_kSimpleShape_shape_pyramid: type = ShapeType_Cone; break; case PFlow_kSimpleShape_shape_cube: type = ShapeType_Box; break; case PFlow_kSimpleShape_shape_sphere: type = ShapeType_Sphere; break; case PFlow_kSimpleShape_shape_vertex: type = ShapeType_Point; break; default: type = ShapeType_Point; } } else if (pSimpleOperator->ClassID() == PFOperatorShapeLib_Class_ID) { IParamBlock2 *pblock = pSimpleOperator->GetParamBlockByID(0); int nDimension = pblock->GetInt(PFlow_kShapeLibary_dimensionType, ticks); if(nDimension == PFlow_kShapeLibrary_dimensionType_2D){ int n2DShapeId = pblock->GetInt(PFlow_kShapeLibary_2DType, ticks); if( n2DShapeId == PFlow_kShapeLibrary_dimensionType_2D_square){ type = ShapeType_Rectangle; } else{ ESS_LOG_INFO("Unsupported shape type."); type = ShapeType_Point; } } else if(nDimension == PFlow_kShapeLibrary_dimensionType_3D){ int n3DShapeId = pblock->GetInt(PFlow_kShapeLibary_3DType, ticks); if(n3DShapeId == PFlow_kShapeLibary_3DType_cube){ type = ShapeType_Box; } else if(n3DShapeId == PFlow_kShapeLibary_3DType_Sphere20sides || n3DShapeId == PFlow_kShapeLibary_3DType_Sphere80sides){ type = ShapeType_Sphere; } else{ ESS_LOG_INFO("Unsupported shape type."); type = ShapeType_Point; } //ShapeType_Cylinder unsupported //ShapeType_Cone unsupported //ShapeType_Disc unsupported //ShapeType_NbElements unsupported } else{ ESS_LOG_INFO("Unknown dimension."); type = ShapeType_Point; } //int nNumParams = pblock->NumParams(); //for(int i=0; i<nNumParams; i++){ // ParamID id = pblock->IndextoID(i); // MSTR paramStr = pblock->GetLocalName(id, 0); // int n = 0; // //} } else if (pSimpleOperator->ClassID() == PFOperatorInstanceShape_Class_ID) { // Assign animation time and shape here IParamBlock2 *pblock = pSimpleOperator->GetParamBlockByID(0); INode *pNode = pblock->GetINode(PFlow_kInstanceShape_objectMaxscript, ticks); if (pNode == NULL || pNode->GetName() == NULL) { return; } type = ShapeType_Instance; bool bFlatten = GetCurrentJob()->GetOption("flattenHierarchy"); std::string nodePath = getNodeAlembicPath( EC_MCHAR_to_UTF8( pNode->GetName() ), bFlatten); // Find if the name is alerady registered, otherwise add it to the list // instanceId = FindInstanceName(nodePath); // if (instanceId == USHRT_MAX) // { //mInstanceNames.push_back(nodePath); // instanceId = (Abc::uint16_t)mInstanceNames.size()-1; // } // Determine if we have an animated shape BOOL animatedShape = pblock->GetInt(PFlow_kInstanceShape_animatedShape); BOOL acquireShape = pblock->GetInt(PFlow_kInstanceShape_acquireShape); if (!animatedShape && !acquireShape) { return; } // Get the necesary particle channels to grab the current time values ::IObject *pCont = particleGroup->GetParticleContainer(); if (!pCont) { return; } // Get synch values that we are interested in fromt the param block int syncType = pblock->GetInt(PFlow_kInstanceShape_syncType); BOOL syncRandom = pblock->GetInt(PFlow_kInstanceShape_syncRandom); IParticleChannelPTVR* chTime = GetParticleChannelTimeRInterface(pCont); if (chTime == NULL) { return; // can't find particle times in the container } IChannelContainer* chCont = GetChannelContainerInterface(pCont); if (chCont == NULL) { return; // can't get access to ChannelContainer interface } IParticleChannelPTVR* chBirthTime = NULL; IParticleChannelPTVR* chEventStartR = NULL; bool initEventStart = false; if (syncType == PFlow_kInstanceShape_syncBy_particleAge) { chBirthTime = GetParticleChannelBirthTimeRInterface(pCont); if (chBirthTime == NULL) { return; // can't read particle age } } else if (syncType == PFlow_kInstanceShape_syncBy_eventStart) { chEventStartR = GetParticleChannelEventStartRInterface(pCont); if (chEventStartR == NULL) { return; // can't read event start time } } IParticleChannelIntR* chLocalOffR = NULL; bool initLocalOff = false; // acquire LocalOffset particle channel; if not present then create it. if (syncRandom) { chLocalOffR = (IParticleChannelIntR*)chCont->GetPrivateInterface(PARTICLECHANNELLOCALOFFSETR_INTERFACE, pSimpleOperator); } // get new shape from the source PreciseTimeValue time = chTime->GetValue(particleId); switch(syncType) { case PFlow_kInstanceShape_syncBy_absoluteTime: break; case PFlow_kInstanceShape_syncBy_particleAge: time -= chBirthTime->GetValue(particleId); break; case PFlow_kInstanceShape_syncBy_eventStart: time -= chEventStartR->GetValue(particleId); break; default: break; } if (syncRandom) { if (chLocalOffR != NULL) time += chLocalOffR->GetValue(particleId); } //timeValueMap::iterator it = mTimeValueMap.find(time); //if( it != mTimeValueMap.end() ){ // ESS_LOG_WARNING("sampleTime already seen."); //} //else{ // mTimeValueMap[time] = true; // mTimeSamplesCount++; // ESS_LOG_WARNING("sampleTime: "<<(float)time<<" totalSamples: "<<mTimeSamplesCount); //} TimeValue t = TimeValue(time); animationTime = (float)GetSecondsFromTimeValue(t); } else if (pSimpleOperator->ClassID() == PFOperatorMarkShape_Class_ID) { ESS_LOG_INFO("Shape Mark operator not supported."); } else if (pSimpleOperator->ClassID() == PFOperatorFacingShape_Class_ID) { ESS_LOG_INFO("Shape Facing operator not supported."); } }
bool AlembicCurves::Save(double time, bool bLastFrame) { ESS_PROFILE_FUNC(); //TimeValue ticks = GET_MAX_INTERFACE()->GetTime(); TimeValue ticks = GetTimeValueFromFrame(time); Object *obj = mMaxNode->EvalWorldState(ticks).obj; if(mNumSamples == 0){ bForever = CheckIfObjIsValidForever(obj, ticks); } else{ bool bNewForever = CheckIfObjIsValidForever(obj, ticks); if(bForever && bNewForever != bForever){ ESS_LOG_INFO( "bForever has changed" ); } } SaveMetaData(mMaxNode, this); // check if the spline is animated if(mNumSamples > 0) { if(bForever) { return true; } } AbcG::OCurvesSchema::Sample curvesSample; std::vector<AbcA::int32_t> nbVertices; std::vector<Point3> vertices; std::vector<float> knotVector; std::vector<Abc::uint16_t> orders; if(obj->ClassID() == EDITABLE_SURF_CLASS_ID){ NURBSSet nurbsSet; BOOL success = GetNURBSSet(obj, ticks, nurbsSet, TRUE); AbcG::CurvePeriodicity cPeriod = AbcG::kNonPeriodic; AbcG::CurveType cType = AbcG::kCubic; AbcG::BasisType cBasis = AbcG::kNoBasis; int n = nurbsSet.GetNumObjects(); for(int i=0; i<n; i++){ NURBSObject* pObject = nurbsSet.GetNURBSObject((int)i); //NURBSType type = pObject->GetType(); if(!pObject){ continue; } if( pObject->GetKind() == kNURBSCurve ){ NURBSCurve* pNurbsCurve = (NURBSCurve*)pObject; int degree; int numCVs; NURBSCVTab cvs; int numKnots; NURBSKnotTab knots; pNurbsCurve->GetNURBSData(ticks, degree, numCVs, cvs, numKnots, knots); orders.push_back(degree+1); const int cvsCount = cvs.Count(); const int knotCount = knots.Count(); for(int j=0; j<cvs.Count(); j++){ NURBSControlVertex cv = cvs[j]; double x, y, z; cv.GetPosition(ticks, x, y, z); vertices.push_back( Point3((float)x, (float)y, (float)z) ); } nbVertices.push_back(cvsCount); //skip the first and last entry because Maya and XSI use this format for(int j=1; j<knots.Count()-1; j++){ knotVector.push_back((float)knots[j]); } if(i == 0){ if(pNurbsCurve->IsClosed()){ cPeriod = AbcG::kPeriodic; } } else{ if(pNurbsCurve->IsClosed()){ if(cPeriod != AbcG::kPeriodic){ ESS_LOG_WARNING("Mixed curve wrap types not supported."); } } else{ if(cPeriod != AbcG::kNonPeriodic){ ESS_LOG_WARNING("Mixed curve wrap types not supported."); } } } } } curvesSample.setType(cType); curvesSample.setWrap(cPeriod); curvesSample.setBasis(cBasis); } else { BezierShape beziershape; PolyShape polyShape; bool bBezier = false; // Get a pointer to the spline shpae ShapeObject *pShapeObject = NULL; if (obj->IsShapeObject()) { pShapeObject = reinterpret_cast<ShapeObject *>(obj); } else { return false; } // Determine if we are a bezier shape if (pShapeObject->CanMakeBezier()) { pShapeObject->MakeBezier(ticks, beziershape); bBezier = true; } else { pShapeObject->MakePolyShape(ticks, polyShape); bBezier = false; } // Get the control points //std::vector<Point3> inTangents; //std::vector<Point3> outTangents; if (bBezier) { int oldVerticesCount = (int)vertices.size(); for (int i = 0; i < beziershape.SplineCount(); i += 1) { Spline3D *pSpline = beziershape.GetSpline(i); int knots = pSpline->KnotCount(); for(int ix = 0; ix < knots; ++ix) { Point3 in = pSpline->GetInVec(ix); Point3 p = pSpline->GetKnotPoint(ix); Point3 out = pSpline->GetOutVec(ix); vertices.push_back( p ); //inTangents.push_back( in ); //outTangents.push_back( out ); } int nNumVerticesAdded = (int)vertices.size() - oldVerticesCount; nbVertices.push_back( nNumVerticesAdded ); oldVerticesCount = (int)vertices.size(); } } else { for (int i = 0; i < polyShape.numLines; i += 1) { PolyLine &refLine = polyShape.lines[i]; nbVertices.push_back(refLine.numPts); for (int j = 0; j < refLine.numPts; j += 1) { Point3 p = refLine.pts[j].p; vertices.push_back(p); } } } // set the type + wrapping curvesSample.setType(bBezier ? AbcG::kCubic : AbcG::kLinear); curvesSample.setWrap(pShapeObject->CurveClosed(ticks, 0) ? AbcG::kPeriodic : AbcG::kNonPeriodic); curvesSample.setBasis(AbcG::kNoBasis); } if(nbVertices.size() == 0 || vertices.size() == 0){ ESS_LOG_WARNING("No curve data to export."); return false; } const int vertCount = (int)vertices.size(); // prepare the bounding box Abc::Box3d bbox; // allocate the points and normals std::vector<Abc::V3f> posVec(vertCount); Matrix3 wm = mMaxNode->GetObjTMAfterWSM(ticks); for(int i=0;i<vertCount;i++) { posVec[i] = ConvertMaxPointToAlembicPoint(vertices[i] ); bbox.extendBy(posVec[i]); // Set the archive bounding box if (mJob) { Point3 worldMaxPoint = wm * vertices[i]; Abc::V3f alembicWorldPoint = ConvertMaxPointToAlembicPoint(worldMaxPoint); mJob->GetArchiveBBox().extendBy(alembicWorldPoint); } } if(knotVector.size() > 0 && orders.size() > 0){ if(!mKnotVectorProperty.valid()){ mKnotVectorProperty = Abc::OFloatArrayProperty(mCurvesSchema.getArbGeomParams(), ".knot_vector", mCurvesSchema.getMetaData(), mJob->GetAnimatedTs() ); } mKnotVectorProperty.set(Abc::FloatArraySample(knotVector)); if(!mOrdersProperty.valid()){ mOrdersProperty = Abc::OUInt16ArrayProperty(mCurvesSchema.getArbGeomParams(), ".orders", mCurvesSchema.getMetaData(), mJob->GetAnimatedTs() ); } mOrdersProperty.set(Abc::UInt16ArraySample(orders)); } // store the bbox curvesSample.setSelfBounds(bbox); mCurvesSchema.getChildBoundsProperty().set(bbox); Abc::Int32ArraySample nbVerticesSample(&nbVertices.front(),nbVertices.size()); curvesSample.setCurvesNumVertices(nbVerticesSample); // allocate for the points and normals Abc::P3fArraySample posSample(&posVec.front(),posVec.size()); curvesSample.setPositions(posSample); mCurvesSchema.set(curvesSample); mNumSamples++; return true; }
bool AlembicCamera::Save(double time, bool bLastFrame) { TimeValue ticks = GetTimeValueFromFrame(time); Object *obj = mMaxNode->EvalWorldState(ticks).obj; if (mNumSamples == 0) { bForever = CheckIfObjIsValidForever(obj, ticks); } else { bool bNewForever = CheckIfObjIsValidForever(obj, ticks); if (bForever && bNewForever != bForever) { ESS_LOG_INFO("bForever has changed"); } } bForever = false; SaveMetaData(mMaxNode, this); // Set the xform sample Matrix3 wm = mMaxNode->GetObjTMAfterWSM(ticks); if (mJob) { Point3 worldMaxPoint = wm.GetTrans(); Abc::V3f alembicWorldPoint = ConvertMaxPointToAlembicPoint(worldMaxPoint); mJob->GetArchiveBBox().extendBy(alembicWorldPoint); } // check if the camera is animated if (mNumSamples > 0) { if (bForever) { return true; } } // Return a pointer to a Camera given an INode or return false if the node // cannot be converted to a Camera CameraObject *cam = NULL; if (obj->CanConvertToType(Class_ID(SIMPLE_CAM_CLASS_ID, 0))) { cam = reinterpret_cast<CameraObject *>( obj->ConvertToType(ticks, Class_ID(SIMPLE_CAM_CLASS_ID, 0))); } else if (obj->CanConvertToType(Class_ID(LOOKAT_CAM_CLASS_ID, 0))) { cam = reinterpret_cast<CameraObject *>( obj->ConvertToType(ticks, Class_ID(LOOKAT_CAM_CLASS_ID, 0))); } else { return false; } CameraState cs; Interval valid = FOREVER; cam->EvalCameraState(ticks, valid, &cs); float tDist = cam->GetTDist(ticks); float ratio = GetCOREInterface()->GetRendImageAspect(); float aperatureWidth = GetCOREInterface()->GetRendApertureWidth(); // this may differ from the // imported value // unfortunately float focalLength = (float)((aperatureWidth / 2.0) / tan(cs.fov / 2.0)); // alembic wants this one in millimeters aperatureWidth /= 10.0f; // convert to centimeters IMultiPassCameraEffect *pCameraEffect = cam->GetIMultiPassCameraEffect(); Interval interval = FOREVER; BOOL bUseTargetDistance = FALSE; const int TARGET_DISTANCE = 0; pCameraEffect->GetParamBlockByID(0)->GetValue(TARGET_DISTANCE, ticks, bUseTargetDistance, interval); float fFocalDepth = 0.0f; const int FOCAL_DEPTH = 1; pCameraEffect->GetParamBlockByID(0)->GetValue(FOCAL_DEPTH, ticks, fFocalDepth, interval); // store the camera data mCameraSample.setNearClippingPlane(cs.hither); mCameraSample.setFarClippingPlane(cs.yon); // mCameraSample.setLensSqueezeRatio(ratio); // should set to 1.0 according the article "Maya to Softimage: Camera // Interoperability" mCameraSample.setLensSqueezeRatio(1.0); mCameraSample.setFocalLength(focalLength); mCameraSample.setHorizontalAperture(aperatureWidth); mCameraSample.setVerticalAperture(aperatureWidth / ratio); if (bUseTargetDistance) { mCameraSample.setFocusDistance(tDist); } else { mCameraSample.setFocusDistance(fFocalDepth); } // save the samples mCameraSchema.set(mCameraSample); mNumSamples++; // Note that the CamObject should only be deleted if the pointer to it is not // equal to the object pointer that called ConvertToType() if (cam != NULL && obj != cam) { delete cam; cam = NULL; return false; } return true; }