This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/geometry/intern/points_to_volume.cc
Erik Abrahamsson 4b30b5c57f Nodes: SDF Volume nodes milestone 1
Geometry Nodes: SDF Volume nodes milestone 1

Adds initial support for SDF volume creation and manipulation.
`SDF volume` is Blender's name of an OpenVDB grid of type Level Set.
See the discussion about naming in #91668.

The new nodes are:
- Mesh to SDF Volume: Converts a mesh to an SDF Volume
- Points to SDF Volume: Converts points to an SDF Volume
- Mean Filter SDF Volume: Applies a Mean Filter to an SDF
- Offset SDF Volume: Applies an offset to an SDF
- SDF Volume Sphere: Creates an SDF Volume in the shape of a sphere

For now an experimental option `New Volume Nodes` needs to be
enabled in Blender preferences for the nodes to be visible.

See the current work plan for Volume Nodes in #103248.

Pull Request: blender/blender#105090
2023-03-19 11:21:08 +01:00

97 lines
3.2 KiB
C++

/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_math_matrix.hh"
#include "BKE_volume.h"
#include "GEO_points_to_volume.hh"
#ifdef WITH_OPENVDB
# include <openvdb/openvdb.h>
# include <openvdb/tools/LevelSetUtil.h>
# include <openvdb/tools/ParticlesToLevelSet.h>
namespace blender::geometry {
/* Implements the interface required by #openvdb::tools::ParticlesToLevelSet. */
struct OpenVDBParticleList {
using PosType = openvdb::Vec3R;
Span<float3> positions;
Span<float> radii;
size_t size() const
{
return size_t(positions.size());
}
void getPos(size_t n, openvdb::Vec3R &xyz) const
{
xyz = &positions[n].x;
}
void getPosRad(size_t n, openvdb::Vec3R &xyz, openvdb::Real &radius) const
{
xyz = &positions[n].x;
radius = radii[n];
}
};
static openvdb::FloatGrid::Ptr points_to_sdf_grid(const Span<float3> positions,
const Span<float> radii)
{
/* Create a new grid that will be filled. #ParticlesToLevelSet requires
* the background value to be positive */
openvdb::FloatGrid::Ptr new_grid = openvdb::FloatGrid::create(1.0f);
/* Create a narrow-band level set grid based on the positions and radii. */
openvdb::tools::ParticlesToLevelSet op{*new_grid};
/* Don't ignore particles based on their radius. */
op.setRmin(0.0f);
op.setRmax(FLT_MAX);
OpenVDBParticleList particles{positions, radii};
op.rasterizeSpheres(particles);
op.finalize();
return new_grid;
}
VolumeGrid *fog_volume_grid_add_from_points(Volume *volume,
const StringRefNull name,
const Span<float3> positions,
const Span<float> radii,
const float voxel_size,
const float density)
{
openvdb::FloatGrid::Ptr new_grid = points_to_sdf_grid(positions, radii);
new_grid->transform().postScale(voxel_size);
new_grid->setGridClass(openvdb::GRID_FOG_VOLUME);
/* Convert the level set to a fog volume. This also sets the background value to zero. Inside the
* fog there will be a density of 1. */
openvdb::tools::sdfToFogVolume(*new_grid);
/* Take the desired density into account. */
openvdb::tools::foreach (new_grid->beginValueOn(),
[&](const openvdb::FloatGrid::ValueOnIter &iter) {
iter.modifyValue([&](float &value) { value *= density; });
});
return BKE_volume_grid_add_vdb(*volume, name, std::move(new_grid));
}
VolumeGrid *sdf_volume_grid_add_from_points(Volume *volume,
const StringRefNull name,
const Span<float3> positions,
const Span<float> radii,
const float voxel_size)
{
openvdb::FloatGrid::Ptr new_grid = points_to_sdf_grid(positions, radii);
new_grid->transform().postScale(voxel_size);
new_grid->setGridClass(openvdb::GRID_LEVEL_SET);
return BKE_volume_grid_add_vdb(*volume, name, std::move(new_grid));
}
} // namespace blender::geometry
#endif