Geometry Nodes: Add volume grid creation nodes
Add three nodes to the currently experimental volume grid nodes: - **Mesh to Density Grid** - **Mesh to SDF Grid** - **Points to SDF Grid** These nodes are just wrappers over basic OpenVDB utilities. The difference from existing volume nodes is that they output a grid directly instead of a geometry set. See the design here: https://devtalk.blender.org/t/volumes-in-geometry-nodes-proposal/31917 Pull Request: https://projects.blender.org/blender/blender/pulls/118761
This commit is contained in:
@@ -410,7 +410,11 @@ class NODE_MT_geometry_node_GEO_MESH_OPERATIONS(Menu):
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeFlipFaces")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeMeshBoolean")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeMeshToCurve")
|
||||
if context.preferences.experimental.use_new_volume_nodes:
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeMeshToDensityGrid")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeMeshToPoints")
|
||||
if context.preferences.experimental.use_new_volume_nodes:
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeMeshToSDFGrid")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeMeshToVolume")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeScaleElements")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeSplitEdges")
|
||||
@@ -476,6 +480,8 @@ class NODE_MT_category_GEO_POINT(Menu):
|
||||
layout.separator()
|
||||
node_add_menu.add_node_type(layout, "GeometryNodePoints")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodePointsToCurves")
|
||||
if context.preferences.experimental.use_new_volume_nodes:
|
||||
node_add_menu.add_node_type(layout, "GeometryNodePointsToSDFGrid")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodePointsToVertices")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodePointsToVolume")
|
||||
layout.separator()
|
||||
|
||||
@@ -1330,6 +1330,9 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
|
||||
#define GEO_NODE_SORT_ELEMENTS 2123
|
||||
#define GEO_NODE_MENU_SWITCH 2124
|
||||
#define GEO_NODE_SAMPLE_GRID 2125
|
||||
#define GEO_NODE_MESH_TO_DENSITY_GRID 2126
|
||||
#define GEO_NODE_MESH_TO_SDF_GRID 2127
|
||||
#define GEO_NODE_POINTS_TO_SDF_GRID 2128
|
||||
|
||||
/** \} */
|
||||
|
||||
|
||||
@@ -56,15 +56,19 @@ bke::VolumeGridData *fog_volume_grid_add_from_mesh(Volume *volume,
|
||||
float voxel_size,
|
||||
float interior_band_width,
|
||||
float density);
|
||||
/**
|
||||
* Add a new SDF VolumeGrid to the Volume by converting the supplied mesh.
|
||||
*/
|
||||
bke::VolumeGridData *sdf_volume_grid_add_from_mesh(Volume *volume,
|
||||
StringRefNull name,
|
||||
Span<float3> positions,
|
||||
Span<int> corner_verts,
|
||||
Span<int3> corner_tris,
|
||||
float voxel_size,
|
||||
float half_band_width);
|
||||
|
||||
bke::VolumeGrid<float> mesh_to_density_grid(const Span<float3> positions,
|
||||
const Span<int> corner_verts,
|
||||
const Span<int3> corner_tris,
|
||||
const float voxel_size,
|
||||
const float interior_band_width,
|
||||
const float density);
|
||||
|
||||
bke::VolumeGrid<float> mesh_to_sdf_grid(Span<float3> positions,
|
||||
Span<int> corner_verts,
|
||||
Span<int3> corner_tris,
|
||||
float voxel_size,
|
||||
float half_band_width);
|
||||
|
||||
#endif
|
||||
} // namespace blender::geometry
|
||||
|
||||
@@ -2,12 +2,8 @@
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BLI_function_ref.hh"
|
||||
#include "BLI_math_matrix_types.hh"
|
||||
#include "BLI_string_ref.hh"
|
||||
|
||||
#include "DNA_modifier_types.h"
|
||||
|
||||
#include "BKE_volume_grid_fwd.hh"
|
||||
|
||||
#pragma once
|
||||
@@ -31,13 +27,10 @@ bke::VolumeGridData *fog_volume_grid_add_from_points(Volume *volume,
|
||||
Span<float> radii,
|
||||
float voxel_size,
|
||||
float density);
|
||||
/**
|
||||
* Add a new SDF VolumeGrid to the Volume by converting the supplied points.
|
||||
*/
|
||||
bke::VolumeGridData *sdf_volume_grid_add_from_points(Volume *volume,
|
||||
StringRefNull name,
|
||||
Span<float3> positions,
|
||||
Span<float> radii,
|
||||
float voxel_size);
|
||||
|
||||
bke::VolumeGrid<float> points_to_sdf_grid(Span<float3> positions,
|
||||
Span<float> radii,
|
||||
float voxel_size);
|
||||
|
||||
#endif
|
||||
} // namespace blender::geometry
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "BLI_task.hh"
|
||||
|
||||
#include "BKE_volume.hh"
|
||||
#include "BKE_volume_grid.hh"
|
||||
#include "BKE_volume_openvdb.hh"
|
||||
|
||||
#include "GEO_mesh_to_volume.hh"
|
||||
@@ -109,7 +110,7 @@ float volume_compute_voxel_size(const Depsgraph *depsgraph,
|
||||
return voxel_size / volume_simplify;
|
||||
}
|
||||
|
||||
static openvdb::FloatGrid::Ptr mesh_to_fog_volume_grid(
|
||||
static openvdb::FloatGrid::Ptr mesh_to_density_grid_impl(
|
||||
const Span<float3> positions,
|
||||
const Span<int> corner_verts,
|
||||
const Span<int3> corner_tris,
|
||||
@@ -147,14 +148,34 @@ static openvdb::FloatGrid::Ptr mesh_to_fog_volume_grid(
|
||||
return new_grid;
|
||||
}
|
||||
|
||||
static openvdb::FloatGrid::Ptr mesh_to_sdf_volume_grid(const Span<float3> positions,
|
||||
const Span<int> corner_verts,
|
||||
const Span<int3> corner_tris,
|
||||
const float voxel_size,
|
||||
const float half_band_width)
|
||||
bke::VolumeGrid<float> mesh_to_density_grid(const Span<float3> positions,
|
||||
const Span<int> corner_verts,
|
||||
const Span<int3> corner_tris,
|
||||
const float voxel_size,
|
||||
const float interior_band_width,
|
||||
const float density)
|
||||
{
|
||||
openvdb::FloatGrid::Ptr grid = mesh_to_density_grid_impl(positions,
|
||||
corner_verts,
|
||||
corner_tris,
|
||||
float4x4::identity(),
|
||||
voxel_size,
|
||||
interior_band_width,
|
||||
density);
|
||||
if (!grid) {
|
||||
return {};
|
||||
}
|
||||
return bke::VolumeGrid<float>(std::move(grid));
|
||||
}
|
||||
|
||||
bke::VolumeGrid<float> mesh_to_sdf_grid(const Span<float3> positions,
|
||||
const Span<int> corner_verts,
|
||||
const Span<int3> corner_tris,
|
||||
const float voxel_size,
|
||||
const float half_band_width)
|
||||
{
|
||||
if (voxel_size <= 0.0f || half_band_width <= 0.0f) {
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<openvdb::Vec3s> points(positions.size());
|
||||
@@ -180,7 +201,7 @@ static openvdb::FloatGrid::Ptr mesh_to_sdf_volume_grid(const Span<float3> positi
|
||||
openvdb::FloatGrid::Ptr new_grid = openvdb::tools::meshToLevelSet<openvdb::FloatGrid>(
|
||||
*transform, points, triangles, half_band_width);
|
||||
|
||||
return new_grid;
|
||||
return bke::VolumeGrid<float>(std::move(new_grid));
|
||||
}
|
||||
|
||||
bke::VolumeGridData *fog_volume_grid_add_from_mesh(Volume *volume,
|
||||
@@ -193,27 +214,15 @@ bke::VolumeGridData *fog_volume_grid_add_from_mesh(Volume *volume,
|
||||
const float interior_band_width,
|
||||
const float density)
|
||||
{
|
||||
openvdb::FloatGrid::Ptr mesh_grid = mesh_to_fog_volume_grid(positions,
|
||||
corner_verts,
|
||||
corner_tris,
|
||||
mesh_to_volume_space_transform,
|
||||
voxel_size,
|
||||
interior_band_width,
|
||||
density);
|
||||
openvdb::FloatGrid::Ptr mesh_grid = mesh_to_density_grid_impl(positions,
|
||||
corner_verts,
|
||||
corner_tris,
|
||||
mesh_to_volume_space_transform,
|
||||
voxel_size,
|
||||
interior_band_width,
|
||||
density);
|
||||
return mesh_grid ? BKE_volume_grid_add_vdb(*volume, name, std::move(mesh_grid)) : nullptr;
|
||||
}
|
||||
|
||||
bke::VolumeGridData *sdf_volume_grid_add_from_mesh(Volume *volume,
|
||||
const StringRefNull name,
|
||||
const Span<float3> positions,
|
||||
const Span<int> corner_verts,
|
||||
const Span<int3> corner_tris,
|
||||
const float voxel_size,
|
||||
const float half_band_width)
|
||||
{
|
||||
openvdb::FloatGrid::Ptr mesh_grid = mesh_to_sdf_volume_grid(
|
||||
positions, corner_verts, corner_tris, voxel_size, half_band_width);
|
||||
return mesh_grid ? BKE_volume_grid_add_vdb(*volume, name, std::move(mesh_grid)) : nullptr;
|
||||
}
|
||||
} // namespace blender::geometry
|
||||
#endif
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "BLI_math_matrix.hh"
|
||||
|
||||
#include "BKE_volume.hh"
|
||||
#include "BKE_volume_grid.hh"
|
||||
#include "BKE_volume_openvdb.hh"
|
||||
|
||||
#include "GEO_points_to_volume.hh"
|
||||
@@ -17,31 +18,47 @@
|
||||
namespace blender::geometry {
|
||||
|
||||
/* Implements the interface required by #openvdb::tools::ParticlesToLevelSet. */
|
||||
struct OpenVDBParticleList {
|
||||
class OpenVDBParticleList {
|
||||
public:
|
||||
using PosType = openvdb::Vec3R;
|
||||
|
||||
Span<float3> positions;
|
||||
Span<float> radii;
|
||||
private:
|
||||
Span<float3> positions_;
|
||||
Span<float> radii_;
|
||||
float voxel_size_inv_;
|
||||
|
||||
public:
|
||||
OpenVDBParticleList(const Span<float3> positions,
|
||||
const Span<float> radii,
|
||||
const float voxel_size)
|
||||
: positions_(positions), radii_(radii), voxel_size_inv_(math::rcp(voxel_size))
|
||||
{
|
||||
BLI_assert(voxel_size > 0.0f);
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return size_t(positions.size());
|
||||
return size_t(positions_.size());
|
||||
}
|
||||
|
||||
void getPos(size_t n, openvdb::Vec3R &xyz) const
|
||||
{
|
||||
xyz = &positions[n].x;
|
||||
float3 pos = positions_[n] * voxel_size_inv_;
|
||||
/* Better align generated grid with source points. */
|
||||
pos -= float3(0.5f);
|
||||
xyz = &pos.x;
|
||||
}
|
||||
|
||||
void getPosRad(size_t n, openvdb::Vec3R &xyz, openvdb::Real &radius) const
|
||||
{
|
||||
xyz = &positions[n].x;
|
||||
radius = radii[n];
|
||||
this->getPos(n, xyz);
|
||||
radius = radii_[n] * voxel_size_inv_;
|
||||
}
|
||||
};
|
||||
|
||||
static openvdb::FloatGrid::Ptr points_to_sdf_grid(const Span<float3> positions,
|
||||
const Span<float> radii)
|
||||
static openvdb::FloatGrid::Ptr points_to_sdf_grid_impl(const Span<float3> positions,
|
||||
const Span<float> radii,
|
||||
const float voxel_size)
|
||||
{
|
||||
/* Create a new grid that will be filled. #ParticlesToLevelSet requires
|
||||
* the background value to be positive */
|
||||
@@ -52,13 +69,23 @@ static openvdb::FloatGrid::Ptr points_to_sdf_grid(const Span<float3> positions,
|
||||
/* Don't ignore particles based on their radius. */
|
||||
op.setRmin(0.0f);
|
||||
op.setRmax(std::numeric_limits<float>::max());
|
||||
OpenVDBParticleList particles{positions, radii};
|
||||
OpenVDBParticleList particles{positions, radii, voxel_size};
|
||||
op.rasterizeSpheres(particles);
|
||||
op.finalize();
|
||||
|
||||
new_grid->transform().postScale(voxel_size);
|
||||
new_grid->setGridClass(openvdb::GRID_LEVEL_SET);
|
||||
|
||||
return new_grid;
|
||||
}
|
||||
|
||||
bke::VolumeGrid<float> points_to_sdf_grid(const Span<float3> positions,
|
||||
const Span<float> radii,
|
||||
const float voxel_size)
|
||||
{
|
||||
return bke::VolumeGrid<float>(points_to_sdf_grid_impl(positions, radii, voxel_size));
|
||||
}
|
||||
|
||||
bke::VolumeGridData *fog_volume_grid_add_from_points(Volume *volume,
|
||||
const StringRefNull name,
|
||||
const Span<float3> positions,
|
||||
@@ -66,8 +93,7 @@ bke::VolumeGridData *fog_volume_grid_add_from_points(Volume *volume,
|
||||
const float voxel_size,
|
||||
const float density)
|
||||
{
|
||||
openvdb::FloatGrid::Ptr new_grid = points_to_sdf_grid(positions, radii);
|
||||
new_grid->transform().postScale(voxel_size);
|
||||
openvdb::FloatGrid::Ptr new_grid = points_to_sdf_grid_impl(positions, radii, 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
|
||||
@@ -83,17 +109,5 @@ bke::VolumeGridData *fog_volume_grid_add_from_points(Volume *volume,
|
||||
return BKE_volume_grid_add_vdb(*volume, name, std::move(new_grid));
|
||||
}
|
||||
|
||||
bke::VolumeGridData *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
|
||||
|
||||
@@ -395,7 +395,9 @@ DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, 0, "MESH_PRIMITIVE_ICO
|
||||
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_LINE, 0, "MESH_PRIMITIVE_LINE",MeshLine, "Mesh Line", "Generate vertices in a line and connect them with edges")
|
||||
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, 0, "MESH_PRIMITIVE_UV_SPHERE", MeshUVSphere, "UV Sphere", "Generate a spherical mesh with quads, except for triangles at the top and bottom")
|
||||
DefNode(GeometryNode, GEO_NODE_MESH_TO_CURVE, 0, "MESH_TO_CURVE", MeshToCurve, "Mesh to Curve", "Generate a curve from a mesh")
|
||||
DefNode(GeometryNode, GEO_NODE_MESH_TO_DENSITY_GRID, 0, "MESH_TO_DENSITY_GRID", MeshToDensityGrid, "Mesh to Density Grid", "Create a filled volume grid from a mesh")
|
||||
DefNode(GeometryNode, GEO_NODE_MESH_TO_POINTS, 0, "MESH_TO_POINTS", MeshToPoints, "Mesh to Points", "Generate a point cloud from a mesh's vertices")
|
||||
DefNode(GeometryNode, GEO_NODE_MESH_TO_SDF_GRID, 0, "MESH_TO_SDF_GRID", MeshToSDFGrid, "Mesh to SDF Grid", "Create a signed distance volume grid from a mesh")
|
||||
DefNode(GeometryNode, GEO_NODE_MESH_TO_VOLUME, 0, "MESH_TO_VOLUME", MeshToVolume, "Mesh to Volume", "Create a fog volume with the shape of the input mesh's surface")
|
||||
DefNode(GeometryNode, GEO_NODE_MESH_TOPOLOGY_CORNERS_OF_EDGE, 0, "CORNERS_OF_EDGE", CornersOfEdge, "Corners of Edge", "Retrieve face corners connected to edges")
|
||||
DefNode(GeometryNode, GEO_NODE_MESH_TOPOLOGY_CORNERS_OF_FACE, 0, "CORNERS_OF_FACE", CornersOfFace, "Corners of Face", "Retrieve corners that make up a face")
|
||||
@@ -408,6 +410,7 @@ DefNode(GeometryNode, GEO_NODE_MESH_TOPOLOGY_VERTEX_OF_CORNER, 0, "VERTEX_OF_COR
|
||||
DefNode(GeometryNode, GEO_NODE_OBJECT_INFO, 0, "OBJECT_INFO", ObjectInfo, "Object Info", "Retrieve information from an object")
|
||||
DefNode(GeometryNode, GEO_NODE_OFFSET_POINT_IN_CURVE, 0, "OFFSET_POINT_IN_CURVE", OffsetPointInCurve, "Offset Point in Curve", "Offset a control point index within its curve")
|
||||
DefNode(GeometryNode, GEO_NODE_POINTS_TO_CURVES, 0, "POINTS_TO_CURVES", PointsToCurves, "Points to Curves", "Split all points to curve by its group ID and reorder by weight")
|
||||
DefNode(GeometryNode, GEO_NODE_POINTS_TO_SDF_GRID, 0, "POINTS_TO_SDF_GRID", PointsToSDFGrid, "Points to SDF Grid", "Create a signed distance volume grid from points")
|
||||
DefNode(GeometryNode, GEO_NODE_POINTS_TO_VERTICES, 0, "POINTS_TO_VERTICES", PointsToVertices, "Points to Vertices", "Generate a mesh vertex for each point cloud point")
|
||||
DefNode(GeometryNode, GEO_NODE_POINTS_TO_VOLUME, 0, "POINTS_TO_VOLUME", PointsToVolume, "Points to Volume", "Generate a fog volume sphere around every point")
|
||||
DefNode(GeometryNode, GEO_NODE_POINTS, 0, "POINTS", Points, "Points", "Generate a point cloud with positions and radii defined by fields")
|
||||
|
||||
@@ -133,7 +133,9 @@ set(SRC
|
||||
nodes/node_geo_mesh_primitive_uv_sphere.cc
|
||||
nodes/node_geo_mesh_subdivide.cc
|
||||
nodes/node_geo_mesh_to_curve.cc
|
||||
nodes/node_geo_mesh_to_density_grid.cc
|
||||
nodes/node_geo_mesh_to_points.cc
|
||||
nodes/node_geo_mesh_to_sdf_grid.cc
|
||||
nodes/node_geo_mesh_to_volume.cc
|
||||
nodes/node_geo_mesh_topology_corners_of_edge.cc
|
||||
nodes/node_geo_mesh_topology_corners_of_face.cc
|
||||
@@ -147,6 +149,7 @@ set(SRC
|
||||
nodes/node_geo_offset_point_in_curve.cc
|
||||
nodes/node_geo_points.cc
|
||||
nodes/node_geo_points_to_curves.cc
|
||||
nodes/node_geo_points_to_sdf_grid.cc
|
||||
nodes/node_geo_points_to_vertices.cc
|
||||
nodes/node_geo_points_to_volume.cc
|
||||
nodes/node_geo_proximity.cc
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_mesh.hh"
|
||||
#include "BKE_volume_grid.hh"
|
||||
|
||||
#include "GEO_mesh_to_volume.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_mesh_to_density_grid_cc {
|
||||
|
||||
NODE_STORAGE_FUNCS(NodeGeometryMeshToVolume)
|
||||
|
||||
static void node_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
b.add_input<decl::Geometry>("Mesh").supported_type(GeometryComponent::Type::Mesh);
|
||||
b.add_input<decl::Float>("Density").default_value(1.0f).min(0.01f).max(FLT_MAX);
|
||||
b.add_input<decl::Float>("Voxel Size")
|
||||
.default_value(0.3f)
|
||||
.min(0.01f)
|
||||
.max(FLT_MAX)
|
||||
.subtype(PROP_DISTANCE);
|
||||
b.add_input<decl::Float>("Gradient Width")
|
||||
.default_value(0.2f)
|
||||
.min(0.0001f)
|
||||
.max(FLT_MAX)
|
||||
.subtype(PROP_DISTANCE)
|
||||
.description("Width of the gradient inside of the mesh");
|
||||
b.add_output<decl::Float>("Density Grid");
|
||||
}
|
||||
|
||||
static void node_geo_exec(GeoNodeExecParams params)
|
||||
{
|
||||
#ifdef WITH_OPENVDB
|
||||
const GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
|
||||
const Mesh *mesh = geometry_set.get_mesh();
|
||||
if (!mesh || mesh->faces_num == 0) {
|
||||
params.set_default_remaining_outputs();
|
||||
return;
|
||||
}
|
||||
bke::VolumeGrid<float> grid = geometry::mesh_to_density_grid(
|
||||
mesh->vert_positions(),
|
||||
mesh->corner_verts(),
|
||||
mesh->corner_tris(),
|
||||
params.extract_input<float>("Voxel Size"),
|
||||
params.extract_input<float>("Gradient Width"),
|
||||
params.extract_input<float>("Density"));
|
||||
params.set_output("Density Grid", std::move(grid));
|
||||
#else
|
||||
node_geo_exec_with_missing_openvdb(params);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void node_register()
|
||||
{
|
||||
static bNodeType ntype;
|
||||
|
||||
geo_node_type_base(
|
||||
&ntype, GEO_NODE_MESH_TO_DENSITY_GRID, "Mesh to Density Grid", NODE_CLASS_GEOMETRY);
|
||||
ntype.declare = node_declare;
|
||||
ntype.geometry_node_execute = node_geo_exec;
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
NOD_REGISTER_NODE(node_register)
|
||||
|
||||
} // namespace blender::nodes::node_geo_mesh_to_density_grid_cc
|
||||
@@ -0,0 +1,62 @@
|
||||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_mesh.hh"
|
||||
#include "BKE_volume_grid.hh"
|
||||
|
||||
#include "GEO_mesh_to_volume.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_mesh_to_sdf_grid_cc {
|
||||
|
||||
static void node_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
b.add_input<decl::Geometry>("Mesh").supported_type(GeometryComponent::Type::Mesh);
|
||||
b.add_input<decl::Float>("Voxel Size")
|
||||
.default_value(0.3f)
|
||||
.min(0.01f)
|
||||
.max(FLT_MAX)
|
||||
.subtype(PROP_DISTANCE);
|
||||
b.add_input<decl::Int>("Band Width")
|
||||
.default_value(3)
|
||||
.min(0)
|
||||
.max(100)
|
||||
.description("Width of the active voxel surface, in voxels");
|
||||
b.add_output<decl::Float>("SDF Grid");
|
||||
}
|
||||
|
||||
static void node_geo_exec(GeoNodeExecParams params)
|
||||
{
|
||||
#ifdef WITH_OPENVDB
|
||||
const GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
|
||||
const Mesh *mesh = geometry_set.get_mesh();
|
||||
if (!mesh || mesh->faces_num == 0) {
|
||||
params.set_default_remaining_outputs();
|
||||
return;
|
||||
}
|
||||
bke::VolumeGrid<float> grid = geometry::mesh_to_sdf_grid(
|
||||
mesh->vert_positions(),
|
||||
mesh->corner_verts(),
|
||||
mesh->corner_tris(),
|
||||
params.extract_input<float>("Voxel Size"),
|
||||
params.extract_input<int>("Band Width"));
|
||||
params.set_output("SDF Grid", std::move(grid));
|
||||
#else
|
||||
node_geo_exec_with_missing_openvdb(params);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void node_register()
|
||||
{
|
||||
static bNodeType ntype;
|
||||
|
||||
geo_node_type_base(&ntype, GEO_NODE_MESH_TO_SDF_GRID, "Mesh to SDF Grid", NODE_CLASS_GEOMETRY);
|
||||
ntype.declare = node_declare;
|
||||
ntype.geometry_node_execute = node_geo_exec;
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
NOD_REGISTER_NODE(node_register)
|
||||
|
||||
} // namespace blender::nodes::node_geo_mesh_to_sdf_grid_cc
|
||||
@@ -0,0 +1,114 @@
|
||||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_volume.hh"
|
||||
#include "BKE_volume_grid.hh"
|
||||
|
||||
#include "GEO_points_to_volume.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_points_to_sdf_grid_cc {
|
||||
|
||||
static void node_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
b.add_input<decl::Geometry>("Points");
|
||||
b.add_input<decl::Float>("Radius")
|
||||
.default_value(0.5f)
|
||||
.min(0.0f)
|
||||
.subtype(PROP_DISTANCE)
|
||||
.field_on_all();
|
||||
b.add_input<decl::Float>("Voxel Size").default_value(0.3f).min(0.01f).subtype(PROP_DISTANCE);
|
||||
b.add_output<decl::Float>("SDF Grid");
|
||||
}
|
||||
|
||||
#ifdef WITH_OPENVDB
|
||||
|
||||
static void gather_positions_from_component(const GeometryComponent &component,
|
||||
Vector<float3> &r_positions)
|
||||
{
|
||||
if (component.is_empty()) {
|
||||
return;
|
||||
}
|
||||
const VArray<float3> positions = *component.attributes()->lookup<float3>("position");
|
||||
r_positions.resize(r_positions.size() + positions.size());
|
||||
positions.materialize(r_positions.as_mutable_span().take_back(positions.size()));
|
||||
}
|
||||
|
||||
static void gather_radii_from_component(const GeometryComponent &component,
|
||||
const Field<float> radius_field,
|
||||
Vector<float> &r_radii)
|
||||
{
|
||||
if (component.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bke::GeometryFieldContext field_context{component, AttrDomain::Point};
|
||||
const int domain_num = component.attribute_domain_size(AttrDomain::Point);
|
||||
|
||||
r_radii.resize(r_radii.size() + domain_num);
|
||||
fn::FieldEvaluator evaluator{field_context, domain_num};
|
||||
evaluator.add_with_destination(radius_field, r_radii.as_mutable_span().take_back(domain_num));
|
||||
evaluator.evaluate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the VolumeComponent of a GeometrySet with a new Volume from points.
|
||||
* The grid class should be either openvdb::GRID_FOG_VOLUME or openvdb::GRID_LEVEL_SET.
|
||||
*/
|
||||
static bke::VolumeGrid<float> points_to_grid(const GeometrySet &geometry_set,
|
||||
const Field<float> &radius_field,
|
||||
const float voxel_size)
|
||||
{
|
||||
const double determinant = std::pow(double(voxel_size), 3.0);
|
||||
if (!BKE_volume_grid_determinant_valid(determinant)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
Vector<float3> positions;
|
||||
Vector<float> radii;
|
||||
for (const GeometryComponent::Type type : {GeometryComponent::Type::Mesh,
|
||||
GeometryComponent::Type::PointCloud,
|
||||
GeometryComponent::Type::Curve})
|
||||
{
|
||||
if (const GeometryComponent *component = geometry_set.get_component(type)) {
|
||||
gather_positions_from_component(*component, positions);
|
||||
gather_radii_from_component(*component, radius_field, radii);
|
||||
}
|
||||
}
|
||||
|
||||
if (positions.is_empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return geometry::points_to_sdf_grid(positions, radii, voxel_size);
|
||||
}
|
||||
|
||||
#endif /* WITH_OPENVDB */
|
||||
|
||||
static void node_geo_exec(GeoNodeExecParams params)
|
||||
{
|
||||
#ifdef WITH_OPENVDB
|
||||
bke::VolumeGrid<float> grid = points_to_grid(params.extract_input<GeometrySet>("Points"),
|
||||
params.extract_input<Field<float>>("Radius"),
|
||||
params.extract_input<float>("Voxel Size"));
|
||||
params.set_output("SDF Grid", std::move(grid));
|
||||
#else
|
||||
node_geo_exec_with_missing_openvdb(params);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void node_register()
|
||||
{
|
||||
static bNodeType ntype;
|
||||
|
||||
geo_node_type_base(
|
||||
&ntype, GEO_NODE_POINTS_TO_SDF_GRID, "Points to SDF Grid", NODE_CLASS_GEOMETRY);
|
||||
ntype.declare = node_declare;
|
||||
ntype.geometry_node_execute = node_geo_exec;
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
NOD_REGISTER_NODE(node_register)
|
||||
|
||||
} // namespace blender::nodes::node_geo_points_to_sdf_grid_cc
|
||||
@@ -69,19 +69,6 @@ static float compute_voxel_size_from_amount(const float voxel_amount,
|
||||
return voxel_size;
|
||||
}
|
||||
|
||||
static void convert_to_grid_index_space(const float voxel_size,
|
||||
MutableSpan<float3> positions,
|
||||
MutableSpan<float> radii)
|
||||
{
|
||||
const float voxel_size_inv = 1.0f / voxel_size;
|
||||
for (const int i : positions.index_range()) {
|
||||
positions[i] *= voxel_size_inv;
|
||||
/* Better align generated grid with source points. */
|
||||
positions[i] -= float3(0.5f);
|
||||
radii[i] *= voxel_size_inv;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the VolumeComponent of a GeometrySet with a new Volume from points.
|
||||
* The grid class should be either openvdb::GRID_FOG_VOLUME or openvdb::GRID_LEVEL_SET.
|
||||
@@ -128,8 +115,6 @@ static void initialize_volume_component_from_points(GeoNodeExecParams ¶ms,
|
||||
|
||||
Volume *volume = reinterpret_cast<Volume *>(BKE_id_new_nomain(ID_VO, nullptr));
|
||||
|
||||
convert_to_grid_index_space(voxel_size, positions, radii);
|
||||
|
||||
const float density = params.get_input<float>("Density");
|
||||
blender::geometry::fog_volume_grid_add_from_points(
|
||||
volume, "density", positions, radii, voxel_size, density);
|
||||
|
||||
Reference in New Issue
Block a user