Esempio n. 1
0
//-*****************************************************************************
void MeshDrwHelper::update( P3fArraySamplePtr iP,
                            V3fArraySamplePtr iN,
                            Abc::Box3d iBounds )
{
    // Check validity.
    if ( !m_valid || !iP || !m_meshP ||
         ( iP->size() != m_meshP->size() ) )
    {
        makeInvalid();
        return;
    }

    // Set meshP
    m_meshP = iP;

    if ( iBounds.isEmpty() )
    {
        computeBounds();
    }
    else
    {
        m_bounds = iBounds;
    }

    updateNormals( iN );
}
Esempio n. 2
0
MStatus AlembicHair::Save(double time, unsigned int timeIndex,
    bool isFirstFrame)
{
  ESS_PROFILE_SCOPE("AlembicHair::Save");
  MStatus status;

  // access the geometry
  MFnPfxGeometry node(GetRef());

  // save the metadata
  SaveMetaData(this);

  // save the attributes
  if (isFirstFrame) {
    Abc::OCompoundProperty cp;
    Abc::OCompoundProperty up;
    if (AttributesWriter::hasAnyAttr(node, *GetJob())) {
      cp = mSchema.getArbGeomParams();
      up = mSchema.getUserProperties();
    }

    mAttrs = AttributesWriterPtr(
        new AttributesWriter(cp, up, GetMyParent(), node, timeIndex, *GetJob())
        );
  }
  else {
    mAttrs->write();
  }

  // prepare the bounding box
  Abc::Box3d bbox;

  // check if we have the global cache option
  const bool globalCache =
      GetJob()->GetOption(L"exportInGlobalSpace").asInt() > 0;

  MRenderLineArray mainLines, leafLines, flowerLines;
  node.getLineData(mainLines, leafLines, flowerLines, true, false,
                   mNumSamples == 0, false, false, mNumSamples == 0, false,
                   true, globalCache);

  // first we need to count the number of points
  unsigned int vertexCount = 0;
  for (unsigned int i = 0; i < (unsigned int)mainLines.length(); i++) {
    vertexCount += mainLines.renderLine(i, &status).getLine().length();
  }

  mPosVec.resize(vertexCount);
  unsigned int offset = 0;
  if (mNumSamples == 0) {
    mNbVertices.resize((size_t)mainLines.length());
    mRadiusVec.resize(vertexCount);
    mColorVec.resize(vertexCount);
    for (unsigned int i = 0; i < (unsigned int)mainLines.length(); i++) {
      const MRenderLine &line = mainLines.renderLine(i, &status);
      const MVectorArray &positions = line.getLine();
      const MDoubleArray &radii = line.getWidth();
      const MVectorArray &colors = line.getColor();
      const MVectorArray &transparencies = line.getTransparency();
      mNbVertices[i] = positions.length();

      for (unsigned int j = 0; j < positions.length(); j++) {
        const MVector &opos = positions[j];
        Imath::V3f &ipos = mPosVec[offset];
        ipos.x = (float)opos.x;
        ipos.y = (float)opos.y;
        ipos.z = (float)opos.z;
        bbox.extendBy(Imath::V3d(ipos));

        mRadiusVec[offset] = (float)radii[j];

        const MVector &ocol = colors[j];
        Imath::C4f &icol = mColorVec[offset];
        icol.r = (float)ocol.x;
        icol.g = (float)ocol.y;
        icol.b = (float)ocol.z;
        icol.a = 1.0f - (float)transparencies[j].x;
        offset++;
      }
    }
  }
  else {
    for (unsigned int i = 0; i < (unsigned int)mainLines.length(); i++) {
      const MRenderLine &line = mainLines.renderLine(i, &status);
      const MVectorArray &positions = line.getLine();
      for (unsigned int j = 0; j < positions.length(); j++) {
        const MVector &opos = positions[j];
        Imath::V3f &ipos = mPosVec[offset];
        ipos.x = (float)opos.x;
        ipos.y = (float)opos.y;
        ipos.z = (float)opos.z;
        bbox.extendBy(Imath::V3d(ipos));
        offset++;
      }
    }
  }

  // store the positions to the samples
  mSample.setPositions(Abc::P3fArraySample(&mPosVec.front(), mPosVec.size()));
  mSample.setSelfBounds(bbox);

  if (mNumSamples == 0) {
    mSample.setCurvesNumVertices(Abc::Int32ArraySample(mNbVertices));
    mSample.setWrap(AbcG::kNonPeriodic);
    mSample.setType(AbcG::kLinear);

    mRadiusProperty.set(
        Abc::FloatArraySample(&mRadiusVec.front(), mRadiusVec.size()));
    mColorProperty.set(
        Abc::C4fArraySample(&mColorVec.front(), mColorVec.size()));
  }

  // save the sample
  mSchema.set(mSample);
  mNumSamples++;

  return MStatus::kSuccess;
}
XSI::CStatus AlembicNurbs::Save(double time)
{
  // store the transform
  Primitive prim(GetRef(REF_PRIMITIVE));
  bool globalSpace = GetJob()->GetOption(L"globalSpace");

  // query the global space
  CTransformation globalXfo;
  if (globalSpace) {
    globalXfo = KinematicState(GetRef(REF_GLOBAL_TRANS)).GetTransform(time);
  }

  // store the metadata
  SaveMetaData(GetRef(REF_NODE), this);

  // check if the nurbs is animated
  if (mNumSamples > 0) {
    if (!isRefAnimated(GetRef(REF_PRIMITIVE))) {
      return CStatus::OK;
    }
  }

  // define additional vectors, necessary for this task
  std::vector<Abc::V3f> posVec;
  std::vector<Abc::N3f> normalVec;
  std::vector<AbcA::uint32_t> normalIndexVec;

  // access the mesh
  NurbsSurfaceMesh nurbs = prim.GetGeometry(time);
  CVector3Array pos = nurbs.GetPoints().GetPositionArray();
  LONG vertCount = pos.GetCount();

  // prepare the bounding box
  Abc::Box3d bbox;

  // allocate the points and normals
  posVec.resize(vertCount);
  for (LONG i = 0; i < vertCount; i++) {
    if (globalSpace) {
      pos[i] = MapObjectPositionToWorldSpace(globalXfo, pos[i]);
    }
    posVec[i].x = (float)pos[i].GetX();
    posVec[i].y = (float)pos[i].GetY();
    posVec[i].z = (float)pos[i].GetZ();
    bbox.extendBy(posVec[i]);
  }

  // allocate the sample for the points
  if (posVec.size() == 0) {
    bbox.extendBy(Abc::V3f(0, 0, 0));
    posVec.push_back(Abc::V3f(FLT_MAX, FLT_MAX, FLT_MAX));
  }
  Abc::P3fArraySample posSample(&posVec.front(), posVec.size());

  // store the positions && bbox
  if (mNumSamples == 0) {
    std::vector<float> knots(1);
    knots[0] = 0.0f;

    mNurbsSample.setUKnot(Abc::FloatArraySample(&knots.front(), knots.size()));
    mNurbsSample.setVKnot(Abc::FloatArraySample(&knots.front(), knots.size()));
  }
  mNurbsSample.setPositions(posSample);
  mNurbsSample.setSelfBounds(bbox);

  // abort here if we are just storing points
  mNurbsSchema.set(mNurbsSample);
  mNumSamples++;
  return CStatus::OK;
}
Esempio n. 4
0
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;
}
Esempio n. 5
0
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;
}
Esempio n. 6
0
//-*****************************************************************************
void MeshDrwHelper::update( P3fArraySamplePtr iP,
                            V3fArraySamplePtr iN,
                            Int32ArraySamplePtr iIndices,
                            Int32ArraySamplePtr iCounts,
                            Abc::Box3d iBounds )
{
    // Before doing a ton, just have a quick look.
    if ( m_meshP && iP &&
         ( m_meshP->size() == iP->size() ) &&
         m_meshIndices &&
         ( m_meshIndices == iIndices ) &&
         m_meshCounts &&
         ( m_meshCounts == iCounts ) )
    {
        if ( m_meshP == iP )
        {
            updateNormals( iN );
        }
        else
        {
            update( iP, iN );
        }
        return;
    }

    // Okay, if we're here, the indices are not equal or the counts
    // are not equal or the P-array size changed.
    // So we can clobber those three, but leave N alone for now.
    m_meshP = iP;
    m_meshIndices = iIndices;
    m_meshCounts = iCounts;
    m_triangles.clear ();

    // Check stuff.
    if ( !m_meshP ||
         !m_meshIndices ||
         !m_meshCounts )
    {
        std::cerr << "Mesh update quitting because no input data"
                  << std::endl;
        makeInvalid();
        return;
    }

    // Get the number of each thing.
    size_t numFaces = m_meshCounts->size();
    size_t numIndices = m_meshIndices->size();
    size_t numPoints = m_meshP->size();
    if ( numFaces < 1 ||
         numIndices < 1 ||
         numPoints < 1 )
    {
        // Invalid.
        std::cerr << "Mesh update quitting because bad arrays"
                  << ", numFaces = " << numFaces
                  << ", numIndices = " << numIndices
                  << ", numPoints = " << numPoints
                  << std::endl;
        makeInvalid();
        return;
    }

    // Make triangles.
    size_t faceIndexBegin = 0;
    size_t faceIndexEnd = 0;
    for ( size_t face = 0; face < numFaces; ++face )
    {
        faceIndexBegin = faceIndexEnd;
        size_t count = (*m_meshCounts)[face];
        faceIndexEnd = faceIndexBegin + count;

        // Check this face is valid
        if ( faceIndexEnd > numIndices ||
             faceIndexEnd < faceIndexBegin )
        {
            std::cerr << "Mesh update quitting on face: "
                      << face
                      << " because of wonky numbers"
                      << ", faceIndexBegin = " << faceIndexBegin
                      << ", faceIndexEnd = " << faceIndexEnd
                      << ", numIndices = " << numIndices
                      << ", count = " << count
                      << std::endl;

            // Just get out, make no more triangles.
            break;
        }

        // Checking indices are valid.
        bool goodFace = true;
        for ( size_t fidx = faceIndexBegin;
              fidx < faceIndexEnd; ++fidx )
        {
            if ( ( size_t ) ( (*m_meshIndices)[fidx] ) >= numPoints )
            {
                std::cout << "Mesh update quitting on face: "
                          << face
                          << " because of bad indices"
                          << ", indexIndex = " << fidx
                          << ", vertexIndex = " << (*m_meshIndices)[fidx]
                          << ", numPoints = " << numPoints
                          << std::endl;
                goodFace = false;
                break;
            }
        }

        // Make triangles to fill this face.
        if ( goodFace && count > 2 )
        {
            m_triangles.push_back(
                Tri( ( unsigned int )(*m_meshIndices)[faceIndexBegin+0],
                     ( unsigned int )(*m_meshIndices)[faceIndexBegin+1],
                     ( unsigned int )(*m_meshIndices)[faceIndexBegin+2] ) );
            for ( size_t c = 3; c < count; ++c )
            {
                m_triangles.push_back(
                    Tri( ( unsigned int )(*m_meshIndices)[faceIndexBegin+0],
                         ( unsigned int )(*m_meshIndices)[faceIndexBegin+c-1],
                         ( unsigned int )(*m_meshIndices)[faceIndexBegin+c]
                         ) );
            }
        }
    }

    // Cool, we made triangles.
    // Pretend the mesh is made...
    m_valid = true;

    // And now update just the P and N, which will update bounds
    // and calculate new normals if necessary.

    if ( iBounds.isEmpty() )
    {
        computeBounds();
    }
    else
    {
        m_bounds = iBounds;
    }

    updateNormals( iN );

    // And that's it.
}
MStatus AlembicCurves::Save(double time, unsigned int timeIndex,
    bool isFirstFrame)
{
  ESS_PROFILE_SCOPE("AlembicCurves::Save");

  if (this->accumRef.get() != 0) {
    accumRef->save(GetRef(), time);
    ++mNumSamples;
    return MStatus::kSuccess;
  }

  // access the geometry
  MFnNurbsCurve node(GetRef());

  // save the metadata
  SaveMetaData(this);

  // save the attributes
  if (isFirstFrame) {
    Abc::OCompoundProperty cp;
    Abc::OCompoundProperty up;
    if (AttributesWriter::hasAnyAttr(node, *GetJob())) {
      cp = mSchema.getArbGeomParams();
      up = mSchema.getUserProperties();
    }

    mAttrs = AttributesWriterPtr(
        new AttributesWriter(cp, up, GetMyParent(), node, timeIndex, *GetJob())
        );
  }
  else {
    mAttrs->write();
  }

  // prepare the bounding box
  Abc::Box3d bbox;

  // check if we have the global cache option
  const bool globalCache =
      GetJob()->GetOption(L"exportInGlobalSpace").asInt() > 0;
  Abc::M44f globalXfo;
  if (globalCache) {
    globalXfo = GetGlobalMatrix(GetRef());
  }

  MPointArray positions;
  node.getCVs(positions);

  mPosVec.resize(positions.length());
  for (unsigned int i = 0; i < positions.length(); i++) {
    const MPoint &outPos = positions[i];
    Imath::V3f &inPos = mPosVec[i];
    inPos.x = (float)outPos.x;
    inPos.y = (float)outPos.y;
    inPos.z = (float)outPos.z;
    if (globalCache) {
      globalXfo.multVecMatrix(inPos, inPos);
    }
    bbox.extendBy(inPos);
  }

  // store the positions to the samples
  mSample.setPositions(Abc::P3fArraySample(&mPosVec.front(), mPosVec.size()));
  mSample.setSelfBounds(bbox);

  if (mNumSamples == 0) {
    // knot vector!
    MDoubleArray knots;
    node.getKnots(knots);

    mKnotVec.resize(knots.length());
    for (unsigned int i = 0; i < knots.length(); ++i) {
      mKnotVec[i] = (float)knots[i];
    }

    mKnotVectorProperty.set(Abc::FloatArraySample(mKnotVec));

    mNbVertices.push_back(node.numCVs());
    mSample.setCurvesNumVertices(Abc::Int32ArraySample(mNbVertices));

    if (node.form() == MFnNurbsCurve::kOpen) {
      mSample.setWrap(AbcG::kNonPeriodic);
    }
    else {
      mSample.setWrap(AbcG::kPeriodic);
    }

    if (node.degree() == 3) {
      mSample.setType(AbcG::kCubic);
    }
    else {
      mSample.setType(AbcG::kLinear);
    }

    MPlug widthPlug = node.findPlug("width");
    if (!widthPlug.isNull()) {
      mRadiusVec.push_back(widthPlug.asFloat());
    }
    else {
      mRadiusVec.push_back(1.0);
    }

    mRadiusProperty.set(
        Abc::FloatArraySample(&mRadiusVec.front(), mRadiusVec.size()));
  }

  // save the sample
  mSchema.set(mSample);
  mNumSamples++;

  return MStatus::kSuccess;
}
Esempio n. 8
0
//-*****************************************************************************
Abc::Box3d computeBoundsFromPositionsByFaces (const Int32ArraySample & faces,
    const Int32ArraySample & meshFaceCounts,
    const Int32ArraySample & vertexIndices,
    const P3fArraySample & meshP)
{
    Abc::Box3d     bounds;
    size_t numFaceSetFaces = faces.size ();

    size_t numFaces = meshFaceCounts.size ();
    size_t numIndices = vertexIndices.size ();
    size_t numPoints = meshP.size ();
    if ( numFaces < 1 ||
         numIndices < 1 ||
         numPoints < 1 ||
         numFaceSetFaces < 1 )
    {
        return bounds;
    }
    // Create ordered list of face numbers in faceset because
    // the list of face numbers in the faceset might be in any
    // order, so we build an ordered vec.
    std::vector <int32_t> faceSetFaceNums (faces.get (),
        faces.get() + numFaceSetFaces);
    std::sort (faceSetFaceNums.begin (), faceSetFaceNums.end ());
    std::vector <int32_t>::iterator curFaceSetFaceIter = faceSetFaceNums.begin ();
    std::vector <int32_t>::iterator faceSetFaceIterEnd = faceSetFaceNums.end ();

    // Run through faces of the polymesh. If the face is in
    // our faceset we get the face's count of vertex indices
    // and extend our bounds by those verts.
    // We stop our iteration once we've reached all faces in
    // our faceset.
    size_t curFaceSetFaceNum = *curFaceSetFaceIter;
    size_t faceIndex;
    size_t vertIndex;
    size_t vertexNum;
    size_t vertIndexBegin = 0;
    size_t vertIndexEnd = 0;
    V3f vertex;
    for ( faceIndex = 0; faceIndex < numFaces &&
        curFaceSetFaceIter != faceSetFaceIterEnd; faceIndex++)
    {
        vertIndexBegin = vertIndexEnd;
        vertIndexEnd = vertIndexBegin + meshFaceCounts[faceIndex];
        ABCA_ASSERT( vertIndexEnd <= numIndices,
                     "Face in mesh has count of vertices that is greater "
                     "than total number of vertex defined in mesh.");

        if (faceIndex == curFaceSetFaceNum)
        {
            // This face is in our faceset
            for (vertIndex = vertIndexBegin; vertIndex < vertIndexEnd;
                vertIndex++)
            {
                vertexNum = vertexIndices[vertIndex];
                vertex = meshP[vertexNum];
                bounds.extendBy (vertex);
            }
            curFaceSetFaceIter++;
            if (curFaceSetFaceIter != faceSetFaceIterEnd)
            {
                // There are more faces in this faceset, so
                // get the next one.
                curFaceSetFaceNum = *curFaceSetFaceIter;
            }
        }
    }
    return bounds;
}
Esempio n. 9
0
XSI::CStatus AlembicSubD::Save(double time)
{
   // store the transform
   Primitive prim(GetRef(REF_PRIMITIVE));
   bool globalSpace = GetJob()->GetOption(L"globalSpace");

   // query the global space
   CTransformation globalXfo;
   if(globalSpace)
      globalXfo = KinematicState(GetRef(REF_GLOBAL_TRANS)).GetTransform(time);
   CTransformation globalRotation;
   globalRotation.SetRotation(globalXfo.GetRotation());

   // store the metadata
   SaveMetaData(GetRef(REF_NODE),this);

   // check if the mesh is animated
   if(mNumSamples > 0) {
      if(!isRefAnimated(GetRef(REF_PRIMITIVE), false, globalSpace))
         return CStatus::OK;
   }

   // determine if we are a pure point cache
   bool purePointCache = (bool)GetJob()->GetOption(L"exportPurePointCache");

   // access the mesh
   PolygonMesh mesh = prim.GetGeometry(time);
   CVector3Array pos = mesh.GetVertices().GetPositionArray();
   LONG vertCount = pos.GetCount();

   // prepare the bounding box
   Abc::Box3d bbox;

   // allocate the points and normals
   std::vector<Abc::V3f> posVec(vertCount);
   for(LONG i=0;i<vertCount;i++)
   {
      if(globalSpace)
         pos[i] = MapObjectPositionToWorldSpace(globalXfo,pos[i]);
      posVec[i].x = (float)pos[i].GetX();
      posVec[i].y = (float)pos[i].GetY();
      posVec[i].z = (float)pos[i].GetZ();
      bbox.extendBy(posVec[i]);
   }

   // allocate the sample for the points
   if(posVec.size() == 0)
   {
      bbox.extendBy(Abc::V3f(0,0,0));
      posVec.push_back(Abc::V3f(FLT_MAX,FLT_MAX,FLT_MAX));
   }
   Abc::P3fArraySample posSample(&posVec.front(),posVec.size());

   // store the positions && bbox
   mSubDSample.setPositions(posSample);
   mSubDSample.setSelfBounds(bbox);

   customAttributes.exportCustomAttributes(mesh);

   // abort here if we are just storing points
   if(purePointCache)
   {
      if(mNumSamples == 0)
      {
         // store a dummy empty topology
         mFaceCountVec.push_back(0);
         mFaceIndicesVec.push_back(0);
         Abc::Int32ArraySample faceCountSample(&mFaceCountVec.front(),mFaceCountVec.size());
         Abc::Int32ArraySample faceIndicesSample(&mFaceIndicesVec.front(),mFaceIndicesVec.size());
         mSubDSample.setFaceCounts(faceCountSample);
         mSubDSample.setFaceIndices(faceIndicesSample);
      }

      mSubDSchema.set(mSubDSample);
      mNumSamples++;
      return CStatus::OK;
   }

   // check if we support changing topology
   bool dynamicTopology = (bool)GetJob()->GetOption(L"exportDynamicTopology");

   CPolygonFaceRefArray faces = mesh.GetPolygons();
   LONG faceCount = faces.GetCount();
   LONG sampleCount = mesh.GetSamples().GetCount();

   // create a sample look table
   LONG offset = 0;
   CLongArray sampleLookup(sampleCount);
   for(LONG i=0;i<faces.GetCount();i++)
   {
      PolygonFace face(faces[i]);
      CLongArray samples = face.GetSamples().GetIndexArray();
      for(LONG j=samples.GetCount()-1;j>=0;j--)
         sampleLookup[offset++] = samples[j];
   }

   // check if we should export the velocities
   if(dynamicTopology)
   {
      ICEAttribute velocitiesAttr = mesh.GetICEAttributeFromName(L"PointVelocity");
      if(velocitiesAttr.IsDefined() && velocitiesAttr.IsValid())
      {
         CICEAttributeDataArrayVector3f velocitiesData;
         velocitiesAttr.GetDataArray(velocitiesData);

         mVelocitiesVec.resize(vertCount);
         for(LONG i=0;i<vertCount;i++)
         {
            CVector3 vel;
            vel.PutX(velocitiesData[i].GetX());
            vel.PutY(velocitiesData[i].GetY());
            vel.PutZ(velocitiesData[i].GetZ());
            if(globalSpace)
               vel = MapObjectPositionToWorldSpace(globalRotation,vel);
            mVelocitiesVec[i].x = (float)vel.GetX();
            mVelocitiesVec[i].y = (float)vel.GetY();
            mVelocitiesVec[i].z = (float)vel.GetZ();
         }

         if(mVelocitiesVec.size() == 0)
            mVelocitiesVec.push_back(Abc::V3f(0,0,0));
         Abc::V3fArraySample sample = Abc::V3fArraySample(&mVelocitiesVec.front(),mVelocitiesVec.size());
         mSubDSample.setVelocities(sample);
      }
   }

   // if we are the first frame!
   if(mNumSamples == 0 || dynamicTopology)
   {
      // we also need to store the face counts as well as face indices
      if(mFaceIndicesVec.size() != sampleCount || sampleCount == 0)
      {
         mFaceCountVec.resize(faceCount);
         mFaceIndicesVec.resize(sampleCount);

         offset = 0;
         for(LONG i=0;i<faceCount;i++)
         {
            PolygonFace face(faces[i]);
            CLongArray indices = face.GetVertices().GetIndexArray();
            mFaceCountVec[i] = indices.GetCount();
            for(LONG j=indices.GetCount()-1;j>=0;j--)
               mFaceIndicesVec[offset++] = indices[j];
         }

         if(mFaceIndicesVec.size() == 0)
         {
            mFaceCountVec.push_back(0);
            mFaceIndicesVec.push_back(0);
         }
         Abc::Int32ArraySample faceCountSample(&mFaceCountVec.front(),mFaceCountVec.size());
         Abc::Int32ArraySample faceIndicesSample(&mFaceIndicesVec.front(),mFaceIndicesVec.size());

         mSubDSample.setFaceCounts(faceCountSample);
         mSubDSample.setFaceIndices(faceIndicesSample);
      }

      // set the subd level
      Property geomApproxProp;
      prim.GetParent3DObject().GetPropertyFromName(L"geomapprox",geomApproxProp);
      mSubDSample.setFaceVaryingInterpolateBoundary(geomApproxProp.GetParameterValue(L"gapproxmordrsl"));

      // also check if we need to store UV
      CRefArray clusters = mesh.GetClusters();
      if((bool)GetJob()->GetOption(L"exportUVs"))
      {
         CGeometryAccessor accessor = mesh.GetGeometryAccessor(siConstructionModeSecondaryShape);
         CRefArray uvPropRefs = accessor.GetUVs();

         // if we now finally found a valid uvprop
         if(uvPropRefs.GetCount() > 0)
         {
            // ok, great, we found UVs, let's set them up
            if(mNumSamples == 0)
            {
               mUvVec.resize(uvPropRefs.GetCount());
               if((bool)GetJob()->GetOption(L"indexedUVs"))
                  mUvIndexVec.resize(uvPropRefs.GetCount());

               // query the names of all uv properties
               std::vector<std::string> uvSetNames;
               for(LONG i=0;i< uvPropRefs.GetCount();i++)
                  uvSetNames.push_back(ClusterProperty(uvPropRefs[i]).GetName().GetAsciiString());

               Abc::OStringArrayProperty uvSetNamesProperty = Abc::OStringArrayProperty(
                  mSubDSchema, ".uvSetNames", mSubDSchema.getMetaData(), GetJob()->GetAnimatedTs() );
               Abc::StringArraySample uvSetNamesSample(&uvSetNames.front(),uvSetNames.size());
               uvSetNamesProperty.set(uvSetNamesSample);
            }

            // loop over all uvsets
            for(LONG uvI=0;uvI<uvPropRefs.GetCount();uvI++)
            {
               mUvVec[uvI].resize(sampleCount);
               CDoubleArray uvValues = ClusterProperty(uvPropRefs[uvI]).GetElements().GetArray();

               for(LONG i=0;i<sampleCount;i++)
               {
                  mUvVec[uvI][i].x = (float)uvValues[sampleLookup[i] * 3 + 0];
                  mUvVec[uvI][i].y = (float)uvValues[sampleLookup[i] * 3 + 1];
               }

               // now let's sort the normals 
               size_t uvCount = mUvVec[uvI].size();
               size_t uvIndexCount = 0;
               if((bool)GetJob()->GetOption(L"indexedUVs")) {
                  std::map<SortableV2f,size_t> uvMap;
                  std::map<SortableV2f,size_t>::const_iterator it;
                  size_t sortedUVCount = 0;
                  std::vector<Abc::V2f> sortedUVVec;
                  mUvIndexVec[uvI].resize(mUvVec[uvI].size());
                  sortedUVVec.resize(mUvVec[uvI].size());

                  // loop over all uvs
                  for(size_t i=0;i<mUvVec[uvI].size();i++)
                  {
                     it = uvMap.find(mUvVec[uvI][i]);
                     if(it != uvMap.end())
                        mUvIndexVec[uvI][uvIndexCount++] = (Abc::uint32_t)it->second;
                     else
                     {
                        mUvIndexVec[uvI][uvIndexCount++] = (Abc::uint32_t)sortedUVCount;
                        uvMap.insert(std::pair<Abc::V2f,size_t>(mUvVec[uvI][i],(Abc::uint32_t)sortedUVCount));
                        sortedUVVec[sortedUVCount++] = mUvVec[uvI][i];
                     }
                  }

                  // use indexed uvs if they use less space
                  mUvVec[uvI] = sortedUVVec;
                  uvCount = sortedUVCount;

                  sortedUVCount = 0;
                  sortedUVVec.clear();
               }

              AbcG::OV2fGeomParam::Sample uvSample(Abc::V2fArraySample(&mUvVec[uvI].front(),uvCount),AbcG::kFacevaryingScope);
               if(mUvIndexVec.size() > 0 && uvIndexCount > 0)
                  uvSample.setIndices(Abc::UInt32ArraySample(&mUvIndexVec[uvI].front(),uvIndexCount));

               if(uvI == 0)
               {
                  mSubDSample.setUVs(uvSample);
               }
               else
               {
                  // create the uv param if required
                  if(mNumSamples == 0)
                  {
                     CString storedUvSetName = CString(L"uv") + CString(uvI);
                     mUvParams.push_back(AbcG::OV2fGeomParam( mSubDSchema, storedUvSetName.GetAsciiString(), uvIndexCount > 0,
                                        AbcG::kFacevaryingScope, 1, GetJob()->GetAnimatedTs()));
                  }
                  mUvParams[uvI-1].set(uvSample);
               }
            }

            // create the uv options
            if(mUvOptionsVec.size() == 0)
            {
				mUvOptionsProperty = Abc::OFloatArrayProperty(mSubDSchema, ".uvOptions", mSubDSchema.getMetaData(), GetJob()->GetAnimatedTs() );

               for(LONG uvI=0;uvI<uvPropRefs.GetCount();uvI++)
               {
				  //ESS_LOG_ERROR( "Cluster Property child name: " << ClusterProperty(uvPropRefs[uvI]).GetFullName().GetAsciiString() );
				  //ESS_LOG_ERROR( "Cluster Property child type: " << ClusterProperty(uvPropRefs[uvI]).GetType().GetAsciiString() );
				  
				  ClusterProperty clusterProperty = (ClusterProperty) uvPropRefs[uvI];
				  bool subdsmooth = false;
				  if( clusterProperty.GetType() == L"uvspace") {
				      subdsmooth = (bool)clusterProperty.GetParameter(L"subdsmooth").GetValue();      
					 // ESS_LOG_ERROR( "subdsmooth: " << subdsmooth );
				  }

                  CRefArray children = clusterProperty.GetNestedObjects();
                  bool uWrap = false;
                  bool vWrap = false;
                  for(LONG i=0; i<children.GetCount(); i++)
                  {
                     ProjectItem child(children.GetItem(i));
                     CString type = child.GetType();
					// ESS_LOG_ERROR( "  Cluster Property child type: " << type.GetAsciiString() );
                     if(type == L"uvprojdef")
                     {
                        uWrap = (bool)child.GetParameter(L"wrap_u").GetValue();
                        vWrap = (bool)child.GetParameter(L"wrap_v").GetValue();
                        break;
                     }
                  }

                  // uv wrapping
                  mUvOptionsVec.push_back(uWrap ? 1.0f : 0.0f);
                  mUvOptionsVec.push_back(vWrap ? 1.0f : 0.0f);
				  mUvOptionsVec.push_back(subdsmooth ? 1.0f : 0.0f);
               }
               mUvOptionsProperty.set(Abc::FloatArraySample(&mUvOptionsVec.front(),mUvOptionsVec.size()));
            }
         }
      }

      // sweet, now let's have a look at face sets
      if(GetJob()->GetOption(L"exportFaceSets") && mNumSamples == 0)
      {
         for(LONG i=0;i<clusters.GetCount();i++)
         {
            Cluster cluster(clusters[i]);
            if(!cluster.GetType().IsEqualNoCase(L"poly"))
               continue;

            CLongArray elements = cluster.GetElements().GetArray();
            if(elements.GetCount() == 0)
               continue;

            std::string name(cluster.GetName().GetAsciiString());

            mFaceSetsVec.push_back(std::vector<Abc::int32_t>());
            std::vector<Abc::int32_t> & faceSetVec = mFaceSetsVec.back();
            for(LONG j=0;j<elements.GetCount();j++)
               faceSetVec.push_back(elements[j]);

            if(faceSetVec.size() > 0)
            {
              AbcG::OFaceSet faceSet = mSubDSchema.createFaceSet(name);
              AbcG::OFaceSetSchema::Sample faceSetSample(Abc::Int32ArraySample(&faceSetVec.front(),faceSetVec.size()));
               faceSet.getSchema().set(faceSetSample);
            }
         }
      }

      // save the sample
      mSubDSchema.set(mSubDSample);

      // check if we need to export the bindpose
      if(GetJob()->GetOption(L"exportBindPose") && prim.GetParent3DObject().GetEnvelopes().GetCount() > 0 && mNumSamples == 0)
      {
         mBindPoseProperty = Abc::OV3fArrayProperty(mSubDSchema, ".bindpose", mSubDSchema.getMetaData(), GetJob()->GetAnimatedTs());

         // store the positions of the modeling stack into here
         PolygonMesh bindPoseGeo = prim.GetGeometry(time, siConstructionModeModeling);
         CVector3Array bindPosePos = bindPoseGeo.GetPoints().GetPositionArray();
         mBindPoseVec.resize((size_t)bindPosePos.GetCount());
         for(LONG i=0;i<bindPosePos.GetCount();i++)
         {
            mBindPoseVec[i].x = (float)bindPosePos[i].GetX();
            mBindPoseVec[i].y = (float)bindPosePos[i].GetY();
            mBindPoseVec[i].z = (float)bindPosePos[i].GetZ();
         }

         Abc::V3fArraySample sample;
         if(mBindPoseVec.size() > 0)
            sample = Abc::V3fArraySample(&mBindPoseVec.front(),mBindPoseVec.size());
         mBindPoseProperty.set(sample);
      }   
   }
   else
   {
      mSubDSchema.set(mSubDSample);
   }

   mNumSamples++;

   return CStatus::OK;
}
Esempio n. 10
0
//-*****************************************************************************
void OFaceSetSchema::set( const Sample &iSamp )
{
    ALEMBIC_ABC_SAFE_CALL_BEGIN( "OFaceSetSchema::set()" );

    Abc::Box3d emptyBox;
    emptyBox.makeEmpty();
    // do we need to create child bounds?
    if ( iSamp.getChildBounds().hasVolume() && !m_childBoundsProperty)
    {
        m_childBoundsProperty = Abc::OBox3dProperty( this->getPtr(), 
            ".childBnds", m_facesProperty.getTimeSampling() );

        // -1 because we just dis an m_positions set above
        size_t numSamples = m_facesProperty.getNumSamples() - 1;

        // set all the missing samples
        for ( size_t i = 0; i < numSamples; ++i )
        {
            m_childBoundsProperty.set( emptyBox );
        }
    }

    // We could add sample integrity checking here.
    if ( m_facesProperty.getNumSamples () == 0 )
    {
        // First sample must provide faces
        ABCA_ASSERT( iSamp.getFaces() ,
                     "Sample 0 must provide the faces that make up the faceset." );
        m_facesProperty.set( iSamp.getFaces() );

        if (m_childBoundsProperty)
        { 
            m_childBoundsProperty.set( iSamp.getChildBounds() ); 
        }
    }
    else
    {
        SetPropUsePrevIfNull( m_facesProperty, iSamp.getFaces() );

        if ( m_childBoundsProperty )
        {
            SetPropUsePrevIfNull( m_childBoundsProperty, 
                iSamp.getChildBounds() );
        }
    }

    // We've now set the sample for the m_faces property.
    if ( iSamp.getSelfBounds().hasVolume() )
    {
        // Caller explicity set bounds for this sample of the faceset.
        m_selfBoundsProperty.set( iSamp.getSelfBounds() );
    }
    else
    {
        m_selfBoundsProperty.set( iSamp.getSelfBounds() );
        // NYI compute self bounds via parent mesh's faces
    }

    if (m_facesExclusive != kFaceSetNonExclusive)
    {
        // The user has changed the exclusivity hint from the
        // default so we'll create a property now and store.
        _recordExclusivityHint();
    }
    ALEMBIC_ABC_SAFE_CALL_END();
}
Esempio n. 11
0
//-*****************************************************************************
Abc::Box3d PolyMesh::writeSample( const Abc::OSampleSelector &iSS )
{
    // First, call base class sample write, which will return bounds
    // of any children.
    Abc::index_t sampleIndex = iSS.getIndex();
    Abc::Box3d bounds = Exportable::writeSample( iSS );

    // If we're not deforming, don't bother with new sample.
    // Do calculate bounds and set them, though.
    if ( sampleIndex != 0 && !m_deforming )
    {
        bounds.extendBy( m_firstSampleSelfBounds );
        m_boundsProperty.set( bounds, iSS );
        return bounds;
    }

    // Make a mesh
    MStatus status;
    MFnMesh mesh( m_dagPath, &status );
    CHECK_MAYA_STATUS;
    mesh.updateSurface();
    mesh.syncObject();

    // Make a sample.
    Abc::OPolyMeshSchema::Sample abcPolyMeshSample;

    //-*************************************************************************
    // WRITE VERTICES
    //-*************************************************************************
    MPointArray vertices;
    mesh.getPoints( vertices );
    size_t npoints = vertices.length();
    std::vector<Abc::V3f> v3fVerts( npoints );

    Abc::Box3d shapeBounds;
    shapeBounds.makeEmpty();
    for ( size_t i = 0; i < npoints; ++i )
    {
        const MPoint &vi = vertices[i];
        Abc::V3f pi( vi.x, vi.y, vi.z );
        v3fVerts[i] = pi;
        shapeBounds.extendBy( Abc::V3d( vi.x, vi.y, vi.z ) );
    }
    if ( sampleIndex == 0 )
    {
        m_firstSampleSelfBounds = shapeBounds;
    }
    bounds.extendBy( shapeBounds );

    // Set the bounds sample.
    m_boundsProperty.set( bounds, iSS );

    // Stuff the positions into the mesh sample.
    abcPolyMeshSample.setPositions( Abc::V3fArraySample( v3fVerts ) );

    //-*************************************************************************
    // OTHER STUFF, FOR FIRST OR LATER VERTICES
    //-*************************************************************************
    std::vector<Abc::int32_t> abcIndices;
    std::vector<Abc::int32_t> abcCounts;
    std::vector<Abc::N3f> abcNormals;
    std::vector<Abc::V2f> abcUvs;

    //-*************************************************************************
    // GET MESH NORMALS & UVS
    //-*************************************************************************
    size_t nnormals = mesh.numNormals();
    MFloatVectorArray meshNorms;
    if ( nnormals > 0 )
    {
        mesh.getNormals( meshNorms, MSpace::kObject );
    }
    
    size_t nuvs = mesh.numUVs();
    MFloatArray meshU;
    MFloatArray meshV;
    if ( nuvs > 0 )
    {
        mesh.getUVs( meshU, meshV );
    }

    //-*************************************************************************
    // LOOP OVER FIRST OR SUBSEQUENT SAMPLES
    //-*************************************************************************
    if ( sampleIndex == 0 )
    {
        // FIRST SAMPLE

        // Loop over polys.
        size_t npolys = mesh.numPolygons();
        abcCounts.resize( npolys );

        Abc::int32_t faceIndex = 0;
        Abc::int32_t faceStartVertexIndex = 0;

        for ( MItMeshPolygon piter( m_dagPath );
              !piter.isDone(); piter.next(), ++faceIndex )
        {
            Abc::int32_t faceCount = piter.polygonVertexCount();
            abcCounts[faceIndex] = faceCount;
            faceStartVertexIndex += faceCount;

            for ( Abc::int32_t faceVertex = 0;
                  faceVertex < faceCount; ++faceVertex )
            {
                abcIndices.push_back( piter.vertexIndex( faceVertex ) );

                if ( nnormals > 0 )
                {
                    size_t normIndex = piter.normalIndex( faceVertex );
                    const MFloatVector &norm = meshNorms[normIndex];
                    Abc::N3f abcNorm( norm[0], norm[1], norm[2] );
                    abcNormals.push_back( abcNorm );
                }

                if ( nuvs > 0 )
                {
                    int uvIndex = 0;
                    piter.getUVIndex( faceVertex, uvIndex );
                    Abc::V2f abcUv( meshU[uvIndex], meshV[uvIndex] );
                    abcUvs.push_back( abcUv );
                }
            }
        }

        // We have now collected abcIndices, abcStarts, abcNormals, and abcUvs.
        // Put them into the sample.
        abcPolyMeshSample.setIndices( Abc::Int32ArraySample( abcIndices ) );
        abcPolyMeshSample.setCounts( Abc::Int32ArraySample( abcCounts ) );

        if ( nnormals > 0 && m_normals )
        {
            m_normals.set( Abc::N3fArraySample( abcNormals ), iSS );
        }
        if ( nuvs > 0 && m_sts )
        {
            m_sts.set( Abc::V2fArraySample( abcUvs ), iSS );
        }
    }
    else if ( ( nnormals > 0 && m_normals ) ||
              ( nuvs > 0 && m_sts ) )
    {
        // SUBSEQUENT SAMPLES
        // Just gathering normals and uvs.
        // (vertices handled above)
        
        // Loop over polys.
        Abc::int32_t faceIndex = 0;
        Abc::int32_t faceStartVertexIndex = 0;
        
        for ( MItMeshPolygon piter( m_dagPath );
              !piter.isDone(); piter.next(), ++faceIndex )
        {
            Abc::int32_t faceCount = piter.polygonVertexCount();
            for ( Abc::int32_t faceVertex = 0;
                  faceVertex < faceCount; ++faceVertex )
            {
                if ( nnormals > 0 )
                {
                    size_t normIndex = piter.normalIndex( faceVertex );
                    const MFloatVector &norm = meshNorms[normIndex];
                    Abc::N3f abcNorm( norm[0], norm[1], norm[2] );
                    abcNormals.push_back( abcNorm );
                }
                
                if ( nuvs > 0 )
                {
                    int uvIndex = 0;
                    piter.getUVIndex( faceVertex, uvIndex );
                    Abc::V2f abcUv( meshU[uvIndex], meshV[uvIndex] );
                    abcUvs.push_back( abcUv );
                }
            }
        }

        // We have now collected abcNormals, and abcUvs.
        // Put them into the sample.
        if ( nnormals > 0 && m_normals )
        {
            m_normals.set( Abc::N3fArraySample( abcNormals ), iSS );
        }
        if ( nuvs > 0 )
        {
            m_sts.set( Abc::V2fArraySample( abcUvs ), iSS );
        }
    }

    // Set the mesh sample.
    m_polyMesh.getSchema().set( abcPolyMeshSample, iSS );

    return bounds;
}