Alembic attribute import remapping #101090

Open
opened 2022-09-15 16:18:49 +02:00 by Kévin Dietrich · 18 comments

D11591: Alembic: import arbitrary attributes adds arbitrary attribute import to the Alembic importer, which allows for attributes other than UVs, vertex colors, and generated coordinates to be imported.

It also introduces a remapping system whose main purpose is to fix data exported by external software who:

  • may not be in the right type: we may have a vec3 (float3) attribute that is not typed as such, but as a flat array of floats that is 3 times the size of the expected domain (a popular node based software does this a lot)
  • may be set in a domain that Blender does not support for the type: we may also have a UV map that is set on the vertex domain, but we only allow for face corner domain
  • may have an ambiguous or unknown domain, where two potential domains have the same size: e.g. a torus has the same number of faces and vertices, so we need to know where to load the data, there are cases in the current code where this fails

The second point is an extension and replacement of 3385c04598.

Scope ambiguity

Alembic actually has some ambiguous scope enumeration, that may be interpreted or used differently:

  • kVaryingScope is left to interpretation. Is it varying over the faces, vertices, or something else?
  • kUniformScope should be for the entire object (i.e. a single value, that could be loaded as IDProperty), but some use it with kVaryingScope to differentiate between vertices/points and face corners
  • kFacevaryingScope is face corners, but can be used to say that the data is for this domain, but written in another domain (likely point domain)

Without remapping, the patch already tries a little to salvage the data when these are used by trying different domains. E.g. for kFacevaryingScope, if face corner is not matching, we try point instead. Although, without a user defined mapping, those checks expect the data size to match.

Another dimension to the problem, is that in Alembic, arrays can have optional index buffers which should be used to determine the actual scope. If there is an index buffer, then surely the data must be the right type, and not some flattened vector.

Limitations

The remapping system only allows to change the type of an attribute if the data size matches (see first point above) and if the domain allows it. For example, a vec2 (float2 in Blender) can be converted to UV map. But we can not convert a float3 to a UV map with it. These types of processing are better left to Geometry Nodes.

Essentially, the remapping system places the burder of telling to Blender what the data is supposed to be on the users so Blender does not have to make wild guesses.

Implementation details.

Attributes are read during import, and during modifier evaluation if they are animated or if the modifiers' or cache file's settings for attributes are modified. Those settings include the already existing read flags (which affect UVs), the standard name of the velocity attribute, and the newly introduced attribute remappings. These settings, along with the output for error messages, are stored in some AttributeReadHelper class to keep them together, and to avoid having too many parameters to functions. Since settings can change, AttributeReadHelper are temporary objects which are created during import and modifier evaluation.

Attributes from the Alembic schemas are analyzed and only attributes which are supposed to be read given the settings (excluding remappings at this step) stored in AttributeReadHelper are considered for import/streaming. Then, we verify if the attribute can be actually loaded to its target destination (e.g. that vertex attributes map to vertices). For this, we use CacheAttributeMappings. If there is no user supplied mapping for the current attribute (looked up via AttributeReadHelper), we create a default one given what we expect the attribute to be and on which domain it should be read. If reading the attribute given this mapping fails, we skip it, an error is printed in the console, and users are notified via a note on the modifiers' UI.

