WIP: Volume grid attribute support in geometry nodes #110044

Closed
Lukas Tönne wants to merge 130 commits from LukasTonne/blender:geometry-nodes-flip into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
9 changed files with 406 additions and 371 deletions
Showing only changes of commit ca6d21e624 - Show all commits

View File

@ -168,11 +168,11 @@ class GeometryFieldInput : public fn::FieldInput {
ResourceScope &scope) const override;
virtual GVArray get_varray_for_context(const GeometryFieldContext &context,
const IndexMask &mask) const = 0;
virtual fn::VolumeGrid get_volume_grid_for_context(const fn::FieldContext &context,
const fn::VolumeMask &mask,
ResourceScope &scope) const override;
virtual fn::VolumeGrid get_volume_grid_for_context(const GeometryFieldContext & /*context*/,
const fn::VolumeMask & /*mask*/) const
virtual volume::VolumeGrid get_volume_grid_for_context(const fn::FieldContext &context,
const volume::VolumeMask &mask,
ResourceScope &scope) const override;
virtual volume::VolumeGrid get_volume_grid_for_context(const GeometryFieldContext & /*context*/,
const volume::VolumeMask & /*mask*/) const
{
return {};
}
@ -225,6 +225,9 @@ class InstancesFieldInput : public fn::FieldInput {
class VolumeFieldInput : public fn::FieldInput {
public:
using VolumeGrid = volume::VolumeGrid;
using VolumeMask = volume::VolumeMask;
using fn::FieldInput::FieldInput;
GVArray get_varray_for_context(const fn::FieldContext & /*context*/,
const IndexMask & /*mask*/,
@ -232,11 +235,11 @@ class VolumeFieldInput : public fn::FieldInput {
{
return {};
}
virtual fn::VolumeGrid get_volume_grid_for_context(const fn::FieldContext &context,
const fn::VolumeMask &mask,
ResourceScope &scope) const override;
virtual fn::VolumeGrid get_volume_grid_for_context(const VolumeGridVector &grids,
const fn::VolumeMask &mask) const = 0;
virtual VolumeGrid get_volume_grid_for_context(const fn::FieldContext &context,
const VolumeMask &mask,
ResourceScope &scope) const override;
virtual VolumeGrid get_volume_grid_for_context(const VolumeGridVector &grids,
const VolumeMask &mask) const = 0;
};
class AttributeFieldInput : public GeometryFieldInput {

View File

@ -21,71 +21,74 @@ namespace blender::bke {
#ifdef WITH_OPENVDB
/**
* Result when looking up an attribute from some geometry with read and write access. After writing
* to the attribute, the #finish method has to be called. This may invalidate caches based on this
* attribute.
*/
template<typename T> struct AttributeGridWriter {
// using GridType =
/**
* Grid pointer giving read and write access to the attribute. This may be empty.
*/
GridT::Ptr VMutableArray<T> varray;
/**
* Domain where the attribute is stored on the geometry. Also determines the size of the virtual
* array.
*/
eAttrDomain domain;
/**
* A function that has to be called after the attribute has been edited. This may be empty.
*/
std::function<void()> tag_modified_fn;
operator bool() const
{
return this->varray;
}
/**
* Has to be called after the attribute has been modified.
*/
void finish()
{
if (this->tag_modified_fn) {
this->tag_modified_fn();
}
}
};
///**
// * Result when looking up an attribute from some geometry with read and write access. After
// writing
// * to the attribute, the #finish method has to be called. This may invalidate caches based on
// this
// * attribute.
// */
// template<typename T> struct AttributeGridWriter {
// // using GridType =
//
// /**
// * Grid pointer giving read and write access to the attribute. This may be empty.
// */
// GridT::Ptr VMutableArray<T> varray;
// /**
// * Domain where the attribute is stored on the geometry. Also determines the size of the
// virtual
// * array.
// */
// eAttrDomain domain;
// /**
// * A function that has to be called after the attribute has been edited. This may be empty.
// */
// std::function<void()> tag_modified_fn;
//
// operator bool() const
// {
// return this->varray;
// }
//
// /**
// * Has to be called after the attribute has been modified.
// */
// void finish()
// {
// if (this->tag_modified_fn) {
// this->tag_modified_fn();
// }
// }
//};
#endif
/**
* A generic version of #AttributeWriter.
*/
struct GAttributeGridWriter {
VolumeGrid *grid;
eAttrDomain domain;
std::function<void()> tag_modified_fn;
operator bool() const
{
return this->grid;
}
void finish()
{
if (this->tag_modified_fn) {
this->tag_modified_fn();
}
}
template<typename T> AttributeWriter<T> typed() const
{
return {grid.typed<T>(), domain, tag_modified_fn};
}
};
///**
// * A generic version of #AttributeWriter.
// */
// struct GAttributeGridWriter {
// VolumeGrid *grid;
// eAttrDomain domain;
// std::function<void()> tag_modified_fn;
//
// operator bool() const
// {
// return this->grid;
// }
//
// void finish()
// {
// if (this->tag_modified_fn) {
// this->tag_modified_fn();
// }
// }
//
// template<typename T> AttributeWriter<T> typed() const
// {
// return {grid.typed<T>(), domain, tag_modified_fn};
// }
//};
/* OLD CODE
* OLD CODE

View File

@ -8,6 +8,9 @@
* \ingroup bli
*/
#include "BLI_math_vector_types.hh"
#include "BLI_parameter_pack_utils.hh"
#ifdef WITH_OPENVDB
# include <openvdb/openvdb.h>
#endif
@ -17,7 +20,22 @@ namespace blender {
class CPPType;
class ResourceScope;
namespace volume_mask {
/* XXX OpenVDB expects some math functions on vector types. */
template<typename T, int Size> inline VecBase<T, Size> Abs(VecBase<T, Size> v)
{
VecBase<T, Size> r;
for (int i = 0; i < Size; i++) {
r[i] = math::abs(v[i]);
}
return r;
}
/* Specialization: math::abs is not defined for unsigned types. */
template<int Size> inline VecBase<uint32_t, Size> Abs(VecBase<uint32_t, Size> v)
{
return v;
}
namespace volume {
/* Mask defined by active voxels of the grid. */
class VolumeMask {
@ -37,10 +55,6 @@ class VolumeMask {
#endif
};
} // namespace volume_mask
using volume_mask::VolumeMask;
struct VolumeGrid {
#ifdef WITH_OPENVDB
openvdb::GridBase::Ptr grid_ = nullptr;
@ -64,4 +78,124 @@ struct VolumeGrid {
operator bool() const;
};
/* -------------------------------------------------------------------- */
/** \name Tree and Grid types for Blender CPP types
* \{ */
#ifdef WITH_OPENVDB
namespace grid_types {
template<typename ValueType>
using TreeCommon = typename openvdb::tree::Tree4<ValueType, 5, 4, 3>::Type;
template<typename ValueType> using GridCommon = typename openvdb::Grid<TreeCommon<ValueType>>;
/* TODO add more as needed. */
/* TODO could use template magic to generate all from 1 list, but not worth it for now. */
/* TODO some types disabled because of missing CPPType registration. */
using BoolTree = TreeCommon<bool>;
using MaskTree = TreeCommon<openvdb::ValueMask>;
using FloatTree = TreeCommon<float>;
using Float2Tree = TreeCommon<float2>;
using Float3Tree = TreeCommon<float3>;
// using Float4Tree = TreeCommon<float4>;
using IntTree = TreeCommon<int32_t>;
using Int2Tree = TreeCommon<int2>;
// using Int3Tree = TreeCommon<int3>;
// using Int4Tree = TreeCommon<int4>;
using UIntTree = TreeCommon<uint32_t>;
// using UInt2Tree = TreeCommon<uint2>;
// using UInt3Tree = TreeCommon<uint3>;
// using UInt4Tree = TreeCommon<uint4>;
using ScalarTree = FloatTree;
using TopologyTree = MaskTree;
using BoolGrid = openvdb::Grid<BoolTree>;
using MaskGrid = openvdb::Grid<MaskTree>;
using FloatGrid = openvdb::Grid<FloatTree>;
using Float2Grid = openvdb::Grid<Float2Tree>;
using Float3Grid = openvdb::Grid<Float3Tree>;
// using Float4Grid = openvdb::Grid<Float4Tree>;
using IntGrid = openvdb::Grid<IntTree>;
using Int2Grid = openvdb::Grid<Int2Tree>;
// using Int3Grid = openvdb::Grid<Int3Tree>;
// using Int4Grid = openvdb::Grid<Int4Tree>;
using UIntGrid = openvdb::Grid<UIntTree>;
// using UInt2Grid = openvdb::Grid<UInt2Tree>;
// using UInt3Grid = openvdb::Grid<UInt3Tree>;
// using UInt4Grid = openvdb::Grid<UInt4Tree>;
using ScalarGrid = openvdb::Grid<ScalarTree>;
using TopologyGrid = openvdb::Grid<TopologyTree>;
using SupportedGridValueTypes = std::tuple<bool,
float,
float2,
float3,
/*float4,*/
int32_t,
int2,
/*int3,*/ /*int4,*/ uint32_t
/*,uint2*/
/*,uint3*/
/*,uint4*/>;
using SupportedGridTypes = openvdb::TypeList<BoolGrid,
MaskGrid,
FloatGrid,
Float2Grid,
Float3Grid,
/*Float4Grid,*/
IntGrid,
Int2Grid,
/*Int3Grid,*/
/*Int4Grid,*/
UIntGrid,
/*UInt2Grid,*/
/*UInt3Grid,*/
/*UInt4Grid,*/
ScalarGrid,
TopologyGrid>;
} // namespace grid_types
/** \} */
namespace detail {
template<typename Func> struct FilterVoidOp {
Func func;
template<typename T> void operator()(TypeTag<T> type_tag) const
{
func(type_tag);
}
template<> void operator()<void>(TypeTag<void> /*type_tag*/) const {}
};
/* Helper function to turn a tuple into a parameter pack by means of the dummy argument. */
template<typename... Types, typename Func>
void field_to_static_type_resolve(std::tuple<Types...> /*dummy*/, const CPPType &type, Func func)
{
FilterVoidOp<Func> wrapper{func};
type.to_static_type_tag<Types...>(wrapper);
}
} // namespace detail
/* Helper function to evaluate a function with a static field type. */
template<typename Func> void field_to_static_type(const CPPType &type, Func func)
{
detail::field_to_static_type_resolve(grid_types::SupportedGridValueTypes(), type, func);
}
/* Helper function to evaluate a function with a static field type. */
template<typename Func> void grid_to_static_type(const openvdb::GridBase::Ptr &grid, Func func)
{
grid->apply<grid_types::SupportedGridTypes>(func);
}
} // namespace volume
#endif
} // namespace blender

View File

@ -157,6 +157,7 @@ set(SRC
intern/timeit.cc
intern/uuid.cc
intern/uvproject.c
intern/volume.cc
intern/voronoi_2d.c
intern/voxel.c
intern/winstuff.c

View File

@ -0,0 +1,146 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup bli
*/
#include "BLI_cpp_type.hh"
#include "BLI_math_base.hh"
#include "BLI_resource_scope.hh"
#include "BLI_volume.hh"
namespace blender {
#ifdef WITH_OPENVDB
namespace volume {
bool VolumeMask::is_empty() const
{
return grid_.empty();
}
int64_t VolumeMask::min_voxel_count() const
{
return grid_.activeVoxelCount();
}
int64_t VolumeGrid::voxel_count() const
{
return grid_ ? grid_->activeVoxelCount() : 0;
}
bool VolumeGrid::is_empty() const
{
return grid_ ? grid_->empty() : true;
}
VolumeGrid::operator bool() const
{
return grid_ != nullptr;
}
VolumeGrid VolumeGrid::create(ResourceScope &scope,
const CPPType &type,
const void *background_value)
{
openvdb::GridBase::Ptr grid;
volume::field_to_static_type(type, [&grid, background_value](auto type_tag) {
using ValueType = typename decltype(type_tag)::type;
const ValueType &value = *static_cast<const ValueType *>(background_value);
grid = grid_types::GridCommon<ValueType>::create(value);
});
return VolumeGrid{scope.add_value<openvdb::GridBase::Ptr>(std::move(grid))};
}
VolumeGrid VolumeGrid::create(ResourceScope &scope, const CPPType &type)
{
openvdb::GridBase::Ptr grid;
volume::field_to_static_type(type, [&grid](auto type_tag) {
using ValueType = typename decltype(type_tag)::type;
const CPPType &type = CPPType::get<ValueType>();
const ValueType &value = *static_cast<const ValueType *>(type.default_value());
grid = grid_types::GridCommon<ValueType>::create(value);
});
return VolumeGrid{scope.add_value<openvdb::GridBase::Ptr>(std::move(grid))};
}
VolumeGrid VolumeGrid::create(ResourceScope &scope,
const CPPType &type,
const VolumeMask &mask,
const void *inactive_value,
const void *active_value)
{
openvdb::GridBase::Ptr grid;
volume::field_to_static_type(type, [&](auto type_tag) {
using ValueType = typename decltype(type_tag)::type;
using TreeType = grid_types::TreeCommon<ValueType>;
using GridType = grid_types::GridCommon<ValueType>;
const ValueType &typed_inactive_value = *static_cast<const ValueType *>(inactive_value);
const ValueType &typed_active_value = *static_cast<const ValueType *>(active_value);
const TreeType::Ptr tree = TreeType::Ptr(new TreeType(
mask.grid().tree(), typed_inactive_value, typed_active_value, openvdb::TopologyCopy{}));
grid = GridType::Ptr(new GridType(tree));
});
return VolumeGrid{scope.add_value<openvdb::GridBase::Ptr>(std::move(grid))};
}
} // namespace volume
#else
namespace volume {
bool VolumeMask::is_empty() const
{
return true;
}
int64_t VolumeMask::min_voxel_count() const
{
return 0;
}
VolumeGrid::operator bool() const
{
return false;
}
int64_t VolumeGrid::voxel_count() const
{
return 0;
}
bool VolumeGrid::is_empty() const
{
return true;
}
VolumeGrid::operator bool() const
{
return false;
}
VolumeGrid VolumeGrid::create(ResourceScope &scope, const CPPType &type, const int64_t voxel_count)
{
return VolumeGrid{};
}
VolumeGrid VolumeGrid::create(ResourceScope &scope,
const CPPType &type,
const void *background_value)
{
return VolumeGrid{};
}
} // namespace volume
#endif
} // namespace blender

View File

@ -259,6 +259,9 @@ class FieldContext;
*/
class FieldInput : public FieldNode {
public:
using VolumeGrid = volume::VolumeGrid;
using VolumeMask = volume::VolumeMask;
/* The order is also used for sorting in socket inspection. */
enum class Category {
NamedAttribute = 0,
@ -334,6 +337,9 @@ struct FieldInputs {
*/
class FieldContext {
public:
using VolumeMask = volume::VolumeMask;
using VolumeGrid = volume::VolumeGrid;
virtual ~FieldContext() = default;
virtual GVArray get_varray_for_input(const FieldInput &field_input,
@ -524,11 +530,11 @@ Vector<GVArray> evaluate_fields(ResourceScope &scope,
* \return The computed virtual arrays for each provided field. If #dst_varrays is passed,
* the provided virtual arrays are returned.
*/
Vector<VolumeGrid> evaluate_volume_fields(ResourceScope &scope,
Span<GFieldRef> fields_to_evaluate,
const VolumeMask &mask,
const FieldContext &context,
Span<VolumeGrid> dst_grids = {});
Vector<volume::VolumeGrid> evaluate_volume_fields(ResourceScope &scope,
Span<GFieldRef> fields_to_evaluate,
const volume::VolumeMask &mask,
const FieldContext &context,
Span<volume::VolumeGrid> dst_grids = {});
/* -------------------------------------------------------------------- */
/** \name Utility functions for simple field creation and evaluation

View File

@ -2,6 +2,8 @@
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_volume.hh"
#include "FN_multi_function_procedure.hh"
#ifdef WITH_OPENVDB
@ -11,12 +13,6 @@
#pragma once
namespace blender {
class CPPType;
class ResourceScope;
template<typename T> class VArray;
class VolumeGrid;
class VolumeMask;
namespace fn {
class GFieldRef;
}
@ -25,19 +21,19 @@ class GFieldRef;
namespace blender::fn {
void evaluate_procedure_on_varying_volume_fields(ResourceScope &scope,
const VolumeMask &mask,
const volume::VolumeMask &mask,
const mf::Procedure &procedure,
Span<VolumeGrid> field_context_inputs,
Span<volume::VolumeGrid> field_context_inputs,
Span<GFieldRef> fields_to_evaluate,
Span<int> field_indices,
Span<VolumeGrid> dst_grids,
MutableSpan<VolumeGrid> r_grids,
Span<volume::VolumeGrid> dst_grids,
MutableSpan<volume::VolumeGrid> r_grids,
MutableSpan<bool> r_is_output_written_to_dst);
void evaluate_procedure_on_constant_volume_fields(ResourceScope &scope,
const mf::Procedure &procedure,
Span<VolumeGrid> field_context_inputs,
Span<volume::VolumeGrid> field_context_inputs,
Span<GFieldRef> fields_to_evaluate,
Span<int> field_indices,
MutableSpan<VolumeGrid> r_grids);
MutableSpan<volume::VolumeGrid> r_grids);
} // namespace blender::fn

View File

@ -18,6 +18,9 @@
namespace blender::fn {
using VolumeGrid = volume::VolumeGrid;
using VolumeMask = volume::VolumeMask;
/* -------------------------------------------------------------------- */
/** \name Field Evaluation
* \{ */

View File

@ -8,6 +8,7 @@
#include "BLI_math_vector_types.hh"
#include "BLI_resource_scope.hh"
#include "BLI_virtual_array.hh"
#include "BLI_volume.hh"
#include "FN_field.hh"
#include "FN_multi_function_builder.hh"
@ -18,222 +19,8 @@
# include <openvdb/tools/ValueTransformer.h>
namespace blender {
/* XXX OpenVDB expects some math functions on vector types. */
template<typename T, int Size> inline VecBase<T, Size> Abs(VecBase<T, Size> v)
{
VecBase<T, Size> r;
for (int i = 0; i < Size; i++) {
r[i] = math::abs(v[i]);
}
return r;
}
/* Specialization: math::abs is not defined for unsigned types. */
template<int Size> inline VecBase<uint32_t, Size> Abs(VecBase<uint32_t, Size> v)
{
return v;
}
}; // namespace blender
/* -------------------------------------------------------------------- */
/** \name Tree and Grid types for Blender CPP types
* \{ */
namespace blender::fn::grid_types {
template<typename ValueType>
using TreeCommon = typename openvdb::tree::Tree4<ValueType, 5, 4, 3>::Type;
template<typename ValueType> using GridCommon = typename openvdb::Grid<TreeCommon<ValueType>>;
/* TODO add more as needed. */
/* TODO could use template magic to generate all from 1 list, but not worth it for now. */
/* TODO some types disabled because of missing CPPType registration. */
using BoolTree = TreeCommon<bool>;
using MaskTree = TreeCommon<openvdb::ValueMask>;
using FloatTree = TreeCommon<float>;
using Float2Tree = TreeCommon<float2>;
using Float3Tree = TreeCommon<float3>;
// using Float4Tree = TreeCommon<float4>;
using IntTree = TreeCommon<int32_t>;
using Int2Tree = TreeCommon<int2>;
// using Int3Tree = TreeCommon<int3>;
// using Int4Tree = TreeCommon<int4>;
using UIntTree = TreeCommon<uint32_t>;
// using UInt2Tree = TreeCommon<uint2>;
// using UInt3Tree = TreeCommon<uint3>;
// using UInt4Tree = TreeCommon<uint4>;
using ScalarTree = FloatTree;
using TopologyTree = MaskTree;
using BoolGrid = openvdb::Grid<BoolTree>;
using MaskGrid = openvdb::Grid<MaskTree>;
using FloatGrid = openvdb::Grid<FloatTree>;
using Float2Grid = openvdb::Grid<Float2Tree>;
using Float3Grid = openvdb::Grid<Float3Tree>;
// using Float4Grid = openvdb::Grid<Float4Tree>;
using IntGrid = openvdb::Grid<IntTree>;
using Int2Grid = openvdb::Grid<Int2Tree>;
// using Int3Grid = openvdb::Grid<Int3Tree>;
// using Int4Grid = openvdb::Grid<Int4Tree>;
using UIntGrid = openvdb::Grid<UIntTree>;
// using UInt2Grid = openvdb::Grid<UInt2Tree>;
// using UInt3Grid = openvdb::Grid<UInt3Tree>;
// using UInt4Grid = openvdb::Grid<UInt4Tree>;
using ScalarGrid = openvdb::Grid<ScalarTree>;
using TopologyGrid = openvdb::Grid<TopologyTree>;
using SupportedGridValueTypes = std::tuple<bool,
float,
float2,
float3,
/*float4,*/
int32_t,
int2,
/*int3,*/ /*int4,*/ uint32_t
/*,uint2*/
/*,uint3*/
/*,uint4*/>;
using SupportedGridTypes = openvdb::TypeList<BoolGrid,
MaskGrid,
FloatGrid,
Float2Grid,
Float3Grid,
/*Float4Grid,*/
IntGrid,
Int2Grid,
/*Int3Grid,*/
/*Int4Grid,*/
UIntGrid,
/*UInt2Grid,*/
/*UInt3Grid,*/
/*UInt4Grid,*/
ScalarGrid,
TopologyGrid>;
} // namespace blender::fn::grid_types
/** \} */
namespace blender::volume_mask {
bool VolumeMask::is_empty() const
{
return grid_.empty();
}
int64_t VolumeMask::min_voxel_count() const
{
return grid_.activeVoxelCount();
}
} // namespace blender::volume_mask
namespace blender::fn {
namespace detail {
template<typename Func> struct FilterVoidOp {
Func func;
template<typename T> void operator()(TypeTag<T> type_tag) const
{
func(type_tag);
}
template<> void operator()<void>(TypeTag<void> /*type_tag*/) const {}
};
/* Helper function to turn a tuple into a parameter pack by means of the dummy argument. */
template<typename... Types, typename Func>
static void field_to_static_type_resolve(std::tuple<Types...> /*dummy*/,
const CPPType &type,
Func func)
{
FilterVoidOp<Func> wrapper{func};
type.to_static_type_tag<Types...>(wrapper);
}
/* Helper function to evaluate a function with a static field type. */
template<typename Func> static void field_to_static_type(const CPPType &type, Func func)
{
field_to_static_type_resolve(grid_types::SupportedGridValueTypes(), type, func);
}
/* Helper function to evaluate a function with a static field type. */
template<typename Func>
static void grid_to_static_type(const openvdb::GridBase::Ptr &grid, Func func)
{
grid->apply<grid_types::SupportedGridTypes>(func);
}
} // namespace detail
int64_t VolumeGrid::voxel_count() const
{
return grid_ ? grid_->activeVoxelCount() : 0;
}
bool VolumeGrid::is_empty() const
{
return grid_ ? grid_->empty() : true;
}
VolumeGrid::operator bool() const
{
return grid_ != nullptr;
}
VolumeGrid VolumeGrid::create(ResourceScope &scope,
const CPPType &type,
const void *background_value)
{
openvdb::GridBase::Ptr grid;
detail::field_to_static_type(type, [&grid, background_value](auto type_tag) {
using ValueType = typename decltype(type_tag)::type;
const ValueType &value = *static_cast<const ValueType *>(background_value);
grid = grid_types::GridCommon<ValueType>::create(value);
});
return VolumeGrid{scope.add_value<openvdb::GridBase::Ptr>(std::move(grid))};
}
VolumeGrid VolumeGrid::create(ResourceScope &scope, const CPPType &type)
{
openvdb::GridBase::Ptr grid;
detail::field_to_static_type(type, [&grid](auto type_tag) {
using ValueType = typename decltype(type_tag)::type;
const CPPType &type = CPPType::get<ValueType>();
const ValueType &value = *static_cast<const ValueType *>(type.default_value());
grid = grid_types::GridCommon<ValueType>::create(value);
});
return VolumeGrid{scope.add_value<openvdb::GridBase::Ptr>(std::move(grid))};
}
VolumeGrid VolumeGrid::create(ResourceScope &scope,
const CPPType &type,
const VolumeMask &mask,
const void *inactive_value,
const void *active_value)
{
openvdb::GridBase::Ptr grid;
detail::field_to_static_type(type, [&](auto type_tag) {
using ValueType = typename decltype(type_tag)::type;
using TreeType = grid_types::TreeCommon<ValueType>;
using GridType = grid_types::GridCommon<ValueType>;
const ValueType &typed_inactive_value = *static_cast<const ValueType *>(inactive_value);
const ValueType &typed_active_value = *static_cast<const ValueType *>(active_value);
const TreeType::Ptr tree = TreeType::Ptr(new TreeType(
mask.grid().tree(), typed_inactive_value, typed_active_value, openvdb::TopologyCopy{}));
grid = GridType::Ptr(new GridType(tree));
});
return VolumeGrid{scope.add_value<openvdb::GridBase::Ptr>(std::move(grid))};
}
/* A VArray implementation using OpenVDB grid accessors.
* The index is converted to global voxel coordinate
* by interpreting it as a leaf buffer index. */
@ -390,6 +177,8 @@ struct TypedAccessorWrapper : public AccessorWrapper<LeafNodeType> {
};
template<typename GridType> struct EvalPerLeafOp {
using VolumeGrid = volume::VolumeGrid;
using VolumeMask = volume::VolumeMask;
using TreeType = typename GridType::TreeType;
using ValueType = typename GridType::ValueType;
@ -419,7 +208,7 @@ template<typename GridType> struct EvalPerLeafOp {
input_accessors_.reinitialize(field_context_inputs.size());
for (const int i : field_context_inputs.index_range()) {
detail::grid_to_static_type(field_context_inputs[i].grid_, [&](auto &input_grid) {
volume::grid_to_static_type(field_context_inputs[i].grid_, [&](auto &input_grid) {
using InputGridType = typename std::decay<decltype(input_grid)>::type;
using AccessorType = typename InputGridType::ConstAccessor;
@ -477,19 +266,22 @@ template<typename GridType> struct EvalPerLeafOp {
};
void evaluate_procedure_on_varying_volume_fields(ResourceScope &scope,
const VolumeMask &mask,
const volume::VolumeMask &mask,
const mf::Procedure &procedure,
Span<VolumeGrid> field_context_inputs,
Span<volume::VolumeGrid> field_context_inputs,
Span<GFieldRef> fields_to_evaluate,
Span<int> field_indices,
Span<VolumeGrid> dst_grids,
MutableSpan<VolumeGrid> r_grids,
Span<volume::VolumeGrid> dst_grids,
MutableSpan<volume::VolumeGrid> r_grids,
MutableSpan<bool> r_is_output_written_to_dst)
{
/* Execute a multifunction procedure on each leaf buffer of the mask.
* Each leaf buffer is a contiguous array that can be used as a span.
* The leaf buffers' active voxel masks are used as index masks. */
using volume::VolumeGrid;
using volume::VolumeMask;
/* Destination arrays are optional. Create a small utility method to access them. */
auto get_dst_grid = [&](int index) -> VolumeGrid {
if (dst_grids.is_empty()) {
@ -527,7 +319,7 @@ void evaluate_procedure_on_varying_volume_fields(ResourceScope &scope,
* Each leaf buffer is a contiguous array that can be used as a span.
* The leaf buffers' active voxel masks are used as index masks. */
detail::grid_to_static_type(dst_grid.grid_, [&](auto &dst_grid) {
volume::grid_to_static_type(dst_grid.grid_, [&](auto &dst_grid) {
using GridType = typename std::decay<decltype(dst_grid)>::type;
EvalPerLeafOp<GridType> func(field_context_inputs, procedure_executor, mask.grid());
@ -541,11 +333,14 @@ void evaluate_procedure_on_varying_volume_fields(ResourceScope &scope,
void evaluate_procedure_on_constant_volume_fields(ResourceScope & /*scope*/,
const mf::Procedure &procedure,
Span<VolumeGrid> field_context_inputs,
Span<volume::VolumeGrid> field_context_inputs,
Span<GFieldRef> fields_to_evaluate,
Span<int> field_indices,
MutableSpan<VolumeGrid> r_grids)
MutableSpan<volume::VolumeGrid> r_grids)
{
using volume::VolumeGrid;
using volume::VolumeMask;
mf::ProcedureExecutor procedure_executor{procedure};
const IndexMask mask(1);
mf::ParamsBuilder mf_params{procedure_executor, &mask};
@ -553,7 +348,7 @@ void evaluate_procedure_on_constant_volume_fields(ResourceScope & /*scope*/,
/* Provide inputs to the procedure executor. */
for (const int i : field_context_inputs.index_range()) {
detail::grid_to_static_type(field_context_inputs[i].grid_, [&](auto &input_grid) {
volume::grid_to_static_type(field_context_inputs[i].grid_, [&](auto &input_grid) {
using InputGridType = typename std::decay<decltype(input_grid)>::type;
using ValueType = typename InputGridType::ValueType;
@ -587,11 +382,11 @@ void evaluate_procedure_on_constant_volume_fields(ResourceScope & /*scope*/,
const CPPType &type = field.cpp_type();
const int out_index = field_indices[i];
detail::field_to_static_type(type, [&](auto type_tag) {
volume::field_to_static_type(type, [&](auto type_tag) {
using ValueType = typename decltype(type_tag)::type;
const ValueType &value = *static_cast<ValueType *>(output_buffers[i]);
r_grids[out_index] = VolumeGrid{grid_types::GridCommon<ValueType>::create(value)};
r_grids[out_index] = VolumeGrid{volume::grid_types::GridCommon<ValueType>::create(value)};
});
/* Destruct output value buffers, value is stored in grid backgrounds now. */
@ -601,56 +396,4 @@ void evaluate_procedure_on_constant_volume_fields(ResourceScope & /*scope*/,
} // namespace blender::fn
#else
namespace blender::volume_mask {
bool VolumeMask::is_empty() const
{
return true;
}
int64_t VolumeMask::min_voxel_count() const
{
return 0;
}
} // namespace blender::volume_mask
namespace blender::fn {
VolumeGrid::operator bool() const
{
return false;
}
int64_t VolumeGrid::voxel_count() const
{
return 0;
}
bool VolumeGrid::is_empty() const
{
return true;
}
VolumeGrid::operator bool() const
{
return false;
}
VolumeGrid VolumeGrid::create(ResourceScope &scope, const CPPType &type, const int64_t voxel_count)
{
return VolumeGrid{};
}
VolumeGrid VolumeGrid::create(ResourceScope &scope,
const CPPType &type,
const void *background_value)
{
return VolumeGrid{};
}
} // namespace blender::fn
#endif