Importing USD `quatf` types was erroneously left disabled after recent
work this past summer for better attribute support. It is already
correctly enabled and validated for Export.
The `half` and `double` variants must still be skipped for now though.
Pull Request: https://projects.blender.org/blender/blender/pulls/132252
Commit 0df5d8220b made a change to have the `USDStageReader` only keep
a reference to the ImportSettings struct. This isn't safe to do because
there's scenarios where the ImportSettings might be defined as a stack
variable but the reader outlives the lifetime of that variable. This
happens inside `USD_create_handle` where the reader is returned to the
caller for instance.
Fix this, and the original issue which lead to the change causing the
regression, by having `USDStageReader` own ImportSettings directly so
it's more obvious that it is A) tied to the lifetime of the reader and
B) can no longer become out of sync with a caller's own ImportSettings
data (since that no longer exists).
Pull Request: https://projects.blender.org/blender/blender/pulls/132095
Import edge crease values and properly configure any added subdivision
modifiers with correct UV and boundary settings. These were already
exported so this now completes our subdivision support.
Pull Request: https://projects.blender.org/blender/blender/pulls/131569
Building the FCurve keyframes one at a time leads to quadratic runtime
behavior due to how the underlying BezTriple array is resized in
`animrig::insert_bezt_fcurve`. Instead, pre-allocate the entire array
upfront and assign the keyframes directly since we are already iterating
our time samples in-order.
In the event that fewer keyframes are ultimately assigned, rare since
this indicates some form of bad data which we skip during iteration, we
will reallocate to the appropriate size right before recalculating the
fcurve handles.
Total import time for the 3000 frame Elephant test asset [1] drops from
~4650 ms to 120 ms, a 38x speedup. A more typical 250 frame armature
animation shows a more modest 1.5-2x reduction in overall import time.
[1] https://github.com/usd-wg/assets/tree/main/full_assets/ElephantWithMonochord
Pull Request: https://projects.blender.org/blender/blender/pulls/131921
While adding tests I found that metaball export has been broken since
Blender 3.4. It would export each metaball geometry twice.
This looks to have been a side effect of a change to `object_dupli.cc`
which no longer sets the `no_draw` flag for metaballs[1]. With the flag
unset we would end up visiting this particular object twice.
Use a direct check for Metaballs now and add test coverage for the
scenario in general.
[1] eaa87101cd
Pull Request: https://projects.blender.org/blender/blender/pulls/131984
Supporting a new on_material_import() USDHook callback.
Also added support for import_texture() and export_texture()
utility functions which can be called from on_material_import() and
on_material_export() Python implementations, respectively.
Pull Request: https://projects.blender.org/blender/blender/pulls/131559
Tidy up:
- Use blender::Map and blender::Vector for newly created `prim_map`
- Leave bread-crumb comment for moving map creation outside of loop
- Expand UI tooltip for newly added export option
Pull Request: https://projects.blender.org/blender/blender/pulls/131770
When importing an USD, the Blender object names do not necessarily match
Prim names:
```
#usda 1.0
def Xform "xform1"
{
def Mesh "MyObject" # Will be imported as "MyObject"
}
def Xform "xform2"
{
def Mesh "MyObject" # Will be imported as "MyObject.001"
}
def Xform "xform2"
{
def Mesh "MyObject" # Will be imported as "MyObject.002"
}
```
This makes it difficult in the [USD Import Hooks]
(https://docs.blender.org/api/current/bpy.types.USDHook.html) to link a
Blender object back to its source Prim for additional processing. A
typical use cases for games is to generate UVs, create and apply a
material on the fly when importing a collision shape that does not have
a visual representation (hence no materials) based on some Prim
attributes, but that the artist needs to differenciate in Blender's
viewport.
The Import context exposes a new method `get_prim_map()` that returns a
`dict` of `prim path` / `list of Blender ID`.
For example, given the following USD scene,
```
/
|--XformThenCube [def Xform]
| `--Cube [def Cube]
|--XformThenXformCube [def Xform]
| `--XformIntermediate [def Xform]
| `--Cube [def Mesh]
|--Cube [def Cube]
`--Material [def Material]
`--Principled_BSDF [def Shader]
```
the `get_prim_map()` method will return a map as:
```python
@static_method
def on_import(import_context):
pprint(import_context.get_prim_map())
```
```json
{
"/Cube": [bpy.data.objects["Cube.002"], bpy.data.meshes["Cube.002"]],
"/XformThenCube": [bpy.data.objects["XformThenCube"]],
"/XformThenCube/Cube": [bpy.data.objects["Cube"], bpy.data.meshes["Cube"]],
"/XformThenXformCube": [bpy.data.objects["XformThenXformCube"]],
"/XformThenXformCube/XformIntermediate": [bpy.data.objects["XformIntermediate"]],
"/XformThenXformCube/XformIntermediate/Cube": [bpy.data.objects["Cube.001"], bpy.data.meshes["Cube.001"]],
"/Material": [bpy.data.materials["Material"]],
}
```
Co-authored-by: Odréanne Breton <odreanne.breton@ubisoft.com>
Co-authored-by: Sttevan Carnali Joga <sttevan.carnali-joga@ubisoft.com>
Co-authored-by: Charles Flèche <charles.fleche@ubisoft.com>
Currently each node's position is stored in the coordinate space of
its parent. To find the location of a node on the canvas, we have to
apply the translation of each of its parents. Also, nodes have hidden
"offset" values used while transforming frame nodes. Together,
those made the system much more complicated than necessary,
and they made the Python API ineffective.
This commit removes usage of the offset values and moves nodes
to be stored in the "global" space of the node canvas. It also resolves
some weird behavior when resizing frame nodes, and fixes a few bugs.
The change is forward compatible, so we still write files with nodes in
the old parent-space format. In 5.0 the conversion when writing can be
removed. The existing Python API also stays the same. A new
"location_absolute" property gives node locations in global space,
and changing the old property also moves the child nodes of frames.
Resolves#92458, #72904.
Pull Request: https://projects.blender.org/blender/blender/pulls/131335
Make use of our sparse value writer in more places. Namely, when using
animated Camera or Light properties, this will prevent a needless stream
of unchanging values being written into the USD file [1]. Skeletons and
armatures benefit too but less so as typically the primary benefit only
applies to the comparatively small `scale` transform attribute, which
typically remains unchanged from frame to frame.
The newly added `set_attribute` common code can, and eventually will, be
used to reduce boilerplate elsewhere where we do the same sparse writing
dance.
Ref #130759
Pull Request: https://projects.blender.org/blender/blender/pulls/131333
While adding tests for subd import I discovered that our vertex crease
data was imported incorrectly.
This PR adds tests and fixes:
- We tried to read crease sharpness data as ints instead of floats. This
caused the import process to early-return, meaning we never load any
data at all
- Empty USD data would still cause us to create the `crease_vert`
attribute unnecessarily
- Sharpness data needs clamped to 0-1 to handle USD's SHARPNESS_INFINITE
value of 10.0
- We need to fill the `crease_vert` span with 0's since incoming USD
data may not have values set for all the verts
Pull Request: https://projects.blender.org/blender/blender/pulls/131516
Rather than using a default "Anim" name when exporting armature
animations, use the animation's Action name instead. Likewise use the
UsdSkelAnimation name for the Action's name during import.
Blendshapes/shapekeys still use the default "Anim" name as there's no
action for these situations.
Pull Request: https://projects.blender.org/blender/blender/pulls/131021
Starting with USD 24.11, the external boost dependency is being phased
out. It will instead use their own internal pxr_boost::python library.
This PR adapts the code inside `usd_hook.cc` to build and run in this
new environment.
Pull Request: https://projects.blender.org/blender/blender/pulls/131343
Adds support of NURBS weights or "rat bspline" in OBJ terms.
Tries to guess Blender knot mode better:
- Detects and closes loops. This decision is based on geometry only. No metadata is provided in OBJ for this, so importer has checkbox to disable this feature.
- Bezier knot mode allows to import circles and circular arcs.
Pull Request: https://projects.blender.org/blender/blender/pulls/131169
The wrong ObjectIdentifier was used when trying to see if the object is
a parent to something else in the export graph. This lead to accessing
an invalid iterator which will assert with MSVC in Debug configurations.
Accidentally regressed during the review of 428ab699dc.
Pull Request: https://projects.blender.org/blender/blender/pulls/131174
When OBJ file contains vertex normals, this can in some cases confuse
the custom loop normals code inside Blender. Since it does not simply
just use custom normals, but rather projects them into "lnor space".
But that "lnor space" calculation can go haywire sometimes, when
degenerate faces are present in the input.
Mark zero-area faces as "sharp" before doing custom normals. This will
make them not try to share the "smooth fan" lnor space with other faces,
and things will look correct.
Previously, OBJ importer was (wrongly) always setting all faces
as "sharp", which avoided this problem, but caused other issues.
Pull Request: https://projects.blender.org/blender/blender/pulls/131041
These are converted on startup to the new type. There are still
some references left, mostly where it looked like there still needs
to be changes to properly deal with the new object type.
Add a `short2` attribute type, intended to store the existing
`CD_CUSTOMLOOPNORMAL` custom data type in order to move the custom
normal storage to generic attributes. This type probably won't get much
use besides that, but generally we don't have reasons not to add these
generic types, besides binary size. In the future we should consolidate
usage of `convert_to_static_type` to avoid large binary size increases
(about 700KB here) for this sort of addition.
This is the first step of #130484.
Pull Request: https://projects.blender.org/blender/blender/pulls/130530
When EEVEE next removed the Alpha Threshold option a node graph setup
was used instead. Based on a USD test asset[1] the original code was
designed around only using the Image A channel during import to wire
up the nodes. However, the other channels (R, G, or B) are just as
valid.
We now handle this by wiring up the Separate RGB node, that is already
inserted for the scenario in general, to the shader nodes handling the
threshold calculation. Also adds additional test coverage for both
export and import as well.
The Round and LessThan+OneMinus networks remain the only shapes that
will be recognized for the processing.
[1] https://github.com/usd-wg/assets/tree/main/test_assets/AlphaBlendModeTest
Pull Request: https://projects.blender.org/blender/blender/pulls/130346
The existing point instancer reader is slightly refactored to allow for
animated setups. The primary change is simply to inherit from
`USDGeomReader` rather than `USDXformReader`. This allows access to the
`read_geometry` API used by the cache modifier.
The existing `read_object_data` method is split into two parts with
`read_geometry` loading per-frame USD data and `read_object_data`
coordinating the initial loading process, including creating the GN node
tree just once.
A new test has been added (a variation of the nested point instancer
file) with time samples on various attributes and on both point
instancers. This also fixes#129502 and the file provided in that issue.
----
The already added test file is `tests/data/usd/usd_point_instancer_anim.usda`
Pull Request: https://projects.blender.org/blender/blender/pulls/129881
Adds the option `merge_parent_xform` to the USD export operator and
panels so the transform and shapes are merged into a single USD Prim.
Without the option (existing default), a top-level mesh would be
exported as a top-level `Xform` that has a `Mesh` child:
```
def Xform "MyBlenderMeshObject"
{
matrix4d xformOp:transform = ...
def Mesh "MyBlenderMeshData"
{
}
}
```
This matches the Blender data model, where a transformable object
contains a geometric shape (like a mesh). This structure is also very
valid in USD, where we don't want to directly instantiate geometric
primitives[1]
However, "since number of prims on a stage is one of the primary factors
that governs how USD scale"[2], to reduce the number of prims in a
stage, geometric primitives *are transformable* themselves (see the
inheritence diagram[3]).
As such, the new export option allows to export geometric primitives
without the parent transform:
```
def Mesh "MyBlenderMeshObject"
{
matrix4d xformOp:transform = ...
}
```
This MR adds a the `is_object_data_context` flag to the
`HierarchyContext` context structure. The point of this change is to
make unambiguous in `USDHierarchyIterator::create_usd_export_context`
the fact that an `object` or a `data` is currently being exported: the
new `merge_parent_xform` option is meaningless for `object`. Only `data`
can be exported with a parent `Xform` or as a child of said `Xform`.
Ideally this flag would not be needed at all: the final USD prim path
*could* be computed in an override of the virtual
`AbstractHierarchyIterator::get_object_data_path` method. However, this
would mean that an `object` and a `data` would have the same export path.
This does not currently play well with
`AbstractHierarchyIterator::ensure_writer`, where `writers` are cached
*by their export path*: it would cache a transform writer, but will skip
the subsequent data writer.
Additionally, another new `is_parent` flag is added to handle the case
where merging the Xform is invalid: objects that are parents to other
objects should remain unmerged as otherwise that would yield invalid USD
files.
[1] https://openusd.org/release/glossary.html#usdglossary-gprim
[2] https://openusd.org/release/glossary.html#usdglossary-instancing
[3] https://openusd.org/release/api/class_usd_geom_xformable.html
Co-authored-by: Odréanne Breton <odreanne.breton@ubisoft.com>
Co-authored-by: Sttevan Carnali Joga <sttevan.carnali-joga@ubisoft.com>
Co-authored-by: Charles Flèche <charles.fleche@ubisoft.com>
Looks like the initial version of this struct was copied from Alembic.
Remove the fields that were never ultimately used and initialize the
remaining fields inline.
Pull Request: https://projects.blender.org/blender/blender/pulls/130492
While adding test coverage for in-memory and packed texture scenarios, I
found that UDIMs were not being handled correctly in both cases. For
in-memory scenarios the per-tile generated/dirty status was not taken
into account. For packed scenarios the wrong filename substitutions were
being used.
This fixes both of these cases and adds test coverage for these
scenarios now. Both relative and absolute path options are validated.
Note: Both in-memory and packed images behave incorrectly when using the
'KEEP' and 'PRESERVE' texture export modes, so those remain untested
currently. A design on exactly what should happen in these modes is TBD.
Pull Request: https://projects.blender.org/blender/blender/pulls/130391
When reading UsdPreviewSurface materials from USD files, duplicate links
between nodes would often result. This typically occurs between the
Image node and its upstream UV Mapping node, or between the Image node
and a downstream Separate RGB node. As processing progresses, we
de-duplicate the nodes themselves as each new input/output socket is
discovered. However, we would unconditionally add a link between the
nodes even if we've already added one.
Cycles will complain about this situation and it's obviously incorrect:
`Cycles shader graph connect: input already connected.`
As most UsdPreviewSurface material networks are all fairly small
(<10 links total) I'm not worried about the cost of counting the links
at this point.
Pull Request: https://projects.blender.org/blender/blender/pulls/130356
This new import option will allow users to chose if we merge USD prims
with their Xform parent.
Given a USD like:
```
def Xform "MyObject"
{
def Mesh "MyObject_LOD0"
{
}
}
```
When the option is set to True (existing default), only the mesh will be
imported and its parent Xform transformation will be baked into the
Mesh.
```
# In blender after import
- MyObject_LOD0 (Mesh)
```
When the option is set to False, the parent Xform will always be
imported as an Empty object:
```
# In blender after import
- MyObject (Empty)
├─ MyObject_LOD0 (Mesh)
```
Co-authored-by: Odréanne Breton <odreanne.breton@ubisoft.com>
Co-authored-by: Sttevan Carnali Joga <sttevan.carnali-joga@ubisoft.com>
OBJ, PLY, and STL used a mix of fprintf, std::cout, and std::cerr to
trace warnings, errors, and general messages to the console.
Now, we instead use CLOG which provides real facilities for warnings and
errors and generally removes the need to pull in and use the heavy
`<iostream>` machinery.
For traces that should always be printed, `fmt::print` is used since
CLOG currently doesn't provide that particular level of trace.
Tests were only minimally changed to drop usage of streams while keeping
their prior usage of older stdio APIs. We can change to using fmtlib
there too if desired.
Pull Request: https://projects.blender.org/blender/blender/pulls/130107
NOTE: This also required some changes to Cycles code itself, who is now
directly including `BKE_image.hh` instead of declaring a few prototypes
of these functions in its `blender/utils.h` header (due to C++ functions
names mangling, this was not working anymore).
Pull Request: https://projects.blender.org/blender/blender/pulls/130174
Previously, some places used `curves.points_num() == 0` some other
places `curves.curves_num() == 0` to check if the geometry is empty.
Rather than having these two ways, add an `is_empty()` function
that replaces all these different checks.
Also update the curves geometry tests to use this function.
Pull Request: https://projects.blender.org/blender/blender/pulls/130168
This seems like a long-standing misuse of the custom vert normal APIs.
It broke, obviously so, in 3.1 but 3.0 was also rather fragile as was
noted in the original bug report.
The `BKE_mesh_set_custom_normals_from_verts` should be the correct API
to use when loading in vert normals from external files. The current
code would yield faceted mesh shading, as-if there were no custom
normals at all.
Pull Request: https://projects.blender.org/blender/blender/pulls/130069
This enables material displacement for UsdPreviewSurface import and
export. Scenarios are limited by what's supported by the preview surface
itself. Namely only Object Space displacement can be used (no vector
displacement)[1] and the Midlevel and Scale parameters are maintained by
adjusting the scale-bias on the image texture controlling the Height
(this means that Midlevel and Scale must be constants).
Hydra/MaterialX support is more complicated. First, there is a bug which
prevents scalar displacment from working correctly and that needs USD
2408+ for the fix[2]. Second, is that there's an open question about
which coordinate system to use for MaterialX's vector displacement maps.
Lastly, Hydra GL does not render displacement, making verification using
only Blender impossible[3]. As a result, this PR only makes MaterialX
"ready" for support, but stops short of actually connecting the final
piece of the node graph until more of the above can be sorted out.
Tests are added which cover:
- Variations of Midlevel and Scale values
- A constant Height setup
- Negative scenarios checking that only Object space is supported
and that midlevel and scale need to be constants
[1] https://openusd.org/release/spec_usdpreviewsurface.html
[2] https://github.com/PixarAnimationStudios/OpenUSD/issues/3325
[3] https://forum.aousd.org/t/materialx-displacement-hydra-storm/1098/2
Pull Request: https://projects.blender.org/blender/blender/pulls/128909