Blender V4.3
blender/pointcloud.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include <optional>
6
7#include "scene/attribute.h"
8#include "scene/pointcloud.h"
9#include "scene/scene.h"
10
12#include "blender/sync.h"
13#include "blender/util.h"
14
15#include "util/color.h"
16#include "util/foreach.h"
17#include "util/hash.h"
18
19#include "BKE_attribute.hh"
20#include "BKE_attribute_math.hh"
21#include "BKE_pointcloud.hh"
22
24
26 const blender::Span<blender::float3> b_attribute,
27 const float motion_scale)
28{
29 const int num_points = pointcloud->get_points().size();
30
31 /* Override motion steps to fixed number. */
32 pointcloud->set_motion_steps(3);
33
34 /* Find or add attribute */
35 float3 *P = pointcloud->get_points().data();
36 float *radius = pointcloud->get_radius().data();
38
39 if (!attr_mP) {
40 attr_mP = pointcloud->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
41 }
42
43 /* Only export previous and next frame, we don't have any in between data. */
44 float motion_times[2] = {-1.0f, 1.0f};
45 for (int step = 0; step < 2; step++) {
46 const float relative_time = motion_times[step] * 0.5f * motion_scale;
47 float4 *mP = attr_mP->data_float4() + step * num_points;
48
49 for (int i = 0; i < num_points; i++) {
50 float3 Pi = P[i] + make_float3(b_attribute[i][0], b_attribute[i][1], b_attribute[i][2]) *
51 relative_time;
52 mP[i] = make_float4(Pi.x, Pi.y, Pi.z, radius[i]);
53 }
54 }
55}
56
57static void copy_attributes(PointCloud *pointcloud,
58 const ::PointCloud &b_pointcloud,
59 const bool need_motion,
60 const float motion_scale)
61{
62 const blender::bke::AttributeAccessor b_attributes = b_pointcloud.attributes();
63 if (b_attributes.domain_size(blender::bke::AttrDomain::Point) == 0) {
64 return;
65 }
66
67 AttributeSet &attributes = pointcloud->attributes;
68 static const ustring u_velocity("velocity");
69 b_attributes.foreach_attribute([&](const blender::bke::AttributeIter &iter) {
70 const ustring name{std::string_view(iter.name)};
71
72 if (need_motion && name == u_velocity) {
73 const blender::VArraySpan b_attr = *iter.get<blender::float3>();
74 attr_create_motion_from_velocity(pointcloud, b_attr, motion_scale);
75 }
76
77 if (attributes.find(name)) {
78 return;
79 }
80
81 const blender::bke::GAttributeReader b_attr = iter.get();
83 using BlenderT = decltype(dummy);
84 using Converter = typename ccl::AttributeConverter<BlenderT>;
85 using CyclesT = typename Converter::CyclesT;
86 if constexpr (!std::is_void_v<CyclesT>) {
87 Attribute *attr = attributes.add(name, Converter::type_desc, ATTR_ELEMENT_VERTEX);
88 CyclesT *data = reinterpret_cast<CyclesT *>(attr->data());
89
90 const blender::VArraySpan src = b_attr.varray.typed<BlenderT>();
91 for (const int i : src.index_range()) {
92 data[i] = Converter::convert(src[i]);
93 }
94 }
95 });
96 });
97}
98
99static void export_pointcloud(Scene *scene,
100 PointCloud *pointcloud,
101 const ::PointCloud &b_pointcloud,
102 const bool need_motion,
103 const float motion_scale)
104{
105 const blender::Span<blender::float3> b_positions = b_pointcloud.positions();
106 const blender::VArraySpan b_radius = *b_pointcloud.attributes().lookup<float>(
108
109 pointcloud->resize(b_positions.size());
110
111 float3 *points = pointcloud->get_points().data();
112
113 for (const int i : b_positions.index_range()) {
114 points[i] = make_float3(b_positions[i][0], b_positions[i][1], b_positions[i][2]);
115 }
116
117 float *radius = pointcloud->get_radius().data();
118 if (!b_radius.is_empty()) {
119 std::copy(b_radius.data(), b_radius.data() + b_positions.size(), radius);
120 }
121 else {
122 std::fill(radius, radius + b_positions.size(), 0.01f);
123 }
124
125 int *shader = pointcloud->get_shader().data();
126 std::fill(shader, shader + b_positions.size(), 0);
127
128 if (pointcloud->need_attribute(scene, ATTR_STD_POINT_RANDOM)) {
129 Attribute *attr_random = pointcloud->attributes.add(ATTR_STD_POINT_RANDOM);
130 float *data = attr_random->data_float();
131 for (const int i : b_positions.index_range()) {
132 data[i] = hash_uint2_to_float(i, 0);
133 }
134 }
135
136 copy_attributes(pointcloud, b_pointcloud, need_motion, motion_scale);
137}
138
139static void export_pointcloud_motion(PointCloud *pointcloud,
140 const ::PointCloud &b_pointcloud,
141 int motion_step)
142{
143 /* Find or add attribute. */
145 bool new_attribute = false;
146
147 if (!attr_mP) {
148 attr_mP = pointcloud->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
149 new_attribute = true;
150 }
151
152 const int num_points = pointcloud->num_points();
153 /* Point cloud attributes are stored as float4 with the radius in the w element.
154 * This is explicit now as float3 is no longer interchangeable with float4 as it
155 * is packed now. */
156 float4 *mP = attr_mP->data_float4() + motion_step * num_points;
157 bool have_motion = false;
158 const array<float3> &pointcloud_points = pointcloud->get_points();
159
160 const blender::Span<blender::float3> b_positions = b_pointcloud.positions();
161 const blender::VArraySpan b_radius = *b_pointcloud.attributes().lookup<float>(
163
164 for (int i = 0; i < std::min<int>(num_points, b_positions.size()); i++) {
165 const float3 P = make_float3(b_positions[i][0], b_positions[i][1], b_positions[i][2]);
166 const float radius = b_radius.is_empty() ? 0.01f : b_radius[i];
167 mP[i] = make_float4(P.x, P.y, P.z, radius);
168 have_motion = have_motion || (P != pointcloud_points[i]);
169 }
170
171 /* In case of new attribute, we verify if there really was any motion. */
172 if (new_attribute) {
173 if (b_positions.size() != num_points || !have_motion) {
175 }
176 else if (motion_step > 0) {
177 /* Motion, fill up previous steps that we might have skipped because
178 * they had no motion, but we need them anyway now. */
179 for (int step = 0; step < motion_step; step++) {
180 pointcloud->copy_center_to_motion_step(step);
181 }
182 }
183 }
184
185 /* Export attributes */
186 copy_attributes(pointcloud, b_pointcloud, false, 0.0f);
187}
188
189void BlenderSync::sync_pointcloud(PointCloud *pointcloud, BObjectInfo &b_ob_info)
190{
191 size_t old_numpoints = pointcloud->num_points();
192
193 array<Node *> used_shaders = pointcloud->get_used_shaders();
194
195 PointCloud new_pointcloud;
196 new_pointcloud.set_used_shaders(used_shaders);
197
198 /* TODO: add option to filter out points in the view layer. */
199 BL::PointCloud b_pointcloud(b_ob_info.object_data);
200 /* Motion blur attribute is relative to seconds, we need it relative to frames. */
201 const bool need_motion = object_need_motion_attribute(b_ob_info, scene);
202 const float motion_scale = (need_motion) ?
203 scene->motion_shutter_time() /
204 (b_scene.render().fps() / b_scene.render().fps_base()) :
205 0.0f;
206 export_pointcloud(scene,
207 &new_pointcloud,
208 *static_cast<const ::PointCloud *>(b_pointcloud.ptr.data),
209 need_motion,
210 motion_scale);
211
212 /* Update original sockets. */
213 for (const SocketType &socket : new_pointcloud.type->inputs) {
214 /* Those sockets are updated in sync_object, so do not modify them. */
215 if (socket.name == "use_motion_blur" || socket.name == "motion_steps" ||
216 socket.name == "used_shaders")
217 {
218 continue;
219 }
220 pointcloud->set_value(socket, new_pointcloud, socket);
221 }
222
223 pointcloud->attributes.clear();
224 foreach (Attribute &attr, new_pointcloud.attributes.attributes) {
225 pointcloud->attributes.attributes.push_back(std::move(attr));
226 }
227
228 /* Tag update. */
229 const bool rebuild = (pointcloud && old_numpoints != pointcloud->num_points());
230 pointcloud->tag_update(scene, rebuild);
231}
232
233void BlenderSync::sync_pointcloud_motion(PointCloud *pointcloud,
234 BObjectInfo &b_ob_info,
235 int motion_step)
236{
237 /* Skip if nothing exported. */
238 if (pointcloud->num_points() == 0) {
239 return;
240 }
241
242 /* Export deformed coordinates. */
243 if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) {
244 /* PointCloud object. */
245 BL::PointCloud b_pointcloud(b_ob_info.object_data);
247 pointcloud, *static_cast<const ::PointCloud *>(b_pointcloud.ptr.data), motion_step);
248 }
249 else {
250 /* No deformation on this frame, copy coordinates if other frames did have it. */
251 pointcloud->copy_center_to_motion_step(motion_step);
252 }
253}
254
General operations for point clouds.
static void export_pointcloud(Scene *scene, PointCloud *pointcloud, const ::PointCloud &b_pointcloud, const bool need_motion, const float motion_scale)
static void export_pointcloud_motion(PointCloud *pointcloud, const ::PointCloud &b_pointcloud, int motion_step)
static void copy_attributes(PointCloud *pointcloud, const ::PointCloud &b_pointcloud, const bool need_motion, const float motion_scale)
static CCL_NAMESPACE_BEGIN void attr_create_motion_from_velocity(PointCloud *pointcloud, const blender::Span< blender::float3 > b_attribute, const float motion_scale)
Attribute * add(ustring name, TypeDesc type, AttributeElement element)
list< Attribute > attributes
Attribute * find(ustring name) const
void remove(ustring name)
void clear(bool preserve_voxel_data=false)
float * data_float()
float4 * data_float4()
void tag_update(Scene *scene, bool rebuild)
bool need_attribute(Scene *scene, AttributeStandard std)
AttributeSet attributes
constexpr const T * data() const
Definition BLI_span.hh:216
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
constexpr bool is_empty() const
Definition BLI_span.hh:261
void foreach_attribute(const FunctionRef< void(const AttributeIter &)> fn) const
int domain_size(const AttrDomain domain) const
GAttributeReader get() const
static bool object_need_motion_attribute(BObjectInfo &b_ob_info, Scene *scene)
#define CCL_NAMESPACE_END
ccl_device_forceinline float4 make_float4(const float x, const float y, const float z, const float w)
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
ccl_device_inline float hash_uint2_to_float(uint kx, uint ky)
Definition hash.h:141
@ ATTR_STD_POINT_RANDOM
@ ATTR_STD_MOTION_VERTEX_POSITION
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
void set_value(const SocketType &input, const Node &other, const SocketType &other_input)
size_t num_points() const
void resize(int numpoints)
void copy_center_to_motion_step(const int motion_step)
float z
Definition sky_float3.h:27
float y
Definition sky_float3.h:27
float x
Definition sky_float3.h:27