[D11591: Alembic: import arbitrary attributes](https://archive.blender.org/developer/D11591) adds arbitrary attribute import to the Alembic importer, which allows for attributes other than UVs, vertex colors, and generated coordinates to be imported. It also introduces a remapping system whose main purpose is to fix data exported by external software who: - may not be in the right type: we may have a vec3 (float3) attribute that is not typed as such, but as a flat array of floats that is 3 times the size of the expected domain (a popular node based software does this a lot) - may be set in a domain that Blender does not support for the type: we may also have a UV map that is set on the vertex domain, but we only allow for face corner domain - may have an ambiguous or unknown domain, where two potential domains have the same size: e.g. a torus has the same number of faces and vertices, so we need to know where to load the data, there are cases in the current code where this fails The second point is an extension and replacement of 3385c04598. **Scope ambiguity** Alembic actually has some ambiguous scope enumeration, that may be interpreted or used differently: - `kVaryingScope` is left to interpretation. Is it varying over the faces, vertices, or something else? - `kUniformScope` should be for the entire object (i.e. a single value, that could be loaded as IDProperty), but some use it with `kVaryingScope` to differentiate between vertices/points and face corners - `kFacevaryingScope` is face corners, but can be used to say that the data is for this domain, but written in another domain (likely point domain) Without remapping, the patch already tries a little to salvage the data when these are used by trying different domains. E.g. for `kFacevaryingScope`, if face corner is not matching, we try point instead. Although, without a user defined mapping, those checks expect the data size to match. Another dimension to the problem, is that in Alembic, arrays can have optional index buffers which should be used to determine the actual scope. If there is an index buffer, then surely the data must be the right type, and not some flattened vector. **Limitations** The remapping system only allows to change the type of an attribute if the data size matches (see first point above) and if the domain allows it. For example, a vec2 (float2 in Blender) can be converted to UV map. But we can not convert a float3 to a UV map with it. These types of processing are better left to Geometry Nodes. Essentially, the remapping system places the burder of telling to Blender what the data is supposed to be on the users so Blender does not have to make wild guesses. **Implementation details.** Attributes are read during import, and during modifier evaluation if they are animated or if the modifiers' or cache file's settings for attributes are modified. Those settings include the already existing read flags (which affect UVs), the standard name of the velocity attribute, and the newly introduced attribute remappings. These settings, along with the output for error messages, are stored in some `AttributeReadHelper` class to keep them together, and to avoid having too many parameters to functions. Since settings can change, `AttributeReadHelper` are temporary objects which are created during import and modifier evaluation. Attributes from the Alembic schemas are analyzed and only attributes which are supposed to be read given the settings (excluding remappings at this step) stored in `AttributeReadHelper` are considered for import/streaming. Then, we verify if the attribute can be actually loaded to its target destination (e.g. that vertex attributes map to vertices). For this, we use `CacheAttributeMappings`. If there is no user supplied mapping for the current attribute (looked up via `AttributeReadHelper`), we create a default one given what we expect the attribute to be and on which domain it should be read. If reading the attribute given this mapping fails, we skip it, an error is printed in the console, and users are notified via a note on the modifiers' UI.
Author
Member

Added subscriber: @kevindietrich

Added subscriber: @kevindietrich
Member

Added subscriber: @HooglyBoogly

Added subscriber: @HooglyBoogly
Member

It would be nice to avoid this sort of complicated system in my opinion, and rely on geometry nodes to do necessary attribute operations afterwards, but..

as a flat array of floats that is 3 times the size of the expected domain

We can't handle this in geometry nodes currently, so it wouldn't be possible.

So I think this sounds like a reasonable solution.

It would be nice to avoid this sort of complicated system in my opinion, and rely on geometry nodes to do necessary attribute operations afterwards, but.. >as a flat array of floats that is 3 times the size of the expected domain We can't handle this in geometry nodes currently, so it wouldn't be possible. So I think this sounds like a reasonable solution.
Member

Changed status from 'Needs Triage' to: 'Confirmed'

Changed status from 'Needs Triage' to: 'Confirmed'

Added subscriber: @brecht

Added subscriber: @brecht

My assumptions was that this was for more general remapping between conventions, but it seems to be mostly for poorly written files? Hopefully USD is better defined and doesn't need this?

To play devil's advocate, I'm wondering if we could get away without the UI.

  • may not be in the right type: we may have a vec3 (float3) attribute that is not typed as such, but as a flat array of floats that is 3 times the size of the expected domain (a popular node based software does this a lot)

This seems like it could be handled automatically? Unless the domain is unkown as in the last point?

If the domain is known it would still have to guess if it's a vector, quaternion or color, though geometry nodes could do the conversion.

  • may be set in a domain that Blender does not support for the type: we may also have a UV map that is set on the vertex domain, but we only allow for face corner domain

Are there cases where 3385c04598 fails that can't be fixed with geometry nodes?

  • may have an ambiguous or unknown domain, where two potential domains have the same size: e.g. a torus has the same number of faces and vertices, so we need to know where to load the data, there are cases in the current code where this fails

Geometry nodes can't handle this, so maybe this is the best motivation. But is this common?

My assumptions was that this was for more general remapping between conventions, but it seems to be mostly for poorly written files? Hopefully USD is better defined and doesn't need this? To play devil's advocate, I'm wondering if we could get away without the UI. > * may not be in the right type: we may have a vec3 (float3) attribute that is not typed as such, but as a flat array of floats that is 3 times the size of the expected domain (a popular node based software does this a lot) This seems like it could be handled automatically? Unless the domain is unkown as in the last point? If the domain is known it would still have to guess if it's a vector, quaternion or color, though geometry nodes could do the conversion. > * may be set in a domain that Blender does not support for the type: we may also have a UV map that is set on the vertex domain, but we only allow for face corner domain Are there cases where 3385c04598 fails that can't be fixed with geometry nodes? > * may have an ambiguous or unknown domain, where two potential domains have the same size: e.g. a torus has the same number of faces and vertices, so we need to know where to load the data, there are cases in the current code where this fails Geometry nodes can't handle this, so maybe this is the best motivation. But is this common?
Author
Member

Added subscriber: @makowalski

Added subscriber: @makowalski
Author
Member

In #101090#1417736, @brecht wrote:
My assumptions was that this was for more general remapping between conventions, but it seems to be mostly for poorly written files? Hopefully USD is better defined and doesn't need this?

Yes, this is for poorly written files, and the lack of good definition. For USD, maybe @makowalski would know better.

To play devil's advocate, I'm wondering if we could get away without the UI.

  • may not be in the right type: we may have a vec3 (float3) attribute that is not typed as such, but as a flat array of floats that is 3 times the size of the expected domain (a popular node based software does this a lot)

This seems like it could be handled automatically? Unless the domain is unkown as in the last point?

If the domain is known it would still have to guess if it's a vector, quaternion or color, though geometry nodes could do the conversion.

Alembic actually has some ambiguous scope enumeration, that may be interpreted or used differently:

  • kVaryingScope is left to interpretation. Is it varying over the faces, vertices, or something else?
  • kUniformScope should be for the entire object (i.e. a single value, that could be loaded as IDProperty), but some use it with kVaryingScope to differentiate between vertices/points and face corners
  • kFacevaryingScope is face corners, but can be used to say that the data is for this domain, but written in another domain (likely point domain)

Without remapping, the patch already tries a little to salvage the data when these are used by trying different domains, because I don't trust people. E.g. for kFacevaryingScope, if face corner is not matching, we try point instead. Although, without a user defined mapping, those checks expect the data size to match. Bumping the number of dimensions until something matches feels like a shot in the dark for me. For point clouds this could work as there is only one domain, but curves and meshes have too many potential matches across domains here.

Another dimension to the problem, is that in Alembic, arrays can have optional index buffers. So now it is the index buffer that should be used to determine the actual scope. I forgot about this "detail" when creating the task. If there is an index buffer, then surely the data must be the right type, and not some flattened vector. Thinking about this, we should be able to get rid of those by always expanding the arrays beforehand, which would use memory but simplify some logic.

  • may be set in a domain that Blender does not support for the type: we may also have a UV map that is set on the vertex domain, but we only allow for face corner domain

Are there cases where 3385c04598 fails that can't be fixed with geometry nodes?

I don't know for sure. If there were failures we would have bug reports already, as the imported UVs would be wrong, and people might not think about using geometry nodes to fix it. Since UVs are now read with the generic attribute reader, it made sense to put that in the remapping.

  • may have an ambiguous or unknown domain, where two potential domains have the same size: e.g. a torus has the same number of faces and vertices, so we need to know where to load the data, there are cases in the current code where this fails

Geometry nodes can't handle this, so maybe this is the best motivation. But is this common?

I don't know how common, but from the files that I have (including those from bug reports), I noticed it is mostly flattened vector arrays the problem. For domain size ambiguity, this comes mostly from what I said above about Alembic scopes.

> In #101090#1417736, @brecht wrote: > My assumptions was that this was for more general remapping between conventions, but it seems to be mostly for poorly written files? Hopefully USD is better defined and doesn't need this? Yes, this is for poorly written files, and the lack of good definition. For USD, maybe @makowalski would know better. > To play devil's advocate, I'm wondering if we could get away without the UI. > >> * may not be in the right type: we may have a vec3 (float3) attribute that is not typed as such, but as a flat array of floats that is 3 times the size of the expected domain (a popular node based software does this a lot) > > This seems like it could be handled automatically? Unless the domain is unkown as in the last point? > > If the domain is known it would still have to guess if it's a vector, quaternion or color, though geometry nodes could do the conversion. Alembic actually has some ambiguous scope enumeration, that may be interpreted or used differently: - `kVaryingScope` is left to interpretation. Is it varying over the faces, vertices, or something else? - `kUniformScope` should be for the entire object (i.e. a single value, that could be loaded as IDProperty), but some use it with `kVaryingScope` to differentiate between vertices/points and face corners - `kFacevaryingScope` is face corners, but can be used to say that the data is for this domain, but written in another domain (likely point domain) Without remapping, the patch already tries a little to salvage the data when these are used by trying different domains, because I don't trust people. E.g. for `kFacevaryingScope`, if face corner is not matching, we try point instead. Although, without a user defined mapping, those checks expect the data size to match. Bumping the number of dimensions until something matches feels like a shot in the dark for me. For point clouds this could work as there is only one domain, but curves and meshes have too many potential matches across domains here. Another dimension to the problem, is that in Alembic, arrays can have optional index buffers. So now it is the index buffer that should be used to determine the actual scope. I forgot about this "detail" when creating the task. If there is an index buffer, then surely the data must be the right type, and not some flattened vector. Thinking about this, we should be able to get rid of those by always expanding the arrays beforehand, which would use memory but simplify some logic. >> * may be set in a domain that Blender does not support for the type: we may also have a UV map that is set on the vertex domain, but we only allow for face corner domain > > Are there cases where 3385c04598 fails that can't be fixed with geometry nodes? I don't know for sure. If there were failures we would have bug reports already, as the imported UVs would be wrong, and people might not think about using geometry nodes to fix it. Since UVs are now read with the generic attribute reader, it made sense to put that in the remapping. >> * may have an ambiguous or unknown domain, where two potential domains have the same size: e.g. a torus has the same number of faces and vertices, so we need to know where to load the data, there are cases in the current code where this fails > > Geometry nodes can't handle this, so maybe this is the best motivation. But is this common? I don't know how common, but from the files that I have (including those from bug reports), I noticed it is mostly flattened vector arrays the problem. For domain size ambiguity, this comes mostly from what I said above about Alembic scopes.

Thanks for the explanation. I wasn't aware it was this bad, I then also don't have any alternative to a UI for this.

Thanks for the explanation. I wasn't aware it was this bad, I then also don't have any alternative to a UI for this.

Added subscriber: @Rowan-Ibbeken

Added subscriber: @Rowan-Ibbeken

In #101090#1417736, @brecht wrote:
My assumptions was that this was for more general remapping between conventions, but it seems to be mostly for poorly written files? Hopefully USD is better defined and doesn't need this?

I don't think there is much ambiguity in how USD interpolation types are defined:

https://graphics.pixar.com/usd/release/api/class_usd_geom_primvar.html#Usd_InterpolationVals

Still, in my opinion, a remapping system like this would be helpful for USD IO as well, to help resolve some of the ambiguous cases Kevin mentioned.

> In #101090#1417736, @brecht wrote: > My assumptions was that this was for more general remapping between conventions, but it seems to be mostly for poorly written files? Hopefully USD is better defined and doesn't need this? I don't think there is much ambiguity in how USD interpolation types are defined: https://graphics.pixar.com/usd/release/api/class_usd_geom_primvar.html#Usd_InterpolationVals Still, in my opinion, a remapping system like this would be helpful for USD IO as well, to help resolve some of the ambiguous cases Kevin mentioned.

In #101090#1419593, @makowalski wrote:
I don't think there is much ambiguity in how USD interpolation types are defined:

https://graphics.pixar.com/usd/release/api/class_usd_geom_primvar.html#Usd_InterpolationVals

Right, from my experience with Renderman and OpenSubdiv these have a clear meaning, where each of these values unambiguously maps to a Blender domain.

The one issue I see is that there is no equivalent to the edge domain in Blender, so conversion to USD can lose some data.

Still, in my opinion, a remapping system like this would be helpful for USD IO as well, to help resolve some of the ambiguous cases Kevin mentioned.

Not sure which ambiguous cases this is referring to, I was hoping none of them exist in USD. But maybe that's too optimistic.

> In #101090#1419593, @makowalski wrote: > I don't think there is much ambiguity in how USD interpolation types are defined: > > https://graphics.pixar.com/usd/release/api/class_usd_geom_primvar.html#Usd_InterpolationVals Right, from my experience with Renderman and OpenSubdiv these have a clear meaning, where each of these values unambiguously maps to a Blender domain. The one issue I see is that there is no equivalent to the edge domain in Blender, so conversion to USD can lose some data. > Still, in my opinion, a remapping system like this would be helpful for USD IO as well, to help resolve some of the ambiguous cases Kevin mentioned. Not sure which ambiguous cases this is referring to, I was hoping none of them exist in USD. But maybe that's too optimistic.
Member

Added subscriber: @JulienKaspar

Added subscriber: @JulienKaspar

In #101090#1423263, @brecht wrote:

In #101090#1419593, @makowalski wrote:

Still, in my opinion, a remapping system like this would be helpful for USD IO as well, to help resolve some of the ambiguous cases Kevin mentioned.

Not sure which ambiguous cases this is referring to, I was hoping none of them exist in USD. But maybe that's too optimistic.

@brecht My apologies for the delayed response! I was referring to cases when the USD was incorrectly authored and the attribute data size doesn't match the given interpolation type. Kevin mentioned that inferring the correct interpolation type from the data size can't always be done unambiguously. However, thinking about this further, I'm reconsidering my original comment. Such cases are sufficiently rare that it probably doesn't justify adding a UI for this reason alone, so I agree with you that this is probably not needed for USD.

> In #101090#1423263, @brecht wrote: >> In #101090#1419593, @makowalski wrote: > >> Still, in my opinion, a remapping system like this would be helpful for USD IO as well, to help resolve some of the ambiguous cases Kevin mentioned. > > Not sure which ambiguous cases this is referring to, I was hoping none of them exist in USD. But maybe that's too optimistic. @brecht My apologies for the delayed response! I was referring to cases when the USD was incorrectly authored and the attribute data size doesn't match the given interpolation type. Kevin mentioned that inferring the correct interpolation type from the data size can't always be done unambiguously. However, thinking about this further, I'm reconsidering my original comment. Such cases are sufficiently rare that it probably doesn't justify adding a UI for this reason alone, so I agree with you that this is probably not needed for USD.

Added subscriber: @dr.sybren

Added subscriber: @dr.sybren

Although the info given in the task description is good to have, there is no actual description of the design of the functionality. How does it work?

Although the info given in the task description is good to have, there is no actual description of the design of the functionality. How does it work?

Attributes from the Alembic schemas are analyzed and only attributes which are supposed to be read given the settings (excluding remappings at this step) stored in AttributeReadHelper are considered for import/streaming.

That's quite a hard sentence to parse. Just to check, is this rewording actually correct?

"Attributes from the Alembic schemas are analyzed, and a subset of those are considered for import/streaming. The settings that determine this subset are stored in AttributeReadHelper."

I'm not sure what "excluding remappings at this step" means, though.

> Attributes from the Alembic schemas are analyzed and only attributes which are supposed to be read given the settings (excluding remappings at this step) stored in `AttributeReadHelper` are considered for import/streaming. That's quite a hard sentence to parse. Just to check, is this rewording actually correct? "Attributes from the Alembic schemas are analyzed, and a subset of those are considered for import/streaming. The settings that determine this subset are stored in `AttributeReadHelper`." I'm not sure what "excluding remappings at this step" means, though.
Author
Member

In #101090#1457639, @dr.sybren wrote:

Attributes from the Alembic schemas are analyzed and only attributes which are supposed to be read given the settings (excluding remappings at this step) stored in AttributeReadHelper are considered for import/streaming.

That's quite a hard sentence to parse. Just to check, is this rewording actually correct?

"Attributes from the Alembic schemas are analyzed, and a subset of those are considered for import/streaming. The settings that determine this subset are stored in AttributeReadHelper."

Yes, the rewording is correct.

I'm not sure what "excluding remappings at this step" means, though.

Remappings are considered at a later time, not during the initial subset filtering.

> In #101090#1457639, @dr.sybren wrote: >> Attributes from the Alembic schemas are analyzed and only attributes which are supposed to be read given the settings (excluding remappings at this step) stored in `AttributeReadHelper` are considered for import/streaming. > > That's quite a hard sentence to parse. Just to check, is this rewording actually correct? > > "Attributes from the Alembic schemas are analyzed, and a subset of those are considered for import/streaming. The settings that determine this subset are stored in `AttributeReadHelper`." Yes, the rewording is correct. > I'm not sure what "excluding remappings at this step" means, though. Remappings are considered at a later time, not during the initial subset filtering.
Bastien Montagne added this to the Pipeline, Assets & IO project 2023-02-09 15:39:30 +01:00
Philipp Oeser removed the
Interest
Pipeline, Assets & IO
label 2023-02-10 08:54:00 +01:00
Sign in to join this conversation.
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No Assignees
7 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender#101090
No description provided.