Blender V5.0
usd_reader_points.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
7
8#include "BKE_geometry_set.hh"
9#include "BKE_object.hh"
10#include "BKE_pointcloud.hh"
11
12#include "BLI_span.hh"
13
14#include "DNA_object_types.h"
16
17#include <pxr/usd/usdGeom/primvar.h>
18#include <pxr/usd/usdGeom/primvarsAPI.h>
19
20namespace blender::io::usd {
21
23{
24 PointCloud *pointcloud = BKE_pointcloud_add(bmain, name_.c_str());
26 object_->data = pointcloud;
27}
28
29void USDPointsReader::read_object_data(Main *bmain, pxr::UsdTimeCode time)
30{
31 const USDMeshReadParams params = create_mesh_read_params(time.GetValue(),
32 import_params_.mesh_read_flag);
33
34 PointCloud *pointcloud = static_cast<PointCloud *>(object_->data);
35
38
39 read_geometry(geometry_set, params, nullptr);
40
41 PointCloud *read_pointcloud =
42 geometry_set.get_component_for_write<bke::PointCloudComponent>().release();
43
44 if (read_pointcloud != pointcloud) {
45 BKE_pointcloud_nomain_to_pointcloud(read_pointcloud, pointcloud);
46 }
47
48 if (is_animated()) {
49 /* If the point cloud has animated positions or attributes, we add the cache
50 * modifier. */
52 }
53
54 /* Update the transform. */
56}
57
60 const char ** /*r_err_str*/)
61{
62 PointCloud *pointcloud = geometry_set.get_pointcloud_for_write();
63
64 /* Get the existing point cloud data. */
65 pxr::VtVec3fArray usd_positions;
66 points_prim_.GetPointsAttr().Get(&usd_positions, params.motion_sample_time);
67
68 if (pointcloud->totpoint != usd_positions.size()) {
69 /* Size changed so we must reallocate. */
70 pointcloud = BKE_pointcloud_new_nomain(usd_positions.size());
71 }
72
73 /* Update point positions and radii */
74 static_assert(sizeof(pxr::GfVec3f) == sizeof(float3));
75 MutableSpan<float3> positions = pointcloud->positions_for_write();
76 positions.copy_from(Span(usd_positions.cdata(), usd_positions.size()).cast<float3>());
77
78 pxr::VtFloatArray usd_widths;
79 points_prim_.GetWidthsAttr().Get(&usd_widths, params.motion_sample_time);
80
81 if (!usd_widths.empty()) {
82 MutableSpan<float> radii = pointcloud->radius_for_write();
83 Span<float> widths = Span(usd_widths.cdata(), usd_widths.size());
84
85 const pxr::TfToken widths_interp = points_prim_.GetWidthsInterpolation();
86 if (widths_interp == pxr::UsdGeomTokens->constant) {
87 radii.fill(widths[0] / 2.0f);
88 }
89 else {
90 for (int i_point = 0; i_point < widths.size(); i_point++) {
91 radii[i_point] = widths[i_point] / 2.0f;
92 }
93 }
94 }
95
96 /* TODO: Read in ID and normal data.
97 * See UsdGeomPoints::GetIdsAttr and UsdGeomPointBased::GetNormalsAttr */
98
99 /* Read in velocity and generic data. */
100 read_velocities(pointcloud, params.motion_sample_time);
101 read_custom_data(pointcloud, params.motion_sample_time);
102
103 geometry_set.replace_pointcloud(pointcloud);
104}
105
106void USDPointsReader::read_velocities(PointCloud *pointcloud, const pxr::UsdTimeCode time) const
107{
108 pxr::VtVec3fArray velocities;
109 points_prim_.GetVelocitiesAttr().Get(&velocities, time);
110
111 if (!velocities.empty()) {
112 bke::MutableAttributeAccessor attributes = pointcloud->attributes_for_write();
115
116 Span<pxr::GfVec3f> usd_data(velocities.cdata(), velocities.size());
117 velocity.span.copy_from(usd_data.cast<float3>());
118 velocity.finish();
119 }
120}
121
122void USDPointsReader::read_custom_data(PointCloud *pointcloud, const pxr::UsdTimeCode time) const
123{
124 pxr::UsdGeomPrimvarsAPI pv_api(points_prim_);
125
126 std::vector<pxr::UsdGeomPrimvar> primvars = pv_api.GetPrimvarsWithValues();
127 for (const pxr::UsdGeomPrimvar &pv : primvars) {
128 const pxr::SdfValueTypeName pv_type = pv.GetTypeName();
129 if (!pv_type.IsArray()) {
130 continue; /* Skip non-array primvar attributes. */
131 }
132
134 const std::optional<bke::AttrType> type = convert_usd_type_to_blender(pv_type);
135 if (!type.has_value()) {
136 return;
137 }
138
139 bke::MutableAttributeAccessor attributes = pointcloud->attributes_for_write();
140 copy_primvar_to_blender_attribute(pv, time, *type, domain, {}, attributes);
141 }
142}
143
145{
146 if (!points_prim_) {
147 return false;
148 }
149
150 bool is_animated = false;
151
152 is_animated |= points_prim_.GetPointsAttr().ValueMightBeTimeVarying();
153
154 is_animated |= points_prim_.GetVelocitiesAttr().ValueMightBeTimeVarying();
155
156 is_animated |= points_prim_.GetWidthsAttr().ValueMightBeTimeVarying();
157
158 pxr::UsdGeomPrimvarsAPI pv_api(points_prim_);
159 std::vector<pxr::UsdGeomPrimvar> primvars = pv_api.GetPrimvarsWithValues();
160 for (const pxr::UsdGeomPrimvar &pv : primvars) {
161 is_animated |= pv.ValueMightBeTimeVarying();
162 }
163
164 return is_animated;
165}
166
167} // namespace blender::io::usd
General operations, lookup, etc. for blender objects.
Object * BKE_object_add_only_object(Main *bmain, int type, const char *name) ATTR_RETURNS_NONNULL
General operations for point clouds.
PointCloud * BKE_pointcloud_add(Main *bmain, const char *name)
void BKE_pointcloud_nomain_to_pointcloud(PointCloud *pointcloud_src, PointCloud *pointcloud_dst)
PointCloud * BKE_pointcloud_new_nomain(int totpoint)
Object is a sort of wrapper for general info.
@ OB_POINTCLOUD
constexpr void fill(const T &value) const
Definition BLI_span.hh:517
constexpr void copy_from(Span< T > values) const
Definition BLI_span.hh:739
Span< NewT > constexpr cast() const
Definition BLI_span.hh:418
constexpr int64_t size() const
Definition BLI_span.hh:252
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, AttrType data_type)
void read_velocities(PointCloud *pointcloud, const pxr::UsdTimeCode time) const
void create_object(Main *bmain) override
void read_geometry(bke::GeometrySet &geometry_set, USDMeshReadParams params, const char **r_err_str) override
void read_custom_data(PointCloud *pointcloud, const pxr::UsdTimeCode time) const
void read_object_data(Main *bmain, pxr::UsdTimeCode time) override
const USDImportParams & import_params_
void read_object_data(Main *bmain, pxr::UsdTimeCode time) override
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
USDMeshReadParams create_mesh_read_params(const double motion_sample_time, const int read_flags)
void copy_primvar_to_blender_attribute(const pxr::UsdGeomPrimvar &primvar, const pxr::UsdTimeCode time, const bke::AttrType data_type, const bke::AttrDomain domain, const OffsetIndices< int > face_indices, bke::MutableAttributeAccessor attributes)
std::optional< bke::AttrType > convert_usd_type_to_blender(const pxr::SdfValueTypeName usd_type)
VecBase< float, 3 > float3
GeometryComponent & get_component_for_write(GeometryComponent::Type component_type)
PointCloud * get_pointcloud_for_write()
void replace_pointcloud(PointCloud *pointcloud, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
static GeometrySet from_pointcloud(PointCloud *pointcloud, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)