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 AlembicPoints::Save(double time, bool bLastFrame) { ESS_PROFILE_FUNC(); // Note: Particles are always considered to be animated even though // the node does not have the IsAnimated() flag. // Extract our particle emitter at the given time TimeValue ticks = GetTimeValueFromFrame(time); Object *obj = mMaxNode->EvalWorldState(ticks).obj; SaveMetaData(mMaxNode, this); SimpleParticle* pSimpleParticle = (SimpleParticle*)obj->GetInterface(I_SIMPLEPARTICLEOBJ); IPFSystem* ipfSystem = GetPFSystemInterface(obj); IParticleObjectExt* particlesExt = GetParticleObjectExtInterface(obj); #ifdef THINKING_PARTICLES ParticleMat* pThinkingParticleMat = NULL; TP_MasterSystemInterface* pTPMasterSystemInt = NULL; if(obj->CanConvertToType(MATTERWAVES_CLASS_ID)) { pThinkingParticleMat = reinterpret_cast<ParticleMat*>(obj->ConvertToType(ticks, MATTERWAVES_CLASS_ID)); pTPMasterSystemInt = reinterpret_cast<TP_MasterSystemInterface*>(obj->GetInterface(IID_TP_MASTERSYSTEM)); } #endif const bool bAutomaticInstancing = GetCurrentJob()->GetOption("automaticInstancing"); if( #ifdef THINKING_PARTICLES !pThinkingParticleMat && #endif !particlesExt && !pSimpleParticle){ return false; } //We have to put the particle system into the renders state so that PFOperatorMaterialFrequency::Proceed will set the materialID channel //Note: settting the render state to true breaks the shape node instancing export bool bRenderStateForced = false; if(bAutomaticInstancing && ipfSystem && !ipfSystem->IsRenderState()){ ipfSystem->SetRenderState(true); bRenderStateForced = true; } int numParticles = 0; #ifdef THINKING_PARTICLES if(pThinkingParticleMat){ numParticles = pThinkingParticleMat->NumParticles(); } else #endif if(particlesExt){ particlesExt->UpdateParticles(mMaxNode, ticks); numParticles = particlesExt->NumParticles(); } else if(pSimpleParticle){ pSimpleParticle->Update(ticks, mMaxNode); numParticles = pSimpleParticle->parts.points.Count(); } // Store positions, velocity, width/size, scale, id, bounding box std::vector<Abc::V3f> positionVec; std::vector<Abc::V3f> velocityVec; std::vector<Abc::V3f> scaleVec; std::vector<float> widthVec; std::vector<float> ageVec; std::vector<float> massVec; std::vector<float> shapeTimeVec; std::vector<Abc::uint64_t> idVec; std::vector<Abc::uint16_t> shapeTypeVec; std::vector<Abc::uint16_t> shapeInstanceIDVec; std::vector<Abc::Quatf> orientationVec; std::vector<Abc::Quatf> angularVelocityVec; std::vector<Abc::C4f> colorVec; positionVec.reserve(numParticles); velocityVec.reserve(numParticles); scaleVec.reserve(numParticles); widthVec.reserve(numParticles); ageVec.reserve(numParticles); massVec.reserve(numParticles); shapeTimeVec.reserve(numParticles); idVec.reserve(numParticles); shapeTypeVec.reserve(numParticles); shapeInstanceIDVec.reserve(numParticles); orientationVec.reserve(numParticles); angularVelocityVec.reserve(numParticles); colorVec.reserve(numParticles); //std::vector<std::string> instanceNamesVec; Abc::Box3d bbox; bool constantPos = true; bool constantVel = true; bool constantScale = true; bool constantWidth = true; bool constantAge = true; bool constantOrientation = true; bool constantAngularVel = true; bool constantColor = true; if(bAutomaticInstancing){ SetMaxSceneTime(ticks); } //The MAX interfaces return everything in world coordinates, //so we need to multiply the inverse the node world transform matrix Matrix3 nodeWorldTM = mMaxNode->GetObjTMAfterWSM(ticks); // Convert the max transform to alembic Matrix3 alembicMatrix; ConvertMaxMatrixToAlembicMatrix(nodeWorldTM, alembicMatrix); Abc::M44d nodeWorldTrans( alembicMatrix.GetRow(0).x, alembicMatrix.GetRow(0).y, alembicMatrix.GetRow(0).z, 0, alembicMatrix.GetRow(1).x, alembicMatrix.GetRow(1).y, alembicMatrix.GetRow(1).z, 0, alembicMatrix.GetRow(2).x, alembicMatrix.GetRow(2).y, alembicMatrix.GetRow(2).z, 0, alembicMatrix.GetRow(3).x, alembicMatrix.GetRow(3).y, alembicMatrix.GetRow(3).z, 1); Abc::M44d nodeWorldTransInv = nodeWorldTrans.inverse(); //ESS_LOG_WARNING("tick: "<<ticks<<" numParticles: "<<numParticles<<"\n"); ExoNullView nullView; particleGroupInterface groupInterface(particlesExt, obj, mMaxNode, &nullView); { ESS_PROFILE_SCOPE("AlembicPoints::SAVE - numParticlesLoop"); for (int i = 0; i < numParticles; ++i) { Abc::V3f pos(0.0); Abc::V3f vel(0.0); Abc::V3f scale(1.0); Abc::C4f color(0.5, 0.5, 0.5, 1.0); float age = 0; Abc::uint64_t id = 0; Abc::Quatd orientation(0.0, 0.0, 1.0, 0.0); Abc::Quatd spin(0.0, 0.0, 1.0, 0.0); // Particle size is a uniform scale multiplier in XSI. In Max, I need to learn where to get this // For now, we'll just default to 1 float width = 1.0f; ShapeType shapetype = ShapeType_Point; float shapeInstanceTime = (float)time; Abc::uint16_t shapeInstanceId = 0; #ifdef THINKING_PARTICLES if(pThinkingParticleMat){ if(pTPMasterSystemInt->IsAlive(i) == FALSE){ continue; } //TimeValue ageValue = particlesExt->GetParticleAgeByIndex(i); TimeValue ageValue = pTPMasterSystemInt->Age(i); if(ageValue == -1){ continue; } ESS_PROFILE_SCOPE("AlembicPoints::SAVE - numParticlesLoop - ThinkingParticles"); age = (float)GetSecondsFromTimeValue(ageValue); //pos = ConvertMaxPointToAlembicPoint(*particlesExt->GetParticlePositionByIndex(i)); pos = ConvertMaxPointToAlembicPoint(pTPMasterSystemInt->Position(i)); //vel = ConvertMaxVectorToAlembicVector(*particlesExt->GetParticleSpeedByIndex(i) * TIME_TICKSPERSEC); vel = ConvertMaxVectorToAlembicVector(pTPMasterSystemInt->Velocity(i) * TIME_TICKSPERSEC); scale = ConvertMaxScaleToAlembicScale(pTPMasterSystemInt->Scale(i)); scale *= pTPMasterSystemInt->Size(i); //ConvertMaxEulerXYZToAlembicQuat(*particlesExt->GetParticleOrientationByIndex(i), orientation); Matrix3 alignmentMatMax = pTPMasterSystemInt->Alignment(i); Abc::M44d alignmentMat; ConvertMaxMatrixToAlembicMatrix(alignmentMatMax, alignmentMat); /*alignmentMat = Abc::M44d( alignmentMatMax.GetRow(0).x, alignmentMatMax.GetRow(0).y, alignmentMatMax.GetRow(0).z, 0, alignmentMatMax.GetRow(1).x, alignmentMatMax.GetRow(1).y, alignmentMatMax.GetRow(1).z, 0, alignmentMatMax.GetRow(2).x, alignmentMatMax.GetRow(2).y, alignmentMatMax.GetRow(2).z, 0, alignmentMatMax.GetRow(3).x, alignmentMatMax.GetRow(3).y, alignmentMatMax.GetRow(3).z, 1);*/ //orientation = ConvertMaxQuatToAlembicQuat(extracctuat(alignmentMat), true); alignmentMat = alignmentMat * nodeWorldTransInv; orientation = extractQuat(alignmentMat); //ConvertMaxAngAxisToAlembicQuat(*particlesExt->GetParticleSpinByIndex(i), spin); ConvertMaxAngAxisToAlembicQuat(pTPMasterSystemInt->Spin(i), spin); id = particlesExt->GetParticleBornIndex(i); //seems to always return 0 //int nPid = pThinkingParticleMat->ParticleID(i); int nMatId = -1; Matrix3 meshTM; meshTM.IdentityMatrix(); BOOL bNeedDelete = FALSE; BOOL bChanged = FALSE; Mesh* pMesh = NULL; { ESS_PROFILE_SCOPE("AlembicPoints::SAVE - numParticlesLoop - ThinkingParticles - GetParticleRenderMesh"); pMesh = pThinkingParticleMat->GetParticleRenderMesh(ticks, mMaxNode, nullView, bNeedDelete, i, meshTM, bChanged); } if(pMesh){ ESS_PROFILE_SCOPE("AlembicPoints::SAVE - numParticlesLoop - ThinkingParticles - CacheShapeMesh"); meshInfo mi = CacheShapeMesh(pMesh, bNeedDelete, meshTM, nMatId, i, ticks, shapetype, shapeInstanceId, shapeInstanceTime); Abc::V3d min = pos + mi.bbox.min; Abc::V3d max = pos + mi.bbox.max; bbox.extendBy(min); bbox.extendBy(max); } else{ shapetype = ShapeType_Point; } } else #endif if(particlesExt && ipfSystem){ TimeValue ageValue = particlesExt->GetParticleAgeByIndex(i); if(ageValue == -1){ continue; } age = (float)GetSecondsFromTimeValue(ageValue); pos = ConvertMaxPointToAlembicPoint(*particlesExt->GetParticlePositionByIndex(i)); vel = ConvertMaxVectorToAlembicVector(*particlesExt->GetParticleSpeedByIndex(i) * TIME_TICKSPERSEC); scale = ConvertMaxScaleToAlembicScale(*particlesExt->GetParticleScaleXYZByIndex(i)); ConvertMaxEulerXYZToAlembicQuat(*particlesExt->GetParticleOrientationByIndex(i), orientation); ConvertMaxAngAxisToAlembicQuat(*particlesExt->GetParticleSpinByIndex(i), spin); //age = (float)GetSecondsFromTimeValue(particlesExt->GetParticleAgeByIndex(i)); id = particlesExt->GetParticleBornIndex(i); if(bAutomaticInstancing){ int nMatId = -1; if(ipfSystem){ if( groupInterface.setCurrentParticle(ticks, i) ){ nMatId = groupInterface.getCurrentMtlId(); } else{ ESS_LOG_WARNING("Error: cound retrieve material ID for particle mesh "<<i); } } Matrix3 meshTM; meshTM.IdentityMatrix(); BOOL bNeedDelete = FALSE; BOOL bChanged = FALSE; Mesh* pMesh = pMesh = particlesExt->GetParticleShapeByIndex(i); if(pMesh){ meshInfo mi = CacheShapeMesh(pMesh, bNeedDelete, meshTM, nMatId, i, ticks, shapetype, shapeInstanceId, shapeInstanceTime); Abc::V3d min = pos + mi.bbox.min; Abc::V3d max = pos + mi.bbox.max; bbox.extendBy(min); bbox.extendBy(max); } else{ shapetype = ShapeType_Point; } } else{ GetShapeType(particlesExt, i, ticks, shapetype, shapeInstanceId, shapeInstanceTime); } color = GetColor(particlesExt, i, ticks); } else if(pSimpleParticle){ if( ! pSimpleParticle->parts.Alive( i ) ) { continue; } pos = ConvertMaxPointToAlembicPoint(pSimpleParticle->ParticlePosition(ticks, i)); vel = ConvertMaxVectorToAlembicVector(pSimpleParticle->ParticleVelocity(ticks, i)); //simple particles have no scale? //simple particles have no orientation? age = (float)GetSecondsFromTimeValue( pSimpleParticle->ParticleAge(ticks, i) ); //simple particles have born index width = pSimpleParticle->ParticleSize(ticks, i); Abc::V3d min(pos.x - width/2, pos.y - width/2, pos.z - width/2); Abc::V3d max(pos.x + width/2, pos.y + width/2, pos.z + width/2); bbox.extendBy(min); bbox.extendBy(max); } { ESS_PROFILE_SCOPE("AlembicPoints::SAVE - numParticlesLoop - end loop save"); //move everything from world space to local space pos = pos * nodeWorldTransInv; Abc::V4f vel4(vel.x, vel.y, vel.z, 0.0); vel4 = vel4 * nodeWorldTransInv; vel.setValue(vel4.x, vel4.y, vel4.z); //scale = scale * nodeWorldTransInv; //orientation = Abc::extractQuat(orientation.toMatrix44() * nodeWorldTransInv); //spin = Abc::extractQuat(spin.toMatrix44() * nodeWorldTransInv); bbox.extendBy( pos ); positionVec.push_back( pos ); velocityVec.push_back( vel ); scaleVec.push_back( scale ); widthVec.push_back( width ); ageVec.push_back( age ); idVec.push_back( id ); orientationVec.push_back( orientation ); angularVelocityVec.push_back( spin ); shapeTypeVec.push_back( shapetype ); shapeInstanceIDVec.push_back( shapeInstanceId ); shapeTimeVec.push_back( shapeInstanceTime ); colorVec.push_back( color ); constantPos &= (pos == positionVec[0]); constantVel &= (vel == velocityVec[0]); constantScale &= (scale == scaleVec[0]); constantWidth &= (width == widthVec[0]); constantAge &= (age == ageVec[0]); constantOrientation &= (orientation == orientationVec[0]); constantAngularVel &= (spin == angularVelocityVec[0]); constantColor &= (color == colorVec[0]); // Set the archive bounding box // Positions for particles are already cnsider to be in world space if (mJob) { mJob->GetArchiveBBox().extendBy(pos); } } } } // if (numParticles > 1) // { // ESS_PROFILE_SCOPE("AlembicPoints::Save - vectorResize"); // if (constantPos) { positionVec.resize(1); } // if (constantVel) { velocityVec.resize(1); } // if (constantScale) { scaleVec.resize(1); } // if (constantWidth) { widthVec.resize(1); } // if (constantAge) { ageVec.resize(1); } // if (constantOrientation){ orientationVec.resize(1); } // if (constantAngularVel) { angularVelocityVec.resize(1); } //if (constantColor) { colorVec.resize(1); } // } { ESS_PROFILE_SCOPE("AlembicPoints::Save - sample writing"); // Store the information into our properties and points schema Abc::P3fArraySample positionSample( positionVec); Abc::P3fArraySample velocitySample(velocityVec); Abc::P3fArraySample scaleSample(scaleVec); Abc::FloatArraySample widthSample(widthVec); Abc::FloatArraySample ageSample(ageVec); Abc::FloatArraySample massSample(massVec); Abc::FloatArraySample shapeTimeSample(shapeTimeVec); Abc::UInt64ArraySample idSample(idVec); Abc::UInt16ArraySample shapeTypeSample(shapeTypeVec); Abc::UInt16ArraySample shapeInstanceIDSample(shapeInstanceIDVec); Abc::QuatfArraySample orientationSample(orientationVec); Abc::QuatfArraySample angularVelocitySample(angularVelocityVec); Abc::C4fArraySample colorSample(colorVec); mScaleProperty.set(scaleSample); mAgeProperty.set(ageSample); mMassProperty.set(massSample); mShapeTimeProperty.set(shapeTimeSample); mShapeTypeProperty.set(shapeTypeSample); mShapeInstanceIDProperty.set(shapeInstanceIDSample); mOrientationProperty.set(orientationSample); mAngularVelocityProperty.set(angularVelocitySample); mColorProperty.set(colorSample); mPointsSample.setPositions(positionSample); mPointsSample.setVelocities(velocitySample); mPointsSample.setWidths(AbcG::OFloatGeomParam::Sample(widthSample, AbcG::kVertexScope)); mPointsSample.setIds(idSample); mPointsSample.setSelfBounds(bbox); mPointsSchema.getChildBoundsProperty().set( bbox); mPointsSchema.set(mPointsSample); } mNumSamples++; //mInstanceNames.pop_back(); if(bAutomaticInstancing){ saveCurrentFrameMeshes(); } if(bRenderStateForced){ ipfSystem->SetRenderState(false); } if(bLastFrame){ ESS_PROFILE_SCOPE("AlembicParticles::Save - save instance names property"); std::vector<std::string> instanceNames(mNumShapeMeshes); for(faceVertexHashToShapeMap::iterator it = mShapeMeshCache.begin(); it != mShapeMeshCache.end(); it++){ std::stringstream pathStream; pathStream << "/" << it->second.name<< "/" << it->second.name <<"Shape"; instanceNames[it->second.nMeshInstanceId] = pathStream.str(); } //for some reason the .dims property is not written when there is exactly one entry if we don't push an empty string //having an extra unreferenced entry seems to be harmless instanceNames.push_back(""); mInstanceNamesProperty.set(Abc::StringArraySample(instanceNames)); } 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; }