Point Cloud: Remove redundant custom data pointers
Similar to e9f82d3dc7, but for point clouds instead.
Differential Revision: https://developer.blender.org/D15487
			
			
This commit is contained in:
		@@ -1,8 +1,10 @@
 | 
			
		||||
/* SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 * Copyright 2011-2022 Blender Foundation */
 | 
			
		||||
 | 
			
		||||
#include "scene/pointcloud.h"
 | 
			
		||||
#include <optional>
 | 
			
		||||
 | 
			
		||||
#include "scene/attribute.h"
 | 
			
		||||
#include "scene/pointcloud.h"
 | 
			
		||||
#include "scene/scene.h"
 | 
			
		||||
 | 
			
		||||
#include "blender/sync.h"
 | 
			
		||||
@@ -138,6 +140,36 @@ static void copy_attributes(PointCloud *pointcloud,
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static std::optional<BL::FloatAttribute> find_radius_attribute(BL::PointCloud b_pointcloud)
 | 
			
		||||
{
 | 
			
		||||
  for (BL::Attribute &b_attribute : b_pointcloud.attributes) {
 | 
			
		||||
    if (b_attribute.name() != "radius") {
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
    if (b_attribute.data_type() != BL::Attribute::data_type_FLOAT) {
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
    return BL::FloatAttribute{b_attribute};
 | 
			
		||||
  }
 | 
			
		||||
  return std::nullopt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static BL::FloatVectorAttribute find_position_attribute(BL::PointCloud b_pointcloud)
 | 
			
		||||
{
 | 
			
		||||
  for (BL::Attribute &b_attribute : b_pointcloud.attributes) {
 | 
			
		||||
    if (b_attribute.name() != "position") {
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
    if (b_attribute.data_type() != BL::Attribute::data_type_FLOAT_VECTOR) {
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
    return BL::FloatVectorAttribute{b_attribute};
 | 
			
		||||
  }
 | 
			
		||||
  /* The position attribute must exist. */
 | 
			
		||||
  assert(false);
 | 
			
		||||
  return BL::FloatVectorAttribute{b_pointcloud.attributes[0]};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void export_pointcloud(Scene *scene,
 | 
			
		||||
                              PointCloud *pointcloud,
 | 
			
		||||
                              BL::PointCloud b_pointcloud,
 | 
			
		||||
@@ -156,18 +188,18 @@ static void export_pointcloud(Scene *scene,
 | 
			
		||||
  const int num_points = b_pointcloud.points.length();
 | 
			
		||||
  pointcloud->reserve(num_points);
 | 
			
		||||
 | 
			
		||||
  BL::FloatVectorAttribute b_attr_position = find_position_attribute(b_pointcloud);
 | 
			
		||||
  std::optional<BL::FloatAttribute> b_attr_radius = find_radius_attribute(b_pointcloud);
 | 
			
		||||
 | 
			
		||||
  /* Export points. */
 | 
			
		||||
  BL::PointCloud::points_iterator b_point_iter;
 | 
			
		||||
  for (b_pointcloud.points.begin(b_point_iter); b_point_iter != b_pointcloud.points.end();
 | 
			
		||||
       ++b_point_iter) {
 | 
			
		||||
    BL::Point b_point = *b_point_iter;
 | 
			
		||||
    const float3 co = get_float3(b_point.co());
 | 
			
		||||
    const float radius = b_point.radius();
 | 
			
		||||
  for (int i = 0; i < num_points; i++) {
 | 
			
		||||
    const float3 co = get_float3(b_attr_position.data[i].vector());
 | 
			
		||||
    const float radius = b_attr_radius ? b_attr_radius->data[i].value() : 0.0f;
 | 
			
		||||
    pointcloud->add_point(co, radius);
 | 
			
		||||
 | 
			
		||||
    /* Random number per point. */
 | 
			
		||||
    if (attr_random != NULL) {
 | 
			
		||||
      attr_random->add(hash_uint2_to_float(b_point.index(), 0));
 | 
			
		||||
      attr_random->add(hash_uint2_to_float(i, 0));
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -195,14 +227,15 @@ static void export_pointcloud_motion(PointCloud *pointcloud,
 | 
			
		||||
  int num_motion_points = 0;
 | 
			
		||||
  const array<float3> &pointcloud_points = pointcloud->get_points();
 | 
			
		||||
 | 
			
		||||
  BL::PointCloud::points_iterator b_point_iter;
 | 
			
		||||
  for (b_pointcloud.points.begin(b_point_iter); b_point_iter != b_pointcloud.points.end();
 | 
			
		||||
       ++b_point_iter) {
 | 
			
		||||
    BL::Point b_point = *b_point_iter;
 | 
			
		||||
  BL::FloatVectorAttribute b_attr_position = find_position_attribute(b_pointcloud);
 | 
			
		||||
  std::optional<BL::FloatAttribute> b_attr_radius = find_radius_attribute(b_pointcloud);
 | 
			
		||||
 | 
			
		||||
  for (int i = 0; i < num_points; i++) {
 | 
			
		||||
    if (num_motion_points < num_points) {
 | 
			
		||||
      float3 P = get_float3(b_point.co());
 | 
			
		||||
      P.w = b_point.radius();
 | 
			
		||||
      const float3 co = get_float3(b_attr_position.data[i].vector());
 | 
			
		||||
      const float radius = b_attr_radius ? b_attr_radius->data[i].value() : 0.0f;
 | 
			
		||||
      float3 P = co;
 | 
			
		||||
      P.w = radius;
 | 
			
		||||
      mP[num_motion_points] = P;
 | 
			
		||||
      have_motion = have_motion || (P != pointcloud_points[num_motion_points]);
 | 
			
		||||
      num_motion_points++;
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,6 @@ struct PointCloud *BKE_pointcloud_new_nomain(int totpoint);
 | 
			
		||||
struct BoundBox *BKE_pointcloud_boundbox_get(struct Object *ob);
 | 
			
		||||
bool BKE_pointcloud_minmax(const struct PointCloud *pointcloud, float r_min[3], float r_max[3]);
 | 
			
		||||
 | 
			
		||||
void BKE_pointcloud_update_customdata_pointers(struct PointCloud *pointcloud);
 | 
			
		||||
bool BKE_pointcloud_customdata_required(const struct PointCloud *pointcloud, const char *name);
 | 
			
		||||
 | 
			
		||||
/* Dependency Graph */
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,7 @@
 | 
			
		||||
#include "BLI_threads.h"
 | 
			
		||||
#include "BLI_utildefines.h"
 | 
			
		||||
 | 
			
		||||
#include "BKE_attribute.hh"
 | 
			
		||||
#include "BKE_bvhutils.h"
 | 
			
		||||
#include "BKE_editmesh.h"
 | 
			
		||||
#include "BKE_mesh.h"
 | 
			
		||||
@@ -1430,13 +1431,17 @@ BVHTree *BKE_bvhtree_from_pointcloud_get(BVHTreeFromPointCloud *data,
 | 
			
		||||
    return nullptr;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  for (int i = 0; i < pointcloud->totpoint; i++) {
 | 
			
		||||
    BLI_bvhtree_insert(tree, i, pointcloud->co[i], 1);
 | 
			
		||||
  blender::bke::AttributeAccessor attributes = blender::bke::pointcloud_attributes(*pointcloud);
 | 
			
		||||
  blender::VArraySpan<blender::float3> positions = attributes.lookup_or_default<blender::float3>(
 | 
			
		||||
      "position", ATTR_DOMAIN_POINT, blender::float3(0));
 | 
			
		||||
 | 
			
		||||
  for (const int i : positions.index_range()) {
 | 
			
		||||
    BLI_bvhtree_insert(tree, i, positions[i], 1);
 | 
			
		||||
  }
 | 
			
		||||
  BLI_assert(BLI_bvhtree_get_len(tree) == pointcloud->totpoint);
 | 
			
		||||
  bvhtree_balance(tree, false);
 | 
			
		||||
 | 
			
		||||
  data->coords = pointcloud->co;
 | 
			
		||||
  data->coords = (const float(*)[3])positions.data();
 | 
			
		||||
  data->tree = tree;
 | 
			
		||||
  data->nearest_callback = nullptr;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -111,10 +111,7 @@ namespace blender::bke {
 | 
			
		||||
 */
 | 
			
		||||
static ComponentAttributeProviders create_attribute_providers_for_point_cloud()
 | 
			
		||||
{
 | 
			
		||||
  static auto update_custom_data_pointers = [](void *owner) {
 | 
			
		||||
    PointCloud *pointcloud = static_cast<PointCloud *>(owner);
 | 
			
		||||
    BKE_pointcloud_update_customdata_pointers(pointcloud);
 | 
			
		||||
  };
 | 
			
		||||
  static auto update_custom_data_pointers = [](void * /*owner*/) {};
 | 
			
		||||
  static CustomDataAccessInfo point_access = {
 | 
			
		||||
      [](void *owner) -> CustomData * {
 | 
			
		||||
        PointCloud *pointcloud = static_cast<PointCloud *>(owner);
 | 
			
		||||
 
 | 
			
		||||
@@ -751,6 +751,8 @@ void BKE_mesh_to_curve(Main *bmain, Depsgraph *depsgraph, Scene *UNUSED(scene),
 | 
			
		||||
 | 
			
		||||
void BKE_pointcloud_from_mesh(Mesh *me, PointCloud *pointcloud)
 | 
			
		||||
{
 | 
			
		||||
  using namespace blender;
 | 
			
		||||
 | 
			
		||||
  BLI_assert(me != nullptr);
 | 
			
		||||
 | 
			
		||||
  pointcloud->totpoint = me->totvert;
 | 
			
		||||
@@ -758,14 +760,17 @@ void BKE_pointcloud_from_mesh(Mesh *me, PointCloud *pointcloud)
 | 
			
		||||
 | 
			
		||||
  /* Copy over all attributes. */
 | 
			
		||||
  CustomData_merge(&me->vdata, &pointcloud->pdata, CD_MASK_PROP_ALL, CD_DUPLICATE, me->totvert);
 | 
			
		||||
  BKE_pointcloud_update_customdata_pointers(pointcloud);
 | 
			
		||||
  CustomData_update_typemap(&pointcloud->pdata);
 | 
			
		||||
 | 
			
		||||
  MVert *mvert;
 | 
			
		||||
  mvert = me->mvert;
 | 
			
		||||
  for (int i = 0; i < me->totvert; i++, mvert++) {
 | 
			
		||||
    copy_v3_v3(pointcloud->co[i], mvert->co);
 | 
			
		||||
  }
 | 
			
		||||
  bke::AttributeAccessor mesh_attributes = bke::mesh_attributes(*me);
 | 
			
		||||
  bke::MutableAttributeAccessor point_attributes = bke::pointcloud_attributes_for_write(
 | 
			
		||||
      *pointcloud);
 | 
			
		||||
 | 
			
		||||
  const VArray<float3> mesh_positions = mesh_attributes.lookup_or_default<float3>(
 | 
			
		||||
      "position", ATTR_DOMAIN_POINT, float3(0));
 | 
			
		||||
  bke::SpanAttributeWriter<float3> point_positions =
 | 
			
		||||
      point_attributes.lookup_or_add_for_write_only_span<float3>("position", ATTR_DOMAIN_POINT);
 | 
			
		||||
  mesh_positions.materialize(point_positions.span);
 | 
			
		||||
  point_positions.finish();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BKE_mesh_to_pointcloud(Main *bmain, Depsgraph *depsgraph, Scene *UNUSED(scene), Object *ob)
 | 
			
		||||
 
 | 
			
		||||
@@ -68,7 +68,6 @@ static void pointcloud_init_data(ID *id)
 | 
			
		||||
                             nullptr,
 | 
			
		||||
                             pointcloud->totpoint,
 | 
			
		||||
                             POINTCLOUD_ATTR_POSITION);
 | 
			
		||||
  BKE_pointcloud_update_customdata_pointers(pointcloud);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void pointcloud_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, const int flag)
 | 
			
		||||
@@ -83,7 +82,6 @@ static void pointcloud_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_s
 | 
			
		||||
                  CD_MASK_ALL,
 | 
			
		||||
                  alloc_type,
 | 
			
		||||
                  pointcloud_dst->totpoint);
 | 
			
		||||
  BKE_pointcloud_update_customdata_pointers(pointcloud_dst);
 | 
			
		||||
 | 
			
		||||
  pointcloud_dst->batch_cache = nullptr;
 | 
			
		||||
}
 | 
			
		||||
@@ -138,7 +136,6 @@ static void pointcloud_blend_read_data(BlendDataReader *reader, ID *id)
 | 
			
		||||
 | 
			
		||||
  /* Geometry */
 | 
			
		||||
  CustomData_blend_read(reader, &pointcloud->pdata, pointcloud->totpoint);
 | 
			
		||||
  BKE_pointcloud_update_customdata_pointers(pointcloud);
 | 
			
		||||
 | 
			
		||||
  /* Materials */
 | 
			
		||||
  BLO_read_pointer_array(reader, (void **)&pointcloud->mat);
 | 
			
		||||
@@ -194,17 +191,28 @@ static void pointcloud_random(PointCloud *pointcloud)
 | 
			
		||||
{
 | 
			
		||||
  pointcloud->totpoint = 400;
 | 
			
		||||
  CustomData_realloc(&pointcloud->pdata, pointcloud->totpoint);
 | 
			
		||||
  BKE_pointcloud_update_customdata_pointers(pointcloud);
 | 
			
		||||
 | 
			
		||||
  RNG *rng = BLI_rng_new(0);
 | 
			
		||||
 | 
			
		||||
  for (int i = 0; i < pointcloud->totpoint; i++) {
 | 
			
		||||
    pointcloud->co[i][0] = 2.0f * BLI_rng_get_float(rng) - 1.0f;
 | 
			
		||||
    pointcloud->co[i][1] = 2.0f * BLI_rng_get_float(rng) - 1.0f;
 | 
			
		||||
    pointcloud->co[i][2] = 2.0f * BLI_rng_get_float(rng) - 1.0f;
 | 
			
		||||
    pointcloud->radius[i] = 0.05f * BLI_rng_get_float(rng);
 | 
			
		||||
  blender::bke::MutableAttributeAccessor attributes =
 | 
			
		||||
      blender::bke::pointcloud_attributes_for_write(*pointcloud);
 | 
			
		||||
  blender::bke::SpanAttributeWriter positions =
 | 
			
		||||
      attributes.lookup_or_add_for_write_only_span<float3>(POINTCLOUD_ATTR_POSITION,
 | 
			
		||||
                                                           ATTR_DOMAIN_POINT);
 | 
			
		||||
  blender::bke::SpanAttributeWriter<float> radii =
 | 
			
		||||
      attributes.lookup_or_add_for_write_only_span<float>(POINTCLOUD_ATTR_RADIUS,
 | 
			
		||||
                                                          ATTR_DOMAIN_POINT);
 | 
			
		||||
 | 
			
		||||
  for (const int i : positions.span.index_range()) {
 | 
			
		||||
    positions.span[i] =
 | 
			
		||||
        float3(BLI_rng_get_float(rng), BLI_rng_get_float(rng), BLI_rng_get_float(rng)) * 2.0f -
 | 
			
		||||
        1.0f;
 | 
			
		||||
    radii.span[i] = 0.05f * BLI_rng_get_float(rng);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  positions.finish();
 | 
			
		||||
  radii.finish();
 | 
			
		||||
 | 
			
		||||
  BLI_rng_free(rng);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -250,7 +258,6 @@ PointCloud *BKE_pointcloud_new_nomain(const int totpoint)
 | 
			
		||||
 | 
			
		||||
  pointcloud->totpoint = totpoint;
 | 
			
		||||
  CustomData_realloc(&pointcloud->pdata, pointcloud->totpoint);
 | 
			
		||||
  BKE_pointcloud_update_customdata_pointers(pointcloud);
 | 
			
		||||
 | 
			
		||||
  return pointcloud;
 | 
			
		||||
}
 | 
			
		||||
@@ -258,10 +265,14 @@ PointCloud *BKE_pointcloud_new_nomain(const int totpoint)
 | 
			
		||||
static std::optional<blender::bounds::MinMaxResult<float3>> point_cloud_bounds(
 | 
			
		||||
    const PointCloud &pointcloud)
 | 
			
		||||
{
 | 
			
		||||
  Span<float3> positions{reinterpret_cast<float3 *>(pointcloud.co), pointcloud.totpoint};
 | 
			
		||||
  if (pointcloud.radius) {
 | 
			
		||||
    Span<float> radii{pointcloud.radius, pointcloud.totpoint};
 | 
			
		||||
    return blender::bounds::min_max_with_radii(positions, radii);
 | 
			
		||||
  blender::bke::AttributeAccessor attributes = blender::bke::pointcloud_attributes(pointcloud);
 | 
			
		||||
  blender::VArraySpan<float3> positions = attributes.lookup_or_default<float3>(
 | 
			
		||||
      POINTCLOUD_ATTR_POSITION, ATTR_DOMAIN_POINT, float3(0));
 | 
			
		||||
  blender::VArray<float> radii = attributes.lookup_or_default<float>(
 | 
			
		||||
      POINTCLOUD_ATTR_RADIUS, ATTR_DOMAIN_POINT, 0.0f);
 | 
			
		||||
 | 
			
		||||
  if (!(radii.is_single() && radii.get_internal_single() == 0.0f)) {
 | 
			
		||||
    return blender::bounds::min_max_with_radii(positions, radii.get_internal_span());
 | 
			
		||||
  }
 | 
			
		||||
  return blender::bounds::min_max(positions);
 | 
			
		||||
}
 | 
			
		||||
@@ -307,14 +318,6 @@ BoundBox *BKE_pointcloud_boundbox_get(Object *ob)
 | 
			
		||||
  return ob->runtime.bb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BKE_pointcloud_update_customdata_pointers(PointCloud *pointcloud)
 | 
			
		||||
{
 | 
			
		||||
  pointcloud->co = static_cast<float(*)[3]>(
 | 
			
		||||
      CustomData_get_layer_named(&pointcloud->pdata, CD_PROP_FLOAT3, POINTCLOUD_ATTR_POSITION));
 | 
			
		||||
  pointcloud->radius = static_cast<float *>(
 | 
			
		||||
      CustomData_get_layer_named(&pointcloud->pdata, CD_PROP_FLOAT, POINTCLOUD_ATTR_RADIUS));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool BKE_pointcloud_customdata_required(const PointCloud *UNUSED(pointcloud), const char *name)
 | 
			
		||||
{
 | 
			
		||||
  return STREQ(name, POINTCLOUD_ATTR_POSITION);
 | 
			
		||||
@@ -334,7 +337,6 @@ PointCloud *BKE_pointcloud_new_for_eval(const PointCloud *pointcloud_src, int to
 | 
			
		||||
  pointcloud_dst->totpoint = totpoint;
 | 
			
		||||
  CustomData_copy(
 | 
			
		||||
      &pointcloud_src->pdata, &pointcloud_dst->pdata, CD_MASK_ALL, CD_CALLOC, totpoint);
 | 
			
		||||
  BKE_pointcloud_update_customdata_pointers(pointcloud_dst);
 | 
			
		||||
 | 
			
		||||
  return pointcloud_dst;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,7 @@
 | 
			
		||||
#include "DNA_object_types.h"
 | 
			
		||||
#include "DNA_pointcloud_types.h"
 | 
			
		||||
 | 
			
		||||
#include "BKE_customdata.h"
 | 
			
		||||
#include "BKE_pointcloud.h"
 | 
			
		||||
 | 
			
		||||
#include "GPU_batch.h"
 | 
			
		||||
@@ -139,7 +140,11 @@ static void pointcloud_batch_cache_ensure_pos(Object *ob, PointCloudBatchCache *
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  PointCloud *pointcloud = ob->data;
 | 
			
		||||
  const bool has_radius = pointcloud->radius != NULL;
 | 
			
		||||
  const float(*positions)[3] = (float(*)[3])CustomData_get_layer_named(
 | 
			
		||||
      &pointcloud->pdata, CD_PROP_FLOAT3, "position");
 | 
			
		||||
  const float *radii = (float *)CustomData_get_layer_named(
 | 
			
		||||
      &pointcloud->pdata, CD_PROP_FLOAT, "radius");
 | 
			
		||||
  const bool has_radius = radii != NULL;
 | 
			
		||||
 | 
			
		||||
  static GPUVertFormat format = {0};
 | 
			
		||||
  static GPUVertFormat format_no_radius = {0};
 | 
			
		||||
@@ -162,14 +167,14 @@ static void pointcloud_batch_cache_ensure_pos(Object *ob, PointCloudBatchCache *
 | 
			
		||||
  if (has_radius) {
 | 
			
		||||
    float(*vbo_data)[4] = (float(*)[4])GPU_vertbuf_get_data(cache->pos);
 | 
			
		||||
    for (int i = 0; i < pointcloud->totpoint; i++) {
 | 
			
		||||
      copy_v3_v3(vbo_data[i], pointcloud->co[i]);
 | 
			
		||||
      copy_v3_v3(vbo_data[i], positions[i]);
 | 
			
		||||
      /* TODO(fclem): remove multiplication here.
 | 
			
		||||
       * Here only for keeping the size correct for now. */
 | 
			
		||||
      vbo_data[i][3] = pointcloud->radius[i] * 100.0f;
 | 
			
		||||
      vbo_data[i][3] = radii[i] * 100.0f;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  else {
 | 
			
		||||
    GPU_vertbuf_attr_fill(cache->pos, pos, pointcloud->co);
 | 
			
		||||
    GPU_vertbuf_attr_fill(cache->pos, pos, positions);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -18,8 +18,10 @@ PointCloud *point_merge_by_distance(const PointCloudComponent &src_points,
 | 
			
		||||
                                    const IndexMask selection)
 | 
			
		||||
{
 | 
			
		||||
  const PointCloud &src_pointcloud = *src_points.get_for_read();
 | 
			
		||||
  const int src_size = src_pointcloud.totpoint;
 | 
			
		||||
  Span<float3> positions{reinterpret_cast<float3 *>(src_pointcloud.co), src_size};
 | 
			
		||||
  bke::AttributeAccessor attributes = bke::pointcloud_attributes(src_pointcloud);
 | 
			
		||||
  VArraySpan<float3> positions = attributes.lookup_or_default<float3>(
 | 
			
		||||
      "position", ATTR_DOMAIN_POINT, float3(0));
 | 
			
		||||
  const int src_size = positions.size();
 | 
			
		||||
 | 
			
		||||
  /* Create the KD tree based on only the selected points, to speed up merge detection and
 | 
			
		||||
   * balancing. */
 | 
			
		||||
@@ -106,10 +108,10 @@ PointCloud *point_merge_by_distance(const PointCloudComponent &src_points,
 | 
			
		||||
 | 
			
		||||
  const bke::AttributeAccessor src_attributes = *src_points.attributes();
 | 
			
		||||
  bke::MutableAttributeAccessor dst_attributes = *dst_points.attributes_for_write();
 | 
			
		||||
  Set<bke::AttributeIDRef> attributes = src_attributes.all_ids();
 | 
			
		||||
  Set<bke::AttributeIDRef> attribute_ids = src_attributes.all_ids();
 | 
			
		||||
 | 
			
		||||
  /* Transfer the ID attribute if it exists, using the ID of the first merged point. */
 | 
			
		||||
  if (attributes.contains("id")) {
 | 
			
		||||
  if (attribute_ids.contains("id")) {
 | 
			
		||||
    VArraySpan<int> src = src_attributes.lookup_or_default<int>("id", ATTR_DOMAIN_POINT, 0);
 | 
			
		||||
    bke::SpanAttributeWriter<int> dst = dst_attributes.lookup_or_add_for_write_only_span<int>(
 | 
			
		||||
        "id", ATTR_DOMAIN_POINT);
 | 
			
		||||
@@ -122,11 +124,11 @@ PointCloud *point_merge_by_distance(const PointCloudComponent &src_points,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    dst.finish();
 | 
			
		||||
    attributes.remove_contained("id");
 | 
			
		||||
    attribute_ids.remove_contained("id");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* Transfer all other attributes. */
 | 
			
		||||
  for (const bke::AttributeIDRef &id : attributes) {
 | 
			
		||||
  for (const bke::AttributeIDRef &id : attribute_ids) {
 | 
			
		||||
    if (!id.should_be_kept()) {
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -69,6 +69,7 @@ struct PointCloudRealizeInfo {
 | 
			
		||||
  /** Matches the order stored in #AllPointCloudsInfo.attributes. */
 | 
			
		||||
  Array<std::optional<GVArraySpan>> attributes;
 | 
			
		||||
  /** Id attribute on the point cloud. If there are no ids, this #Span is empty. */
 | 
			
		||||
  Span<float3> positions;
 | 
			
		||||
  Span<int> stored_ids;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -665,6 +666,9 @@ static AllPointCloudsInfo preprocess_pointclouds(const GeometrySet &geometry_set
 | 
			
		||||
        pointcloud_info.stored_ids = ids_attribute.varray.get_internal_span().typed<int>();
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    const VArray<float3> position_attribute = attributes.lookup_or_default<float3>(
 | 
			
		||||
        "position", ATTR_DOMAIN_POINT, float3(0));
 | 
			
		||||
    pointcloud_info.positions = position_attribute.get_internal_span();
 | 
			
		||||
  }
 | 
			
		||||
  return info;
 | 
			
		||||
}
 | 
			
		||||
@@ -673,18 +677,16 @@ static void execute_realize_pointcloud_task(
 | 
			
		||||
    const RealizeInstancesOptions &options,
 | 
			
		||||
    const RealizePointCloudTask &task,
 | 
			
		||||
    const OrderedAttributes &ordered_attributes,
 | 
			
		||||
    PointCloud &dst_pointcloud,
 | 
			
		||||
    MutableSpan<GSpanAttributeWriter> dst_attribute_writers,
 | 
			
		||||
    MutableSpan<int> all_dst_ids)
 | 
			
		||||
    MutableSpan<int> all_dst_ids,
 | 
			
		||||
    MutableSpan<float3> all_dst_positions)
 | 
			
		||||
{
 | 
			
		||||
  const PointCloudRealizeInfo &pointcloud_info = *task.pointcloud_info;
 | 
			
		||||
  const PointCloud &pointcloud = *pointcloud_info.pointcloud;
 | 
			
		||||
  const Span<float3> src_positions{(float3 *)pointcloud.co, pointcloud.totpoint};
 | 
			
		||||
  const IndexRange point_slice{task.start_index, pointcloud.totpoint};
 | 
			
		||||
  MutableSpan<float3> dst_positions{(float3 *)dst_pointcloud.co + task.start_index,
 | 
			
		||||
                                    pointcloud.totpoint};
 | 
			
		||||
 | 
			
		||||
  copy_transformed_positions(src_positions, task.transform, dst_positions);
 | 
			
		||||
  copy_transformed_positions(
 | 
			
		||||
      pointcloud_info.positions, task.transform, all_dst_positions.slice(point_slice));
 | 
			
		||||
 | 
			
		||||
  /* Create point ids. */
 | 
			
		||||
  if (!all_dst_ids.is_empty()) {
 | 
			
		||||
@@ -726,6 +728,9 @@ static void execute_realize_pointcloud_tasks(const RealizeInstancesOptions &opti
 | 
			
		||||
  bke::MutableAttributeAccessor dst_attributes = bke::pointcloud_attributes_for_write(
 | 
			
		||||
      *dst_pointcloud);
 | 
			
		||||
 | 
			
		||||
  SpanAttributeWriter<float3> positions = dst_attributes.lookup_or_add_for_write_only_span<float3>(
 | 
			
		||||
      "position", ATTR_DOMAIN_POINT);
 | 
			
		||||
 | 
			
		||||
  /* Prepare id attribute. */
 | 
			
		||||
  SpanAttributeWriter<int> point_ids;
 | 
			
		||||
  if (all_pointclouds_info.create_id_attribute) {
 | 
			
		||||
@@ -748,9 +753,9 @@ static void execute_realize_pointcloud_tasks(const RealizeInstancesOptions &opti
 | 
			
		||||
      execute_realize_pointcloud_task(options,
 | 
			
		||||
                                      task,
 | 
			
		||||
                                      ordered_attributes,
 | 
			
		||||
                                      *dst_pointcloud,
 | 
			
		||||
                                      dst_attribute_writers,
 | 
			
		||||
                                      point_ids.span);
 | 
			
		||||
                                      point_ids.span,
 | 
			
		||||
                                      positions.span);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
@@ -758,6 +763,7 @@ static void execute_realize_pointcloud_tasks(const RealizeInstancesOptions &opti
 | 
			
		||||
  for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) {
 | 
			
		||||
    dst_attribute.finish();
 | 
			
		||||
  }
 | 
			
		||||
  positions.finish();
 | 
			
		||||
  if (point_ids) {
 | 
			
		||||
    point_ids.finish();
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -18,13 +18,9 @@ typedef struct PointCloud {
 | 
			
		||||
  struct AnimData *adt; /* animation data (must be immediately after id) */
 | 
			
		||||
 | 
			
		||||
  int flag;
 | 
			
		||||
  int _pad1[1];
 | 
			
		||||
 | 
			
		||||
  /* Geometry */
 | 
			
		||||
  float (*co)[3];
 | 
			
		||||
  float *radius;
 | 
			
		||||
  int totpoint;
 | 
			
		||||
  int _pad2[1];
 | 
			
		||||
 | 
			
		||||
  /* Custom Data */
 | 
			
		||||
  struct CustomData pdata;
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,7 @@
 | 
			
		||||
 | 
			
		||||
#  include "BLI_math_vector.h"
 | 
			
		||||
 | 
			
		||||
#  include "BKE_customdata.h"
 | 
			
		||||
#  include "BKE_pointcloud.h"
 | 
			
		||||
 | 
			
		||||
#  include "DEG_depsgraph.h"
 | 
			
		||||
@@ -36,7 +37,9 @@ static int rna_Point_index_get_const(const PointerRNA *ptr)
 | 
			
		||||
{
 | 
			
		||||
  const PointCloud *pointcloud = rna_pointcloud(ptr);
 | 
			
		||||
  const float(*co)[3] = ptr->data;
 | 
			
		||||
  return (int)(co - pointcloud->co);
 | 
			
		||||
  const float(*positions)[3] = (const float(*)[3])CustomData_get_layer_named(
 | 
			
		||||
      &pointcloud->pdata, CD_PROP_FLOAT3, "position");
 | 
			
		||||
  return (int)(co - positions);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int rna_Point_index_get(PointerRNA *ptr)
 | 
			
		||||
@@ -44,6 +47,21 @@ static int rna_Point_index_get(PointerRNA *ptr)
 | 
			
		||||
  return rna_Point_index_get_const(ptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int rna_PointCloud_points_length(PointerRNA *ptr)
 | 
			
		||||
{
 | 
			
		||||
  const PointCloud *pointcloud = rna_pointcloud(ptr);
 | 
			
		||||
  return pointcloud->totpoint;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rna_PointCloud_points_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
 | 
			
		||||
{
 | 
			
		||||
  const PointCloud *pointcloud = rna_pointcloud(ptr);
 | 
			
		||||
  const float(*positions)[3] = (const float(*)[3])CustomData_get_layer_named(
 | 
			
		||||
      &pointcloud->pdata, CD_PROP_FLOAT3, "position");
 | 
			
		||||
  rna_iterator_array_begin(
 | 
			
		||||
      iter, (void *)positions, sizeof(float[3]), pointcloud->totpoint, false, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rna_Point_location_get(PointerRNA *ptr, float value[3])
 | 
			
		||||
{
 | 
			
		||||
  copy_v3_v3(value, (const float *)ptr->data);
 | 
			
		||||
@@ -57,21 +75,22 @@ static void rna_Point_location_set(PointerRNA *ptr, const float value[3])
 | 
			
		||||
static float rna_Point_radius_get(PointerRNA *ptr)
 | 
			
		||||
{
 | 
			
		||||
  const PointCloud *pointcloud = rna_pointcloud(ptr);
 | 
			
		||||
  if (pointcloud->radius == NULL) {
 | 
			
		||||
  const float *radii = (const float *)CustomData_get_layer_named(
 | 
			
		||||
      &pointcloud->pdata, CD_PROP_FLOAT, "radius");
 | 
			
		||||
  if (radii == NULL) {
 | 
			
		||||
    return 0.0f;
 | 
			
		||||
  }
 | 
			
		||||
  const float(*co)[3] = ptr->data;
 | 
			
		||||
  return pointcloud->radius[co - pointcloud->co];
 | 
			
		||||
  return radii[rna_Point_index_get_const(ptr)];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rna_Point_radius_set(PointerRNA *ptr, float value)
 | 
			
		||||
{
 | 
			
		||||
  const PointCloud *pointcloud = rna_pointcloud(ptr);
 | 
			
		||||
  if (pointcloud->radius == NULL) {
 | 
			
		||||
  PointCloud *pointcloud = rna_pointcloud(ptr);
 | 
			
		||||
  float *radii = (float *)CustomData_get_layer_named(&pointcloud->pdata, CD_PROP_FLOAT, "radius");
 | 
			
		||||
  if (radii == NULL) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  const float(*co)[3] = ptr->data;
 | 
			
		||||
  pointcloud->radius[co - pointcloud->co] = value;
 | 
			
		||||
  radii[rna_Point_index_get_const(ptr)] = value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *rna_Point_path(const PointerRNA *ptr)
 | 
			
		||||
@@ -130,13 +149,18 @@ static void rna_def_pointcloud(BlenderRNA *brna)
 | 
			
		||||
  RNA_def_struct_ui_icon(srna, ICON_POINTCLOUD_DATA);
 | 
			
		||||
 | 
			
		||||
  /* geometry */
 | 
			
		||||
  /* TODO: better solution for (*co)[3] parsing issue. */
 | 
			
		||||
  RNA_define_verify_sdna(0);
 | 
			
		||||
  prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE);
 | 
			
		||||
  RNA_def_property_collection_sdna(prop, NULL, "co", "totpoint");
 | 
			
		||||
  RNA_def_property_struct_type(prop, "Point");
 | 
			
		||||
  RNA_def_property_collection_funcs(prop,
 | 
			
		||||
                                    "rna_PointCloud_points_begin",
 | 
			
		||||
                                    "rna_iterator_array_next",
 | 
			
		||||
                                    "rna_iterator_array_end",
 | 
			
		||||
                                    "rna_iterator_array_get",
 | 
			
		||||
                                    "rna_PointCloud_points_length",
 | 
			
		||||
                                    NULL,
 | 
			
		||||
                                    NULL,
 | 
			
		||||
                                    NULL);
 | 
			
		||||
  RNA_def_property_ui_text(prop, "Points", "");
 | 
			
		||||
  RNA_define_verify_sdna(1);
 | 
			
		||||
 | 
			
		||||
  /* materials */
 | 
			
		||||
  prop = RNA_def_property(srna, "materials", PROP_COLLECTION, PROP_NONE);
 | 
			
		||||
 
 | 
			
		||||
@@ -149,12 +149,17 @@ static Mesh *compute_hull(const GeometrySet &geometry_set)
 | 
			
		||||
 | 
			
		||||
  if (geometry_set.has_pointcloud()) {
 | 
			
		||||
    count++;
 | 
			
		||||
    span_count++;
 | 
			
		||||
    const PointCloudComponent *component =
 | 
			
		||||
        geometry_set.get_component_for_read<PointCloudComponent>();
 | 
			
		||||
    const PointCloud *pointcloud = component->get_for_read();
 | 
			
		||||
    positions_span = {reinterpret_cast<const float3 *>(pointcloud->co), pointcloud->totpoint};
 | 
			
		||||
    total_num += pointcloud->totpoint;
 | 
			
		||||
    const bke::AttributeAccessor attributes = bke::pointcloud_attributes(*pointcloud);
 | 
			
		||||
    const VArray<float3> positions = attributes.lookup_or_default<float3>(
 | 
			
		||||
        "position", ATTR_DOMAIN_POINT, float3(0));
 | 
			
		||||
    if (positions.is_span()) {
 | 
			
		||||
      span_count++;
 | 
			
		||||
      positions_span = positions.get_internal_span();
 | 
			
		||||
    }
 | 
			
		||||
    total_num += positions.size();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (geometry_set.has_curves()) {
 | 
			
		||||
 
 | 
			
		||||
@@ -497,8 +497,17 @@ static void point_distribution_calculate(GeometrySet &geometry_set,
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  PointCloud *pointcloud = BKE_pointcloud_new_nomain(positions.size());
 | 
			
		||||
  memcpy(pointcloud->co, positions.data(), sizeof(float3) * positions.size());
 | 
			
		||||
  uninitialized_fill_n(pointcloud->radius, pointcloud->totpoint, 0.05f);
 | 
			
		||||
  bke::MutableAttributeAccessor point_attributes = bke::pointcloud_attributes_for_write(
 | 
			
		||||
      *pointcloud);
 | 
			
		||||
  bke::SpanAttributeWriter<float3> point_positions =
 | 
			
		||||
      point_attributes.lookup_or_add_for_write_only_span<float3>("position", ATTR_DOMAIN_POINT);
 | 
			
		||||
  bke::SpanAttributeWriter<float> point_radii =
 | 
			
		||||
      point_attributes.lookup_or_add_for_write_only_span<float>("radius", ATTR_DOMAIN_POINT);
 | 
			
		||||
  point_positions.span.copy_from(positions);
 | 
			
		||||
  point_radii.span.fill(0.05f);
 | 
			
		||||
  point_positions.finish();
 | 
			
		||||
  point_radii.finish();
 | 
			
		||||
 | 
			
		||||
  geometry_set.replace_pointcloud(pointcloud);
 | 
			
		||||
 | 
			
		||||
  PointCloudComponent &point_component =
 | 
			
		||||
 
 | 
			
		||||
@@ -51,16 +51,24 @@ static void convert_instances_to_points(GeometrySet &geometry_set,
 | 
			
		||||
  if (selection.is_empty()) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  const VArray<float3> &positions = evaluator.get_evaluated<float3>(0);
 | 
			
		||||
  const VArray<float> radii = evaluator.get_evaluated<float>(1);
 | 
			
		||||
 | 
			
		||||
  PointCloud *pointcloud = BKE_pointcloud_new_nomain(selection.size());
 | 
			
		||||
  geometry_set.replace_pointcloud(pointcloud);
 | 
			
		||||
 | 
			
		||||
  PointCloudComponent &points = geometry_set.get_component_for_write<PointCloudComponent>();
 | 
			
		||||
  bke::MutableAttributeAccessor point_attributes = bke::pointcloud_attributes_for_write(
 | 
			
		||||
      *pointcloud);
 | 
			
		||||
 | 
			
		||||
  const VArray<float3> &positions = evaluator.get_evaluated<float3>(0);
 | 
			
		||||
  copy_attribute_to_points(positions, selection, {(float3 *)pointcloud->co, pointcloud->totpoint});
 | 
			
		||||
  const VArray<float> radii = evaluator.get_evaluated<float>(1);
 | 
			
		||||
  copy_attribute_to_points(radii, selection, {pointcloud->radius, pointcloud->totpoint});
 | 
			
		||||
  bke::SpanAttributeWriter<float3> point_positions =
 | 
			
		||||
      point_attributes.lookup_or_add_for_write_only_span<float3>("position", ATTR_DOMAIN_POINT);
 | 
			
		||||
  bke::SpanAttributeWriter<float> point_radii =
 | 
			
		||||
      point_attributes.lookup_or_add_for_write_only_span<float>("radius", ATTR_DOMAIN_POINT);
 | 
			
		||||
 | 
			
		||||
  copy_attribute_to_points(positions, selection, point_positions.span);
 | 
			
		||||
  copy_attribute_to_points(radii, selection, point_radii.span);
 | 
			
		||||
  point_positions.finish();
 | 
			
		||||
  point_radii.finish();
 | 
			
		||||
 | 
			
		||||
  Map<AttributeIDRef, AttributeKind> attributes_to_propagate;
 | 
			
		||||
  geometry_set.gather_attributes_for_propagation({GEO_COMPONENT_TYPE_INSTANCES},
 | 
			
		||||
@@ -78,7 +86,7 @@ static void convert_instances_to_points(GeometrySet &geometry_set,
 | 
			
		||||
    const GVArray src = instances.attributes()->lookup_or_default(
 | 
			
		||||
        attribute_id, ATTR_DOMAIN_INSTANCE, attribute_kind.data_type);
 | 
			
		||||
    BLI_assert(src);
 | 
			
		||||
    GSpanAttributeWriter dst = points.attributes_for_write()->lookup_or_add_for_write_only_span(
 | 
			
		||||
    GSpanAttributeWriter dst = point_attributes.lookup_or_add_for_write_only_span(
 | 
			
		||||
        attribute_id, ATTR_DOMAIN_POINT, attribute_kind.data_type);
 | 
			
		||||
    BLI_assert(dst);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -47,21 +47,24 @@ static void transform_mesh(Mesh &mesh, const float4x4 &transform)
 | 
			
		||||
 | 
			
		||||
static void translate_pointcloud(PointCloud &pointcloud, const float3 translation)
 | 
			
		||||
{
 | 
			
		||||
  CustomData_duplicate_referenced_layer(&pointcloud.pdata, CD_PROP_FLOAT3, pointcloud.totpoint);
 | 
			
		||||
  BKE_pointcloud_update_customdata_pointers(&pointcloud);
 | 
			
		||||
  for (const int i : IndexRange(pointcloud.totpoint)) {
 | 
			
		||||
    add_v3_v3(pointcloud.co[i], translation);
 | 
			
		||||
  MutableAttributeAccessor attributes = bke::pointcloud_attributes_for_write(pointcloud);
 | 
			
		||||
  SpanAttributeWriter position = attributes.lookup_or_add_for_write_span<float3>(
 | 
			
		||||
      "position", ATTR_DOMAIN_POINT);
 | 
			
		||||
  for (const int i : position.span.index_range()) {
 | 
			
		||||
    position.span[i] += translation;
 | 
			
		||||
  }
 | 
			
		||||
  position.finish();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void transform_pointcloud(PointCloud &pointcloud, const float4x4 &transform)
 | 
			
		||||
{
 | 
			
		||||
  CustomData_duplicate_referenced_layer(&pointcloud.pdata, CD_PROP_FLOAT3, pointcloud.totpoint);
 | 
			
		||||
  BKE_pointcloud_update_customdata_pointers(&pointcloud);
 | 
			
		||||
  for (const int i : IndexRange(pointcloud.totpoint)) {
 | 
			
		||||
    float3 &co = *(float3 *)pointcloud.co[i];
 | 
			
		||||
    co = transform * co;
 | 
			
		||||
  MutableAttributeAccessor attributes = bke::pointcloud_attributes_for_write(pointcloud);
 | 
			
		||||
  SpanAttributeWriter position = attributes.lookup_or_add_for_write_span<float3>(
 | 
			
		||||
      "position", ATTR_DOMAIN_POINT);
 | 
			
		||||
  for (const int i : position.span.index_range()) {
 | 
			
		||||
    position.span[i] = transform * position.span[i];
 | 
			
		||||
  }
 | 
			
		||||
  position.finish();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void translate_instances(InstancesComponent &instances, const float3 translation)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user