void getSubDTimeSpan(ISubD iSub, chrono_t& first, chrono_t& last) { ISubDSchema mesh = iSub.getSchema(); TimeSamplingPtr ts = mesh.getTimeSampling(); first = std::min(first, ts->getSampleTime(0) ); last = std::max(last, ts->getSampleTime(mesh.getNumSamples()-1) ); }
//-***************************************************************************** void getABCTimeSpan(IArchive archive, chrono_t& first, chrono_t& last) { // TO DO: Is the childBounds property reliable to get the full archive's span? if (!archive.valid()) return; IObject archiveTop = archive.getTop(); if ( archiveTop.getProperties().getPropertyHeader( ".childBnds" ) != NULL ) { // Try to get timing from childBounds first IBox3dProperty childbnds = Alembic::Abc::IBox3dProperty( archive.getTop().getProperties(), ".childBnds", ErrorHandler::kQuietNoopPolicy); TimeSamplingPtr ts = childbnds.getTimeSampling(); first = std::min(first, ts->getSampleTime(0) ); last = std::max(last, ts->getSampleTime(childbnds.getNumSamples()-1) ); return; } unsigned int numChildren = archiveTop.getNumChildren(); for (unsigned i=0; i<numChildren; ++i) // Visit every object to get its first and last sample { IObject obj( archiveTop.getChild( i )); getObjectTimeSpan(obj, first, last, true); } }
void getCameraTimeSpan(ICamera iCam, chrono_t& first, chrono_t& last) { ICameraSchema cam = iCam.getSchema(); TimeSamplingPtr ts = cam.getTimeSampling(); first = std::min(first, ts->getSampleTime(0) ); last = std::max(last, ts->getSampleTime(cam.getNumSamples()-1) ); }
//-***************************************************************************** IPolyMeshDrw::IPolyMeshDrw( IPolyMesh &iPmesh, std::vector<std::string> path ) : IObjectDrw( iPmesh, false, path ) , m_polyMesh( iPmesh ) { // Get out if problems. if ( !m_polyMesh.valid() ) { return; } if ( m_polyMesh.getSchema().getNumSamples() > 0 ) { m_polyMesh.getSchema().get( m_samp ); } m_boundsProp = m_polyMesh.getSchema().getSelfBoundsProperty(); // The object has already set up the min time and max time of // all the children. // if we have a non-constant time sampling, we should get times // out of it. TimeSamplingPtr iTsmp = m_polyMesh.getSchema().getTimeSampling(); if ( !m_polyMesh.getSchema().isConstant() ) { size_t numSamps = m_polyMesh.getSchema().getNumSamples(); if ( numSamps > 0 ) { chrono_t minTime = iTsmp->getSampleTime( 0 ); m_minTime = std::min( m_minTime, minTime ); chrono_t maxTime = iTsmp->getSampleTime( numSamps-1 ); m_maxTime = std::max( m_maxTime, maxTime ); } } m_drwHelper.setName(m_object.getFullName()); }
//-***************************************************************************** ISubDDrw::ISubDDrw( ISubD &iPmesh ) : IObjectDrw( iPmesh, false ) , m_subD( iPmesh ) { // Get out if problems. if ( !m_subD.valid() ) { return; } // The object has already set up the min time and max time of // all the children. // if we have a non-constant time sampling, we should get times // out of it. TimeSamplingPtr iTsmp = m_subD.getSchema().getTimeSampling(); if ( !m_subD.getSchema().isConstant() ) { size_t numSamps = m_subD.getSchema().getNumSamples(); if ( numSamps > 0 ) { chrono_t minTime = iTsmp->getSampleTime( 0 ); m_minTime = std::min( m_minTime, minTime ); chrono_t maxTime = iTsmp->getSampleTime( numSamps-1 ); m_maxTime = std::max( m_maxTime, maxTime ); } } }
void getPolyMeshTimeSpan(IPolyMesh iPoly, chrono_t& first, chrono_t& last) { IPolyMeshSchema mesh = iPoly.getSchema(); TimeSamplingPtr ts = mesh.getTimeSampling(); first = std::min(first, ts->getSampleTime(0) ); last = std::max(last, ts->getSampleTime(mesh.getNumSamples()-1) ); }
//-***************************************************************************** INuPatchDrw::INuPatchDrw( INuPatch &iNuPatch ) : IObjectDrw( iNuPatch, false ) , m_nuPatch( iNuPatch ) { // create our nurb renderer. nurb = gluNewNurbsRenderer(); gluNurbsProperty(nurb, GLU_SAMPLING_TOLERANCE, 25.0); gluNurbsProperty(nurb, GLU_DISPLAY_MODE, GLU_FILL); // Get out if problems. if ( !m_nuPatch.valid() ) { return; } // The object has already set up the min time and max time of // all the children. // if we have a non-constant time sampling, we should get times // out of it. TimeSamplingPtr iTsmp = m_nuPatch.getSchema().getTimeSampling(); if ( !m_nuPatch.getSchema().isConstant() ) { size_t numSamps = m_nuPatch.getSchema().getNumSamples(); if ( numSamps > 0 ) { chrono_t minTime = iTsmp->getSampleTime( 0 ); m_minTime = std::min( m_minTime, minTime ); chrono_t maxTime = iTsmp->getSampleTime( numSamps-1 ); m_maxTime = std::max( m_maxTime, maxTime ); } } }
/** * init */ bool UMAbcNurbsPatch::init(bool recursive) { if (!is_valid()) return false; // // create our nurb renderer. // nurb = gluNewNurbsRenderer(); // gluNurbsProperty(nurb, GLU_SAMPLING_TOLERANCE, 25.0); // gluNurbsProperty(nurb, GLU_DISPLAY_MODE, GLU_FILL); size_t num_samples = patch_.getSchema().getNumSamples(); if (num_samples > 0) { // get constant sample patch_.getSchema().get(initial_sample_); // if not consistant, we get time if (!patch_.getSchema().isConstant()) { TimeSamplingPtr time = patch_.getSchema().getTimeSampling(); min_time_ = static_cast<unsigned long>(time->getSampleTime(0)*1000); max_time_ = static_cast<unsigned long>(time->getSampleTime(num_samples-1)*1000); } } return false; }
void getXformTimeSpan(IXform iXf, chrono_t& first, chrono_t& last, bool inherits) { IXformSchema xf = iXf.getSchema(); TimeSamplingPtr ts = xf.getTimeSampling(); first = std::min(first, ts->getSampleTime(0) ); if (xf.isConstant()) { last = first; } else { last = std::max(last, ts->getSampleTime(xf.getNumSamples()-1) ); } if (inherits && xf.getInheritsXforms()) { IObject parent = iXf.getParent(); // Once the Archive's Top Object is reached, IObject::getParent() will // return an invalid IObject, and that will evaluate to False. while ( parent ) { if ( Alembic::AbcGeom::IXform::matches(parent.getHeader()) ) { IXform x( parent, kWrapExisting ); getXformTimeSpan(x, first, last, inherits); } } } }
void ofxAlembic::IGeom::update_timestamp(T& object) { TimeSamplingPtr iTsmp = object.getSchema().getTimeSampling(); if (!object.getSchema().isConstant()) { size_t numSamps = object.getSchema().getNumSamples(); if (numSamps > 0) { m_minTime = iTsmp->getSampleTime(0); m_maxTime = iTsmp->getSampleTime(numSamps - 1); } } }
//-***************************************************************************** void simpleTestIn( const std::string &iArchiveName ) { IArchive archive( Alembic::AbcCoreHDF5::ReadArchive(), iArchiveName, ErrorHandler::kThrowPolicy ); IObject archiveTop = archive.getTop(); IObject c0( archiveTop, "c0" ); ICompoundProperty c0Props = c0.getProperties(); TimeSamplingPtr uts = c0Props.getPtr()-> getScalarProperty( "uniformdoubleprop" )->getTimeSampling(); TimeSamplingPtr ats = c0Props.getPtr()-> getScalarProperty( "acyclicdoubleprop" )->getTimeSampling(); //IDoubleProperty dp0( c0Props, "uniformdoubleprop" ); //IDoubleProperty dp1( c0Props, "acyclicdoubleprop" ); //size_t numReadDoubleSamps = dp0.getNumSamples(); //TESTING_ASSERT( numReadDoubleSamps == g_numDoubleSamps ); //TESTING_ASSERT( dp1.getNumSamples() == numReadDoubleSamps ); //scramble_heap(); //const TimeSamplingType &utst = uts.getTimeSamplingType(); const TimeSamplingType utst = c0Props.getPtr()->getScalarProperty( "uniformdoubleprop" )->getTimeSampling()->getTimeSamplingType(); for ( size_t j = 0 ; j < g_numDoubleSamps ; j++ ) { chrono_t utime = uts->getSampleTime( j ); chrono_t atime = ats->getSampleTime( j ); chrono_t reftime = g_doubleStartTime + ( j * g_dt ); std::cout << "reference time: " << reftime << std::endl; std::cout << "uniform sample time: " << utime << std::endl; std::cout << "acyclic sample time: " << atime << std::endl; chrono_t ABSERROR = 0.00001; TESTING_ASSERT( Imath::equalWithAbsError( utime, reftime, ABSERROR ) ); TESTING_ASSERT( Imath::equalWithAbsError( atime, reftime, ABSERROR ) ); TESTING_ASSERT( Imath::equalWithAbsError( atime, utime, ABSERROR ) ); } }
ofxAlembic::IXform::IXform(Alembic::AbcGeom::IXform object) : ofxAlembic::IGeom(object), m_xform(object) { TimeSamplingPtr iTsmp = m_xform.getSchema().getTimeSampling(); if (!m_xform.getSchema().isConstant()) { size_t numSamps = m_xform.getSchema().getNumSamples(); if (numSamps > 0) { chrono_t minTime = iTsmp->getSampleTime(0); m_minTime = std::min(m_minTime, minTime); chrono_t maxTime = iTsmp->getSampleTime(numSamps - 1); m_maxTime = std::max(m_maxTime, maxTime); } } type = XFORM; }
ofxAlembic::IPolyMesh::IPolyMesh(Alembic::AbcGeom::IPolyMesh object) : ofxAlembic::IGeom(object), m_polyMesh(object) { TimeSamplingPtr iTsmp = m_polyMesh.getSchema().getTimeSampling(); if (!m_polyMesh.getSchema().isConstant()) { size_t numSamps = m_polyMesh.getSchema().getNumSamples(); if (numSamps > 0) { chrono_t minTime = iTsmp->getSampleTime(0); m_minTime = std::min(m_minTime, minTime); chrono_t maxTime = iTsmp->getSampleTime(numSamps - 1); m_maxTime = std::max(m_maxTime, maxTime); } } type = POLYMESH; }
ofxAlembic::ICurves::ICurves(Alembic::AbcGeom::ICurves object) : ofxAlembic::IGeom(object), m_curves(object) { TimeSamplingPtr iTsmp = m_curves.getSchema().getTimeSampling(); if (!object.getSchema().isConstant()) { size_t numSamps = object.getSchema().getNumSamples(); if (numSamps > 0) { chrono_t minTime = iTsmp->getSampleTime(0); m_minTime = std::min(m_minTime, minTime); chrono_t maxTime = iTsmp->getSampleTime(numSamps - 1); m_maxTime = std::max(m_maxTime, maxTime); } } type = CURVES; }
//-***************************************************************************** IPointsDrw::IPointsDrw( IPoints &iPmesh ) : IObjectDrw( iPmesh, false ) , m_points( iPmesh ) { // Get out if problems. if ( !m_points.valid() ) { return; } // Try to create colors, if possible. IPointsSchema &pointsSchema = m_points.getSchema(); const PropertyHeader *phead = pointsSchema.getPropertyHeader( "Cs" ); if ( phead && IC3fArrayProperty::matches( *phead ) ) { m_colorProp = IC3fArrayProperty( pointsSchema, "Cs" ); } phead = pointsSchema.getPropertyHeader( "N" ); if ( phead && IN3fArrayProperty::matches( *phead ) ) { m_normalProp = IN3fArrayProperty( pointsSchema, "N" ); } // The object has already set up the min time and max time of // all the children. // if we have a non-constant time sampling, we should get times // out of it. TimeSamplingPtr iTsmp = m_points.getSchema().getTimeSampling(); if ( !m_points.getSchema().isConstant() ) { size_t numSamps = m_points.getSchema().getNumSamples(); if ( numSamps > 0 ) { chrono_t minTime = iTsmp->getSampleTime( 0 ); m_minTime = std::min( m_minTime, minTime ); chrono_t maxTime = iTsmp->getSampleTime( numSamps-1 ); m_maxTime = std::max( m_maxTime, maxTime ); } } }
void readV3fArrayProperty(const std::string &archiveName, bool useOgawa) { // Open an existing archive for reading. Indicate that we want // Alembic to throw exceptions on errors. std::cout << "Reading " << archiveName << std::endl; AbcF::IFactory factory; factory.setPolicy( ErrorHandler::kThrowPolicy ); AbcF::IFactory::CoreType coreType; IArchive archive = factory.getArchive(archiveName, coreType); TESTING_ASSERT( (useOgawa && coreType == AbcF::IFactory::kOgawa) || (!useOgawa && coreType == AbcF::IFactory::kHDF5) ); IObject archiveTop = archive.getTop(); // Determine the number of (top level) children the archive has const unsigned int numChildren = archiveTop.getNumChildren(); ABCA_ASSERT( numChildren == 1, "Wrong number of children (expected 1)"); std::cout << "The archive has " << numChildren << " children:" << std::endl; // Iterate through them, print out their names IObject child( archiveTop, archiveTop.getChildHeader(0).getName() ); std::cout << " named '" << child.getName() << "'"; // Properties ICompoundProperty props = child.getProperties(); size_t numProperties = props.getNumProperties(); // only top-level props ABCA_ASSERT( numProperties == 1, "Expected 1 property, found " << numProperties); std::cout << " with one property"; std::vector<std::string> propNames(1); propNames[0] = props.getPropertyHeader(0).getName(); std::cout << " named '" << propNames[0] << "'" << std::endl; PropertyType pType = props.getPropertyHeader(0).getPropertyType(); ABCA_ASSERT( pType == kArrayProperty, "Expected an array property, but didn't find one" ); std::cout << " which is an array property"; DataType dType = props.getPropertyHeader(0).getDataType(); ABCA_ASSERT( dType.getPod() == kFloat32POD, "Expected an v3f property, but didn't find one" ); // We know this is an array property (I'm eliding the if/else // statements required to recognize and handle this properly) IV3fArrayProperty positions( props, propNames[0] ); size_t numSamples = positions.getNumSamples(); std::cout << ".. it has " << numSamples << " samples" << std::endl; ABCA_ASSERT( numSamples == 5, "Expected 5 samples, found " << numSamples ); TimeSamplingPtr ts = positions.getTimeSampling(); std::cout << "..with time/value pairs: " << std::endl;; for (unsigned int ss=0; ss<numSamples; ss++) { std::cout << " "; ISampleSelector iss( (index_t) ss); std::cout << ts->getSampleTime( (index_t) ss ) << " / "; V3fArraySamplePtr samplePtr; positions.get( samplePtr, iss ); std::cout << "[ "; size_t numPoints = samplePtr->size(); for ( size_t jj=0 ; jj<numPoints ; jj++ ) std::cout << (*samplePtr)[jj] << " "; std::cout << "]" << std::endl; if (ss == 2) // no entries in sample #2 { ABCA_ASSERT( numPoints == 0, "Expected an empty sample, but found " << numPoints << " entries." ); } else { for ( size_t jj=0 ; jj<numPoints ; jj++ ) ABCA_ASSERT( (*samplePtr)[jj] == g_vectors[jj], "Incorrect value read from archive." ); } } ABCA_ASSERT( archive.getMaxNumSamplesForTimeSamplingIndex(1) == (index_t) numSamples, "Incorrect number of max samples in readV3fArrayProperty." ); std::cout << std::endl; // Done - the archive closes itself double start, end; GetArchiveStartAndEndTime( archive, start, end ); TESTING_ASSERT( almostEqual(start, 123.0) ); TESTING_ASSERT( almostEqual(end, 123.0 + 4.0 / 24.0) ); }
void readProperty(const std::string &archiveName, bool useOgawa) { // Open an existing archive for reading. Indicate that we want // Alembic to throw exceptions on errors. std::cout << "Reading " << archiveName << std::endl; AbcF::IFactory factory; factory.setPolicy( ErrorHandler::kThrowPolicy ); AbcF::IFactory::CoreType coreType; IArchive archive = factory.getArchive(archiveName, coreType); ABCA_ASSERT( (useOgawa && coreType == AbcF::IFactory::kOgawa) || (!useOgawa && coreType == AbcF::IFactory::kHDF5), "File did not open as the expected type." ); IObject archiveTop = archive.getTop(); // Determine the number of (top level) children the archive has const unsigned int numChildren = archiveTop.getNumChildren(); ABCA_ASSERT( numChildren == 1, "Wrong number of children (expected 1)"); std::cout << "The archive has " << numChildren << " children:" << std::endl; // Iterate through them, print out their names IObject child( archiveTop, archiveTop.getChildHeader( 0 ).getName() ); std::cout << " " << child.getName(); // Properties ICompoundProperty props = child.getProperties(); size_t numProperties = props.getNumProperties(); // only top-level props ABCA_ASSERT( numProperties == 1, "Expected 1 property, found " << numProperties); std::cout << " with one property"; std::vector<std::string> propNames(1); propNames[0] = props.getPropertyHeader(0).getName(); std::cout << " named " << propNames[0] << std::endl; PropertyType pType = props.getPropertyHeader(0).getPropertyType(); ABCA_ASSERT( pType == kScalarProperty, "Expected a scalar property, but didn't find one" ); std::cout << " which is a scalar property"; DataType dType = props.getPropertyHeader(0).getDataType(); ABCA_ASSERT( dType.getPod() == kFloat64POD, "Expected a double (kFloat64POD) property, but didn't" " find one" ); // We know this is a scalar property (I'm eliding the if/else // statements required to recognize this) IDoubleProperty mass( props, propNames[0] ); size_t numSamples = mass.getNumSamples(); std::cout << ".. it has " << numSamples << " samples" << std::endl; //ABCA_ASSERT( numSamples == 5, "Expected 5 samples, found " << numSamples ); TimeSamplingPtr ts = mass.getTimeSampling(); std::cout << "..with time/value pairs: "; for (unsigned int ss=0; ss<numSamples; ss++) { ISampleSelector iss( (index_t) ss); std::cout << ts->getSampleTime( (index_t) ss ) << "/"; printSampleValue( mass, iss ); std::cout << " "; double timeDiff = ts->getSampleTime( (index_t) ss ) - (g_startTime + (ss*(g_dt/3.0))); ABCA_ASSERT( fabs(timeDiff) < 1e-12, "Incorrect sample time read" ); double massDiff = mass.getValue( iss ) - (1.0 + 0.1*ss); ABCA_ASSERT( fabs(massDiff) < 1e-12, "Incorrect sample value read" ); } ABCA_ASSERT( archive.getMaxNumSamplesForTimeSamplingIndex(1) == (index_t) numSamples, "Incorrect number of max samples for Time Sampling ID 1."); std::cout << std::endl; // Done - the archive closes itself }
void readSimpleProperties(const std::string &archiveName) { // Open an existing archive for reading. Indicate that we want // Alembic to throw exceptions on errors. AbcF::IFactory factory; factory.setPolicy( ErrorHandler::kThrowPolicy ); AbcF::IFactory::CoreType coreType; IArchive archive = factory.getArchive(archiveName, coreType); IObject archiveTop = archive.getTop(); // Determine the number of (top level) children the archive has const int numChildren = archiveTop.getNumChildren(); TESTING_ASSERT( numChildren == 4 ); std::cout << "The archive has " << numChildren << " children:" << std::endl; // Iterate through them, print out their names for (int ii=0; ii<numChildren; ii++) { IObject child( archiveTop, archiveTop.getChildHeader( ii ).getName() ); std::cout << " " << child.getName(); std::cout << " has " << child.getNumChildren() << " children" << std::endl; // Properties ICompoundProperty props = child.getProperties(); int numProperties = props.getNumProperties(); std::cout << " ..and " << numProperties << " simple properties" << std::endl; std::vector<std::string> propNames; for (int pp=0; pp<numProperties; pp++) propNames.push_back( props.getPropertyHeader(pp).getName() ); for (int jj=0; jj<numProperties; jj++) { std::cout << " ..named " << propNames[jj] << std::endl; std::cout << " ..with type: "; PropertyType pType = props.getPropertyHeader(jj).getPropertyType(); if (pType == kCompoundProperty) { std::cout << "compound" << std::endl; } else if (pType == kScalarProperty) { std::cout << "scalar" << std::endl; } else if (pType == kArrayProperty) { std::cout << "array" << std::endl; } DataType dType = props.getPropertyHeader(jj).getDataType(); std::cout << " ..with POD-type: "; switch (dType.getPod()) { case kBooleanPOD: std::cout << "boolean" << std::endl; break; // Char/UChar case kUint8POD: std::cout << "unsigned char" << std::endl; break; case kInt8POD: std::cout << "char" << std::endl; break; // Short/UShort case kUint16POD: std::cout << "short unsigned int" << std::endl; break; case kInt16POD: std::cout << "short int" << std::endl; break; // Int/UInt case kUint32POD: std::cout << "unsigned int" << std::endl; break; case kInt32POD: std::cout << "int" << std::endl; break; // Long/ULong case kUint64POD: std::cout << "unsigned long int" << std::endl; break; case kInt64POD: std::cout << "long int" << std::endl; break; // Half/Float/Double case kFloat16POD: std::cout << "half" << std::endl; break; case kFloat32POD: std::cout << "float" << std::endl; break; case kFloat64POD: std::cout << "double" << std::endl; break; case kStringPOD: std::cout << "string" << std::endl; break; case kUnknownPOD: default: std::cout << " Unknown! (this is bad)" << std::endl; }; TimeSamplingPtr ts = GetCompoundPropertyReaderPtr(props)-> getScalarProperty( propNames[jj] )->getTimeSampling(); int numSamples = ts->getNumStoredTimes(); std::cout << " ..and " << ts->getTimeSamplingType() << std::endl << " ..and " << numSamples << " samples at times: "; if (numSamples > 0) { std::cout << " ( "; for (int ss=0; ss<numSamples; ss++) std::cout << ts->getSampleTime(ss) << " "; std::cout << ")"; } std::cout << std::endl; std::cout << " ..and values: "; if (numSamples > 0) { for (int ss=0; ss<numSamples; ss++) { ISampleSelector iss( (index_t) ss); switch (dType.getPod()) { // Boolean case kBooleanPOD: { IBoolProperty prop( props, propNames[jj] ); printSampleValue( prop, iss ); break; } // Char/UChar case kUint8POD: { IUcharProperty prop( props, propNames[jj] ); printSampleValue( prop, iss ); break; } case kInt8POD: { ICharProperty prop( props, propNames[jj] ); printSampleValue( prop, iss ); break; } // Short/UShort case kUint16POD: { IUInt16Property prop( props, propNames[jj] ); printSampleValue( prop, iss ); break; } case kInt16POD: { IInt16Property prop( props, propNames[jj] ); printSampleValue( prop, iss ); break; } // Int/UInt case kUint32POD: { IUInt32Property prop( props, propNames[jj] ); printSampleValue( prop, iss ); break; } case kInt32POD: { IInt32Property prop( props, propNames[jj] ); printSampleValue( prop, iss ); break; } // Long/ULong case kUint64POD: { IUInt64Property prop( props, propNames[jj] ); printSampleValue( prop, iss ); break; } case kInt64POD: { IInt64Property prop( props, propNames[jj] ); printSampleValue( prop, iss ); break; } // Half/Float/Double case kFloat16POD: // iostream doesn't understand float_16's //printSampleValue( IHalfProperty( props, propNames[jj] ), // iss ); break; case kFloat32POD: { IFloatProperty prop( props, propNames[jj] ); printSampleValue( prop, iss ); break; } case kFloat64POD: { IDoubleProperty prop( props, propNames[jj] ); printSampleValue( prop, iss ); break; } case kUnknownPOD: default: std::cout << " Unknown! (this is bad)" << std::endl; }; } } std::cout << std::endl; std::cout << std::endl; // done parsing property } } // Done - the archive closes itself }
//-***************************************************************************** void GetRelevantSampleTimes( ProcArgs &args, TimeSamplingPtr timeSampling, size_t numSamples, SampleTimeSet &output ) { if ( numSamples < 2 ) { output.insert( 0.0 ); return; } chrono_t frameTime = args.frame / args.fps; chrono_t shutterOpenTime = ( args.frame + args.shutterOpen ) / args.fps; chrono_t shutterCloseTime = ( args.frame + args.shutterClose ) / args.fps; std::pair<index_t, chrono_t> shutterOpenFloor = timeSampling->getFloorIndex( shutterOpenTime, numSamples ); std::pair<index_t, chrono_t> shutterCloseCeil = timeSampling->getCeilIndex( shutterCloseTime, numSamples ); //TODO, what's a reasonable episilon? static const chrono_t epsilon = 1.0 / 10000.0; //check to see if our second sample is really the //floor that we want due to floating point slop //first make sure that we have at least two samples to work with if ( shutterOpenFloor.first < shutterCloseCeil.first ) { //if our open sample is less than open time, //look at the next index time if ( shutterOpenFloor.second < shutterOpenTime ) { chrono_t nextSampleTime = timeSampling->getSampleTime( shutterOpenFloor.first + 1 ); if ( fabs( nextSampleTime - shutterOpenTime ) < epsilon ) { shutterOpenFloor.first += 1; shutterOpenFloor.second = nextSampleTime; } } } for ( index_t i = shutterOpenFloor.first; i < shutterCloseCeil.first; ++i ) { output.insert( timeSampling->getSampleTime( i ) ); } //no samples above? put frame time in there and get out if ( output.size() == 0 ) { output.insert( frameTime ); return; } chrono_t lastSample = *(output.rbegin() ); //determine whether we need the extra sample at the end if ( ( fabs( lastSample - shutterCloseTime ) > epsilon ) && lastSample < shutterCloseTime ) { output.insert( shutterCloseCeil.second ); } }
AtNode * ProcessPointsBase( IPoints & prim, ProcArgs & args, SampleTimeSet & sampleTimes, std::vector<AtPoint> & vidxs, std::vector<float> & radius, MatrixSampleMap * xformSamples ) { if ( !prim.valid() ) { return NULL; } Alembic::AbcGeom::IPointsSchema &ps = prim.getSchema(); TimeSamplingPtr ts = ps.getTimeSampling(); sampleTimes.insert( ts->getFloorIndex(args.frame / args.fps, ps.getNumSamples()).second ); std::string name = args.nameprefix + prim.getFullName(); AtNode * instanceNode = NULL; std::string cacheId; SampleTimeSet singleSampleTimes; singleSampleTimes.insert( ts->getFloorIndex(args.frame / args.fps, ps.getNumSamples()).second ); ICompoundProperty arbGeomParams = ps.getArbGeomParams(); ISampleSelector frameSelector( *singleSampleTimes.begin() ); std::vector<std::string> tags; //get tags if ( arbGeomParams != NULL && arbGeomParams.valid() ) { if (arbGeomParams.getPropertyHeader("mtoa_constant_tags") != NULL) { const PropertyHeader * tagsHeader = arbGeomParams.getPropertyHeader("mtoa_constant_tags"); if (IStringGeomParam::matches( *tagsHeader )) { IStringGeomParam param( arbGeomParams, "mtoa_constant_tags" ); if ( param.valid() ) { IStringGeomParam::prop_type::sample_ptr_type valueSample = param.getExpandedValue( frameSelector ).getVals(); if ( param.getScope() == kConstantScope || param.getScope() == kUnknownScope) { Json::Value jtags; Json::Reader reader; if(reader.parse(valueSample->get()[0], jtags)) for( Json::ValueIterator itr = jtags.begin() ; itr != jtags.end() ; itr++ ) { tags.push_back(jtags[itr.key().asUInt()].asString()); } } } } } } if ( args.makeInstance ) { std::ostringstream buffer; AbcA::ArraySampleKey sampleKey; for ( SampleTimeSet::iterator I = sampleTimes.begin(); I != sampleTimes.end(); ++I ) { ISampleSelector sampleSelector( *I ); ps.getPositionsProperty().getKey(sampleKey, sampleSelector); buffer << GetRelativeSampleTime( args, (*I) ) << ":"; sampleKey.digest.print(buffer); buffer << ":"; } cacheId = buffer.str(); instanceNode = AiNode( "ginstance" ); AiNodeSetStr( instanceNode, "name", name.c_str() ); args.createdNodes.push_back(instanceNode); if ( args.proceduralNode ) { AiNodeSetByte( instanceNode, "visibility", AiNodeGetByte( args.proceduralNode, "visibility" ) ); } else { AiNodeSetByte( instanceNode, "visibility", AI_RAY_ALL ); } ApplyTransformation( instanceNode, xformSamples, args ); NodeCache::iterator I = g_meshCache.find(cacheId); // parameters overrides if(args.linkOverride) ApplyOverrides(name, instanceNode, tags, args); // shader assignation if (nodeHasParameter( instanceNode, "shader" ) ) { if(args.linkShader) { ApplyShaders(name, instanceNode, tags, args); } else { AtArray* shaders = AiNodeGetArray(args.proceduralNode, "shader"); if (shaders->nelements != 0) AiNodeSetArray(instanceNode, "shader", AiArrayCopy(shaders)); } } if ( I != g_meshCache.end() ) { AiNodeSetPtr(instanceNode, "node", (*I).second ); return NULL; } } bool isFirstSample = true; float radiusPoint = 0.1f; if (AiNodeLookUpUserParameter(args.proceduralNode, "radiusPoint") !=NULL ) radiusPoint = AiNodeGetFlt(args.proceduralNode, "radiusPoint"); bool useVelocities = false; if ((sampleTimes.size() == 1) && (args.shutterOpen != args.shutterClose)) { // no sample, and motion blur needed, let's try to get velocities. if(ps.getVelocitiesProperty().valid()) useVelocities = true; } for ( SampleTimeSet::iterator I = sampleTimes.begin(); I != sampleTimes.end(); ++I, isFirstSample = false) { ISampleSelector sampleSelector( *I ); Alembic::AbcGeom::IPointsSchema::Sample sample = ps.getValue( sampleSelector ); Alembic::Abc::P3fArraySamplePtr v3ptr = sample.getPositions(); size_t pSize = sample.getPositions()->size(); if(useVelocities && isFirstSample) { float scaleVelocity = 1.0f; if (AiNodeLookUpUserParameter(args.proceduralNode, "scaleVelocity") !=NULL ) scaleVelocity = AiNodeGetFlt(args.proceduralNode, "scaleVelocity"); vidxs.resize(pSize*2); Alembic::Abc::V3fArraySamplePtr velptr = sample.getVelocities(); float timeoffset = ((args.frame / args.fps) - ts->getFloorIndex((*I), ps.getNumSamples()).second) * args.fps; for ( size_t pId = 0; pId < pSize; ++pId ) { Alembic::Abc::V3f posAtOpen = ((*v3ptr)[pId] + (*velptr)[pId] * scaleVelocity *-timeoffset); AtPoint pos1; pos1.x = posAtOpen.x; pos1.y = posAtOpen.y; pos1.z = posAtOpen.z; vidxs[pId]= pos1; Alembic::Abc::V3f posAtEnd = ((*v3ptr)[pId] + (*velptr)[pId]* scaleVelocity *(1.0f-timeoffset)); AtPoint pos2; pos2.x = posAtEnd.x; pos2.y = posAtEnd.y; pos2.z = posAtEnd.z; vidxs[pId+pSize]= pos2; radius.push_back(radiusPoint); } } else // not motion blur or correctly sampled particles { for ( size_t pId = 0; pId < pSize; ++pId ) { AtPoint pos; pos.x = (*v3ptr)[pId].x; pos.y = (*v3ptr)[pId].y; pos.z = (*v3ptr)[pId].z; vidxs.push_back(pos); radius.push_back(radiusPoint); } } } AtNode* pointsNode = AiNode( "points" ); if (!pointsNode) { AiMsgError("Failed to make points node for %s", prim.getFullName().c_str()); return NULL; } args.createdNodes.push_back(pointsNode); if ( instanceNode != NULL) { AiNodeSetStr( pointsNode, "name", (name + ":src").c_str() ); } else { AiNodeSetStr( pointsNode, "name", name.c_str() ); } if(!useVelocities) { AiNodeSetArray(pointsNode, "points", AiArrayConvert( vidxs.size() / sampleTimes.size(), sampleTimes.size(), AI_TYPE_POINT, (void*)(&(vidxs[0])) )); AiNodeSetArray(pointsNode, "radius", AiArrayConvert( vidxs.size() / sampleTimes.size(), sampleTimes.size(), AI_TYPE_FLOAT, (void*)(&(radius[0])) )); if ( sampleTimes.size() > 1 ) { std::vector<float> relativeSampleTimes; relativeSampleTimes.reserve( sampleTimes.size() ); for (SampleTimeSet::const_iterator I = sampleTimes.begin(); I != sampleTimes.end(); ++I ) { chrono_t sampleTime = GetRelativeSampleTime( args, (*I) ); relativeSampleTimes.push_back(sampleTime); } AiNodeSetArray( pointsNode, "deform_time_samples", AiArrayConvert(relativeSampleTimes.size(), 1, AI_TYPE_FLOAT, &relativeSampleTimes[0])); } } else { AiNodeSetArray(pointsNode, "points", AiArrayConvert( vidxs.size() / 2, 2, AI_TYPE_POINT, (void*)(&(vidxs[0])) )); AiNodeSetArray(pointsNode, "radius", AiArrayConvert( vidxs.size() /2 / sampleTimes.size(), sampleTimes.size(), AI_TYPE_FLOAT, (void*)(&(radius[0])) )); AiNodeSetArray( pointsNode, "deform_time_samples", AiArray(2, 1, AI_TYPE_FLOAT, 0.f, 1.f)); } AddArbitraryGeomParams( arbGeomParams, frameSelector, pointsNode ); if ( instanceNode == NULL ) { if ( xformSamples ) { ApplyTransformation( pointsNode, xformSamples, args ); } return pointsNode; } else { AiNodeSetByte( pointsNode, "visibility", 0 ); AiNodeSetInt( pointsNode, "mode", 1 ); AiNodeSetPtr(instanceNode, "node", pointsNode ); g_meshCache[cacheId] = pointsNode; return pointsNode; } }