-
Notifications
You must be signed in to change notification settings - Fork 132
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
OpenVDB and Alembic reader #102
base: main
Are you sure you want to change the base?
Conversation
Ping |
This is super cool. I'll file some internal issues so that we can have our partio maintainer chime in as well. I'll leave a few review notes here so we can push this forward. |
set(TBB_INCLUDE_DIRS "$ENV{TBB_ROOT}/include") | ||
set(CMAKE_MODULE_PATH "$ENV{OpenVDB_ROOT}/lib/cmake/OpenVDB" | ||
"${OpenVDB_ROOT}/lib/cmake/OpenVDB" | ||
${CMAKE_MODULE_PATH}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CMAKE_MODULE_PATH
usually shouldn't need to be modified. If you set CMAKE_PREFIX_PATH
to include the OpenVDB_ROOT
then in theory find_package(OpenVDB)
should work without needing to special-case openvdb here.
|
||
target_link_libraries(partio PRIVATE Alembic::Alembic OpenVDB::openvdb) | ||
target_include_directories(partio PRIVATE ${TBB_INCLUDE_DIRS}) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right now partio has a really minimal set of dependencies.
Since these are new dependencies it would be good to ease into them. Can we please make these opt-in and not built by default?
I would suggest adding some option(...)
variables that default to OFF
. Maybe call them something like PARTIO_ENABLE_ALEMBIC
and PARTIO_ENABLE_OPENVDB
so that we can opt-in to these settings.
TBB is needed for openvb so we can bundle those settings alongside PARTIO_ENABLE_OPENVDB
.
{ | ||
// partio looks for the extension .abc to decide to call readABC | ||
// and we want to be able to accept a time to read (right now in seconds) | ||
// so we will pass in /tmp/[email protected] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, bummer. That's really unfortunate. Would it help at all if we let you pass in something that looked like a URL? eg. foo.abc?time=42.5
. Just thinking out loud for the future..
If we start to support this construct now then we will have to forever support it, so we should think about it.
name = name.substr(0, lastAt) + ".abc"; | ||
} | ||
catch(...) | ||
{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should be explicit about what we're catching here. It looks like the idea is that if it's not something that converts via stod
then we'll ignore the exception it throws?
*errorStream << "Partio: Unable to open file Alembic: " << name << std::endl; | ||
*errorStream << "(" << filename << ")" << std::endl; | ||
} | ||
return 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sug: prefer nullptr
over 0
@@ -54,6 +54,8 @@ readers() | |||
static bool initialized=false; | |||
if(!initialized){ | |||
initializationMutex.lock(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if we make these plugins opt-in then we'll probably need #defines
that match them so that we can conditionally compile these lines below.
} | ||
tbb::task_scheduler_init schedulerInit((numThreads == 0) ? tbb::task_scheduler_init::automatic : numThreads); | ||
|
||
initLibrary(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
initLibrary() and all this TBB scheduler initialization stuff seems like it's main()
's responsibility rather than the responsibility of a plugin.
CUE_THREADS
is rather specific and seeing openvb::uninitialize()
makes me a bit nervous because I'm assuming that it's touching some global state.
I think this would be better mentioned in the readme with some example code showing what users need to do in order to use the library rather than taking on these responsibilities inside library code.
Try to keep these parts generic and reusable with as little assumptions as possible.
struct AttributeCache { | ||
std::vector<AttributeIndex> indices; | ||
ParticleAttribute partio; // partio.type contains the type that partio will store / allocate | ||
unsigned tupleSize; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I dunno if it's just me, but I prefer seeing unsigned int
over unsigned
even though I know it's implied.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great, thanks again for getting this working.
We'll see if others have any notes but this looks like a good place to start refining. I'm not opposed to merging this in if this feature can be made optional / opt-in and the implementation issues are be resolved.
cache.indices.clear(); | ||
cache.partio.type = NONE; | ||
continue; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note to self: the style above with the if (..) {
opening brace on the same line as the if/while/switch/for
control statements is preferred. We should probably share our internal clang-format config in this repo so that no one has to think about it. We haven't applied it to this repo yet.
convertScalar<float>(*float32, *indexIter, particles, cache.partio, static_cast<size_t>(offset++)); | ||
else | ||
convertScalar<float>(*float64, *indexIter, particles, cache.partio, static_cast<size_t>(offset++)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not a big deal, but it's unfortunate for performance that we end up in these situations with a loop followed by a conditional.
It's clunky to flip the loop around as well since we end up having to repeat that for (...)
expression just to get rid of the extra branching. The branch predictor probably deals with these alright since float32
is a loop invariant, though.
if (precision == Precision32) | ||
float32.reset(new openvdb::points::AttributeHandle<float>(*vdbAttr)); | ||
else | ||
float64.reset(new openvdb::points::AttributeHandle<double>(*vdbAttr)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh.. I see. calling new
in a loop is probably something that should be avoided. It's slow and it looks like we can avoid the heap altogether.
Can we keep uninitialized handles on the stack instead? If that's tricky because the types are different then that might be another vote towards restructuring this loop below to instead have a top-level conditional for Precision32
and then dispatching from there rather than pushing the float32 vs float64 stuff down into the loop bodies.
One way to do that without having to have too much duplicate code just for AttributeHandle<double>
vs <float>
would be to add a template function to handle the loop body and then we can dispatch from this point down.
That would make it much faster too. What do you think?
if (precision == Precision32) | ||
int32.reset(new openvdb::points::AttributeHandle<openvdb::Int32>(*vdbAttr)); | ||
else | ||
int64.reset(new openvdb::points::AttributeHandle<openvdb::Int64>(*vdbAttr)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto -- same as above. Try to avoid new
whenever possible, especially inside loops.
oAttrMap[keyName] = ioData->addAttribute( | ||
propName.c_str(), INT, extent); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does this need break;
to avoid fallthrough?
oAttrMap[keyName] = ioData->addAttribute( | ||
propName.c_str(), ptype, extent); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto, do we need break above and below?
@@ -36,6 +36,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. | |||
#define _READERS_h_ | |||
|
|||
namespace Partio{ | |||
ParticlesDataMutable* readABC( const char* filename,const bool headersOnly,std::ostream* errorStream); | |||
ParticlesDataMutable* readVDB( const char* filename,const bool headersOnly,std::ostream* errorStream); | |||
ParticlesDataMutable* readBGEO( const char* filename,const bool headersOnly,std::ostream* errorStream); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note: this part would also nee some special ifdef handling if we made openvb + alembic optional.
|
||
std::map<std::string, ParticleAttribute>::const_iterator it; | ||
for (it = iAttrMap.begin(); it != iAttrMap.end(); ++it) | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tiny style sug ~ map iterators are one of those areas where auto
is kind of nice. Could we even go one step further and use a new-style loop here?
for (const auto& entry : iAttrMap) {
// entry.first, entry.second
}
Adding OpenVDB point reader contributed by Roman Zulak and Alembic point reader contributed by Lucas Miller.