Awesome
USD device for ANARI
Device which generates USD output from intercepted ANARI API calls to, optionally with Omniverse support.
This project can be used purely to output USD files to local disk without any further run- or buildtime dependencies, and does therefore not require the use of Omniverse if not desired. If Omniverse output is enabled, it can be configured to transfer USD data to an Omniverse service of choice.
Prerequisites
On Windows and Linux this library builds against: - ANARI SDK (corresponding to git tagged version of this repo) at https://github.com/KhronosGroup/ANARI-SDK - USD version 23.xx or 24.xx, with (if enabled) OpenVDB 10 or 11.
USD can be built/installed in any of the following ways (depending on desired capabilities):
- Get prebuilt USD and optional Omniverse packages according to Downloading the Omniverse libraries
- Build USD from source (https://github.com/PixarAnimationStudios/USD/), optionally with OpenVDB support according to Building USD Manually
- For release/debug versions, observe the directory structure guidelines in Debug Builds section
- (Experimental) Automatic installation of USD as part of the superbuild, see superbuild/README.md
Note that on Linux, GCC only guarantees forward ABI-compatibility, so libraries downloaded from external sources built with newer versions of GCC than the USD device may not link to it properly.
Building the ANARI USD device
From this directory, run mkdir _build && cd _build
, after which there are two ways to build the USD Device:
- Regular build: Directly run
(c)cmake(-gui)
on the root directory.- Example of release configuration with Omniverse support, without OpenVDB:
ccmake .. -D "USD_DEVICE_USE_OMNIVERSE=ON" -D "ANARI_ROOT_DIR=<anari_install_path>" -D "USD_ROOT_DIR=<usd_install_path>" -D "OMNIUSDRESOLVER_ROOT_DIR=<omni_usd_resolver_install_path>" -D "OMNICLIENT_ROOT_DIR=<omni_client_install_path>" -D "Python3_ROOT_DIR=<python_install_path>" -D "Python3_FIND_STRATEGY_LOCATION=ON" -D "CMAKE_POSITION_INDEPENDENT_CODE=ON" -D "CMAKE_BUILD_TYPE=Release" -D "CMAKE_INSTALL_PREFIX=<install_path>"
- If you want all dependencies to be installed alongside the USD device's binaries, add
-D "INSTALL_ANARI_DEPS=ON" -D "INSTALL_ANARI_COMPILE_DEPS=ON" -D "INSTALL_USD_DEPS=ON" -D "INSTALL_OMNIVERSE_DEPS=ON"
- If you also want to generate the example executables, add
-D "USD_DEVICE_BUILD_EXAMPLES=ON"
. They can be executed standalone if the dependencies from the previous step are installed.
- Example of release configuration with Omniverse support, without OpenVDB:
- (Experimental) Superbuild: run
(c)cmake(-gui)
on the../superbuild
subdir, for detailed instructions seesuperbuild/README.md
.
After configuring and generating any of the above builds, run cmake --build . --config [Release|Debug] --target install
to build and install.
Usage notes
- Library and device names are both
usd
- All device-specific parameters are prefixed with
usd::
- See
usd_device_features.json
for parameter names and descriptions - Examples in
examples/anariTutorial_usd(_time).c
More details about specific parameters and unsupported features follow below.
Basic parameters
Specific ANARIDevice object parameters:
- Set
usd::serialize.location
string to the output location on disk,usd::serialize.outputBinary
bool for binary or text output. These parameters are immutable (after firstanariCommit
). - Alternatively,
usd::serialize.location
will also try theANARI_USD_SERIALIZE_LOCATION
environment variable. If neither are specified, it will default to"./"
and emit a warning. - Parameter
usd::serialize.hostName
has to be used to specify the server name (if Omniverse support is available) and optional port for Omniverse connections. This parameter is immutable. - Use
usd::time
to set a global timestep for USD output. All parameters and references from parent to child ANARI objects will be converted into USD for this particular global timestep, with the optional exception of "timed objects" (see below). The value of this parameter can be changed at any time, but make sure to callanariCommit
on the device after setting it.
Specific ANARI scene object parameters (World, Instancer, Group, Surface, Geometry, Volume, Spatialfield, Material, Sampler, Light):
- Each ANARI scene object has a
name
parameter as scenegraph identifier (over time). Upon setting this name, a formatted version is stored in theusd::name
property (with corresponding.size
as uint64). AfteranariRenderFrame
(or, if theusd::writeAtCommit
device parameter is enabled, afteranariCommit
for some objects), its full USD primpath can be retrieved by querying theusd::primPath
property (with corresponding.size
as uint64). - Changes to data are actually saved to USD output when
anariRenderFrame()
is called. - If ANARI objects of a certain
name
are not referenced from within any committed timestep, their internal data is cleaned up when callinganariDeviceSetParam(d, "usd::garbageCollect", ANARI_VOID_POINTER, 0)
. This is advised after everyanariRenderFrame()
or a subfrequency thereof. - If there is a desire to remove individual objects from USD, use the parameter
usd::removePrim
. It will throw a warning if the object is still referenced by any other objects.
Specific ANARI timed object parameters (Geometry, Material, Spatialfield, Sampler):
- A
usd::time
parameter to define the time at whichcommit()
will add the data to the scenegraph object indicated byusd::name
, regardless of the global timestep set for the ANARIDevice object. The effect of setting this parameter is that the parent objects referencing these "timed objects" will keep a USD-based time-mapping per global timestep. This way, a child reference defined at a particular global timestep will point to the data output of the child object at itsusd::time
, thereby avoiding data duplication. This parameter is applied like any other parameter duringanariCommit
.
For Surface and Volume:
- A
usd::isInstanceable
parameter is defined to allow the user to write theinstanceable
metadata to the corresponding USD output prim.
Advanced parameters
ANARIDevice object parameters:
- Device parameter
usd::sceneStage
allows the user to provide a pre-constructed stage, into which the USD output will be constructed. For correct operation, make sure thatanariSetParameter
forusd::sceneStage
takes aUsdStage*
(ie. themem
argument is directly ofUsdStage*
type) withANARI_VOID_POINTER
as type enumeration. This parameter is immutable. - Device parameter
usd::enableSaving
of typeANARI_BOOL
(defaultON
) allows the user to explicitly control whether USD output is written out to disk, or kept in memory. Assets that are not stored in USD format, such as MDL materials, texture images and volumes, will always be written to disk regardless of the value of this parameter. In order for no files to be written at all, additionally pass the special string"void"
tousd::serialize.location
. This parameter can be changed at any time and applies immediately. - Device parameter
usd::serialize.newSession
of typeANARI_BOOL
(defaultON
) allows the user to explicitly control whether a new empty session directory has to be created for USD output, or whether the last written session and its USD files have to be reopened, after which the device will continue (over-)writing the existing files. In the latter case, existing prims will be changed to match the contents of any committed ANARI objects that go by their corresponding name, but other already existing prims within the USD files will be left untouched. This parameter is immutable. - Device parameters
usd::output.<x>
, which give control over what or how certain objects are converted to USD, to increase compatibility with certain renderers or reduce clutter in the resulting USD graph. All of them are immutable. Permissible values for<x>
are:material
: Whether material objects are included in the outputpreviewsurfaceshader
: Whether previewsurface shader prims are output for material objectsmdlshader
: Whether mdl shader prims are output for material objects
- Device parameter
usd::writeAtCommit
controls whether writing to USD will happen immediately at theanariCommit
call, or atanariRenderFrame
(default). The potential advantage of the former is that one has more granular control over USD processing time. Note that if this parameter is set, the ANARIDevice (specifically itsusd::time
) should be committed before any other object in the scene. This parameter can be changed at any time and applies immediately. - For Geometry objects, the
primitive/vertex.attribute<x>
parameters are typically output as primvars namedattribute<x>
on the USD prim. However, custom names are supported by using theusd::attribute<x>.name
parameter on the Geometry object, which will directly correspond to the name of the primvar output. So make sure these names are not clashing with in-built USD primvar names (eg. by prefixing the attribute names) and that any sampler/material attribute bindings are directly set to that name as well.
ANARI scene objects:
- Use individual bits of the
usd::timeVarying
parameter to control which exact ANARI object parameters should vary over time, and which ones should store only one value over all timesteps. Parameters that are possibly timevarying can be gathered fromusd_device_features.json
, by looking at theusd::timeVarying.<parametername>
parameter names. For certain parameters referring to ANARI object references (such as geometries/volumes/materials/samplers), the value of their referenced timestep can be set with the parameterusd:time.<parametername>
. All these parameters can be changed at any time and are applied like any other parameter duringanariCommit
.
Not supported
- Geometries:
- all fixed point color array types will be normalized to float, double will be type-cast
- Cones/Cylinders/Glyphs do not support the
caps
parameter, or thevertex.cap
attribute - For triangles and quads, the
vertex.tangent
attribute is not supported
- Volumes and SpatialFields:
unitDistance
has no effectfilter
has no effect
- Materials:
- Setting a parameter to an attribute string will only produce valid output if the parameter value and connected attribute array type are an exact match, unless:
- A float4/float3 attribute is bound to a float3/color input.
- Attribute strings
primitiveId
,worldPosition
andworldNormal
are unsupported - Beyond the parameters already present in the matte material, the physicallyBased material only supports
emissive
,metallic
,roughness
andior
- Setting a parameter to an attribute string will only produce valid output if the parameter value and connected attribute array type are an exact match, unless:
- Samplers:
- setting
inAttribute
will only produce valid output if the parameter value type and connected attribute array type are an exact match - Attribute strings
primitiveId
,worldPosition
andworldNormal
are unsupported - the
<in/out>Transform
and<in/out>Offset
parameters
- setting
- Lights:
- unsupported for now
- Properties:
bounds
property not queryable (World, Instance, etc.)
Detailed build info
Debug builds
If you have separate release and debug versions of USD, (or standalone OpenVDB, Blosc, Zlib), make sure the /lib
and /include
directories of the respective installations exist within /release
and /debug
directories, ie. for USD: <USD_ROOT_DIR>/release
and <USD_ROOT_DIR>/debug
.
Downloading the Omniverse libraries
- Clone the Connect Sample on Github: https://github.com/NVIDIA-Omniverse/connect-samples
- Make sure you check out a tag using a supported USD version for this USD device: inspect the
deps/target-deps.packman.xml
file, and make sure that theomni_connect_sdk
entry contains a major version of thepxr-<version>
substring corresponding to what is listed at the top of thisREADME.md
. - Build the connect sample by running
repo.sh/.bat build
in its folder - Locate the
usd
,omni_usd_resolver
,omni_client_library
andpython
folders in the_build/target-deps
subfolder - The location of the previous four subfolders respectively can directly be set as
USD_ROOT_DIR
,OMNIUSDRESOLVER_ROOT_DIR
,OMNICLIENT_ROOT_DIR
,Python3_ROOT_DIR
in the ANARI CMake (superbuild) configuration, as demonstrated in Building the ANARI USD device.
Building USD Manually
- The environment variable BOOST_ROOT should not be set
- On Linux:
- Zlib has to either be installed on a system level or built from source (with
-fPIC
added toCMAKE_CXX_FLAGS
)- Run, for a particular value of
<zlib_install_dir>
:export CMAKE_ZLIB_ARGS="-D ZLIB_ROOT=<zlib_install_dir>
- Run, for a particular value of
- If using Anaconda:
- The pyside2 and pyopengl package has to be included in the environment
- Make sure a Python include directory without
m
suffix exists (create a symbolic link if necessary)
- Run, for a particular value of
<config>
:export LD_LIBRARY_PATH=<USD_ROOT_DIR>/<config>/lib:$LD_LIBRARY_PATH
- Zlib has to either be installed on a system level or built from source (with
- On Windows:
- Make sure
pyside2-uic.exe
from your Python./Scripts
directory is in thePATH
- only for debug builds: In pyconfig.h all
pragma comment(lib,"pythonXX.lib")
statements should change topragma comment(lib,"pythonXX_d.lib")
. They can be changed back after building USD.
- Make sure
- Build and install USD by running the buildscript
python <usd_source_dir>/build_scripts/build_usd.py <USD_ROOT_DIR>/<config>
(whereUSD_ROOT_DIR
is the desired installation location)- Add
--debug
(v21.08-) or--build-variant debug
(v21.11+) for debug builds - For OpenVDB on Windows, run in a developer command prompt and add the following flags:
--openvdb --build-args openvdb,"-DCMAKE_CXX_FLAGS=\"-D__TBB_NO_IMPLICIT_LINKAGE /EHsc\""
- OpenVDB's FindIlmBase.cmake might be broken for debug builds; make sure that the
_d
suffix is removed from<USD_ROOT_DIR>/<config>/lib/Half-X_X_d.lib
and<USD_ROOT_DIR>/<config>/bin/Half-X_X_d.dll
after running the build once, then run it again.
- OpenVDB's FindIlmBase.cmake might be broken for debug builds; make sure that the
- For OpenVDB on Linux, add the following flags:
--openvdb --build-args openvdb,"-D CMAKE_CXX_FLAGS:STRING=-fPIC $CMAKE_ZLIB_ARGS" blosc,"-D CMAKE_C_FLAGS:STRING=-fPIC -D CMAKE_CXX_FLAGS:STRING=-fPIC" openexr,"$CMAKE_ZLIB_ARGS"
- Add