Skip to content

Commit

Permalink
ValueMightBeTimeVarying now takes splines into account
Browse files Browse the repository at this point in the history
- Updated UsdStage::_ValueMightBeTimeVaryingFromResolveInfo, which
  determines if the resolveInfo's source is UsdResolveInfoSourceSpline,
  in which case it returns true.
  Do note that we do not inspect the spline itself here to determine if
  the spline represents a constant in time function, as doing so will be
  expensive. Our aim is to give the clients a hint that the attribute
  you are dealing with, "might" be time varying. This is similar to what
  is done with TimeSamples, where we don't go and inspect every time
  samples on an attribute to determine if its constant across time or
  not.

- Note that UsdAttributeQuery's ValueMightBeTimeVarying will
  automatically work since it relies on the
  UsdStage::_ValueMightBeTimeVaryingFromResolveInfo itself.

- Updated testUsdSplines* to test the modified API.

(Internal change: 2357151)
  • Loading branch information
tallytalwar authored and pixar-oss committed Feb 14, 2025
1 parent 1e087b6 commit 7f5e519
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 11 deletions.
25 changes: 15 additions & 10 deletions pxr/usd/usd/attribute.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ typedef std::vector<UsdAttribute> UsdAttributeVector;
/// \class UsdAttribute
///
/// Scenegraph object for authoring and retrieving numeric, string, and array
/// valued data, sampled over time.
/// valued data, sampled over time, or animated by a spline
///
/// The allowed value types for UsdAttribute are dictated by the Sdf
/// ("Scene Description Foundations") core's data model, which we summarize in
Expand All @@ -46,15 +46,15 @@ typedef std::vector<UsdAttribute> UsdAttributeVector;
/// In addition to its value type, an Attribute has two other defining
/// qualities:
/// \li <b>Variability</b> Expresses whether an attribute is intended to
/// have time samples (GetVariability() == \c SdfVariabilityVarying), or only
/// a default (GetVariability() == \c SdfVariabilityUniform). For more on
/// reasoning about time samples,
/// have time samples or a spline (GetVariability() == \c SdfVariabilityVarying),
/// or only a default (GetVariability() == \c SdfVariabilityUniform). For more
/// on reasoning about time samples,
/// see \ref Usd_AttributeValueMethods "Value & Time-Sample Accessors".
///
/// \li <b>Custom</b> Determines whether an attribute belongs to a
/// schema (IsCustom() == \c false), or is a user-defined, custom attribute.
/// schema attributes will always be defined on a prim of the schema type,
/// ans may possess fallback values from the schema, whereas custom
/// and may possess fallback values from the schema, whereas custom
/// attributes must always first be authored in order to be defined. Note
/// that \em custom is actually an aspect of UsdProperty, as UsdRelationship
/// can also be custom or provided by a schema.
Expand Down Expand Up @@ -90,6 +90,10 @@ typedef std::vector<UsdAttribute> UsdAttributeVector;
/// The desired behavior may be specified via UsdStage::SetInterpolationType.
/// That behavior will be used for all calls to UsdAttribute::Get.
///
/// Note that for attributes with spline value sources, the interpolation
/// behavior is determined by the spline itself, and the interpolation type
/// set on the stage is ignored.
///
/// The supported interpolation types are:
///
/// \li <b>Held</b> Attribute values are held constant between authored
Expand Down Expand Up @@ -169,8 +173,8 @@ class UsdAttribute : public UsdProperty {
/// @{

/// An attribute's variability expresses whether it is intended to have
/// time-samples (\c SdfVariabilityVarying), or only a single default
/// value (\c SdfVariabilityUniform).
/// time-samples or splines (\c SdfVariabilityVarying), or only a single
/// default value (\c SdfVariabilityUniform).
///
/// Variability is required meta-data of all attributes, and its fallback
/// value is SdfVariabilityVarying.
Expand Down Expand Up @@ -374,9 +378,10 @@ class UsdAttribute : public UsdProperty {
/// If this function returns false, it is certain that this attribute's
/// value remains constant over time.
///
/// This function is equivalent to checking if GetNumTimeSamples() > 1,
/// but may be more efficient since it does not actually need to get a
/// full count of all time samples.
/// This function checks if the attribute either has more than 1 time
/// samples or is spline valued. Which is more efficient than actually
/// counting the time samples or evaluating the spline, both of which
/// are potentially expensive operations.
USD_API
bool ValueMightBeTimeVarying() const;

Expand Down
7 changes: 7 additions & 0 deletions pxr/usd/usd/stage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9397,6 +9397,13 @@ bool
UsdStage::_ValueMightBeTimeVaryingFromResolveInfo(const UsdResolveInfo &info,
const UsdAttribute &attr) const
{
if (info._source == UsdResolveInfoSourceSpline) {
// Although a spline could represent a constant function, determining
// this would require analyzing the spline, which is potentially
// expensive. Hence, all splines are deemed as possibly time varying.
return true;
}

if (info._source == UsdResolveInfoSourceValueClips) {
// Do a specialized check for value clips instead of falling through
// to calling _GetNumTimeSamplesFromResolveInfo, which requires opening
Expand Down
11 changes: 10 additions & 1 deletion pxr/usd/usd/testenv/testUsdSplines.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,10 @@ def _DoSerializationTest(
prim = stage.DefinePrim(Sdf.Path("/MyPrim"))
attr = prim.CreateAttribute("myAttr", attrType)
self.assertFalse(attr.HasSpline())
self.assertFalse(attr.ValueMightBeTimeVarying())
attr.SetSpline(spline)
self.assertTrue(attr.HasSpline())
self.assertTrue(attr.ValueMightBeTimeVarying())
print(f"Original spline, {case}, {format}:")
print(spline)

Expand Down Expand Up @@ -230,7 +232,11 @@ def _DoLayerOffsetTest(self, case, attrType, timeValued, scale):

prim = stage.DefinePrim(Sdf.Path("/MyPrim"))
attr = prim.CreateAttribute("myAttr", attrType)
self.assertFalse(attr.HasSpline())
self.assertFalse(attr.ValueMightBeTimeVarying())
attr.SetSpline(spline)
self.assertTrue(attr.HasSpline())
self.assertTrue(attr.ValueMightBeTimeVarying())

sdfAttr = deepLayer.GetAttributeAtPath("/MyPrim.myAttr")
sdfSpline = sdfAttr.GetInfo("spline")
Expand Down Expand Up @@ -283,6 +289,8 @@ def test_InvalidType(self):
spline = self._GetTestSpline()

gotException = False
self.assertFalse(attr.HasSpline())
self.assertFalse(attr.ValueMightBeTimeVarying())
try:
attr.SetSpline(spline)
except Tf.ErrorException as e:
Expand All @@ -291,8 +299,9 @@ def test_InvalidType(self):
print(e)
except:
pass

self.assertTrue(gotException)
self.assertFalse(attr.HasSpline())
self.assertFalse(attr.ValueMightBeTimeVarying())


if __name__ == "__main__":
Expand Down
11 changes: 11 additions & 0 deletions pxr/usd/usd/testenv/testUsdSplinesCpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,11 @@ _DoSerializationTest(
const UsdPrim prim = stage->DefinePrim(SdfPath("/MyPrim"));
UsdAttribute attr = prim.CreateAttribute(TfToken("myAttr"), attrType);
TF_AXIOM(!attr.HasSpline());
TF_AXIOM(!attr.ValueMightBeTimeVarying());
attr.SetSpline(spline);
TF_AXIOM(attr.HasSpline());
// Having a spline makes this attr might be time varying.
TF_AXIOM(attr.ValueMightBeTimeVarying());

stage->Save();
stage->GetRootLayer()->Export(filename2);
Expand Down Expand Up @@ -158,7 +161,11 @@ _DoLayerOffsetTest(

const UsdPrim prim = stage->DefinePrim(SdfPath("/MyPrim"));
UsdAttribute attr = prim.CreateAttribute(TfToken("myAttr"), attrType);
TF_AXIOM(!attr.HasSpline());
TF_AXIOM(!attr.ValueMightBeTimeVarying());
attr.SetSpline(spline);
TF_AXIOM(attr.HasSpline());
TF_AXIOM(attr.ValueMightBeTimeVarying());

_TestSplineAndAttr(spline, attr);

Expand Down Expand Up @@ -362,10 +369,14 @@ TestInvalidType()
const TsSpline spline = _GetTestSpline();

TfErrorMark m;
TF_AXIOM(!attr.HasSpline());
attr.SetSpline(spline);

// A coding error should have been posted as String value splines are not
// allowed. Only double, float or GfHalf!
TF_AXIOM(!m.IsClean());
TF_AXIOM(!attr.HasSpline());
TF_AXIOM(!attr.ValueMightBeTimeVarying());
}

int main()
Expand Down

0 comments on commit 7f5e519

Please sign in to comment.