2023-05-31 16:19:06 +02:00
|
|
|
/* SPDX-FileCopyrightText: 2023 Nvidia. All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2023-02-13 19:49:24 +01:00
|
|
|
|
2024-02-28 03:02:38 +01:00
|
|
|
#include "BKE_geometry_set.hh"
|
2024-01-15 12:44:04 -05:00
|
|
|
#include "BKE_lib_id.hh"
|
2023-03-12 22:29:15 +01:00
|
|
|
#include "BKE_mesh.hh"
|
2023-10-09 23:41:53 +02:00
|
|
|
#include "BKE_object.hh"
|
2024-02-10 18:34:29 +01:00
|
|
|
#include "BKE_report.hh"
|
2023-02-13 19:49:24 +01:00
|
|
|
|
2024-04-24 20:58:53 +02:00
|
|
|
#include "DNA_modifier_types.h"
|
2023-02-13 19:49:24 +01:00
|
|
|
#include "DNA_object_types.h"
|
|
|
|
|
#include "DNA_windowmanager_types.h"
|
|
|
|
|
|
2024-05-15 05:44:26 +02:00
|
|
|
#include "usd_attribute_utils.hh"
|
2024-04-24 20:58:53 +02:00
|
|
|
#include "usd_mesh_utils.hh"
|
2024-02-05 19:02:00 +01:00
|
|
|
#include "usd_reader_shape.hh"
|
2023-02-13 19:49:24 +01:00
|
|
|
|
|
|
|
|
#include <pxr/usd/usdGeom/capsule.h>
|
2025-02-21 22:54:09 +01:00
|
|
|
#include <pxr/usd/usdGeom/capsule_1.h>
|
2023-02-13 19:49:24 +01:00
|
|
|
#include <pxr/usd/usdGeom/cone.h>
|
|
|
|
|
#include <pxr/usd/usdGeom/cube.h>
|
|
|
|
|
#include <pxr/usd/usdGeom/cylinder.h>
|
2025-02-21 22:54:09 +01:00
|
|
|
#include <pxr/usd/usdGeom/cylinder_1.h>
|
2025-02-11 19:56:15 +01:00
|
|
|
#include <pxr/usd/usdGeom/plane.h>
|
2023-02-13 19:49:24 +01:00
|
|
|
#include <pxr/usd/usdGeom/sphere.h>
|
|
|
|
|
#include <pxr/usdImaging/usdImaging/capsuleAdapter.h>
|
|
|
|
|
#include <pxr/usdImaging/usdImaging/coneAdapter.h>
|
|
|
|
|
#include <pxr/usdImaging/usdImaging/cubeAdapter.h>
|
|
|
|
|
#include <pxr/usdImaging/usdImaging/cylinderAdapter.h>
|
2025-02-11 19:56:15 +01:00
|
|
|
#include <pxr/usdImaging/usdImaging/planeAdapter.h>
|
2023-02-13 19:49:24 +01:00
|
|
|
#include <pxr/usdImaging/usdImaging/sphereAdapter.h>
|
|
|
|
|
|
|
|
|
|
namespace blender::io::usd {
|
|
|
|
|
|
|
|
|
|
USDShapeReader::USDShapeReader(const pxr::UsdPrim &prim,
|
|
|
|
|
const USDImportParams &import_params,
|
|
|
|
|
const ImportSettings &settings)
|
|
|
|
|
: USDGeomReader(prim, import_params, settings)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void USDShapeReader::create_object(Main *bmain, double /*motionSampleTime*/)
|
|
|
|
|
{
|
|
|
|
|
Mesh *mesh = BKE_mesh_add(bmain, name_.c_str());
|
|
|
|
|
object_ = BKE_object_add_only_object(bmain, OB_MESH, name_.c_str());
|
|
|
|
|
object_->data = mesh;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void USDShapeReader::read_object_data(Main *bmain, double motionSampleTime)
|
|
|
|
|
{
|
2023-02-22 11:22:48 -05:00
|
|
|
const USDMeshReadParams params = create_mesh_read_params(motionSampleTime,
|
|
|
|
|
import_params_.mesh_read_flag);
|
2023-02-13 19:49:24 +01:00
|
|
|
Mesh *mesh = (Mesh *)object_->data;
|
2023-02-22 11:22:48 -05:00
|
|
|
Mesh *read_mesh = this->read_mesh(mesh, params, nullptr);
|
2023-02-13 19:49:24 +01:00
|
|
|
|
|
|
|
|
if (read_mesh != mesh) {
|
|
|
|
|
BKE_mesh_nomain_to_mesh(read_mesh, mesh, object_);
|
|
|
|
|
if (is_time_varying()) {
|
|
|
|
|
USDGeomReader::add_cache_modifier();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
USDXformReader::read_object_data(bmain, motionSampleTime);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename Adapter>
|
|
|
|
|
void USDShapeReader::read_values(const double motionSampleTime,
|
|
|
|
|
pxr::VtVec3fArray &positions,
|
|
|
|
|
pxr::VtIntArray &face_indices,
|
|
|
|
|
pxr::VtIntArray &face_counts) const
|
|
|
|
|
{
|
|
|
|
|
Adapter adapter;
|
|
|
|
|
pxr::VtValue points_val = adapter.GetPoints(prim_, motionSampleTime);
|
|
|
|
|
|
|
|
|
|
if (points_val.IsHolding<pxr::VtVec3fArray>()) {
|
|
|
|
|
positions = points_val.Get<pxr::VtVec3fArray>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pxr::VtValue topology_val = adapter.GetTopology(prim_, pxr::SdfPath(), motionSampleTime);
|
|
|
|
|
|
|
|
|
|
if (topology_val.IsHolding<pxr::HdMeshTopology>()) {
|
|
|
|
|
const pxr::HdMeshTopology &topology = topology_val.Get<pxr::HdMeshTopology>();
|
|
|
|
|
face_counts = topology.GetFaceVertexCounts();
|
|
|
|
|
face_indices = topology.GetFaceVertexIndices();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool USDShapeReader::read_mesh_values(double motionSampleTime,
|
|
|
|
|
pxr::VtVec3fArray &positions,
|
|
|
|
|
pxr::VtIntArray &face_indices,
|
|
|
|
|
pxr::VtIntArray &face_counts) const
|
|
|
|
|
{
|
2025-02-21 22:54:09 +01:00
|
|
|
if (prim_.IsA<pxr::UsdGeomCapsule>() || prim_.IsA<pxr::UsdGeomCapsule_1>()) {
|
2023-02-13 19:49:24 +01:00
|
|
|
read_values<pxr::UsdImagingCapsuleAdapter>(
|
|
|
|
|
motionSampleTime, positions, face_indices, face_counts);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-21 22:54:09 +01:00
|
|
|
if (prim_.IsA<pxr::UsdGeomCylinder>() || prim_.IsA<pxr::UsdGeomCylinder_1>()) {
|
2023-02-13 19:49:24 +01:00
|
|
|
read_values<pxr::UsdImagingCylinderAdapter>(
|
|
|
|
|
motionSampleTime, positions, face_indices, face_counts);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (prim_.IsA<pxr::UsdGeomCone>()) {
|
|
|
|
|
read_values<pxr::UsdImagingConeAdapter>(
|
|
|
|
|
motionSampleTime, positions, face_indices, face_counts);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (prim_.IsA<pxr::UsdGeomCube>()) {
|
|
|
|
|
read_values<pxr::UsdImagingCubeAdapter>(
|
|
|
|
|
motionSampleTime, positions, face_indices, face_counts);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (prim_.IsA<pxr::UsdGeomSphere>()) {
|
|
|
|
|
read_values<pxr::UsdImagingSphereAdapter>(
|
|
|
|
|
motionSampleTime, positions, face_indices, face_counts);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-11 19:56:15 +01:00
|
|
|
if (prim_.IsA<pxr::UsdGeomPlane>()) {
|
|
|
|
|
read_values<pxr::UsdImagingPlaneAdapter>(
|
|
|
|
|
motionSampleTime, positions, face_indices, face_counts);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-13 11:46:02 +02:00
|
|
|
BKE_reportf(reports(),
|
|
|
|
|
RPT_ERROR,
|
|
|
|
|
"Unhandled Gprim type: %s (%s)",
|
|
|
|
|
prim_.GetTypeName().GetText(),
|
|
|
|
|
prim_.GetPath().GetText());
|
2023-02-13 19:49:24 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-25 13:31:18 +10:00
|
|
|
Mesh *USDShapeReader::read_mesh(Mesh *existing_mesh,
|
2023-02-22 11:22:48 -05:00
|
|
|
const USDMeshReadParams params,
|
2024-08-23 13:09:20 +10:00
|
|
|
const char ** /*r_err_str*/)
|
2023-02-13 19:49:24 +01:00
|
|
|
{
|
|
|
|
|
pxr::VtIntArray face_indices;
|
|
|
|
|
pxr::VtIntArray face_counts;
|
|
|
|
|
|
|
|
|
|
if (!prim_) {
|
|
|
|
|
return existing_mesh;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Should have a good set of data by this point-- copy over. */
|
2024-04-24 20:58:53 +02:00
|
|
|
Mesh *active_mesh = mesh_from_prim(existing_mesh, params, face_indices, face_counts);
|
|
|
|
|
|
2023-02-13 19:49:24 +01:00
|
|
|
if (active_mesh == existing_mesh) {
|
|
|
|
|
return existing_mesh;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-24 22:06:55 +02:00
|
|
|
MutableSpan<int> face_offsets = active_mesh->face_offsets_for_write();
|
|
|
|
|
for (const int i : IndexRange(active_mesh->faces_num)) {
|
|
|
|
|
face_offsets[i] = face_counts[i];
|
Mesh: Replace MPoly struct with offset indices
Implements #95967.
Currently the `MPoly` struct is 12 bytes, and stores the index of a
face's first corner and the number of corners/verts/edges. Polygons
and corners are always created in order by Blender, meaning each
face's corners will be after the previous face's corners. We can take
advantage of this fact and eliminate the redundancy in mesh face
storage by only storing a single integer corner offset for each face.
The size of the face is then encoded by the offset of the next face.
The size of a single integer is 4 bytes, so this reduces memory
usage by 3 times.
The same method is used for `CurvesGeometry`, so Blender already has
an abstraction to simplify using these offsets called `OffsetIndices`.
This class is used to easily retrieve a range of corner indices for
each face. This also gives the opportunity for sharing some logic with
curves.
Another benefit of the change is that the offsets and sizes stored in
`MPoly` can no longer disagree with each other. Storing faces in the
order of their corners can simplify some code too.
Face/polygon variables now use the `IndexRange` type, which comes with
quite a few utilities that can simplify code.
Some:
- The offset integer array has to be one longer than the face count to
avoid a branch for every face, which means the data is no longer part
of the mesh's `CustomData`.
- We lose the ability to "reference" an original mesh's offset array
until more reusable CoW from #104478 is committed. That will be added
in a separate commit.
- Since they aren't part of `CustomData`, poly offsets often have to be
copied manually.
- To simplify using `OffsetIndices` in many places, some functions and
structs in headers were moved to only compile in C++.
- All meshes created by Blender use the same order for faces and face
corners, but just in case, meshes with mismatched order are fixed by
versioning code.
- `MeshPolygon.totloop` is no longer editable in RNA. This API break is
necessary here unfortunately. It should be worth it in 3.6, since
that's the best way to allow loading meshes from 4.0, which is
important for an LTS version.
Pull Request: https://projects.blender.org/blender/blender/pulls/105938
2023-04-04 20:39:28 +02:00
|
|
|
}
|
2023-07-24 22:06:55 +02:00
|
|
|
offset_indices::accumulate_counts_to_offsets(face_offsets);
|
2023-02-13 19:49:24 +01:00
|
|
|
|
Mesh: Move face shade smooth flag to a generic attribute
Currently the shade smooth status for mesh faces is stored as part of
`MPoly::flag`. As described in #95967, this moves that information
to a separate boolean attribute. It also flips its status, so the
attribute is now called `sharp_face`, which mirrors the existing
`sharp_edge` attribute. The attribute doesn't need to be allocated
when all faces are smooth. Forward compatibility is kept until
4.0 like the other mesh refactors.
This will reduce memory bandwidth requirements for some operations,
since the array of booleans uses 12 times less memory than `MPoly`.
It also allows faces to be stored more efficiently in the future, since
the flag is now unused. It's also possible to use generic functions to
process the values. For example, finding whether there is a sharp face
is just `sharp_faces.contains(true)`.
The `shade_smooth` attribute is no longer accessible with geometry nodes.
Since there were dedicated accessor nodes for that data, that shouldn't
be a problem. That's difficult to version automatically since the named
attribute nodes could be used in arbitrary combinations.
**Implementation notes:**
- The attribute and array variables in the code use the `sharp_faces`
term, to be consistent with the user-facing "sharp faces" wording,
and to avoid requiring many renames when #101689 is implemented.
- Cycles now accesses smooth face status with the generic attribute,
to avoid overhead.
- Changing the zero-value from "smooth" to "flat" takes some care to
make sure defaults are the same.
- Versioning for the edge mode extrude node is particularly complex.
New nodes are added by versioning to propagate the attribute in its
old inverted state.
- A lot of access is still done through the `CustomData` API rather
than the attribute API because of a few functions. That can be
cleaned up easily in the future.
- In the future we would benefit from a way to store attributes as a
single value for when all faces are sharp.
Pull Request: https://projects.blender.org/blender/blender/pulls/104422
2023-03-08 15:36:18 +01:00
|
|
|
/* Don't smooth-shade cubes; we're not worrying about sharpness for Gprims. */
|
2023-12-13 09:50:24 -05:00
|
|
|
bke::mesh_smooth_set(*active_mesh, !prim_.IsA<pxr::UsdGeomCube>());
|
2023-02-13 19:49:24 +01:00
|
|
|
|
Mesh: Replace MPoly struct with offset indices
Implements #95967.
Currently the `MPoly` struct is 12 bytes, and stores the index of a
face's first corner and the number of corners/verts/edges. Polygons
and corners are always created in order by Blender, meaning each
face's corners will be after the previous face's corners. We can take
advantage of this fact and eliminate the redundancy in mesh face
storage by only storing a single integer corner offset for each face.
The size of the face is then encoded by the offset of the next face.
The size of a single integer is 4 bytes, so this reduces memory
usage by 3 times.
The same method is used for `CurvesGeometry`, so Blender already has
an abstraction to simplify using these offsets called `OffsetIndices`.
This class is used to easily retrieve a range of corner indices for
each face. This also gives the opportunity for sharing some logic with
curves.
Another benefit of the change is that the offsets and sizes stored in
`MPoly` can no longer disagree with each other. Storing faces in the
order of their corners can simplify some code too.
Face/polygon variables now use the `IndexRange` type, which comes with
quite a few utilities that can simplify code.
Some:
- The offset integer array has to be one longer than the face count to
avoid a branch for every face, which means the data is no longer part
of the mesh's `CustomData`.
- We lose the ability to "reference" an original mesh's offset array
until more reusable CoW from #104478 is committed. That will be added
in a separate commit.
- Since they aren't part of `CustomData`, poly offsets often have to be
copied manually.
- To simplify using `OffsetIndices` in many places, some functions and
structs in headers were moved to only compile in C++.
- All meshes created by Blender use the same order for faces and face
corners, but just in case, meshes with mismatched order are fixed by
versioning code.
- `MeshPolygon.totloop` is no longer editable in RNA. This API break is
necessary here unfortunately. It should be worth it in 3.6, since
that's the best way to allow loading meshes from 4.0, which is
important for an LTS version.
Pull Request: https://projects.blender.org/blender/blender/pulls/105938
2023-04-04 20:39:28 +02:00
|
|
|
MutableSpan<int> corner_verts = active_mesh->corner_verts_for_write();
|
|
|
|
|
for (const int i : corner_verts.index_range()) {
|
|
|
|
|
corner_verts[i] = face_indices[i];
|
2023-02-13 19:49:24 +01:00
|
|
|
}
|
|
|
|
|
|
2023-12-20 17:47:10 -05:00
|
|
|
bke::mesh_calc_edges(*active_mesh, false, false);
|
2023-02-13 19:49:24 +01:00
|
|
|
return active_mesh;
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-28 03:02:38 +01:00
|
|
|
void USDShapeReader::read_geometry(bke::GeometrySet &geometry_set,
|
|
|
|
|
USDMeshReadParams params,
|
2024-08-23 13:09:20 +10:00
|
|
|
const char **r_err_str)
|
2024-02-28 03:02:38 +01:00
|
|
|
{
|
|
|
|
|
Mesh *existing_mesh = geometry_set.get_mesh_for_write();
|
2024-08-23 13:09:20 +10:00
|
|
|
Mesh *new_mesh = read_mesh(existing_mesh, params, r_err_str);
|
2024-02-28 03:02:38 +01:00
|
|
|
|
|
|
|
|
if (new_mesh != existing_mesh) {
|
|
|
|
|
geometry_set.replace_mesh(new_mesh);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-24 20:58:53 +02:00
|
|
|
void USDShapeReader::apply_primvars_to_mesh(Mesh *mesh, const double motionSampleTime) const
|
|
|
|
|
{
|
|
|
|
|
/* TODO: also handle the displayOpacity primvar. */
|
|
|
|
|
if (!mesh || !prim_) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pxr::UsdGeomPrimvarsAPI pv_api = pxr::UsdGeomPrimvarsAPI(prim_);
|
|
|
|
|
std::vector<pxr::UsdGeomPrimvar> primvars = pv_api.GetPrimvarsWithValues();
|
|
|
|
|
|
|
|
|
|
pxr::TfToken active_color_name;
|
|
|
|
|
|
2024-08-04 22:42:08 +02:00
|
|
|
for (const pxr::UsdGeomPrimvar &pv : primvars) {
|
2025-01-09 00:16:18 +01:00
|
|
|
const pxr::SdfValueTypeName pv_type = pv.GetTypeName();
|
|
|
|
|
if (!pv_type.IsArray()) {
|
|
|
|
|
continue; /* Skip non-array primvar attributes. */
|
2024-04-24 20:58:53 +02:00
|
|
|
}
|
|
|
|
|
|
2024-08-04 22:42:08 +02:00
|
|
|
const pxr::TfToken name = pxr::UsdGeomPrimvar::StripPrimvarsName(pv.GetPrimvarName());
|
2024-04-24 20:58:53 +02:00
|
|
|
|
|
|
|
|
/* Skip reading primvars that have been read before and are not time varying. */
|
|
|
|
|
if (primvar_time_varying_map_.contains(name) && !primvar_time_varying_map_.lookup(name)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-09 00:16:18 +01:00
|
|
|
const std::optional<eCustomDataType> type = convert_usd_type_to_blender(pv_type);
|
2024-04-24 20:58:53 +02:00
|
|
|
if (type == CD_PROP_COLOR) {
|
|
|
|
|
/* Set the active color name to 'displayColor', if a color primvar
|
|
|
|
|
* with this name exists. Otherwise, use the name of the first
|
|
|
|
|
* color primvar we find for the active color. */
|
|
|
|
|
if (active_color_name.IsEmpty() || name == usdtokens::displayColor) {
|
|
|
|
|
active_color_name = name;
|
|
|
|
|
}
|
2024-09-24 19:05:55 +02:00
|
|
|
}
|
2024-04-24 20:58:53 +02:00
|
|
|
|
2024-09-24 19:05:55 +02:00
|
|
|
read_generic_mesh_primvar(mesh, pv, motionSampleTime, false);
|
2024-04-24 20:58:53 +02:00
|
|
|
|
2024-09-24 19:05:55 +02:00
|
|
|
/* Record whether the primvar attribute might be time varying. */
|
|
|
|
|
if (!primvar_time_varying_map_.contains(name)) {
|
|
|
|
|
primvar_time_varying_map_.add(name, pv.ValueMightBeTimeVarying());
|
2024-04-24 20:58:53 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!active_color_name.IsEmpty()) {
|
|
|
|
|
BKE_id_attributes_default_color_set(&mesh->id, active_color_name.GetText());
|
|
|
|
|
BKE_id_attributes_active_color_set(&mesh->id, active_color_name.GetText());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-13 19:49:24 +01:00
|
|
|
Mesh *USDShapeReader::mesh_from_prim(Mesh *existing_mesh,
|
2024-04-24 20:58:53 +02:00
|
|
|
const USDMeshReadParams params,
|
2023-02-13 19:49:24 +01:00
|
|
|
pxr::VtIntArray &face_indices,
|
|
|
|
|
pxr::VtIntArray &face_counts) const
|
|
|
|
|
{
|
|
|
|
|
pxr::VtVec3fArray positions;
|
|
|
|
|
|
2024-04-24 20:58:53 +02:00
|
|
|
if (!read_mesh_values(params.motion_sample_time, positions, face_indices, face_counts)) {
|
2023-02-13 19:49:24 +01:00
|
|
|
return existing_mesh;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-24 22:06:55 +02:00
|
|
|
const bool poly_counts_match = existing_mesh ? face_counts.size() == existing_mesh->faces_num :
|
2023-02-13 19:49:24 +01:00
|
|
|
false;
|
2023-12-20 02:21:48 +01:00
|
|
|
const bool position_counts_match = existing_mesh ? positions.size() == existing_mesh->verts_num :
|
2023-02-13 19:49:24 +01:00
|
|
|
false;
|
|
|
|
|
|
|
|
|
|
Mesh *active_mesh = nullptr;
|
|
|
|
|
if (!position_counts_match || !poly_counts_match) {
|
|
|
|
|
active_mesh = BKE_mesh_new_nomain_from_template(
|
2023-04-19 15:28:53 -04:00
|
|
|
existing_mesh, positions.size(), 0, face_counts.size(), face_indices.size());
|
2023-02-13 19:49:24 +01:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
active_mesh = existing_mesh;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MutableSpan<float3> vert_positions = active_mesh->vert_positions_for_write();
|
2024-09-23 21:16:44 +02:00
|
|
|
vert_positions.copy_from(Span(positions.data(), positions.size()).cast<float3>());
|
2023-02-13 19:49:24 +01:00
|
|
|
|
2024-04-24 20:58:53 +02:00
|
|
|
if (params.read_flags & MOD_MESHSEQ_READ_COLOR) {
|
|
|
|
|
if (active_mesh != existing_mesh) {
|
|
|
|
|
/* Clear the primvar map to force attributes to be reloaded. */
|
|
|
|
|
this->primvar_time_varying_map_.clear();
|
|
|
|
|
}
|
|
|
|
|
apply_primvars_to_mesh(active_mesh, params.motion_sample_time);
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-13 19:49:24 +01:00
|
|
|
return active_mesh;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool USDShapeReader::is_time_varying()
|
|
|
|
|
{
|
2024-04-24 20:58:53 +02:00
|
|
|
for (const bool animating_flag : primvar_time_varying_map_.values()) {
|
|
|
|
|
if (animating_flag) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-13 19:49:24 +01:00
|
|
|
if (prim_.IsA<pxr::UsdGeomCapsule>()) {
|
|
|
|
|
pxr::UsdGeomCapsule geom(prim_);
|
|
|
|
|
return (geom.GetAxisAttr().ValueMightBeTimeVarying() ||
|
|
|
|
|
geom.GetHeightAttr().ValueMightBeTimeVarying() ||
|
|
|
|
|
geom.GetRadiusAttr().ValueMightBeTimeVarying());
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-21 22:54:09 +01:00
|
|
|
if (prim_.IsA<pxr::UsdGeomCapsule_1>()) {
|
|
|
|
|
pxr::UsdGeomCapsule_1 geom(prim_);
|
|
|
|
|
return (geom.GetAxisAttr().ValueMightBeTimeVarying() ||
|
|
|
|
|
geom.GetHeightAttr().ValueMightBeTimeVarying() ||
|
|
|
|
|
geom.GetRadiusTopAttr().ValueMightBeTimeVarying() ||
|
|
|
|
|
geom.GetRadiusBottomAttr().ValueMightBeTimeVarying());
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-13 19:49:24 +01:00
|
|
|
if (prim_.IsA<pxr::UsdGeomCylinder>()) {
|
|
|
|
|
pxr::UsdGeomCylinder geom(prim_);
|
|
|
|
|
return (geom.GetAxisAttr().ValueMightBeTimeVarying() ||
|
|
|
|
|
geom.GetHeightAttr().ValueMightBeTimeVarying() ||
|
|
|
|
|
geom.GetRadiusAttr().ValueMightBeTimeVarying());
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-21 22:54:09 +01:00
|
|
|
if (prim_.IsA<pxr::UsdGeomCylinder_1>()) {
|
|
|
|
|
pxr::UsdGeomCylinder_1 geom(prim_);
|
|
|
|
|
return (geom.GetAxisAttr().ValueMightBeTimeVarying() ||
|
|
|
|
|
geom.GetHeightAttr().ValueMightBeTimeVarying() ||
|
|
|
|
|
geom.GetRadiusTopAttr().ValueMightBeTimeVarying() ||
|
|
|
|
|
geom.GetRadiusBottomAttr().ValueMightBeTimeVarying());
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-13 19:49:24 +01:00
|
|
|
if (prim_.IsA<pxr::UsdGeomCone>()) {
|
|
|
|
|
pxr::UsdGeomCone geom(prim_);
|
|
|
|
|
return (geom.GetAxisAttr().ValueMightBeTimeVarying() ||
|
|
|
|
|
geom.GetHeightAttr().ValueMightBeTimeVarying() ||
|
|
|
|
|
geom.GetRadiusAttr().ValueMightBeTimeVarying());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (prim_.IsA<pxr::UsdGeomCube>()) {
|
|
|
|
|
pxr::UsdGeomCube geom(prim_);
|
|
|
|
|
return geom.GetSizeAttr().ValueMightBeTimeVarying();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (prim_.IsA<pxr::UsdGeomSphere>()) {
|
|
|
|
|
pxr::UsdGeomSphere geom(prim_);
|
|
|
|
|
return geom.GetRadiusAttr().ValueMightBeTimeVarying();
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-11 19:56:15 +01:00
|
|
|
if (prim_.IsA<pxr::UsdGeomPlane>()) {
|
|
|
|
|
pxr::UsdGeomPlane geom(prim_);
|
|
|
|
|
return (geom.GetWidthAttr().ValueMightBeTimeVarying() ||
|
|
|
|
|
geom.GetLengthAttr().ValueMightBeTimeVarying() ||
|
|
|
|
|
geom.GetAxisAttr().ValueMightBeTimeVarying());
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-13 11:46:02 +02:00
|
|
|
BKE_reportf(reports(),
|
|
|
|
|
RPT_ERROR,
|
|
|
|
|
"Unhandled Gprim type: %s (%s)",
|
|
|
|
|
prim_.GetTypeName().GetText(),
|
|
|
|
|
prim_.GetPath().GetText());
|
2023-02-13 19:49:24 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace blender::io::usd
|