Geometry Nodes: Add Mesh To Volume Node
This adds a Mesh To Volume Node T86838 based on the existing modifier. The mesh to volume conversion is implemented in the geometry module, and shared between the node and the modifier. Currently the node outputs a grid with the name "density". This may change in the future depending on the decisions made in T91668. The original patch was by Kris (@Metricity), further implementation by Geramy Loveless (@GeramyLoveless), then finished by Erik Abrahamsson (@erik85). Differential Revision: https://developer.blender.org/D10895
This commit is contained in:
@@ -102,6 +102,7 @@ void register_node_type_geo_mesh_primitive_uv_sphere(void);
|
||||
void register_node_type_geo_mesh_subdivide(void);
|
||||
void register_node_type_geo_mesh_to_curve(void);
|
||||
void register_node_type_geo_mesh_to_points(void);
|
||||
void register_node_type_geo_mesh_to_volume(void);
|
||||
void register_node_type_geo_object_info(void);
|
||||
void register_node_type_geo_points(void);
|
||||
void register_node_type_geo_points_to_vertices(void);
|
||||
|
||||
@@ -357,6 +357,7 @@ DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_LINE, def_geo_mesh_line, "MESH_PRI
|
||||
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, 0, "MESH_PRIMITIVE_UV_SPHERE", MeshUVSphere, "UV Sphere", "")
|
||||
DefNode(GeometryNode, GEO_NODE_MESH_TO_CURVE, 0, "MESH_TO_CURVE", MeshToCurve, "Mesh to Curve", "")
|
||||
DefNode(GeometryNode, GEO_NODE_MESH_TO_POINTS, def_geo_mesh_to_points, "MESH_TO_POINTS", MeshToPoints, "Mesh to Points", "")
|
||||
DefNode(GeometryNode, GEO_NODE_MESH_TO_VOLUME, def_geo_mesh_to_volume, "MESH_TO_VOLUME", MeshToVolume, "Mesh To Volume", "")
|
||||
DefNode(GeometryNode, GEO_NODE_OBJECT_INFO, def_geo_object_info, "OBJECT_INFO", ObjectInfo, "Object Info", "")
|
||||
DefNode(GeometryNode, GEO_NODE_POINTS, 0, "POINTS", Points, "Points", "")
|
||||
DefNode(GeometryNode, GEO_NODE_POINTS_TO_VERTICES, 0, "POINTS_TO_VERTICES", PointsToVertices, "Points to Vertices", "")
|
||||
|
||||
@@ -112,6 +112,7 @@ set(SRC
|
||||
nodes/node_geo_mesh_subdivide.cc
|
||||
nodes/node_geo_mesh_to_curve.cc
|
||||
nodes/node_geo_mesh_to_points.cc
|
||||
nodes/node_geo_mesh_to_volume.cc
|
||||
nodes/node_geo_object_info.cc
|
||||
nodes/node_geo_points.cc
|
||||
nodes/node_geo_points_to_vertices.cc
|
||||
|
||||
183
source/blender/nodes/geometry/nodes/node_geo_mesh_to_volume.cc
Normal file
183
source/blender/nodes/geometry/nodes/node_geo_mesh_to_volume.cc
Normal file
@@ -0,0 +1,183 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "DEG_depsgraph_query.h"
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_mesh_runtime.h"
|
||||
#include "BKE_mesh_wrapper.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_volume.h"
|
||||
|
||||
#include "GEO_mesh_to_volume.hh"
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
#include "UI_resources.h"
|
||||
|
||||
namespace blender::nodes::node_geo_mesh_to_volume_cc {
|
||||
|
||||
NODE_STORAGE_FUNCS(NodeGeometryMeshToVolume)
|
||||
|
||||
static void node_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
|
||||
b.add_input<decl::Float>(N_("Density")).default_value(1.0f).min(0.01f).max(FLT_MAX);
|
||||
b.add_input<decl::Float>(N_("Voxel Size"))
|
||||
.default_value(0.3f)
|
||||
.min(0.01f)
|
||||
.max(FLT_MAX)
|
||||
.subtype(PROP_DISTANCE);
|
||||
b.add_input<decl::Float>(N_("Voxel Amount")).default_value(64.0f).min(0.0f).max(FLT_MAX);
|
||||
b.add_input<decl::Float>(N_("Exterior Band Width"))
|
||||
.default_value(0.1f)
|
||||
.min(0.0f)
|
||||
.max(FLT_MAX)
|
||||
.subtype(PROP_DISTANCE)
|
||||
.description(N_("Width of the volume outside of the mesh"));
|
||||
b.add_input<decl::Float>(N_("Interior Band Width"))
|
||||
.default_value(0.0f)
|
||||
.min(0.0f)
|
||||
.max(FLT_MAX)
|
||||
.subtype(PROP_DISTANCE)
|
||||
.description(N_("Width of the volume inside of the mesh"));
|
||||
b.add_input<decl::Bool>(N_("Fill Volume"))
|
||||
.default_value(true)
|
||||
.description(N_("Initialize the density grid in every cell inside the enclosed volume"));
|
||||
b.add_output<decl::Geometry>(N_("Volume"));
|
||||
}
|
||||
|
||||
static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
|
||||
{
|
||||
uiLayoutSetPropSep(layout, true);
|
||||
uiLayoutSetPropDecorate(layout, false);
|
||||
uiItemR(layout, ptr, "resolution_mode", 0, IFACE_("Resolution"), ICON_NONE);
|
||||
}
|
||||
|
||||
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
|
||||
{
|
||||
NodeGeometryMeshToVolume *data = (NodeGeometryMeshToVolume *)MEM_callocN(
|
||||
sizeof(NodeGeometryMeshToVolume), __func__);
|
||||
data->resolution_mode = MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT;
|
||||
node->storage = data;
|
||||
}
|
||||
|
||||
static void node_update(bNodeTree *ntree, bNode *node)
|
||||
{
|
||||
NodeGeometryMeshToVolume *data = (NodeGeometryMeshToVolume *)node->storage;
|
||||
|
||||
bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size");
|
||||
bNodeSocket *voxel_amount_socket = nodeFindSocket(node, SOCK_IN, "Voxel Amount");
|
||||
nodeSetSocketAvailability(ntree,
|
||||
voxel_amount_socket,
|
||||
data->resolution_mode == MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT);
|
||||
nodeSetSocketAvailability(ntree,
|
||||
voxel_size_socket,
|
||||
data->resolution_mode == MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE);
|
||||
}
|
||||
|
||||
#ifdef WITH_OPENVDB
|
||||
|
||||
static Volume *create_volume_from_mesh(const Mesh &mesh, GeoNodeExecParams ¶ms)
|
||||
{
|
||||
const NodeGeometryMeshToVolume &storage =
|
||||
*(const NodeGeometryMeshToVolume *)params.node().storage;
|
||||
|
||||
const float density = params.get_input<float>("Density");
|
||||
const float exterior_band_width = params.get_input<float>("Exterior Band Width");
|
||||
const float interior_band_width = params.get_input<float>("Interior Band Width");
|
||||
const bool fill_volume = params.get_input<bool>("Fill Volume");
|
||||
|
||||
geometry::MeshToVolumeResolution resolution;
|
||||
resolution.mode = (MeshToVolumeModifierResolutionMode)storage.resolution_mode;
|
||||
if (resolution.mode == MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT) {
|
||||
resolution.settings.voxel_amount = params.get_input<float>("Voxel Amount");
|
||||
if (resolution.settings.voxel_amount <= 0.0f) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else if (resolution.mode == MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE) {
|
||||
resolution.settings.voxel_size = params.get_input<float>("Voxel Size");
|
||||
if (resolution.settings.voxel_size <= 0.0f) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
float3 min, max;
|
||||
INIT_MINMAX(min, max);
|
||||
if (!BKE_mesh_wrapper_minmax(&mesh, min, max)) {
|
||||
min = float3(-1.0f);
|
||||
max = float3(1.0f);
|
||||
}
|
||||
|
||||
const float4x4 mesh_to_volume_space_transform = float4x4::identity();
|
||||
|
||||
const float voxel_size = geometry::volume_compute_voxel_size(params.depsgraph(),
|
||||
min,
|
||||
max,
|
||||
resolution,
|
||||
exterior_band_width,
|
||||
mesh_to_volume_space_transform);
|
||||
|
||||
Volume *volume = (Volume *)BKE_id_new_nomain(ID_VO, nullptr);
|
||||
BKE_volume_init_grids(volume);
|
||||
|
||||
/* Convert mesh to grid and add to volume. */
|
||||
geometry::volume_grid_add_from_mesh(volume,
|
||||
"density",
|
||||
&mesh,
|
||||
mesh_to_volume_space_transform,
|
||||
voxel_size,
|
||||
fill_volume,
|
||||
exterior_band_width,
|
||||
interior_band_width,
|
||||
density);
|
||||
|
||||
return volume;
|
||||
}
|
||||
|
||||
#endif /* WITH_OPENVDB */
|
||||
|
||||
static void node_geo_exec(GeoNodeExecParams params)
|
||||
{
|
||||
#ifdef WITH_OPENVDB
|
||||
GeometrySet geometry_set(params.extract_input<GeometrySet>("Mesh"));
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
if (geometry_set.has_mesh()) {
|
||||
Volume *volume = create_volume_from_mesh(*geometry_set.get_mesh_for_read(), params);
|
||||
geometry_set.replace_volume(volume);
|
||||
geometry_set.keep_only({GEO_COMPONENT_TYPE_VOLUME, GEO_COMPONENT_TYPE_INSTANCES});
|
||||
}
|
||||
});
|
||||
params.set_output("Volume", std::move(geometry_set));
|
||||
#else
|
||||
params.error_message_add(NodeWarningType::Error,
|
||||
TIP_("Disabled, Blender was compiled without OpenVDB"));
|
||||
params.set_default_remaining_outputs();
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace blender::nodes::node_geo_mesh_to_volume_cc
|
||||
|
||||
void register_node_type_geo_mesh_to_volume()
|
||||
{
|
||||
namespace file_ns = blender::nodes::node_geo_mesh_to_volume_cc;
|
||||
|
||||
static bNodeType ntype;
|
||||
|
||||
geo_node_type_base(&ntype, GEO_NODE_MESH_TO_VOLUME, "Mesh to Volume", NODE_CLASS_GEOMETRY);
|
||||
ntype.declare = file_ns::node_declare;
|
||||
node_type_size(&ntype, 200, 120, 700);
|
||||
node_type_init(&ntype, file_ns::node_init);
|
||||
node_type_update(&ntype, file_ns::node_update);
|
||||
ntype.geometry_node_execute = file_ns::node_geo_exec;
|
||||
ntype.draw_buttons = file_ns::node_layout;
|
||||
node_type_storage(
|
||||
&ntype, "NodeGeometryMeshToVolume", node_free_standard_storage, node_copy_standard_storage);
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
Reference in New Issue
Block a user