OpenVDB 12.1.0
Loading...
Searching...
No Matches
PointRasterizeTrilinearImpl.h
Go to the documentation of this file.
1// Copyright Contributors to the OpenVDB Project
2// SPDX-License-Identifier: Apache-2.0
3//
4/// @author Nick Avramoussis
5///
6/// @file PointRasterizeTrilinearImpl.h
7///
8
9#ifndef OPENVDB_POINTS_RASTERIZE_TRILINEAR_IMPL_HAS_BEEN_INCLUDED
10#define OPENVDB_POINTS_RASTERIZE_TRILINEAR_IMPL_HAS_BEEN_INCLUDED
11
12namespace openvdb {
14namespace OPENVDB_VERSION_NAME {
15namespace points {
16
17/// @cond OPENVDB_DOCS_INTERNAL
18
19namespace rasterize_trilinear_internal {
20
21template <typename TreeType,
22 typename PositionCodecT,
23 typename SourceValueT,
24 typename SourceCodecT,
25 typename FilterT>
26struct TrilinearTransfer :
27 public VolumeTransfer<TreeType>,
28 public FilteredTransfer<FilterT>
29{
30 using BaseT = VolumeTransfer<TreeType>;
31 using FilterTransferT = FilteredTransfer<FilterT>;
32 using WeightT = typename TreeType::ValueType;
33 using PositionHandleT = points::AttributeHandle<Vec3f, PositionCodecT>;
34 using SourceHandleT = points::AttributeHandle<SourceValueT, SourceCodecT>;
35
36 // precision of kernel arithmetic - aliased to the floating point
37 // element type of the source attribute.
38 using SourceElementT = typename ValueTraits<SourceValueT>::ElementType;
39 using RealT = SourceElementT;
40
41 static_assert(std::is_floating_point<SourceElementT>::value,
42 "Trilinear rasterization only supports floating point values.");
43
44 static const Index NUM_VALUES = TreeType::LeafNodeType::NUM_VALUES;
45
46 TrilinearTransfer(const size_t pidx,
47 const size_t sidx,
48 const FilterT& filter,
49 TreeType& tree)
50 : BaseT(tree)
51 , FilterTransferT(filter)
52 , mPIdx(pidx)
53 , mSIdx(sidx)
54 , mPHandle()
55 , mSHandle()
56 , mWeights() {}
57
58 TrilinearTransfer(const TrilinearTransfer& other)
59 : BaseT(other)
60 , FilterTransferT(other)
61 , mPIdx(other.mPIdx)
62 , mSIdx(other.mSIdx)
63 , mPHandle()
64 , mSHandle()
65 , mWeights() {}
66
67 //// @note Kernel value evaluator
68 static inline RealT value(const RealT x)
69 {
70 const RealT abs_x = std::fabs(x);
71 if (abs_x < RealT(1.0)) return RealT(1.0) - abs_x;
72 return RealT(0.0);
73 }
74
75 inline static Int32 range() { return 1; }
76 inline Int32 range(const Coord&, size_t) const { return this->range(); }
77
78 inline void initialize(const Coord& origin, const size_t idx, const CoordBBox& bounds)
79 {
80 this->BaseT::initialize(origin, idx, bounds);
81 this->FilterTransferT::initialize(origin, idx, bounds);
82 mWeights.fill(openvdb::zeroVal<WeightT>());
83 }
84
85 inline bool startPointLeaf(const PointDataTree::LeafNodeType& leaf)
86 {
87 this->FilterTransferT::startPointLeaf(leaf);
88 mPHandle.reset(new PositionHandleT(leaf.constAttributeArray(mPIdx)));
89 mSHandle.reset(new SourceHandleT(leaf.constAttributeArray(mSIdx)));
90 return true;
91 }
92
93 inline bool endPointLeaf(const PointDataTree::LeafNodeType&) { return true; }
94
95protected:
96 const size_t mPIdx;
97 const size_t mSIdx;
98 typename PositionHandleT::UniquePtr mPHandle;
99 typename SourceHandleT::UniquePtr mSHandle;
100 std::array<WeightT, NUM_VALUES> mWeights;
101};
102
103template <typename TreeType,
104 typename PositionCodecT,
105 typename SourceValueT,
106 typename SourceCodecT,
107 typename FilterT>
108struct StaggeredTransfer :
109 public TrilinearTransfer<TreeType, PositionCodecT, SourceValueT, SourceCodecT, FilterT>
110{
111 using BaseT = TrilinearTransfer<TreeType, PositionCodecT, SourceValueT, SourceCodecT, FilterT>;
112 using RealT = typename BaseT::RealT;
113 using BaseT::value;
114
115 static_assert(VecTraits<typename TreeType::ValueType>::IsVec,
116 "Target Tree must be a vector tree for staggered rasterization");
117
118 static const Index DIM = TreeType::LeafNodeType::DIM;
119 static const Index LOG2DIM = TreeType::LeafNodeType::LOG2DIM;
120
121 StaggeredTransfer(const size_t pidx,
122 const size_t sidx,
123 const FilterT& filter,
124 TreeType& tree)
125 : BaseT(pidx, sidx, filter, tree) {}
126
127 void rasterizePoint(const Coord& ijk,
128 const Index id,
129 const CoordBBox& bounds)
130 {
131 if (!BaseT::filter(id)) return;
132
133 CoordBBox intersectBox(ijk.offsetBy(-1), ijk.offsetBy(1));
134 intersectBox.intersect(bounds);
135 if (intersectBox.empty()) return;
136
137 auto* const data = this->buffer();
138 const auto& mask = *(this->mask());
139
140 const math::Vec3<RealT> P(this->mPHandle->get(id));
141 const SourceValueT s(this->mSHandle->get(id));
142
143 math::Vec3<RealT> centerw, macw;
144
145 const Coord& a(intersectBox.min());
146 const Coord& b(intersectBox.max());
147 for (Coord c = a; c.x() <= b.x(); ++c.x()) {
148 // @todo can probably simplify the double call to value() in some way
149 const Index i = ((c.x() & (DIM-1u)) << 2*LOG2DIM); // unsigned bit shift mult
150 const RealT x = static_cast<RealT>(c.x()-ijk.x()); // distance from ijk to c
151 centerw[0] = value(P.x() - x); // center dist
152 macw.x() = value(P.x() - (x-RealT(0.5))); // mac dist
153
154 for (c.y() = a.y(); c.y() <= b.y(); ++c.y()) {
155 const Index ij = i + ((c.y() & (DIM-1u)) << LOG2DIM);
156 const RealT y = static_cast<RealT>(c.y()-ijk.y());
157 centerw[1] = value(P.y() - y);
158 macw.y() = value(P.y() - (y-RealT(0.5)));
159
160 for (c.z() = a.z(); c.z() <= b.z(); ++c.z()) {
161 OPENVDB_ASSERT(bounds.isInside(c));
162 const Index offset = ij + /*k*/(c.z() & (DIM-1u));
163 if (!mask.isOn(offset)) continue;
164 const RealT z = static_cast<RealT>(c.z()-ijk.z());
165 centerw[2] = value(P.z() - z);
166 macw.z() = value(P.z() - (z-RealT(0.5)));
167
168 const math::Vec3<RealT> r {
169 (macw[0] * centerw[1] * centerw[2]),
170 (macw[1] * centerw[0] * centerw[2]),
171 (macw[2] * centerw[0] * centerw[1])
172 };
173
174 data[offset] += s * r;
175 this->mWeights[offset] += r;
176 }
177 }
178 }
179 }
180
181 inline bool finalize(const Coord&, const size_t)
182 {
183 auto* const data = this->buffer();
184 const auto& mask = *(this->mask());
185
186 for (auto iter = mask.beginOn(); iter; ++iter) {
187 const Index offset = iter.pos();
188 const auto& w = this->mWeights[offset];
189 auto& v = data[offset];
190 if (!math::isZero(w[0])) v[0] /= w[0];
191 if (!math::isZero(w[1])) v[1] /= w[1];
192 if (!math::isZero(w[2])) v[2] /= w[2];
193 }
194
195 return true;
196 }
197};
198
199template <typename TreeType,
200 typename PositionCodecT,
201 typename SourceValueT,
202 typename SourceCodecT,
203 typename FilterT>
204struct CellCenteredTransfer :
205 public TrilinearTransfer<TreeType, PositionCodecT, SourceValueT, SourceCodecT, FilterT>
206{
207 using BaseT = TrilinearTransfer<TreeType, PositionCodecT, SourceValueT, SourceCodecT, FilterT>;
208 using RealT = typename BaseT::RealT;
209 using BaseT::value;
210
211 static const Index DIM = TreeType::LeafNodeType::DIM;
212 static const Index LOG2DIM = TreeType::LeafNodeType::LOG2DIM;
213
214 CellCenteredTransfer(const size_t pidx,
215 const size_t sidx,
216 const FilterT& filter,
217 TreeType& tree)
218 : BaseT(pidx, sidx, filter, tree) {}
219
220 void rasterizePoint(const Coord& ijk,
221 const Index id,
222 const CoordBBox& bounds)
223 {
224 if (!BaseT::filter(id)) return;
225
226 const Vec3f P(this->mPHandle->get(id));
227
228 // build area of influence depending on point position
229 CoordBBox intersectBox(ijk, ijk);
230 if (P.x() < 0.0f) intersectBox.min().x() -= 1;
231 else intersectBox.max().x() += 1;
232 if (P.y() < 0.0f) intersectBox.min().y() -= 1;
233 else intersectBox.max().y() += 1;
234 if (P.z() < 0.0f) intersectBox.min().z() -= 1;
235 else intersectBox.max().z() += 1;
236 OPENVDB_ASSERT(intersectBox.volume() == 8);
237
238 intersectBox.intersect(bounds);
239 if (intersectBox.empty()) return;
240
241 auto* const data = this->buffer();
242 const auto& mask = *(this->mask());
243
244 const SourceValueT s(this->mSHandle->get(id));
245 math::Vec3<RealT> centerw;
246
247 const Coord& a(intersectBox.min());
248 const Coord& b(intersectBox.max());
249 for (Coord c = a; c.x() <= b.x(); ++c.x()) {
250 const Index i = ((c.x() & (DIM-1u)) << 2*LOG2DIM); // unsigned bit shift mult
251 const RealT x = static_cast<RealT>(c.x()-ijk.x()); // distance from ijk to c
252 centerw[0] = value(P.x() - x); // center dist
253
254 for (c.y() = a.y(); c.y() <= b.y(); ++c.y()) {
255 const Index ij = i + ((c.y() & (DIM-1u)) << LOG2DIM);
256 const RealT y = static_cast<RealT>(c.y()-ijk.y());
257 centerw[1] = value(P.y() - y);
258
259 for (c.z() = a.z(); c.z() <= b.z(); ++c.z()) {
260 OPENVDB_ASSERT(bounds.isInside(c));
261 const Index offset = ij + /*k*/(c.z() & (DIM-1u));
262 if (!mask.isOn(offset)) continue;
263 const RealT z = static_cast<RealT>(c.z()-ijk.z());
264 centerw[2] = value(P.z() - z);
265
266 OPENVDB_ASSERT(centerw[0] >= 0.0f && centerw[0] <= 1.0f);
267 OPENVDB_ASSERT(centerw[1] >= 0.0f && centerw[1] <= 1.0f);
268 OPENVDB_ASSERT(centerw[2] >= 0.0f && centerw[2] <= 1.0f);
269
270 const RealT weight = centerw.product();
271 data[offset] += s * weight;
272 this->mWeights[offset] += weight;
273 }
274 }
275 }
276 }
277
278 inline bool finalize(const Coord&, const size_t)
279 {
280 auto* const data = this->buffer();
281 const auto& mask = *(this->mask());
282
283 for (auto iter = mask.beginOn(); iter; ++iter) {
284 const Index offset = iter.pos();
285 const auto& w = this->mWeights[offset];
286 auto& v = data[offset];
287 if (!math::isZero(w)) v /= w;
288 }
289 return true;
290 }
291};
292
293// @note If building with MSVC we have to use auto to deduce the return type
294// due to a compiler bug. We can also use that for the public API - but
295// we explicitly define it in non-msvc builds to ensure the API remains
296// consistent
297template <bool Staggered,
298 typename ValueT,
299 typename CodecT,
300 typename PositionCodecT,
301 typename FilterT,
302 typename PointDataTreeT>
303inline
304#ifndef _MSC_VER
305typename TrilinearTraits<ValueT, Staggered>::template TreeT<PointDataTreeT>::Ptr
306#else
307auto
308#endif
309rasterizeTrilinear(const PointDataTreeT& points,
310 const size_t pidx,
311 const size_t sidx,
312 const FilterT& filter)
313{
314 using TraitsT = TrilinearTraits<ValueT, Staggered>;
315 using TargetTreeT = typename TraitsT::template TreeT<PointDataTree>;
316 using TransferT = typename std::conditional<Staggered,
317 StaggeredTransfer<TargetTreeT, PositionCodecT, ValueT, CodecT, FilterT>,
318 CellCenteredTransfer<TargetTreeT, PositionCodecT, ValueT, CodecT, FilterT>
319 >::type;
320
321 typename TargetTreeT::Ptr tree = std::make_shared<TargetTreeT>();
322 if (std::is_same<FilterT, NullFilter>::value) {
323 tree->topologyUnion(points);
324 }
325 else {
326 using MaskTreeT = typename PointDataTreeT::template ValueConverter<ValueMask>::Type;
327 auto mask = convertPointsToMask<PointDataTreeT, MaskTreeT>(points, filter);
328 tree->topologyUnion(*mask);
329 }
330
331 TransferT transfer(pidx, sidx, filter, *tree);
332 tools::dilateActiveValues(*tree, transfer.range(),
333 tools::NN_FACE_EDGE_VERTEX, tools::EXPAND_TILES);
334
335 rasterize<PointDataTreeT, TransferT>(points, transfer);
336 return tree;
337}
338
339} // namespace rasterize_trilinear_internal
340
341/// @endcond
342
343///////////////////////////////////////////////////
344
345template <bool Staggered,
346 typename ValueT,
347 typename FilterT,
348 typename PointDataTreeT>
349inline auto
350rasterizeTrilinear(const PointDataTreeT& points,
351 const std::string& attribute,
352 const FilterT& filter)
353{
355 using TargetTreeT = typename TraitsT::template TreeT<PointDataTree>;
356
357 const auto iter = points.cbeginLeaf();
358 if (!iter) return typename TargetTreeT::Ptr(new TargetTreeT);
359
360 const AttributeSet::Descriptor& descriptor = iter->attributeSet().descriptor();
361 const size_t pidx = descriptor.find("P");
362 const size_t sidx = descriptor.find(attribute);
363 if (pidx == AttributeSet::INVALID_POS) {
364 OPENVDB_THROW(RuntimeError, "Failed to find position attribute");
365 }
366 if (sidx == AttributeSet::INVALID_POS) {
367 OPENVDB_THROW(RuntimeError, "Failed to find source attribute");
368 }
369
370 const NamePair& ptype = descriptor.type(pidx);
371 const NamePair& stype = descriptor.type(sidx);
372 if (ptype.second == NullCodec::name()) {
373 if (stype.second == NullCodec::name()) {
374 return rasterize_trilinear_internal::rasterizeTrilinear
375 <Staggered, ValueT, NullCodec, NullCodec>
376 (points, pidx, sidx, filter);
377 }
378 else {
379 return rasterize_trilinear_internal::rasterizeTrilinear
380 <Staggered, ValueT, UnknownCodec, NullCodec>
381 (points, pidx, sidx, filter);
382 }
383 }
384 else {
385 if (stype.second == NullCodec::name()) {
386 return rasterize_trilinear_internal::rasterizeTrilinear
387 <Staggered, ValueT, NullCodec, UnknownCodec>
388 (points, pidx, sidx, filter);
389 }
390 else {
391 return rasterize_trilinear_internal::rasterizeTrilinear
392 <Staggered, ValueT, UnknownCodec, UnknownCodec>
393 (points, pidx, sidx, filter);
394 }
395 }
396}
397
398
399} // namespace points
400} // namespace OPENVDB_VERSION_NAME
401} // namespace openvdb
402
403#endif //OPENVDB_POINTS_RASTERIZE_TRILINEAR_IMPL_HAS_BEEN_INCLUDED
#define OPENVDB_ASSERT(X)
Definition Assert.h:41
Definition Exceptions.h:63
An immutable object that stores name, type and AttributeSet position for a constant collection of att...
Definition AttributeSet.h:311
size_t find(const std::string &name) const
Return the position of the attribute array whose name is name, or INVALID_POS if no match is found.
const NamePair & type(size_t pos) const
Return the name of the attribute array's type.
@ INVALID_POS
Definition AttributeSet.h:42
@ Staggered
Definition NanoVDB.h:294
Definition AttributeArray.h:42
auto rasterizeTrilinear(const PointDataTreeT &points, const std::string &attribute, const FilterT &filter=NullFilter())
Perform weighted trilinear rasterization of all points within a voxel. This method takes and returns ...
Definition PointRasterizeTrilinearImpl.h:350
Index32 Index
Definition Types.h:54
std::pair< Name, Name > NamePair
Definition AttributeArray.h:40
math::Vec3< float > Vec3f
Definition Types.h:74
OPENVDB_IMPORT void initialize()
Global registration of native Grid, Transform, Metadata and Point attribute types....
constexpr T zeroVal()
Return the value of type T that corresponds to zero.
Definition Math.h:70
int32_t Int32
Definition Types.h:56
Definition Exceptions.h:13
#define OPENVDB_THROW(exception, message)
Definition Exceptions.h:74
Definition AttributeArray.h:437
static const char * name()
Definition AttributeArray.h:443
Definition PointRasterizeTrilinear.h:37
Definition AttributeArray.h:433
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition version.h.in:121
#define OPENVDB_USE_VERSION_NAMESPACE
Definition version.h.in:218