【行业知识】Alembic文件格式简介–设计思想和理念 3

10 九月, 2016
13
0

Alembic

时间

因为Alembic是抽样系统,并不存储像动画曲线,也不提供本地差值。有很多系统来纪录和恢复和数据存在一起的时间信息。
在AbcA::TimeSamplingType和AbcA::TimeSampling中你会找到接口。

TimeSamplingType

TimeSamplingType控制着property如何连接时间和sample的索引。

默认情况下样本0会有时间连接,随后的样本会添加一个统一的时间。统一时间样本,应该和每秒1/24帧的抽样对应,样本间若没有明确
间隔,默认为1.0时间单位(Alembic中的时间在c++中用chrono_t表示,在AbcCoreAbstract中是64位的浮点数)。

第二行为对分布不均匀的样本有一个时间周期,想象通过快门来渲染的场景,有快门开,快门全开,快门关,快门全关。这就是周期时间样本。

最后就是时间样本后没有重复的scheme,时间必须是严格递增的。这叫非周期时间样本。

大多数情况下,创建TimeSamplingType的实例需要两个数据:无符号32bit整形(uint32_t),表示每个周期内的样本数量。另一个是64位
浮点型(chrono_t)表示每个周期的时间。对统一时间样本有更简便的构造方法:

TimeSamplingType() :m_numSamplesPerCycle(1), m_timePerCycle(1.0){} explicitTimeSamplingType( chrono_t iTimePerCycle ): m_numSamplesPerCycle(1), m_timePerCycle( iTimePerCycle ){}
TimeSampling

TimeSampling是时间信息的主要接口。通常由TimeSamplingType的实例和长度为TimeSamplingType::m_numSamplesPerCycle的chrono_t
数组来构造,如果TimeSamplingType的实例不是无环的,那么在stratTime+timePerCycle之外的所有时间都是计算出来的,而不是存下来
的,但这些对客户来说是透明的。统一的TimeSamplingType有方便构造法门:

TimeSampling(chrono_t iTimePerCycle,chrono_t iStartTime ); 

当读取时间信息时,返回的是std::pair<index_t, chrono_t=””>。index_t在AbcCoreAbstract里面定义为有符号64位的整形,用作抽样的索
引;请查看lib/Alembic/AbcCoreAbstract/Foundation.h 类TimeSampling有4个方法来获取时间信息。

chrono_t getSampleTime( index_t iIndex )const;
//! Find the largest valid index that has a time less than or equal
//! to the given time. Invalid to call this with zero samples.
//! If the minimum sample time is greater than iTime, index
//! 0 will be returned.
std::pair<index_t, chrono_t> getFloorIndex( chrono_t iTime,
index_t iNumSamples )const;
//! Find the smallest valid index that has a time greater
//! than the given time. Invalid to call this with zero samples.
//! If the maximum sample time is less than iTime, index
//! numSamples-1 will be returned.
std::pair<index_t, chrono_t> getCeilIndex( chrono_t iTime, index_t iNumSamples )const;
//! Find the valid index with the closest time to the given
//! time. Invalid to call this with zero samples.std::pair<index_t, chrono_t> getNearIndex( chrono_t iTime,
index_t iNumSamples )const;

你会注意到getSampleTime()仅接收一个索引,TimeSampling实例中的TimeSamplingType会利用scheme,通过索引计算出实际的时间值。
三个getFooIndex()方法,接收大量的样本用来将返回值限制在iNumSamples-1范围之内。

返回值为啥是pair呢,是为了检测请求的时间和样本索引对应的时间。下面的关系总是true的:

getFloorIndex (someTime, numSamples).second ==
getSampleTime (getFloorIndex(someTime).first, numSamples);

不仅仅对getFloorIndex(),getCeilIndex(),getNearIndex()也有效。
有了这4个函数,我希望客户端知道如何实现插值了。
在Archive中TimeSampling的实例被存在数组里。写入时查询Simple Property,会提供那个数组的索引给Property的构造函数。因此,
给Property的样本所关联的时间就正确了。如果没给这个索引,会假设一个默认的TimeSampling,统一开始时间为0.0,每周期1.0
chrono_t.