Hello,
I’m trying to learn about open exec and created a simple function based on the documentation:
static VtVec3fArray _ChangeVerts(const VdfContext& ctx)
{
const VtVec3fArray* const originalPoints = ctx.GetInputValuePtr(TfToken(“points”));
VtVec3fArray res;
if (originalPoints) {
res.resize(originalPoints->size());
if (originalPoints) {
for (size_t i = 0; i < originalPoints->size(); ++i) {
auto p = (*originalPoints)[i];
res[i] = p * std::rand() * 10;
}
}
}
return res;
}
EXEC_REGISTER_COMPUTATIONS_FOR_SCHEMA(UsdGeomXformable)
{
self.PrimComputation(TfToken(“computePoints”))
.Callback<VtVec3fArray>(&_ChangeVerts)
.Inputs(AttributeValue<VtVec3fArray>(TfToken(“points”)));
}
This failed during compilation saying that VtVec3fArray is not an allowed type.
Is it possible to assign the points attribute of a mesh to compute values on it? If not, is there another way to achieve this?
Hi @barbalt.
First off, thanks for playing with OpenExec. That’s really exciting!
Second, our apologies for the lack of documentation (and test cases to draw inspiration from) for array-valued AttributeValue inputs. We’re adding this to the list of upcoming tasks for OpenExec.
To answer your question: As a rule-of-thumb, the type to use for array-valued attributes in OpenExec is always the array element type. This is because OpenExec has the ability to encode arrays in different ways, depending on how it chooses to optimize the storage of the array in memory (and later, which device it chooses to offload the data to). This functionality is not currently leveraged in OpenExec today, but it is an important aspect of how we plan to accelerate mesh deformation in the future. As a consequence the specific array encoding is an implementation detail of OpenExec, and it might be different for different array-valued attribute in the same scene. Callbacks and inputs need to be generalized to not rely on the array encoding, hence the need for using array element types and iterator patterns.
In summary, this means your code must be modified in two ways:
- The input should be
AttributeValue<GfVec3f> in accordance with the rule of using the array element type.
- In the callback, the input value must be retrieved using the element type to match the type used in the input:
VdfContext::GetInputValue<GfVec3f> (and friends) only give you the first entry in the array. If you need to iterate over all entries the VdfReadIterator<GfVec3f> is the right construct. If you want random access, you can also take a look at VdfInputValuesPtr<GfVec3f> (with caveats explained in its doxygen documentation).
I took the liberty of rewriting your code with these changes. My changes are untested, but you should get the general idea:
TF_DEFINE_PRIVATE_TOKENS(
_tokens,
(computePoints),
(points)
);
TF_REGISTRY_FUNCTION(ExecTypeRegistry)
{
ExecTypeRegistry::RegisterType(std::vector<GfVec3f>{});
}
static std::vector<GfVec3f> _ChangeVerts(const VdfContext& ctx)
{
VdfReadIterator<GfVec3f> it(ctx, _tokens->points);
std::vector<GfVec3f> res;
res.reserve(it.ComputeSize());
for (; !it.IsAtEnd(); ++it) {
res.push_back(*it * std::rand() * 10);
}
return res;
}
EXEC_REGISTER_COMPUTATIONS_FOR_SCHEMA(UsdGeomXformable)
{
self.PrimComputation(_tokens->computePoints)
.Callback<std::vector<GfVec3f>>(&_ChangeVerts)
.Inputs(AttributeValue<GfVec3f>(_tokens->points));
}
PS: Note that because of this TODO item, extracting array results from OpenExec is currently a bit of a pain, which is why I changed your code to produce a std::vector<GfVec3f> instead of a VtVec3fArray, but this will be fixed soon.
Hope this helps! Please, let us know of any other hiccups you run into, so that we can prioritize the fixes!
Thank you very much, @florianz
This worked perfectly. The change to std::vector and registering it were the key missing pieces.
One thing that was not very clear to me is that documentation here it says that I need to update the plugInfo.json to allowsPluginComputation, but I was able to change the UsdGeom without it. Is that a requirement only for custom schemas?
Setting allowsPluginComputation is required for any schema that advertises exec computations. Having said that, it should already be set on UsdGeomXformable , since one of our early examples registers computations on that schema.
That makes sense! Thanks for all the help once again
1 Like