9 #ifndef OPENVDB_POINTS_POINT_RASTERIZE_FRUSTUM_IMPL_HAS_BEEN_INCLUDED
10 #define OPENVDB_POINTS_POINT_RASTERIZE_FRUSTUM_IMPL_HAS_BEEN_INCLUDED
19 namespace point_rasterize_internal {
23 template <
typename FilterT>
24 struct RasterGroupTraits
26 using NewFilterT = FilterT;
27 static NewFilterT resolve(
const FilterT&
filter,
const points::AttributeSet&)
35 struct RasterGroupTraits<RasterGroups>
37 using NewFilterT = points::MultiGroupFilter;
38 static NewFilterT resolve(
const RasterGroups& groups,
const points::AttributeSet& attributeSet)
40 return NewFilterT(groups.includeNames, groups.excludeNames, attributeSet);
46 template <
typename T>
struct BoolTraits {
static const bool IsBool =
false; };
47 template <>
struct BoolTraits<bool> {
static const bool IsBool =
true; };
48 template <>
struct BoolTraits<ValueMask> {
static const bool IsBool =
true; };
53 explicit TrueOp(
double scale) : mOn(scale > 0.0) { }
54 template<
typename ValueType>
59 template <
typename ValueT>
60 typename std::enable_if<std::is_integral<typename ValueTraits<ValueT>::ElementType>
::value, ValueT>
::type
61 castValue(
const double value)
67 template <
typename ValueT>
68 typename std::enable_if<!std::is_integral<typename ValueTraits<ValueT>::ElementType>
::value, ValueT>
::type
69 castValue(
const double value)
71 return static_cast<ValueT
>(
value);
75 template <
typename ValueT>
76 typename std::enable_if<!ValueTraits<ValueT>::IsVec,
bool>
::type
77 greaterThan(
const ValueT& value,
const float threshold)
79 return value >=
static_cast<ValueT
>(threshold);
83 template <
typename ValueT>
84 typename std::enable_if<ValueTraits<ValueT>::IsVec,
bool>
::type
85 greaterThan(
const ValueT& value,
const float threshold)
87 return static_cast<double>(value.lengthSqr()) >= threshold*threshold;
91 template <
typename AttributeT,
typename HandleT,
typename Str
idedHandleT>
92 typename std::enable_if<!ValueTraits<AttributeT>::IsVec, AttributeT>
::type
93 getAttributeScale(HandleT& handlePtr, StridedHandleT&, Index
index)
96 return handlePtr->get(index);
102 template <
typename AttributeT,
typename HandleT,
typename Str
idedHandleT>
103 typename std::enable_if<ValueTraits<AttributeT>::IsVec, AttributeT>
::type
104 getAttributeScale(HandleT& handlePtr, StridedHandleT& stridedHandlePtr, Index index)
107 return handlePtr->get(index);
108 }
else if (stridedHandlePtr) {
110 stridedHandlePtr->get(index, 0),
111 stridedHandlePtr->get(index, 1),
112 stridedHandlePtr->get(index, 2));
114 return AttributeT(1);
118 template <
typename ValueT>
121 template <
typename AttributeT>
122 static ValueT
mul(
const ValueT&
a,
const AttributeT&
b)
129 struct MultiplyOp<bool>
131 template <
typename AttributeT>
132 static bool mul(
const bool&
a,
const AttributeT&
b)
134 return a && (b != zeroVal<AttributeT>());
138 template <
typename PointDataGridT,
typename AttributeT,
typename GridT,
142 using TreeT =
typename GridT::TreeType;
143 using LeafT =
typename TreeT::LeafNodeType;
145 using PointLeafT =
typename PointDataGridT::TreeType::LeafNodeType;
147 using CombinableT = tbb::combinable<GridT>;
148 using SumOpT = tools::valxform::SumOp<ValueT>;
149 using MaxOpT = tools::valxform::MaxOp<ValueT>;
150 using PositionHandleT = openvdb::points::AttributeHandle<Vec3f>;
151 using VelocityHandleT = openvdb::points::AttributeHandle<Vec3f>;
152 using RadiusHandleT = openvdb::points::AttributeHandle<float>;
155 static const int interruptThreshold = 32*32*32;
158 const PointDataGridT& grid,
159 const std::vector<Index64>&
offsets,
160 const size_t attributeIndex,
161 const Name& velocityAttribute,
162 const Name& radiusAttribute,
163 CombinableT& combinable,
164 CombinableT* weightCombinable,
165 const bool dropBuffers,
168 const bool computeMax,
169 const bool alignedTransform,
170 const bool staticCamera,
171 const FrustumRasterizerSettings& settings,
172 const FrustumRasterizerMask&
mask,
173 util::NullInterrupter* interrupt)
176 , mAttributeIndex(attributeIndex)
177 , mVelocityAttribute(velocityAttribute)
178 , mRadiusAttribute(radiusAttribute)
179 , mCombinable(combinable)
180 , mWeightCombinable(weightCombinable)
181 , mDropBuffers(dropBuffers)
184 , mComputeMax(computeMax)
185 , mAlignedTransform(alignedTransform)
186 , mStaticCamera(staticCamera)
187 , mSettings(settings)
189 , mInterrupter(interrupt) { }
191 template <
typename Po
intOpT>
192 static void rasterPoint(
const Coord& ijk,
const double scale,
193 const AttributeT& attributeScale, PointOpT& op)
195 op(ijk, scale, attributeScale);
198 template <
typename Po
intOpT>
199 static void rasterPoint(
const Vec3d&
position,
const double scale,
200 const AttributeT& attributeScale, PointOpT& op)
203 op(ijk, scale, attributeScale);
206 template <
typename SphereOpT>
207 static void rasterVoxelSphere(
const Vec3d&
position,
const double scale,
208 const AttributeT& attributeScale,
const float radius, util::NullInterrupter* interrupter, SphereOpT& op)
210 assert(radius > 0.0
f);
212 int &i = ijk[0], &
j = ijk[1], &k = ijk[2];
217 const bool interrupt = interrupter && (imax-imin)*(jmax-jmin)*(kmax-kmin) > interruptThreshold;
219 for (i = imin; i <= imax; ++i) {
220 if (interrupt && interrupter->wasInterrupted())
break;
222 for (j = jmin; j <= jmax; ++
j) {
223 if (interrupt && interrupter->wasInterrupted())
break;
225 for (k = kmin; k <= kmax; ++k) {
226 const auto x2y2z2 = x2y2 +
math::Pow2(k - position[2]);
227 op(ijk, scale, attributeScale, x2y2z2, radius*radius);
233 template <
typename SphereOpT>
234 static void rasterApproximateFrustumSphere(
const Vec3d& position,
const double scale,
235 const AttributeT& attributeScale,
const float radiusWS,
236 const math::Transform& frustum,
const CoordBBox* clipBBox,
237 util::NullInterrupter* interrupter, SphereOpT& op)
239 Vec3d voxelSize = frustum.voxelSize(position);
245 frustumBBox.intersect(*clipBBox);
248 Vec3i outMin = frustumBBox.min().asVec3i();
249 Vec3i outMax = frustumBBox.max().asVec3i();
251 const bool interrupt = interrupter && frustumBBox.volume() > interruptThreshold;
256 int &
x = outXYZ.
x(), &
y = outXYZ.y(), &
z = outXYZ.z();
257 for (x = outMin.x(); x <= outMax.x(); ++
x) {
258 if (interrupt && interrupter->wasInterrupted())
break;
260 for (
y = outMin.y();
y <= outMax.y(); ++
y) {
261 if (interrupt && interrupter->wasInterrupted())
break;
263 for (
z = outMin.z();
z <= outMax.z(); ++
z) {
270 double distanceSqr = offset.
dot(offset);
272 op(outXYZ, scale, attributeScale, distanceSqr, radiusWS*radiusWS);
278 template <
typename SphereOpT>
279 static void rasterFrustumSphere(
const Vec3d& position,
const double scale,
280 const AttributeT& attributeScale,
const float radiusWS,
281 const math::Transform& frustum,
const CoordBBox* clipBBox,
282 util::NullInterrupter* interrupter, SphereOpT& op)
284 const Vec3d positionWS = frustum.indexToWorld(position);
286 BBoxd inputBBoxWS(positionWS-radiusWS, positionWS+radiusWS);
292 frustumMin, frustumMax);
297 frustumBBox.intersect(*clipBBox);
300 Vec3i outMin = frustumBBox.min().asVec3i();
301 Vec3i outMax = frustumBBox.max().asVec3i();
303 const bool interrupt = interrupter && frustumBBox.volume() > interruptThreshold;
308 int &x = outXYZ.
x(), &
y = outXYZ.y(), &
z = outXYZ.z();
309 for (x = outMin.x(); x <= outMax.x(); ++
x) {
310 if (interrupt && interrupter->wasInterrupted())
break;
312 for (
y = outMin.y();
y <= outMax.y(); ++
y) {
313 if (interrupt && interrupter->wasInterrupted())
break;
315 for (
z = outMin.z();
z <= outMax.z(); ++
z) {
318 Vec3R xyzWS = frustum.indexToWorld(xyz);
320 double xDist = xyzWS.
x() - positionWS.x();
321 double yDist = xyzWS.y() - positionWS.y();
322 double zDist = xyzWS.z() - positionWS.z();
324 double distanceSqr = xDist*xDist+yDist*yDist+zDist*zDist;
325 op(outXYZ, scale, attributeScale, distanceSqr, radiusWS*radiusWS);
331 void operator()(
const PointLeafT& leaf,
size_t)
const
333 if (mInterrupter && mInterrupter->wasInterrupted()) {
334 thread::cancelGroupExecution();
338 using AccessorT = tree::ValueAccessor<typename GridT::TreeType>;
339 using MaskAccessorT = tree::ValueAccessor<const MaskTree>;
341 constexpr
bool isBool = BoolTraits<ValueT>::IsBool;
342 const bool isFrustum = !mSettings.transform->isLinear();
344 const bool useRaytrace = mSettings.velocityMotionBlur || !mStaticCamera;
345 const bool useRadius = mSettings.useRadius;
346 const float radiusScale = mSettings.radiusScale;
347 const float radiusThreshold =
std::sqrt(3.0
f);
349 const float threshold = mSettings.threshold;
350 const bool scaleByVoxelVolume = !useRadius && mSettings.scaleByVoxelVolume;
352 const float shutterStartDt = mSettings.camera.shutterStart()/mSettings.framesPerSecond;
353 const float shutterEndDt = mSettings.camera.shutterEnd()/mSettings.framesPerSecond;
354 const int motionSteps =
std::max(1, mSettings.motionSamples-1);
356 std::vector<Vec3d> motionPositions(motionSteps+1,
Vec3d());
357 std::vector<Vec2s> frustumRadiusSizes(motionSteps+1,
Vec2s());
359 const auto& pointsTransform = mGrid.constTransform();
361 const float voxelSize =
static_cast<float>(mSettings.transform->voxelSize()[0]);
363 auto& grid = mCombinable.local();
364 auto& tree = grid.tree();
365 const auto&
transform = *(mSettings.transform);
367 grid.setTransform(mSettings.transform->copy());
369 AccessorT valueAccessor(tree);
371 std::unique_ptr<MaskAccessorT> maskAccessor;
372 auto maskTree =
mMask.getTreePtr();
373 if (maskTree) maskAccessor.reset(
new MaskAccessorT(*maskTree));
377 std::unique_ptr<AccessorT> weightAccessor;
378 if (mWeightCombinable) {
379 auto& weightGrid = mWeightCombinable->local();
380 auto& weightTree = weightGrid.tree();
381 weightAccessor.reset(
new AccessorT(weightTree));
387 std::unique_ptr<TreeT> tempTree;
388 std::unique_ptr<TreeT> tempWeightTree;
389 std::unique_ptr<AccessorT> tempValueAccessor;
390 std::unique_ptr<AccessorT> tempWeightAccessor;
391 if (useRadius && !mComputeMax) {
392 tempTree.reset(
new TreeT(tree.background()));
393 tempValueAccessor.reset(
new AccessorT(*tempTree));
394 if (weightAccessor) {
395 tempWeightTree.reset(
new TreeT(weightAccessor->tree().background()));
396 tempWeightAccessor.reset(
new AccessorT(*tempWeightTree));
403 auto doModifyVoxelOp = [&](
const Coord& ijk,
const double scale,
const AttributeT& attributeScale,
404 const bool isTemp,
const bool forceSum)
406 if (
mMask && !
mMask.valid(ijk, maskAccessor.get()))
return;
409 if (!math::isZero<AttributeT>(attributeScale) && !math::isNegative<AttributeT>(attributeScale)) {
410 valueAccessor.modifyValue(ijk, TrueOp(scale));
413 ValueT weightValue = castValue<ValueT>(
scale);
415 if (scaleByVoxelVolume) {
416 newValue /=
static_cast<ValueT
>(
transform.voxelSize(ijk.asVec3d()).product());
418 if (point_rasterize_internal::greaterThan(newValue, threshold)) {
420 tempValueAccessor->modifyValue(ijk, MaxOpT(newValue));
421 if (tempWeightAccessor) {
422 tempWeightAccessor->modifyValue(ijk, MaxOpT(weightValue));
425 if (mComputeMax && !forceSum) {
426 valueAccessor.modifyValue(ijk, MaxOpT(newValue));
428 valueAccessor.modifyValue(ijk, SumOpT(newValue));
430 if (weightAccessor) {
431 weightAccessor->modifyValue(ijk, SumOpT(weightValue));
439 auto modifyVoxelOp = [&](
const Coord& ijk,
const double scale,
const AttributeT& attributeScale)
441 doModifyVoxelOp(ijk, scale, attributeScale,
false,
false);
445 auto sumVoxelOp = [&](
const Coord& ijk,
const double scale,
const AttributeT& attributeScale)
447 doModifyVoxelOp(ijk, scale, attributeScale,
false,
true);
453 auto doModifyVoxelByDistanceOp = [&](
const Coord& ijk,
const double scale,
const AttributeT& attributeScale,
454 const double distanceSqr,
const double radiusSqr,
const bool isTemp)
456 if (distanceSqr >= radiusSqr)
return;
458 valueAccessor.modifyValue(ijk, TrueOp(scale));
462 double result = 1.0 - distance/radius;
463 doModifyVoxelOp(ijk, result * scale, attributeScale, isTemp,
false);
468 auto modifyVoxelByDistanceOp = [&](
const Coord& ijk,
const double scale,
const AttributeT& attributeScale,
469 const double distanceSqr,
const double radiusSqr)
471 doModifyVoxelByDistanceOp(ijk, scale, attributeScale, distanceSqr, radiusSqr,
false);
475 auto modifyTempVoxelByDistanceOp = [&](
const Coord& ijk,
const double scale,
const AttributeT& attributeScale,
476 const double distanceSqr,
const double radiusSqr)
478 doModifyVoxelByDistanceOp(ijk, scale, attributeScale, distanceSqr, radiusSqr,
true);
481 typename points::AttributeHandle<AttributeT>::Ptr attributeHandle;
482 using ElementT =
typename ValueTraits<AttributeT>::ElementType;
483 typename points::AttributeHandle<ElementT>::Ptr stridedAttributeHandle;
486 const auto& attributeArray = leaf.constAttributeArray(mAttributeIndex);
487 if (attributeArray.stride() == 3) {
494 size_t positionIndex = leaf.attributeSet().find(
"P");
495 size_t velocityIndex = leaf.attributeSet().find(mVelocityAttribute);
496 size_t radiusIndex = leaf.attributeSet().find(mRadiusAttribute);
498 auto positionHandle = PositionHandleT::create(
499 leaf.constAttributeArray(positionIndex));
500 auto velocityHandle = (useRaytrace && leaf.hasAttribute(velocityIndex)) ?
501 VelocityHandleT::create(leaf.constAttributeArray(velocityIndex)) :
502 VelocityHandleT::Ptr();
503 auto radiusHandle = (useRadius && leaf.hasAttribute(radiusIndex)) ?
504 RadiusHandleT::create(leaf.constAttributeArray(radiusIndex)) :
505 RadiusHandleT::Ptr();
507 for (
auto iter = leaf.beginIndexOn(mFilter); iter; ++iter) {
512 const AttributeT attributeScale = getAttributeScale<AttributeT>(
513 attributeHandle, stridedAttributeHandle, *iter);
515 float radiusWS = 1.0f, radius = 1.0f;
517 radiusWS *= radiusScale;
518 if (radiusHandle) radiusWS *= radiusHandle->get(*iter);
521 }
else if (voxelSize > 0.0
f) {
522 radius = radiusWS / voxelSize;
528 bool doRadius = useRadius;
529 if (!isFrustum && radius < radiusThreshold) {
533 float increment = shutterEndDt - shutterStartDt;
537 openvdb::Vec3f velocity(0.0
f);
538 bool doRaytrace = useRaytrace;
543 if (velocityHandle) velocity = velocityHandle->get(*iter);
550 if (motionSteps > 1) increment /=
float(motionSteps);
552 Vec3d position = positionHandle->get(*iter) + iter.getCoord().asVec3d();
556 position = pointsTransform.indexToWorld(position);
558 for (
int motionStep = 0; motionStep <= motionSteps; motionStep++) {
560 float offset = motionStep == motionSteps ? shutterEndDt :
561 (shutterStartDt + increment *
static_cast<float>(motionStep));
562 Vec3d samplePosition = position + velocity *
offset;
564 const math::Transform* sampleTransform = &
transform;
565 if (!mSettings.camera.isStatic()) {
566 sampleTransform = &mSettings.camera.transform(motionStep);
567 if (mSettings.camera.hasWeight(motionStep)) {
568 const float weight = mSettings.camera.weight(motionStep);
569 const Vec3d referencePosition =
transform.worldToIndex(samplePosition);
570 const Vec3d adjustedPosition = sampleTransform->worldToIndex(samplePosition);
571 motionPositions[motionStep] = referencePosition + (adjustedPosition - referencePosition) * weight;
573 motionPositions[motionStep] = sampleTransform->worldToIndex(samplePosition);
576 motionPositions[motionStep] = sampleTransform->worldToIndex(samplePosition);
578 if (doRadius && isFrustum) {
579 Vec3d left = sampleTransform->worldToIndex(samplePosition -
Vec3d(radiusWS, 0, 0));
580 Vec3d right = sampleTransform->worldToIndex(samplePosition +
Vec3d(radiusWS, 0, 0));
582 Vec3d top = sampleTransform->worldToIndex(samplePosition +
Vec3d(0, radiusWS, 0));
583 Vec3d bottom = sampleTransform->worldToIndex(samplePosition -
Vec3d(0, radiusWS, 0));
585 frustumRadiusSizes[motionStep].x() =
width;
586 frustumRadiusSizes[motionStep].y() =
height;
590 double totalDistance = 0.0;
591 for (
size_t i = 0; i < motionPositions.size()-1; i++) {
597 double distanceWeight = totalDistance > 0.0 ? 1.0 / totalDistance : 1.0;
599 if (doRadius && !mComputeMax) {
601 for (
auto leaf = tempTree->beginLeaf(); leaf; ++leaf) {
602 leaf->setValuesOff();
604 if (tempWeightAccessor) {
605 for (
auto leaf = tempWeightTree->beginLeaf(); leaf; ++leaf) {
606 leaf->setValuesOff();
611 for (
int motionStep = 0; motionStep < motionSteps; motionStep++) {
613 Vec3d startPosition = motionPositions[motionStep];
614 Vec3d endPosition = motionPositions[motionStep+1];
617 double distance = direction.length();
622 float maxRadius = radius;
624 if (doRadius && isFrustum) {
625 const Vec2s& startRadius = frustumRadiusSizes[motionStep];
626 const Vec2s& endRadius = frustumRadiusSizes[motionStep+1];
628 if (startRadius[0] < radiusThreshold && startRadius[1] < radiusThreshold &&
629 endRadius[0] < radiusThreshold && endRadius[1] < radiusThreshold) {
634 maxRadius =
std::max(startRadius[0], startRadius[1]);
635 maxRadius =
std::max(maxRadius, endRadius[0]);
636 maxRadius =
std::max(maxRadius, endRadius[1]);
641 distanceWeight =
std::min(distanceWeight, 1.0);
648 double spherePacking = mSettings.accurateSphereMotionBlur ? 4.0 : 2.0;
650 const int steps =
std::max(2,
math::Ceil(distance * spherePacking /
double(maxRadius)) + 1);
652 Vec3d sample(startPosition);
655 for (
int step = 0; step < steps; step++) {
658 if (mSettings.accurateFrustumRadius) {
659 this->rasterFrustumSphere(sample, mScale * distanceWeight,
660 attributeScale, radiusWS,
transform, clipBBox, mInterrupter, modifyVoxelByDistanceOp);
662 this->rasterApproximateFrustumSphere(sample, mScale * distanceWeight,
663 attributeScale, radiusWS,
transform, clipBBox, mInterrupter, modifyVoxelByDistanceOp);
666 if (mSettings.accurateFrustumRadius) {
667 this->rasterFrustumSphere(sample, mScale * distanceWeight,
668 attributeScale, radiusWS,
transform, clipBBox, mInterrupter, modifyTempVoxelByDistanceOp);
670 this->rasterApproximateFrustumSphere(sample, mScale * distanceWeight,
671 attributeScale, radiusWS,
transform, clipBBox, mInterrupter, modifyTempVoxelByDistanceOp);
676 this->rasterVoxelSphere(sample, mScale * distanceWeight,
677 attributeScale, radius, mInterrupter, modifyVoxelByDistanceOp);
679 this->rasterVoxelSphere(sample, mScale * distanceWeight,
680 attributeScale, radius, mInterrupter, modifyTempVoxelByDistanceOp);
683 if (step < (steps-1)) sample +=
offset;
684 else sample = endPosition;
692 direction.normalize();
693 mDdaRay.setDir(direction);
696 mDdaRay.setEye(startPosition +
Vec3d(0.5));
700 mDdaRay.clip(*clipBBox);
705 bool forceSum = motionStep > 0;
709 const Coord& voxel = mDda.voxel();
710 double delta = (mDda.next() - mDda.time()) * distanceWeight;
712 this->rasterPoint(voxel, mScale * delta,
713 attributeScale, sumVoxelOp);
716 this->rasterPoint(voxel, mScale * delta,
717 attributeScale, modifyVoxelOp);
719 if (!mDda.step())
break;
724 if (doRadius && !mComputeMax) {
726 for (
auto iter = tempTree->cbeginValueOn(); iter; ++iter) {
727 valueAccessor.modifyValue(iter.getCoord(), SumOpT(*iter));
731 if (weightAccessor) {
732 for (
auto iter = tempWeightTree->cbeginValueOn(); iter; ++iter) {
733 weightAccessor->modifyValue(iter.getCoord(), SumOpT(*iter));
739 if (!mAlignedTransform) {
741 pointsTransform.indexToWorld(position));
746 if (mSettings.accurateFrustumRadius) {
747 this->rasterFrustumSphere(position, mScale, attributeScale,
748 radiusWS,
transform, clipBBox, mInterrupter, modifyVoxelByDistanceOp);
750 this->rasterApproximateFrustumSphere(position, mScale, attributeScale,
751 radiusWS,
transform, clipBBox, mInterrupter, modifyVoxelByDistanceOp);
754 this->rasterVoxelSphere(position, mScale, attributeScale,
755 radius, mInterrupter, modifyVoxelByDistanceOp);
758 this->rasterPoint(position, mScale, attributeScale, modifyVoxelOp);
767 typename PointLeafT::Buffer emptyBuffer(PartialCreate(), zeroVal<PointIndexT>());
768 (
const_cast<PointLeafT&
>(leaf)).swap(emptyBuffer);
775 mutable math::Ray<double> mDdaRay;
776 mutable math::DDA<openvdb::math::Ray<double>> mDda;
777 const PointDataGridT& mGrid;
778 const std::vector<Index64>& mOffsets;
779 const size_t mAttributeIndex;
780 const Name mVelocityAttribute;
781 const Name mRadiusAttribute;
782 CombinableT& mCombinable;
783 CombinableT* mWeightCombinable;
784 const bool mDropBuffers;
786 const FilterT& mFilter;
787 const bool mComputeMax;
788 const bool mAlignedTransform;
789 const bool mStaticCamera;
790 const FrustumRasterizerSettings& mSettings;
791 const FrustumRasterizerMask&
mMask;
792 util::NullInterrupter* mInterrupter;
798 template<
typename Gr
idT>
799 struct GridCombinerOp
801 using CombinableT =
typename tbb::combinable<GridT>;
803 using TreeT =
typename GridT::TreeType;
804 using LeafT =
typename TreeT::LeafNodeType;
806 using SumOpT = tools::valxform::SumOp<typename TreeT::ValueType>;
807 using MaxOpT = tools::valxform::MaxOp<typename TreeT::ValueType>;
809 GridCombinerOp(GridT& grid,
bool sum)
813 void operator()(
const GridT& grid)
815 for (
auto leaf = grid.tree().beginLeaf(); leaf; ++leaf) {
816 auto* newLeaf = mTree.probeLeaf(leaf->origin());
819 auto& tree =
const_cast<GridT&
>(grid).tree();
820 mTree.addLeaf(tree.template stealNode<LeafT>(leaf->origin(),
821 zeroVal<ValueType>(),
false));
826 for (
auto iter = leaf->cbeginValueOn(); iter; ++iter) {
827 newLeaf->modifyValue(iter.offset(), SumOpT(
ValueType(*iter)));
830 for (
auto iter = leaf->cbeginValueOn(); iter; ++iter) {
831 newLeaf->modifyValue(iter.offset(), MaxOpT(
ValueType(*iter)));
844 template<
typename Gr
idT>
845 struct CombinableTraits {
846 using OpT = GridCombinerOp<GridT>;
847 using T =
typename OpT::CombinableT;
851 template <
typename Po
intDataGr
idT>
852 class GridToRasterize
855 using GridPtr =
typename PointDataGridT::Ptr;
856 using GridConstPtr =
typename PointDataGridT::ConstPtr;
857 using PointDataTreeT =
typename PointDataGridT::TreeType;
858 using PointDataLeafT =
typename PointDataTreeT::LeafNodeType;
860 GridToRasterize(GridPtr& grid,
bool stream,
861 const FrustumRasterizerSettings& settings,
862 const FrustumRasterizerMask&
mask)
865 , mSettings(settings)
868 GridToRasterize(GridConstPtr& grid,
const FrustumRasterizerSettings& settings,
869 const FrustumRasterizerMask&
mask)
872 , mSettings(settings)
875 const typename PointDataGridT::TreeType& tree()
const
877 return mGrid->constTree();
880 void setLeafPercentage(
int percentage)
885 int leafPercentage()
const
887 return mLeafPercentage;
892 return mGrid->memUsage() + mLeafOffsets.capacity();
895 template <
typename AttributeT,
typename Gr
idT,
typename FilterT>
897 typename CombinableTraits<GridT>::T& combiner,
typename CombinableTraits<GridT>::T* weightCombiner,
898 const float scale,
const FilterT& groupFilter,
const bool computeMax,
const bool reduceMemory,
899 util::NullInterrupter* interrupter)
901 using point_rasterize_internal::RasterizeOp;
903 const auto& velocityAttribute = mSettings.velocityMotionBlur ?
904 mSettings.velocityAttribute :
"";
905 const auto& radiusAttribute = mSettings.useRadius ?
906 mSettings.radiusAttribute :
"";
908 bool isPositionAttribute = attribute ==
"P";
909 bool isVelocityAttribute = attribute == mSettings.velocityAttribute;
910 bool isRadiusAttribute = attribute == mSettings.radiusAttribute;
913 const auto& attributeSet = mGrid->constTree().cbeginLeaf()->attributeSet();
914 const size_t attributeIndex = attributeSet.find(attribute);
920 const auto* attributeArray = attributeSet.getConst(attributeIndex);
921 const Index stride = bool(attributeArray) ? attributeArray->stride() :
Index(1);
922 const auto& actualValueType = attributeSet.descriptor().valueType(attributeIndex);
923 const auto requestedValueType =
Name(typeNameAsString<AttributeT>());
924 const bool packVector = stride == 3 &&
930 requestedValueType == typeNameAsString<Vec3I>()));
931 if (!packVector && actualValueType != requestedValueType) {
933 "Attribute type requested for rasterization \"" << requestedValueType <<
"\""
934 " must match attribute value type \"" << actualValueType <<
"\"");
938 tree::LeafManager<PointDataTreeT> leafManager(mGrid->tree());
941 const bool dropBuffers = mStream && reduceMemory;
944 using ResolvedFilterT =
typename point_rasterize_internal::RasterGroupTraits<FilterT>::NewFilterT;
945 auto resolvedFilter = point_rasterize_internal::RasterGroupTraits<FilterT>::resolve(
946 groupFilter, attributeSet);
949 if (mLeafOffsets.empty()) {
951 false, mSettings.threaded);
956 if (attributeExists && !isPositionAttribute && !isVelocityAttribute && !isRadiusAttribute) {
958 [&](PointDataLeafT& leaf,
size_t ) {
959 leaf.attributeArray(attributeIndex).setStreaming(
true);
965 size_t positionIndex = attributeSet.find(
"P");
967 [&](PointDataLeafT& leaf,
size_t ) {
968 leaf.attributeArray(positionIndex).setStreaming(
true);
971 if (mSettings.velocityMotionBlur || !mSettings.camera.isStatic()) {
972 size_t velocityIndex = attributeSet.find(velocityAttribute);
975 [&](PointDataLeafT& leaf,
size_t ) {
976 leaf.attributeArray(velocityIndex).setStreaming(
true);
981 if (mSettings.useRadius) {
982 size_t radiusIndex = attributeSet.find(radiusAttribute);
985 [&](PointDataLeafT& leaf,
size_t ) {
986 leaf.attributeArray(radiusIndex).setStreaming(
true);
994 const bool alignedTransform = *(mSettings.transform) == mGrid->constTransform();
996 RasterizeOp<PointDataGridT, AttributeT, GridT, ResolvedFilterT> rasterizeOp(
997 *mGrid, mLeafOffsets, attributeIndex, velocityAttribute, radiusAttribute, combiner, weightCombiner,
998 dropBuffers, scale, resolvedFilter, computeMax, alignedTransform, mSettings.camera.isStatic(),
999 mSettings,
mMask, interrupter);
1000 leafManager.foreach(rasterizeOp, mSettings.threaded);
1003 if (reduceMemory && !mLeafOffsets.empty()) {
1004 mLeafOffsets.clear();
1006 mLeafOffsets.shrink_to_fit();
1013 const FrustumRasterizerSettings& mSettings;
1014 const FrustumRasterizerMask&
mMask;
1015 int mLeafPercentage = -1;
1016 std::vector<Index64> mLeafOffsets;
1020 template <
typename ValueT>
1021 typename std::enable_if<!ValueTraits<ValueT>::IsVec, ValueT>
::type
1022 computeWeightedValue(
const ValueT& value,
const ValueT& weight)
1024 constexpr
bool isSignedInt = std::is_integral<ValueT>() && std::is_signed<ValueT>();
1028 return zeroVal<ValueT>();
1030 return value / weight;
1035 template <
typename ValueT>
1036 typename std::enable_if<ValueTraits<ValueT>::IsVec, ValueT>
::type
1037 computeWeightedValue(
const ValueT& value,
const ValueT& weight)
1039 using ElementT =
typename ValueTraits<ValueT>::ElementType;
1041 constexpr
bool isSignedInt = std::is_integral<ElementT>() && std::is_signed<ElementT>();
1044 for (
int i=0; i<ValueTraits<ValueT>::Size; ++i) {
1047 result[i] = zeroVal<ElementT>();
1049 result[i] = value[i] / weight[i];
1064 : mTransforms{transform}
1069 return mTransforms.size() <= 1;
1074 mTransforms.clear();
1080 mTransforms.push_back(transform);
1081 mWeights.push_back(weight);
1086 return mTransforms.size();
1092 if (mTransforms.size() >= 2) {
1093 const auto&
transform = mTransforms.front();
1095 for (
const auto& testTransform : mTransforms) {
1101 while (mTransforms.size() > 1) {
1102 mTransforms.pop_back();
1107 if (!mWeights.empty()) {
1109 for (
Index i = 0; i < mWeights.size(); i++) {
1115 if (!hasWeight) mWeights.clear();
1121 if (mWeights.empty())
return false;
1122 assert(i < mWeights.size());
1128 if (mWeights.empty()) {
1131 assert(i < mWeights.size());
1138 if (mTransforms.size() == 1) {
1139 return mTransforms.front();
1141 assert(i < mTransforms.size());
1142 return mTransforms[i];
1148 assert(!mTransforms.empty());
1149 return mTransforms.front();
1154 assert(!mTransforms.empty());
1155 return mTransforms.back();
1160 mShutterStart =
start;
1166 return mShutterStart;
1181 const bool clipToFrustum,
1182 const bool invertMask)
1185 , mInvert(invertMask)
1196 mMask->setTransform(transform.
copy());
1197 tools::resampleToMatch<tools::PointSampler>(*
mask, *mMask);
1204 if (!bbox.
empty()) {
1209 tempMask->sparseFill(coordBBox,
true,
true);
1213 bboxMask->setTransform(mMask ? mMask->transformPtr() : transform.
copy());
1214 tools::resampleToMatch<tools::PointSampler>(*tempMask, *bboxMask);
1218 mMask->topologyUnion(*bboxMask);
1224 if (clipToFrustum) {
1225 auto frustumMap = transform.template constMap<math::NonlinearFrustumMap>();
1227 const auto& frustumBBox = frustumMap->getBBox();
1234 FrustumRasterizerMask::operator bool()
const
1236 return mMask || !mClipBBox.empty();
1254 const bool maskValue = acc ? acc->
isValueOn(ijk) :
true;
1255 const bool insideMask = mInvert ? !maskValue : maskValue;
1256 const bool insideFrustum = mClipBBox.empty() ?
true : mClipBBox.isInside(ijk);
1257 return insideMask && insideFrustum;
1264 template <
typename Po
intDataGr
idT>
1268 : mSettings(settings)
1270 , mInterrupter(interrupt)
1274 "Using velocity motion blur during rasterization requires a velocity attribute.");
1278 template <
typename Po
intDataGr
idT>
1283 if (!grid || grid->tree().empty())
return;
1286 mPointGrids.emplace_back(grid, mSettings, mMask);
1289 template <
typename Po
intDataGr
idT>
1294 if (!grid || grid->tree().empty())
return;
1296 mPointGrids.emplace_back(grid, stream, mSettings, mMask);
1299 template <
typename Po
intDataGr
idT>
1303 mPointGrids.clear();
1306 template <
typename Po
intDataGr
idT>
1310 return mPointGrids.size();
1313 template <
typename Po
intDataGr
idT>
1317 size_t mem =
sizeof(*this) +
sizeof(mPointGrids);
1318 for (
const auto& grid : mPointGrids) {
1319 mem += grid.memUsage();
1324 template <
typename Po
intDataGr
idT>
1325 template <
typename FilterT>
1331 auto density = rasterizeAttribute<FloatGrid, float>(
"",
mode, reduceMemory,
scale,
filter);
1333 density->setName(
"density");
1337 template <
typename Po
intDataGr
idT>
1338 template <
typename FilterT>
1345 density->setName(
"density");
1349 template <
typename Po
intDataGr
idT>
1350 template <
typename FilterT>
1359 for (
const auto&
points : mPointGrids) {
1360 auto leaf =
points.tree().cbeginLeaf();
1361 const auto& descriptor = leaf->attributeSet().descriptor();
1362 const size_t targetIndex = descriptor.find(attribute);
1365 const auto* attributeArray = leaf->attributeSet().getConst(attribute);
1366 if (!attributeArray)
continue;
1367 stride = attributeArray->stride();
1368 sourceType = descriptor.valueType(targetIndex);
1369 if (!sourceType.empty())
break;
1374 if (sourceType.empty())
return {};
1381 #ifndef ONLY_RASTER_FLOAT
1411 std::ostringstream ostr;
1412 ostr <<
"Cannot rasterize attribute of type - " << sourceType;
1413 if (stride > 1) ostr <<
" x " <<
stride;
1418 template <
typename Po
intDataGr
idT>
1419 template <
typename Gr
idT,
typename AttributeT,
typename FilterT>
1422 bool reduceMemory,
float scale,
const FilterT&
filter)
1424 if (attribute ==
"P") {
1425 OPENVDB_THROW(ValueError,
"Cannot rasterize position attribute.")
1428 auto grid = GridT::create();
1429 grid->setName(attribute);
1430 grid->setTransform(mSettings.transform->copy());
1437 template <
typename Po
intDataGr
idT>
1438 template <
typename Gr
idT,
typename FilterT>
1444 static_assert(point_rasterize_internal::BoolTraits<ValueT>::IsBool,
1445 "Value type of mask to be rasterized must be bool or ValueMask.");
1448 grid->setName(
"mask");
1453 template <
typename Po
intDataGr
idT>
1454 template <
typename AttributeT,
typename Gr
idT,
typename FilterT>
1458 float scale,
const FilterT&
filter)
1460 using openvdb::points::point_mask_internal::GridCombinerOp;
1461 using point_rasterize_internal::computeWeightedValue;
1463 using TreeT =
typename GridT::TreeType;
1464 using LeafT =
typename TreeT::LeafNodeType;
1466 using CombinerOpT =
typename point_rasterize_internal::CombinableTraits<GridT>::OpT;
1467 using CombinableT =
typename point_rasterize_internal::CombinableTraits<GridT>::T;
1471 std::stringstream ss;
1472 ss <<
"Rasterizing Points ";
1473 if (!mSettings.camera.isStatic() || mSettings.velocityMotionBlur) {
1474 ss <<
"with Motion Blur ";
1476 if (mSettings.transform->isLinear()) {
1477 ss <<
"to Linear Volume";
1479 ss <<
"to Frustum Volume";
1481 mInterrupter->start(ss.str().c_str());
1487 if (useMaximum && VecTraits<ValueT>::IsVec) {
1489 "Cannot use maximum mode when rasterizing vector attributes.");
1492 if ((useMaximum || useWeight) && point_rasterize_internal::BoolTraits<ValueT>::IsBool) {
1494 "Cannot use maximum or average modes when rasterizing bool attributes.");
1497 CombinableT combiner;
1498 CombinableT weightCombiner;
1499 CombinableT* weightCombinerPtr = useWeight ? &weightCombiner :
nullptr;
1505 if (mPointGrids.size() == 1) {
1506 mPointGrids[0].setLeafPercentage(100);
1511 std::vector<Index64> leafCounts;
1512 leafCounts.reserve(mPointGrids.size());
1513 for (
auto&
points : mPointGrids) {
1514 leafCount +=
points.tree().leafCount();
1515 leafCounts.push_back(leafCount);
1519 if (leafCount ==
Index64(0)) leafCount++;
1522 for (
size_t i = 0; i < leafCounts.size(); i++) {
1523 int percentage =
static_cast<int>(
math::Round((static_cast<float>(leafCounts[i]))/
1524 static_cast<float>(leafCount)));
1525 mPointGrids[i].setLeafPercentage(percentage);
1532 for (
auto&
points : mPointGrids) {
1534 points.template rasterize<AttributeT, GridT>(
1542 mInterrupter->wasInterrupted(
points.leafPercentage())) {
1550 combiner.combine_each(combineOp);
1556 auto weightGrid = GridT::create(ValueT(1));
1557 CombinerOpT weightCombineOp(*weightGrid,
true);
1558 weightCombiner.combine_each(weightCombineOp);
1560 tree::LeafManager<TreeT> leafManager(grid.tree());
1561 leafManager.foreach(
1562 [&](LeafT& leaf,
size_t ) {
1563 auto weightAccessor = weightGrid->getConstAccessor();
1564 for (
auto iter = leaf.beginValueOn(); iter; ++iter) {
1565 auto weight = weightAccessor.getValue(iter.getCoord());
1566 iter.setValue(computeWeightedValue(iter.getValue(), weight));
1569 mSettings.threaded);
1572 if (mInterrupter) mInterrupter->end();
1580 #endif // OPENVDB_POINTS_POINT_RASTERIZE_FRUSTUM_IMPL_HAS_BEEN_INCLUDED
float weight(Index i) const
Efficient rasterization of one or more VDB Points grids into a linear or frustum volume with the opti...
int Ceil(float x)
Return the ceiling of x.
bool isValueOn(const Coord &xyz) const
Return the active state of the voxel at the given coordinates.
GLdouble GLdouble GLint GLint const GLdouble * points
SharedPtr< GridBase > Ptr
void rasterize(const PointDataTreeOrGridT &points, TransferT &transfer, const FilterT &filter=NullFilter(), InterrupterT *interrupter=nullptr)
Perform potentially complex rasterization from a user defined transfer scheme.
RasterMode
How to composite points into a volume.
Type Pow2(Type x)
Return x2.
const math::Transform & lastTransform() const
IMATH_HOSTDEVICE constexpr int floor(T x) IMATH_NOEXCEPT
IMF_EXPORT IMATH_NAMESPACE::V3f direction(const IMATH_NAMESPACE::Box2i &dataWindow, const IMATH_NAMESPACE::V2f &pixelPosition)
const char * typeNameAsString< int32_t >()
const char * typeNameAsString< Vec3i >()
GLsizei const GLfloat * value
MaskTree::ConstPtr getTreePtr() const
vfloat4 sqrt(const vfloat4 &a)
GLdouble GLdouble GLdouble z
bool hasWeight(Index i) const
const char * typeNameAsString< int16_t >()
size_t size() const
Return number of PointDataGrids in the rasterizer.
GLboolean GLboolean GLboolean GLboolean a
GLuint GLsizei GLsizei * length
#define OPENVDB_USE_VERSION_NAMESPACE
FrustumRasterizer(const FrustumRasterizerSettings &settings, const FrustumRasterizerMask &mask=FrustumRasterizerMask(), util::NullInterrupter *interrupt=nullptr)
main constructor
ImageBuf OIIO_API min(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
The Value Accessor Implementation and API methods. The majoirty of the API matches the API of a compa...
**But if you need a result
Base class for interrupters.
bool isNegative(const Type &x)
Return true if x is less than zero.
const char * typeNameAsString< Vec3d >()
FloatGrid::Ptr rasterizeUniformDensity(RasterMode mode=RasterMode::MAXIMUM, bool reduceMemory=false, float scale=1.0f, const FilterT &filter=FilterT())
SharedPtr< T > ConstPtrCast(const SharedPtr< U > &ptr)
Return a new shared pointer that points to the same object as the given pointer but with possibly dif...
GLuint GLsizei const GLuint const GLintptr * offsets
GA_API const UT_StringHolder scale
const char * typeNameAsString< Vec3f >()
GridBase::Ptr rasterizeAttribute(const Name &attribute, RasterMode mode=RasterMode::ACCUMULATE, bool reduceMemory=false, float scale=1.0f, const FilterT &filter=FilterT())
GLint GLsizei GLsizei height
bool valid(const Coord &ijk, AccessorT *acc) const
void appendTransform(const math::Transform &, float weight=1.0f)
bool isApproxEqual(const Type &a, const Type &b, const Type &tolerance)
Return true if a is equal to b to within the given tolerance.
const CoordBBox & clipBBox() const
IMATH_NAMESPACE::V2f float
const math::Transform & transform(Index i) const
const Vec3T & min() const
Return a const reference to the minimum point of this bounding box.
static Ptr create()
Return a new grid with background value zero.
float Round(float x)
Return x rounded to the nearest integer.
const char * typeNameAsString< float >()
size_t memUsage() const
Return memory usage of the rasterizer.
RasterCamera(const math::Transform &transform)
GLint GLenum GLboolean GLsizei stride
OPENVDB_API void calculateBounds(const Transform &t, const Vec3d &minWS, const Vec3d &maxWS, Vec3d &minIS, Vec3d &maxIS)
Calculate an axis-aligned bounding box in index space from an axis-aligned bounding box in world spac...
void addPoints(GridConstPtr &points)
Append a PointDataGrid to the rasterizer (but don't rasterize yet).
Tree< typename RootNodeType::template ValueConverter< Int32 >::Type > Type
const math::Transform & firstTransform() const
const char * typeNameAsString< int64_t >()
bool empty() const
Return true if this bounding box is empty, i.e., it has no (positive) volume.
SharedPtr< const Tree > ConstPtr
float shutterStart() const
bool isApproxZero(const Type &x)
Return true if x is equal to zero to within the default floating-point comparison tolerance...
vfloat4 round(const vfloat4 &a)
GLboolean GLboolean GLboolean b
GA_API const UT_StringHolder transform
Container class that associates a tree with a transform and metadata.
const Vec3T & max() const
Return a const reference to the maximum point of this bounding box.
GridT::Ptr rasterizeMask(bool reduceMemory=false, const FilterT &filter=FilterT())
typename PointDataGridT::ConstPtr GridConstPtr
const char * typeNameAsString< double >()
Type Clamp(Type x, Type min, Type max)
Return x clamped to [min, max].
IMATH_HOSTDEVICE constexpr int ceil(T x) IMATH_NOEXCEPT
static Ptr create(const AttributeArray &array, const bool collapseOnDestruction=true)
__hostdev__ T dot(const Vec3T &v) const
const char * typeNameAsString< bool >()
T & x()
Reference to the component, e.g. v.x() = 4.5f;.
SIM_API const UT_StringHolder position
A group of shared settings to be used in the Volume Rasterizer.
FrustumRasterizerMask()=default
ImageBuf OIIO_API max(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
math::BBox< Vec3d > BBoxd
Index64 pointOffsets(std::vector< Index64 > &pointOffsets, const PointDataTreeT &tree, const FilterT &filter, const bool inCoreOnly, const bool threaded)
Populate an array of cumulative point offsets per leaf node.
void setShutter(float start, float end)
OIIO_API bool attribute(string_view name, TypeDesc type, const void *val)
GLdouble GLdouble GLdouble top
int Floor(float x)
Return the floor of x.
SIM_API const UT_StringHolder distance
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
typename PointDataGridT::Ptr GridPtr
void clear()
Clear all PointDataGrids in the rasterizer.
#define OPENVDB_THROW(exception, message)
bool isFinite(const float x)
Return true if x is finite.
ImageBuf OIIO_API mul(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
FloatGrid::Ptr rasterizeDensity(const openvdb::Name &attribute, RasterMode mode=RasterMode::MAXIMUM, bool reduceMemory=false, float scale=1.0f, const FilterT &filter=FilterT())