Isotropix Forums

Alembic to USD Python helper

Clarisse Scripting related topics

Alembic to USD Python helper

Unread postby anemoff » Wed Sep 18, 2019 2:28 pm

Hi all,

Here is a Python helper to call the tool "abc2usd" (available since Clarisse 4.0) that converts an Alembic file to an USD file.

python code

def abc2usd(input_abc_file, output_usd_file):
"""
Convert the input Alembic file to USD.

Parameters
----------
input_abc_file:
> Resolved path (i.e. variables are expanded) to the input Alembic file to be converted.

output_usd_file:
> Resolved path (i.e. variables are expanded) of the output USD file.
> File extension must be '.usda' or '.usdc' (recommended), or empty, in which case it will default to '.usdc'.

Returns
-------
On success, returns the USD file path.
On failure, returns None.
"""

print('abc2usd: converting "{}" to "{}" ...'.format(input_abc_file, output_usd_file))

bin_dir = ix.application.get_factory().get_vars().get('CLARISSE_BIN_DIR').get_string()
bin = os.path.join(bin_dir, 'abc2usd')
if platform.system() == 'Windows':
bin += '.exe'

if not os.path.isfile(bin):
ix.log_error('Error: abc2usd binary "{}" not found.'.format(bin))
return None

if not os.path.isfile(input_abc_file):
ix.log_error('Error: input Alembic file "{}" not found.'.format(input_abc_file))
return None

try:
cmd = '{} -input {} -output {}'.format(bin, input_abc_file, output_usd_file)
output = subprocess.check_output(cmd)
print(output)
return output_usd_file
except subprocess.CalledProcessError as e:
ix.log_error('abc2usd failed:\n{}'.format(e.output))
return None
except Exception as e:
ix.log_error('abc2usd failed:\n{}'.format(e))
return None


Simple usage example:

python code

abc_file = 'path/to/file.abc'

# use the same filename but change the file extension
usd_file, _ = os.path.splitext(abc_file)
usd_file += '.usdc'

# do the conversion
final_usd_file = abc2usd(abc_file, usd_file)
if os.path.isfile(final_usd_file):
ix.log_info('Alembic to USD conversion succeeded!')
# do something with the USD file ...
else:
ix.log_error('Alembic to USD conversion failed!')


Advanced example:
In this example, we look for all Reference Contexts that reference an Alembic file, convert the file to USD, and update the reference to use the USD file.

Note:
The example doesn't update material assignments. And you must be aware that shading group names differ slightly between Alembic and USD.
Historically in Clarisse, we collapse the Alembic xforms/shapes (coming from Maya) into 1 node, and we use the shape's name.
USD does the same internally, but unfortunately, they use the name of the xform...
E.g. in Alembic, the kinematic paths will look like "root/cubeShape" and the same converted to USD "root/cube"
So if you have shading applied through a shading layer, you might need to modify some rules to accommodate this change too (but most rules should work without modifications as they usually target groups instead of individual shapes, so the names don't change).
(Thanks to Damien for the details!)

python code

def get_file_references(parent_context, file_ext, filter='*'):
"""
Get all File Reference Contexts children of parent_context that match the path `filter`.

Parameters
---------
parent_context
> Parent context where we want to search for File Reference Contexts.

file_ext:
> Desired file extension. Example: '.abc' to look for Alembic File References, '.project' for Projects, ...

filter:
> Path filter expression. Example: '*foo*' will only match contexts with 'foo' in their path.

Returns
-------
A list of OfContexts.
"""
sub_contexts = ix.api.OfContextSet()
ix.application.get_matching_contexts(sub_contexts, filter, ix.get_item(parent_context))

file_refs = []
for ctx in sub_contexts:
if ctx.is_reference():
file_attr = ctx.get_attribute('filename')
if file_attr:
file = file_attr.get_string()
if file and file.lower().endswith(file_ext):
file_refs.append(ctx)

return file_refs


# Example: convert all Alembic refs to USD refs

def convert_abc_refs_to_usd_refs(parent_context):
ix.enable_command_history()
ix.begin_command_batch('Convert Alembic references to USD references')

# get all alembic reference contexts
abc_refs = get_file_references(parent_context, '.abc')

# create a progress bar for feedback
pbar = ix.application.create_progress_bar('Converting Alembic references to USD references...', True, True)
pbar.set_step_count(len(abc_refs))
pbar_step = 0

# to avoid converting the same file multiple times, group contexts by referenced file
file_dict = {}
for ref_ctx in abc_refs:
file_attr = ref_ctx.get_attribute('filename')
if file_attr:
file = file_attr.get_string()
if file:
if file not in file_dict:
file_dict[file] = []
file_dict[file].append(ref_ctx)

# convert and update the refs
for abc_file, contexts in file_dict.items():
# convert the file once
usd_file, _ = os.path.splitext(abc_file)
usd_file += '.usdc'
usd_file = abc2usd(abc_file, usd_file)

# update all associated refs
if os.path.isfile(usd_file):
for ref_ctx in contexts:
file_attr = ref_ctx.get_attribute('filename')
ix.cmds.SetValues([str(file_attr)], [usd_file])

pbar_step += 1
pbar.step(pbar_step)

pbar.destroy()
ix.end_command_batch()
ix.disable_command_history()

convert_abc_refs_to_usd_refs('project:/')


Feedback is welcome.
Enjoy!
Anthony Nemoff
Isotropix
R&D Engineer
User avatar
anemoff
 
Posts: 191
Joined: Wed Jan 13, 2016 10:10 am

Re: Alembic to USD Python helper

Unread postby gerdhofer » Thu Sep 19, 2019 12:20 pm

Thanks for the script Anthony. Really helpful. Not just in terms of functionality, but also when I think of scripting in general.
gerdhofer
 
Posts: 42
Joined: Thu Aug 30, 2018 11:05 am

Re: Alembic to USD Python helper

Unread postby anemoff » Thu Sep 19, 2019 12:53 pm

You're welcome!
Anthony Nemoff
Isotropix
R&D Engineer
User avatar
anemoff
 
Posts: 191
Joined: Wed Jan 13, 2016 10:10 am

Re: Alembic to USD Python helper

Unread postby mati » Sat Sep 21, 2019 12:01 am

Does abc2usd do anything more than usdcat?
mati
 
Posts: 35
Joined: Fri Apr 19, 2019 8:35 pm

Re: Alembic to USD Python helper

Unread postby anemoff » Mon Sep 23, 2019 9:50 am

Not really. Basically, it flattens an Alembic file layer in a USD stage, but it also cleanups unnecessary samples from the Alembic (this can be disabled if needed).
You could achieve the same with usdcat, minus the samples cleanup part, by writing an .usda file that references the Alembic, and then flattening it to .usdc.

Check abc2usd help with "abc2usd -help" for more details.
Anthony Nemoff
Isotropix
R&D Engineer
User avatar
anemoff
 
Posts: 191
Joined: Wed Jan 13, 2016 10:10 am


Return to Scripting