The `motionSampleTime` argument to `create_object` has been unused since the dawn of time, and it's not expected to be used in the future either. Remove the clutter. Pull Request: https://projects.blender.org/blender/blender/pulls/136587
168 lines
5.4 KiB
C++
168 lines
5.4 KiB
C++
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
#include "usd_reader_points.hh"
|
|
#include "usd_attribute_utils.hh"
|
|
|
|
#include "BKE_geometry_set.hh"
|
|
#include "BKE_object.hh"
|
|
#include "BKE_pointcloud.hh"
|
|
|
|
#include "BLI_span.hh"
|
|
|
|
#include "DNA_object_types.h"
|
|
#include "DNA_pointcloud_types.h"
|
|
|
|
#include <pxr/usd/usdGeom/primvar.h>
|
|
#include <pxr/usd/usdGeom/primvarsAPI.h>
|
|
|
|
namespace blender::io::usd {
|
|
|
|
void USDPointsReader::create_object(Main *bmain)
|
|
{
|
|
PointCloud *pointcloud = BKE_pointcloud_add(bmain, name_.c_str());
|
|
object_ = BKE_object_add_only_object(bmain, OB_POINTCLOUD, name_.c_str());
|
|
object_->data = pointcloud;
|
|
}
|
|
|
|
void USDPointsReader::read_object_data(Main *bmain, double motionSampleTime)
|
|
{
|
|
const USDMeshReadParams params = create_mesh_read_params(motionSampleTime,
|
|
import_params_.mesh_read_flag);
|
|
|
|
PointCloud *pointcloud = static_cast<PointCloud *>(object_->data);
|
|
|
|
bke::GeometrySet geometry_set = bke::GeometrySet::from_pointcloud(
|
|
pointcloud, bke::GeometryOwnershipType::Editable);
|
|
|
|
read_geometry(geometry_set, params, nullptr);
|
|
|
|
PointCloud *read_pointcloud =
|
|
geometry_set.get_component_for_write<bke::PointCloudComponent>().release();
|
|
|
|
if (read_pointcloud != pointcloud) {
|
|
BKE_pointcloud_nomain_to_pointcloud(read_pointcloud, pointcloud);
|
|
}
|
|
|
|
if (is_animated()) {
|
|
/* If the point cloud has animated positions or attributes, we add the cache
|
|
* modifier. */
|
|
add_cache_modifier();
|
|
}
|
|
|
|
/* Update the transform. */
|
|
USDXformReader::read_object_data(bmain, motionSampleTime);
|
|
}
|
|
|
|
void USDPointsReader::read_geometry(bke::GeometrySet &geometry_set,
|
|
USDMeshReadParams params,
|
|
const char ** /*r_err_str*/)
|
|
{
|
|
PointCloud *pointcloud = geometry_set.get_pointcloud_for_write();
|
|
|
|
/* Get the existing point cloud data. */
|
|
pxr::VtVec3fArray usd_positions;
|
|
points_prim_.GetPointsAttr().Get(&usd_positions, params.motion_sample_time);
|
|
|
|
if (pointcloud->totpoint != usd_positions.size()) {
|
|
/* Size changed so we must reallocate. */
|
|
pointcloud = BKE_pointcloud_new_nomain(usd_positions.size());
|
|
}
|
|
|
|
/* Update point positions and radii */
|
|
static_assert(sizeof(pxr::GfVec3f) == sizeof(float3));
|
|
MutableSpan<float3> positions = pointcloud->positions_for_write();
|
|
positions.copy_from(Span(usd_positions.cdata(), usd_positions.size()).cast<float3>());
|
|
|
|
pxr::VtFloatArray usd_widths;
|
|
points_prim_.GetWidthsAttr().Get(&usd_widths, params.motion_sample_time);
|
|
|
|
if (!usd_widths.empty()) {
|
|
MutableSpan<float> radii = pointcloud->radius_for_write();
|
|
Span<float> widths = Span(usd_widths.cdata(), usd_widths.size());
|
|
|
|
const pxr::TfToken widths_interp = points_prim_.GetWidthsInterpolation();
|
|
if (widths_interp == pxr::UsdGeomTokens->constant) {
|
|
radii.fill(widths[0] / 2.0f);
|
|
}
|
|
else {
|
|
for (int i_point = 0; i_point < widths.size(); i_point++) {
|
|
radii[i_point] = widths[i_point] / 2.0f;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* TODO: Read in ID and normal data.
|
|
* See UsdGeomPoints::GetIdsAttr and UsdGeomPointBased::GetNormalsAttr */
|
|
|
|
/* Read in velocity and generic data. */
|
|
read_velocities(pointcloud, params.motion_sample_time);
|
|
read_custom_data(pointcloud, params.motion_sample_time);
|
|
|
|
geometry_set.replace_pointcloud(pointcloud);
|
|
}
|
|
|
|
void USDPointsReader::read_velocities(PointCloud *pointcloud, const double motionSampleTime) const
|
|
{
|
|
pxr::VtVec3fArray velocities;
|
|
points_prim_.GetVelocitiesAttr().Get(&velocities, motionSampleTime);
|
|
|
|
if (!velocities.empty()) {
|
|
bke::MutableAttributeAccessor attributes = pointcloud->attributes_for_write();
|
|
bke::SpanAttributeWriter<float3> velocity =
|
|
attributes.lookup_or_add_for_write_only_span<float3>("velocity", bke::AttrDomain::Point);
|
|
|
|
Span<pxr::GfVec3f> usd_data(velocities.cdata(), velocities.size());
|
|
velocity.span.copy_from(usd_data.cast<float3>());
|
|
velocity.finish();
|
|
}
|
|
}
|
|
|
|
void USDPointsReader::read_custom_data(PointCloud *pointcloud, const double motionSampleTime) const
|
|
{
|
|
pxr::UsdGeomPrimvarsAPI pv_api(points_prim_);
|
|
|
|
std::vector<pxr::UsdGeomPrimvar> primvars = pv_api.GetPrimvarsWithValues();
|
|
for (const pxr::UsdGeomPrimvar &pv : primvars) {
|
|
const pxr::SdfValueTypeName pv_type = pv.GetTypeName();
|
|
if (!pv_type.IsArray()) {
|
|
continue; /* Skip non-array primvar attributes. */
|
|
}
|
|
|
|
const bke::AttrDomain domain = bke::AttrDomain::Point;
|
|
const std::optional<eCustomDataType> type = convert_usd_type_to_blender(pv_type);
|
|
if (!type.has_value()) {
|
|
return;
|
|
}
|
|
|
|
bke::MutableAttributeAccessor attributes = pointcloud->attributes_for_write();
|
|
copy_primvar_to_blender_attribute(pv, motionSampleTime, *type, domain, {}, attributes);
|
|
}
|
|
}
|
|
|
|
bool USDPointsReader::is_animated() const
|
|
{
|
|
if (!points_prim_) {
|
|
return false;
|
|
}
|
|
|
|
bool is_animated = false;
|
|
|
|
is_animated |= points_prim_.GetPointsAttr().ValueMightBeTimeVarying();
|
|
|
|
is_animated |= points_prim_.GetVelocitiesAttr().ValueMightBeTimeVarying();
|
|
|
|
is_animated |= points_prim_.GetWidthsAttr().ValueMightBeTimeVarying();
|
|
|
|
pxr::UsdGeomPrimvarsAPI pv_api(points_prim_);
|
|
std::vector<pxr::UsdGeomPrimvar> primvars = pv_api.GetPrimvarsWithValues();
|
|
for (const pxr::UsdGeomPrimvar &pv : primvars) {
|
|
is_animated |= pv.ValueMightBeTimeVarying();
|
|
}
|
|
|
|
return is_animated;
|
|
}
|
|
|
|
} // namespace blender::io::usd
|