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