Geometry Nodes: Remove experimental volume nodes #115567
@ -407,8 +407,6 @@ class NODE_MT_geometry_node_GEO_MESH_OPERATIONS(Menu):
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeMeshBoolean")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeMeshToCurve")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeMeshToPoints")
|
||||
if context.preferences.experimental.use_new_volume_nodes:
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeMeshToSDFVolume")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeMeshToVolume")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeScaleElements")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeSplitEdges")
|
||||
@ -475,8 +473,6 @@ class NODE_MT_category_GEO_POINT(Menu):
|
||||
node_add_menu.add_node_type(layout, "GeometryNodePoints")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodePointsToCurves")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodePointsToVertices")
|
||||
if context.preferences.experimental.use_new_volume_nodes:
|
||||
node_add_menu.add_node_type(layout, "GeometryNodePointsToSDFVolume")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodePointsToVolume")
|
||||
layout.separator()
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeSetPointRadius")
|
||||
@ -637,13 +633,6 @@ class NODE_MT_category_GEO_VOLUME(Menu):
|
||||
layout = self.layout
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeVolumeCube")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeVolumeToMesh")
|
||||
if context.preferences.experimental.use_new_volume_nodes:
|
||||
layout.separator()
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeMeanFilterSDFVolume")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeOffsetSDFVolume")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeSampleVolume")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeSDFVolumeSphere")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeInputSignedDistance")
|
||||
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
|
||||
|
||||
|
||||
|
@ -1291,17 +1291,17 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
|
||||
#define GEO_NODE_IMAGE 1191
|
||||
#define GEO_NODE_INTERPOLATE_CURVES 1192
|
||||
#define GEO_NODE_EDGES_TO_FACE_GROUPS 1193
|
||||
#define GEO_NODE_POINTS_TO_SDF_VOLUME 1194
|
||||
#define GEO_NODE_MESH_TO_SDF_VOLUME 1195
|
||||
#define GEO_NODE_SDF_VOLUME_SPHERE 1196
|
||||
#define GEO_NODE_MEAN_FILTER_SDF_VOLUME 1197
|
||||
#define GEO_NODE_OFFSET_SDF_VOLUME 1198
|
||||
// #define GEO_NODE_POINTS_TO_SDF_VOLUME 1194
|
||||
// #define GEO_NODE_MESH_TO_SDF_VOLUME 1195
|
||||
// #define GEO_NODE_SDF_VOLUME_SPHERE 1196
|
||||
// #define GEO_NODE_MEAN_FILTER_SDF_VOLUME 1197
|
||||
// #define GEO_NODE_OFFSET_SDF_VOLUME 1198
|
||||
#define GEO_NODE_INDEX_OF_NEAREST 1199
|
||||
/* Function nodes use the range starting at 1200. */
|
||||
#define GEO_NODE_SIMULATION_INPUT 2100
|
||||
#define GEO_NODE_SIMULATION_OUTPUT 2101
|
||||
#define GEO_NODE_INPUT_SIGNED_DISTANCE 2102
|
||||
#define GEO_NODE_SAMPLE_VOLUME 2103
|
||||
// #define GEO_NODE_INPUT_SIGNED_DISTANCE 2102
|
||||
// #define GEO_NODE_SAMPLE_VOLUME 2103
|
||||
#define GEO_NODE_MESH_TOPOLOGY_CORNERS_OF_EDGE 2104
|
||||
/* Leaving out two indices to avoid crashes with files that were created during the development of
|
||||
* the repeat zone. */
|
||||
|
@ -1882,13 +1882,6 @@ typedef struct NodeGeometryDistributePointsInVolume {
|
||||
uint8_t mode;
|
||||
} NodeGeometryDistributePointsInVolume;
|
||||
|
||||
typedef struct NodeGeometrySampleVolume {
|
||||
/** #eCustomDataType. */
|
||||
int8_t grid_type;
|
||||
/** #GeometryNodeSampleVolumeInterpolationMode */
|
||||
int8_t interpolation_mode;
|
||||
} NodeGeometrySampleVolume;
|
||||
|
||||
typedef struct NodeFunctionCompare {
|
||||
/** #NodeCompareOperation */
|
||||
int8_t operation;
|
||||
@ -2781,12 +2774,6 @@ typedef enum GeometryNodeScaleElementsMode {
|
||||
GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS = 1,
|
||||
} GeometryNodeScaleElementsMode;
|
||||
|
||||
typedef enum GeometryNodeSampleVolumeInterpolationMode {
|
||||
GEO_NODE_SAMPLE_VOLUME_INTERPOLATION_MODE_NEAREST = 0,
|
||||
GEO_NODE_SAMPLE_VOLUME_INTERPOLATION_MODE_TRILINEAR = 1,
|
||||
GEO_NODE_SAMPLE_VOLUME_INTERPOLATION_MODE_TRIQUADRATIC = 2,
|
||||
} GeometryNodeSampleVolumeInterpolationMode;
|
||||
|
||||
typedef enum NodeCombSepColorMode {
|
||||
NODE_COMBSEP_COLOR_RGB = 0,
|
||||
NODE_COMBSEP_COLOR_HSV = 1,
|
||||
|
@ -360,7 +360,6 @@ DefNode(GeometryNode, GEO_NODE_INPUT_RADIUS, 0, "INPUT_RADIUS", InputRadius, "Ra
|
||||
DefNode(GeometryNode, GEO_NODE_INPUT_SCENE_TIME, 0, "INPUT_SCENE_TIME", InputSceneTime, "Scene Time", "Retrieve the current time in the scene's animation in units of seconds or frames")
|
||||
DefNode(GeometryNode, GEO_NODE_INPUT_FACE_SMOOTH, 0, "INPUT_SHADE_SMOOTH", InputShadeSmooth, "Is Face Smooth", "Retrieve whether each face is marked for smooth or sharp normals")
|
||||
DefNode(GeometryNode, GEO_NODE_INPUT_SHORTEST_EDGE_PATHS, 0, "SHORTEST_EDGE_PATHS", InputShortestEdgePaths, "Shortest Edge Paths", "Find the shortest paths along mesh edges to selected end vertices, with customizable cost per edge")
|
||||
DefNode(GeometryNode, GEO_NODE_INPUT_SIGNED_DISTANCE, 0, "SIGNED_DISTANCE", InputSignedDistance, "Signed Distance", "Retrieve the signed distance field grid called 'distance' from a volume")
|
||||
DefNode(GeometryNode, GEO_NODE_INPUT_SPLINE_CYCLIC, 0, "INPUT_SPLINE_CYCLIC",InputSplineCyclic, "Is Spline Cyclic", "Retrieve whether each spline endpoint connects to the beginning")
|
||||
DefNode(GeometryNode, GEO_NODE_INPUT_SPLINE_LENGTH, 0, "SPLINE_LENGTH", SplineLength, "Spline Length", "Retrieve the total length of each spline, as a distance or as a number of points")
|
||||
DefNode(GeometryNode, GEO_NODE_INPUT_SPLINE_RESOLUTION, 0, "INPUT_SPLINE_RESOLUTION", InputSplineResolution, "Spline Resolution", "Retrieve the number of evaluated points that will be generated for every control point on curves")
|
||||
@ -370,7 +369,6 @@ DefNode(GeometryNode, GEO_NODE_INSTANCES_TO_POINTS, 0, "INSTANCES_TO_POINTS",Ins
|
||||
DefNode(GeometryNode, GEO_NODE_IS_VIEWPORT, 0, "IS_VIEWPORT", IsViewport, "Is Viewport", "Retrieve whether the nodes are being evaluated for the viewport rather than the final render")
|
||||
DefNode(GeometryNode, GEO_NODE_JOIN_GEOMETRY, 0, "JOIN_GEOMETRY", JoinGeometry, "Join Geometry", "Merge separately generated geometries into a single one")
|
||||
DefNode(GeometryNode, GEO_NODE_MATERIAL_SELECTION, 0, "MATERIAL_SELECTION", MaterialSelection, "Material Selection", "Provide a selection of faces that use the specified material")
|
||||
DefNode(GeometryNode, GEO_NODE_MEAN_FILTER_SDF_VOLUME, 0, "MEAN_FILTER_SDF_VOLUME", MeanFilterSDFVolume, "Mean Filter SDF Volume", "Smooth the surface of an SDF volume by applying a mean filter")
|
||||
DefNode(GeometryNode, GEO_NODE_MERGE_BY_DISTANCE, 0, "MERGE_BY_DISTANCE", MergeByDistance, "Merge by Distance", "Merge vertices or points within a given distance")
|
||||
DefNode(GeometryNode, GEO_NODE_MESH_BOOLEAN, 0, "MESH_BOOLEAN", MeshBoolean, "Mesh Boolean", "Cut, subtract, or join multiple mesh inputs")
|
||||
DefNode(GeometryNode, GEO_NODE_MESH_FACE_GROUP_BOUNDARIES, 0, "MESH_FACE_SET_BOUNDARIES", MeshFaceSetBoundaries, "Face Group Boundaries", "Find edges on the boundaries between groups of faces with the same ID value")
|
||||
@ -384,7 +382,6 @@ DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_LINE, 0, "MESH_PRIMITIVE_LINE",Mes
|
||||
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_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_VOLUME, 0, "MESH_TO_SDF_VOLUME", MeshToSDFVolume, "Mesh to SDF Volume", "Create an SDF volume with the shape of the input mesh's surface")
|
||||
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")
|
||||
@ -396,13 +393,11 @@ DefNode(GeometryNode, GEO_NODE_MESH_TOPOLOGY_OFFSET_CORNER_IN_FACE, 0, "OFFSET_C
|
||||
DefNode(GeometryNode, GEO_NODE_MESH_TOPOLOGY_VERTEX_OF_CORNER, 0, "VERTEX_OF_CORNER", VertexOfCorner, "Vertex of Corner", "Retrieve the vertex each face corner is attached to")
|
||||
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_OFFSET_SDF_VOLUME, 0, "OFFSET_SDF_VOLUME", OffsetSDFVolume, "Offset SDF Volume", "Move the surface of an SDF volume inwards or outwards")
|
||||
DefNode(GeometryNode, GEO_NODE_TOOL_FACE_SET, 0, "TOOL_FACE_SET", ToolFaceSet, "Face Set", "Each face's sculpt face set value")
|
||||
DefNode(GeometryNode, GEO_NODE_TOOL_3D_CURSOR, 0, "TOOL_3D_CURSOR", Tool3DCursor, "3D Cursor", "The scene's 3D cursor location and rotation")
|
||||
DefNode(GeometryNode, GEO_NODE_TOOL_SELECTION, 0, "TOOL_SELECTION", ToolSelection, "Selection", "User selection of the edited geometry, for tool execution")
|
||||
DefNode(GeometryNode, GEO_NODE_TOOL_SET_SELECTION, 0, "TOOL_SELECTION_SET", ToolSetSelection, "Set Selection", "Set selection of the edited geometry, for tool execution")
|
||||
DefNode(GeometryNode, GEO_NODE_TOOL_SET_FACE_SET, 0, "TOOL_SET_FACE_SET", ToolSetFaceSet, "Set Face Set", "Set sculpt face set values for faces")
|
||||
DefNode(GeometryNode, GEO_NODE_POINTS_TO_SDF_VOLUME, 0, "POINTS_TO_SDF_VOLUME", PointsToSDFVolume, "Points to SDF Volume", "Generate an SDF volume sphere around every point")
|
||||
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")
|
||||
@ -421,10 +416,8 @@ DefNode(GeometryNode, GEO_NODE_SAMPLE_INDEX, def_geo_sample_index, "SAMPLE_INDEX
|
||||
DefNode(GeometryNode, GEO_NODE_SAMPLE_NEAREST_SURFACE, 0, "SAMPLE_NEAREST_SURFACE", SampleNearestSurface, "Sample Nearest Surface", "Calculate the interpolated value of a mesh attribute on the closest point of its surface")
|
||||
DefNode(GeometryNode, GEO_NODE_SAMPLE_NEAREST, 0, "SAMPLE_NEAREST", SampleNearest, "Sample Nearest", "Find the element of a geometry closest to a position. Similar to the \"Index of Nearest\" node")
|
||||
DefNode(GeometryNode, GEO_NODE_SAMPLE_UV_SURFACE, 0, "SAMPLE_UV_SURFACE", SampleUVSurface, "Sample UV Surface", "Calculate the interpolated values of a mesh attribute at a UV coordinate")
|
||||
DefNode(GeometryNode, GEO_NODE_SAMPLE_VOLUME, 0, "SAMPLE_VOLUME", SampleVolume, "Sample Volume", "Calculate the interpolated values of a Volume grid at the specified position")
|
||||
DefNode(GeometryNode, GEO_NODE_SCALE_ELEMENTS, 0, "SCALE_ELEMENTS", ScaleElements, "Scale Elements", "Scale groups of connected edges and faces")
|
||||
DefNode(GeometryNode, GEO_NODE_SCALE_INSTANCES, 0, "SCALE_INSTANCES", ScaleInstances, "Scale Instances", "Scale geometry instances in local or global space")
|
||||
DefNode(GeometryNode, GEO_NODE_SDF_VOLUME_SPHERE, 0, "SDF_VOLUME_SPHERE", SDFVolumeSphere, "SDF Volume Sphere", "Generate an SDF Volume Sphere")
|
||||
DefNode(GeometryNode, GEO_NODE_SELF_OBJECT, 0, "SELF_OBJECT", SelfObject, "Self Object", "Retrieve the object that contains the geometry nodes modifier currently being executed")
|
||||
DefNode(GeometryNode, GEO_NODE_SEPARATE_COMPONENTS, 0, "SEPARATE_COMPONENTS",SeparateComponents, "Separate Components", "Split a geometry into a separate output for each type of data in the geometry")
|
||||
DefNode(GeometryNode, GEO_NODE_SEPARATE_GEOMETRY, 0, "SEPARATE_GEOMETRY", SeparateGeometry, "Separate Geometry", "Split a geometry into two geometry outputs based on a selection")
|
||||
|
@ -105,7 +105,6 @@ set(SRC
|
||||
nodes/node_geo_input_radius.cc
|
||||
nodes/node_geo_input_scene_time.cc
|
||||
nodes/node_geo_input_shortest_edge_paths.cc
|
||||
nodes/node_geo_input_signed_distance.cc
|
||||
nodes/node_geo_input_spline_cyclic.cc
|
||||
nodes/node_geo_input_spline_length.cc
|
||||
nodes/node_geo_input_spline_resolution.cc
|
||||
@ -117,7 +116,6 @@ set(SRC
|
||||
nodes/node_geo_join_geometry.cc
|
||||
nodes/node_geo_material_replace.cc
|
||||
nodes/node_geo_material_selection.cc
|
||||
nodes/node_geo_mean_filter_sdf_volume.cc
|
||||
nodes/node_geo_merge_by_distance.cc
|
||||
nodes/node_geo_mesh_face_group_boundaries.cc
|
||||
nodes/node_geo_mesh_primitive_circle.cc
|
||||
@ -131,7 +129,6 @@ 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_sdf_volume.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
|
||||
@ -143,10 +140,8 @@ set(SRC
|
||||
nodes/node_geo_mesh_topology_vertex_of_corner.cc
|
||||
nodes/node_geo_object_info.cc
|
||||
nodes/node_geo_offset_point_in_curve.cc
|
||||
nodes/node_geo_offset_sdf_volume.cc
|
||||
nodes/node_geo_points.cc
|
||||
nodes/node_geo_points_to_curves.cc
|
||||
nodes/node_geo_points_to_sdf_volume.cc
|
||||
nodes/node_geo_points_to_vertices.cc
|
||||
nodes/node_geo_points_to_volume.cc
|
||||
nodes/node_geo_proximity.cc
|
||||
@ -160,10 +155,8 @@ set(SRC
|
||||
nodes/node_geo_sample_nearest.cc
|
||||
nodes/node_geo_sample_nearest_surface.cc
|
||||
nodes/node_geo_sample_uv_surface.cc
|
||||
nodes/node_geo_sample_volume.cc
|
||||
nodes/node_geo_scale_elements.cc
|
||||
nodes/node_geo_scale_instances.cc
|
||||
nodes/node_geo_sdf_volume_sphere.cc
|
||||
nodes/node_geo_self_object.cc
|
||||
nodes/node_geo_separate_components.cc
|
||||
nodes/node_geo_separate_geometry.cc
|
||||
|
@ -1,41 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "NOD_socket_search_link.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_input_signed_distance_cc {
|
||||
|
||||
static void node_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
b.add_output<decl::Float>("Signed Distance").field_source();
|
||||
}
|
||||
|
||||
static void search_link_ops(GatherLinkSearchOpParams ¶ms)
|
||||
{
|
||||
if (U.experimental.use_new_volume_nodes) {
|
||||
nodes::search_link_ops_for_basic_node(params);
|
||||
}
|
||||
}
|
||||
|
||||
static void node_geo_exec(GeoNodeExecParams params)
|
||||
{
|
||||
Field<float> signed_distance_field{AttributeFieldInput::Create<float>("distance")};
|
||||
params.set_output("Signed Distance", std::move(signed_distance_field));
|
||||
}
|
||||
|
||||
static void node_register()
|
||||
{
|
||||
static bNodeType ntype;
|
||||
|
||||
geo_node_type_base(&ntype, GEO_NODE_INPUT_SIGNED_DISTANCE, "Signed Distance", NODE_CLASS_INPUT);
|
||||
ntype.geometry_node_execute = node_geo_exec;
|
||||
ntype.declare = node_declare;
|
||||
ntype.gather_link_search_ops = search_link_ops;
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
NOD_REGISTER_NODE(node_register)
|
||||
|
||||
} // namespace blender::nodes::node_geo_input_signed_distance_cc
|
@ -1,100 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "DEG_depsgraph_query.hh"
|
||||
#ifdef WITH_OPENVDB
|
||||
# include <openvdb/tools/LevelSetFilter.h>
|
||||
#endif
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
#include "BKE_volume.hh"
|
||||
#include "BKE_volume_openvdb.hh"
|
||||
|
||||
#include "DNA_node_types.h"
|
||||
|
||||
#include "NOD_socket_search_link.hh"
|
||||
|
||||
#include "UI_interface.hh"
|
||||
#include "UI_resources.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_mean_filter_sdf_volume_cc {
|
||||
|
||||
static void node_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
b.add_input<decl::Geometry>("Volume")
|
||||
.supported_type(GeometryComponent::Type::Volume)
|
||||
.translation_context(BLT_I18NCONTEXT_ID_ID);
|
||||
b.add_input<decl::Int>("Iterations").min(1).max(256).default_value(1);
|
||||
b.add_input<decl::Int>("Width").min(0).default_value(1);
|
||||
b.add_output<decl::Geometry>("Volume").translation_context(BLT_I18NCONTEXT_ID_ID);
|
||||
}
|
||||
|
||||
static void search_link_ops(GatherLinkSearchOpParams ¶ms)
|
||||
{
|
||||
if (U.experimental.use_new_volume_nodes) {
|
||||
blender::nodes::search_link_ops_for_basic_node(params);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WITH_OPENVDB
|
||||
static void sdf_volume_mean_filter(Volume &volume, const GeoNodeExecParams ¶ms)
|
||||
{
|
||||
VolumeGrid *volume_grid = BKE_volume_grid_find_for_write(&volume, "distance");
|
||||
if (volume_grid == nullptr) {
|
||||
return;
|
||||
}
|
||||
openvdb::GridBase::Ptr base_grid = BKE_volume_grid_openvdb_for_write(
|
||||
&volume, volume_grid, false);
|
||||
|
||||
if (!base_grid->isType<openvdb::FloatGrid>()) {
|
||||
return;
|
||||
}
|
||||
openvdb::FloatGrid::Ptr levelset_grid = openvdb::gridPtrCast<openvdb::FloatGrid>(base_grid);
|
||||
openvdb::tools::LevelSetFilter<openvdb::FloatGrid> filter(*levelset_grid);
|
||||
|
||||
int iterations = params.get_input<int>("Iterations");
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
filter.mean(params.get_input<int>("Width"));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void node_geo_exec(GeoNodeExecParams params)
|
||||
{
|
||||
#ifdef WITH_OPENVDB
|
||||
GeometrySet geometry_set = params.extract_input<GeometrySet>("Volume");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
if (!geometry_set.has_volume()) {
|
||||
return;
|
||||
}
|
||||
VolumeComponent &component = geometry_set.get_component_for_write<VolumeComponent>();
|
||||
Volume *volume = component.get_for_write();
|
||||
BKE_volume_load(volume, DEG_get_bmain(params.depsgraph()));
|
||||
sdf_volume_mean_filter(*volume, params);
|
||||
});
|
||||
params.set_output("Volume", std::move(geometry_set));
|
||||
#else
|
||||
params.set_default_remaining_outputs();
|
||||
params.error_message_add(NodeWarningType::Error,
|
||||
TIP_("Disabled, Blender was compiled without OpenVDB"));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void node_register()
|
||||
{
|
||||
static bNodeType ntype;
|
||||
|
||||
geo_node_type_base(
|
||||
&ntype, GEO_NODE_MEAN_FILTER_SDF_VOLUME, "Mean Filter SDF Volume", NODE_CLASS_GEOMETRY);
|
||||
blender::bke::node_type_size(&ntype, 160, 120, 700);
|
||||
ntype.declare = node_declare;
|
||||
ntype.geometry_node_execute = node_geo_exec;
|
||||
ntype.gather_link_search_ops = search_link_ops;
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
NOD_REGISTER_NODE(node_register)
|
||||
|
||||
} // namespace blender::nodes::node_geo_mean_filter_sdf_volume_cc
|
@ -1,200 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "DEG_depsgraph_query.hh"
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_mesh.hh"
|
||||
#include "BKE_mesh_runtime.hh"
|
||||
#include "BKE_mesh_wrapper.hh"
|
||||
#include "BKE_object.hh"
|
||||
#include "BKE_volume.hh"
|
||||
|
||||
#include "GEO_mesh_to_volume.hh"
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
|
||||
#include "NOD_socket_search_link.hh"
|
||||
|
||||
#include "NOD_rna_define.hh"
|
||||
|
||||
#include "UI_interface.hh"
|
||||
#include "UI_resources.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_mesh_to_sdf_volume_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>("Voxel Size")
|
||||
.default_value(0.3f)
|
||||
.min(0.01f)
|
||||
.max(FLT_MAX)
|
||||
.subtype(PROP_DISTANCE);
|
||||
b.add_input<decl::Float>("Voxel Amount").default_value(64.0f).min(0.0f).max(FLT_MAX);
|
||||
b.add_input<decl::Float>("Half-Band Width")
|
||||
.default_value(3.0f)
|
||||
.min(1.01f)
|
||||
.max(10.0f)
|
||||
.description("Half the width of the narrow band in voxel units");
|
||||
b.add_output<decl::Geometry>("Volume").translation_context(BLT_I18NCONTEXT_ID_ID);
|
||||
}
|
||||
|
||||
static void search_link_ops(GatherLinkSearchOpParams ¶ms)
|
||||
{
|
||||
if (U.experimental.use_new_volume_nodes) {
|
||||
nodes::search_link_ops_for_basic_node(params);
|
||||
}
|
||||
}
|
||||
|
||||
static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
|
||||
{
|
||||
uiLayoutSetPropSep(layout, true);
|
||||
uiLayoutSetPropDecorate(layout, false);
|
||||
uiItemR(layout, ptr, "resolution_mode", UI_ITEM_NONE, IFACE_("Resolution"), ICON_NONE);
|
||||
}
|
||||
|
||||
static void node_init(bNodeTree * /*tree*/, bNode *node)
|
||||
{
|
||||
NodeGeometryMeshToVolume *data = MEM_cnew<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 = node_storage(*node);
|
||||
|
||||
bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size");
|
||||
bNodeSocket *voxel_amount_socket = nodeFindSocket(node, SOCK_IN, "Voxel Amount");
|
||||
bke::nodeSetSocketAvailability(ntree,
|
||||
voxel_amount_socket,
|
||||
data.resolution_mode ==
|
||||
MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT);
|
||||
bke::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 = node_storage(params.node());
|
||||
|
||||
const float half_band_width = params.get_input<float>("Half-Band Width");
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (mesh.faces_num == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const float4x4 mesh_to_volume_space_transform = float4x4::identity();
|
||||
|
||||
const float voxel_size = geometry::volume_compute_voxel_size(
|
||||
params.depsgraph(),
|
||||
[&]() { return *mesh.bounds_min_max(); },
|
||||
resolution,
|
||||
half_band_width,
|
||||
mesh_to_volume_space_transform);
|
||||
|
||||
if (voxel_size < 1e-5f) {
|
||||
/* The voxel size is too small. */
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Volume *volume = reinterpret_cast<Volume *>(BKE_id_new_nomain(ID_VO, nullptr));
|
||||
|
||||
/* Convert mesh to grid and add to volume. */
|
||||
geometry::sdf_volume_grid_add_from_mesh(volume, "distance", mesh, voxel_size, half_band_width);
|
||||
|
||||
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(), params);
|
||||
geometry_set.replace_volume(volume);
|
||||
geometry_set.keep_only_during_modify({GeometryComponent::Type::Volume});
|
||||
}
|
||||
});
|
||||
params.set_output("Volume", std::move(geometry_set));
|
||||
#else
|
||||
params.set_default_remaining_outputs();
|
||||
params.error_message_add(NodeWarningType::Error,
|
||||
TIP_("Disabled, Blender was compiled without OpenVDB"));
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void node_rna(StructRNA *srna)
|
||||
{
|
||||
static EnumPropertyItem resolution_mode_items[] = {
|
||||
{MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT,
|
||||
"VOXEL_AMOUNT",
|
||||
0,
|
||||
"Amount",
|
||||
"Desired number of voxels along one axis"},
|
||||
{MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE,
|
||||
"VOXEL_SIZE",
|
||||
0,
|
||||
"Size",
|
||||
"Desired voxel side length"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
RNA_def_node_enum(srna,
|
||||
"resolution_mode",
|
||||
"Resolution Mode",
|
||||
"How the voxel size is specified",
|
||||
resolution_mode_items,
|
||||
NOD_storage_enum_accessors(resolution_mode),
|
||||
MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT);
|
||||
}
|
||||
|
||||
static void node_register()
|
||||
{
|
||||
static bNodeType ntype;
|
||||
|
||||
geo_node_type_base(
|
||||
&ntype, GEO_NODE_MESH_TO_SDF_VOLUME, "Mesh to SDF Volume", NODE_CLASS_GEOMETRY);
|
||||
ntype.declare = node_declare;
|
||||
blender::bke::node_type_size(&ntype, 180, 120, 300);
|
||||
ntype.initfunc = node_init;
|
||||
ntype.updatefunc = node_update;
|
||||
ntype.geometry_node_execute = node_geo_exec;
|
||||
ntype.draw_buttons = node_layout;
|
||||
ntype.gather_link_search_ops = search_link_ops;
|
||||
node_type_storage(
|
||||
&ntype, "NodeGeometryMeshToVolume", node_free_standard_storage, node_copy_standard_storage);
|
||||
nodeRegisterType(&ntype);
|
||||
|
||||
node_rna(ntype.rna_ext.srna);
|
||||
}
|
||||
NOD_REGISTER_NODE(node_register)
|
||||
|
||||
} // namespace blender::nodes::node_geo_mesh_to_sdf_volume_cc
|
@ -1,94 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "DEG_depsgraph_query.hh"
|
||||
#ifdef WITH_OPENVDB
|
||||
# include <openvdb/tools/LevelSetFilter.h>
|
||||
#endif
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
#include "BKE_volume.hh"
|
||||
#include "BKE_volume_openvdb.hh"
|
||||
|
||||
#include "DNA_node_types.h"
|
||||
|
||||
#include "NOD_socket_search_link.hh"
|
||||
|
||||
#include "UI_interface.hh"
|
||||
#include "UI_resources.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_offset_sdf_volume_cc {
|
||||
|
||||
static void node_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
b.add_input<decl::Geometry>("Volume")
|
||||
.supported_type(GeometryComponent::Type::Volume)
|
||||
.translation_context(BLT_I18NCONTEXT_ID_ID);
|
||||
b.add_input<decl::Float>("Distance").default_value(0.1f).subtype(PROP_DISTANCE);
|
||||
b.add_output<decl::Geometry>("Volume").translation_context(BLT_I18NCONTEXT_ID_ID);
|
||||
}
|
||||
|
||||
static void search_link_ops(GatherLinkSearchOpParams ¶ms)
|
||||
{
|
||||
if (U.experimental.use_new_volume_nodes) {
|
||||
nodes::search_link_ops_for_basic_node(params);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WITH_OPENVDB
|
||||
static void sdf_volume_offset(Volume &volume, const GeoNodeExecParams ¶ms)
|
||||
{
|
||||
VolumeGrid *volume_grid = BKE_volume_grid_find_for_write(&volume, "distance");
|
||||
if (volume_grid == nullptr) {
|
||||
return;
|
||||
}
|
||||
openvdb::GridBase::Ptr base_grid = BKE_volume_grid_openvdb_for_write(
|
||||
&volume, volume_grid, false);
|
||||
|
||||
if (!base_grid->isType<openvdb::FloatGrid>()) {
|
||||
return;
|
||||
}
|
||||
openvdb::FloatGrid::Ptr levelset_grid = openvdb::gridPtrCast<openvdb::FloatGrid>(base_grid);
|
||||
openvdb::tools::LevelSetFilter<openvdb::FloatGrid> filter(*levelset_grid);
|
||||
|
||||
filter.offset(-params.get_input<float>("Distance"));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void node_geo_exec(GeoNodeExecParams params)
|
||||
{
|
||||
#ifdef WITH_OPENVDB
|
||||
GeometrySet geometry_set = params.extract_input<GeometrySet>("Volume");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
if (!geometry_set.has_volume()) {
|
||||
return;
|
||||
}
|
||||
VolumeComponent &component = geometry_set.get_component_for_write<VolumeComponent>();
|
||||
Volume *volume = component.get_for_write();
|
||||
BKE_volume_load(volume, DEG_get_bmain(params.depsgraph()));
|
||||
sdf_volume_offset(*volume, params);
|
||||
});
|
||||
params.set_output("Volume", std::move(geometry_set));
|
||||
#else
|
||||
params.set_default_remaining_outputs();
|
||||
params.error_message_add(NodeWarningType::Error,
|
||||
TIP_("Disabled, Blender was compiled without OpenVDB"));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void node_register()
|
||||
{
|
||||
static bNodeType ntype;
|
||||
|
||||
geo_node_type_base(&ntype, GEO_NODE_OFFSET_SDF_VOLUME, "Offset SDF Volume", NODE_CLASS_GEOMETRY);
|
||||
ntype.declare = node_declare;
|
||||
ntype.geometry_node_execute = node_geo_exec;
|
||||
ntype.gather_link_search_ops = search_link_ops;
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
NOD_REGISTER_NODE(node_register)
|
||||
|
||||
} // namespace blender::nodes::node_geo_offset_sdf_volume_cc
|
@ -1,149 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#ifdef WITH_OPENVDB
|
||||
# include <openvdb/Types.h>
|
||||
#endif
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
#include "GEO_points_to_volume.hh"
|
||||
|
||||
#include "NOD_socket_search_link.hh"
|
||||
|
||||
#include "NOD_rna_define.hh"
|
||||
|
||||
#include "UI_interface.hh"
|
||||
#include "UI_resources.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_points_to_sdf_volume_cc {
|
||||
|
||||
NODE_STORAGE_FUNCS(NodeGeometryPointsToVolume)
|
||||
|
||||
static void node_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
b.add_input<decl::Geometry>("Points");
|
||||
b.add_input<decl::Float>("Voxel Size")
|
||||
.default_value(0.3f)
|
||||
.min(0.01f)
|
||||
.subtype(PROP_DISTANCE)
|
||||
.make_available([](bNode &node) {
|
||||
node_storage(node).resolution_mode = GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE;
|
||||
});
|
||||
b.add_input<decl::Float>("Voxel Amount")
|
||||
.default_value(64.0f)
|
||||
.min(0.0f)
|
||||
.make_available([](bNode &node) {
|
||||
node_storage(node).resolution_mode = GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT;
|
||||
});
|
||||
b.add_input<decl::Float>("Radius")
|
||||
.default_value(0.5f)
|
||||
.min(0.0f)
|
||||
.subtype(PROP_DISTANCE)
|
||||
.field_on_all();
|
||||
b.add_output<decl::Geometry>("Volume").translation_context(BLT_I18NCONTEXT_ID_ID);
|
||||
}
|
||||
|
||||
static void search_link_ops(GatherLinkSearchOpParams ¶ms)
|
||||
{
|
||||
if (U.experimental.use_new_volume_nodes) {
|
||||
nodes::search_link_ops_for_basic_node(params);
|
||||
}
|
||||
}
|
||||
|
||||
static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
|
||||
{
|
||||
uiLayoutSetPropSep(layout, true);
|
||||
uiLayoutSetPropDecorate(layout, false);
|
||||
uiItemR(layout, ptr, "resolution_mode", UI_ITEM_NONE, IFACE_("Resolution"), ICON_NONE);
|
||||
}
|
||||
|
||||
static void node_init(bNodeTree * /*tree*/, bNode *node)
|
||||
{
|
||||
NodeGeometryPointsToVolume *data = MEM_cnew<NodeGeometryPointsToVolume>(__func__);
|
||||
data->resolution_mode = GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT;
|
||||
node->storage = data;
|
||||
}
|
||||
|
||||
static void node_update(bNodeTree *ntree, bNode *node)
|
||||
{
|
||||
const NodeGeometryPointsToVolume &storage = node_storage(*node);
|
||||
bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size");
|
||||
bNodeSocket *voxel_amount_socket = nodeFindSocket(node, SOCK_IN, "Voxel Amount");
|
||||
bke::nodeSetSocketAvailability(ntree,
|
||||
voxel_amount_socket,
|
||||
storage.resolution_mode ==
|
||||
GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT);
|
||||
bke::nodeSetSocketAvailability(ntree,
|
||||
voxel_size_socket,
|
||||
storage.resolution_mode ==
|
||||
GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE);
|
||||
}
|
||||
|
||||
static void node_geo_exec(GeoNodeExecParams params)
|
||||
{
|
||||
#ifdef WITH_OPENVDB
|
||||
GeometrySet geometry_set = params.extract_input<GeometrySet>("Points");
|
||||
const NodeGeometryPointsToVolume &storage = node_storage(params.node());
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
initialize_volume_component_from_points(
|
||||
params, storage, geometry_set, openvdb::GRID_LEVEL_SET);
|
||||
});
|
||||
params.set_output("Volume", std::move(geometry_set));
|
||||
#else
|
||||
params.set_default_remaining_outputs();
|
||||
params.error_message_add(NodeWarningType::Error,
|
||||
TIP_("Disabled, Blender was compiled without OpenVDB"));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void node_rna(StructRNA *srna)
|
||||
{
|
||||
static EnumPropertyItem resolution_mode_items[] = {
|
||||
{GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT,
|
||||
"VOXEL_AMOUNT",
|
||||
0,
|
||||
"Amount",
|
||||
"Specify the approximate number of voxels along the diagonal"},
|
||||
{GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE,
|
||||
"VOXEL_SIZE",
|
||||
0,
|
||||
"Size",
|
||||
"Specify the voxel side length"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
RNA_def_node_enum(srna,
|
||||
"resolution_mode",
|
||||
"Resolution Mode",
|
||||
"How the voxel size is specified",
|
||||
resolution_mode_items,
|
||||
NOD_storage_enum_accessors(resolution_mode),
|
||||
GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT);
|
||||
}
|
||||
|
||||
static void node_register()
|
||||
{
|
||||
static bNodeType ntype;
|
||||
|
||||
geo_node_type_base(
|
||||
&ntype, GEO_NODE_POINTS_TO_SDF_VOLUME, "Points to SDF Volume", NODE_CLASS_GEOMETRY);
|
||||
node_type_storage(&ntype,
|
||||
"NodeGeometryPointsToVolume",
|
||||
node_free_standard_storage,
|
||||
node_copy_standard_storage);
|
||||
bke::node_type_size(&ntype, 170, 120, 700);
|
||||
ntype.initfunc = node_init;
|
||||
ntype.updatefunc = node_update;
|
||||
ntype.declare = node_declare;
|
||||
ntype.geometry_node_execute = node_geo_exec;
|
||||
ntype.draw_buttons = node_layout;
|
||||
ntype.gather_link_search_ops = search_link_ops;
|
||||
nodeRegisterType(&ntype);
|
||||
|
||||
node_rna(ntype.rna_ext.srna);
|
||||
}
|
||||
NOD_REGISTER_NODE(node_register)
|
||||
|
||||
} // namespace blender::nodes::node_geo_points_to_sdf_volume_cc
|
@ -1,431 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "DEG_depsgraph_query.hh"
|
||||
|
||||
#include "BKE_type_conversions.hh"
|
||||
#include "BKE_volume.hh"
|
||||
#include "BKE_volume_openvdb.hh"
|
||||
|
||||
#include "BLI_virtual_array.hh"
|
||||
|
||||
#include "NOD_socket_search_link.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
#include "NOD_rna_define.hh"
|
||||
|
||||
#include "UI_interface.hh"
|
||||
#include "UI_resources.hh"
|
||||
|
||||
#ifdef WITH_OPENVDB
|
||||
# include <openvdb/openvdb.h>
|
||||
# include <openvdb/tools/Interpolation.h>
|
||||
#endif
|
||||
|
||||
namespace blender::nodes::node_geo_sample_volume_cc {
|
||||
|
||||
NODE_STORAGE_FUNCS(NodeGeometrySampleVolume)
|
||||
|
||||
static void node_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
b.add_input<decl::Geometry>(CTX_N_(BLT_I18NCONTEXT_ID_ID, "Volume"))
|
||||
.supported_type(GeometryComponent::Type::Volume)
|
||||
.translation_context(BLT_I18NCONTEXT_ID_ID);
|
||||
|
||||
std::string grid_socket_description = N_(
|
||||
"Expects a Named Attribute with the name of a Grid in the Volume");
|
||||
|
||||
b.add_input<decl::Vector>("Grid", "Grid_Vector")
|
||||
.field_on_all()
|
||||
.hide_value()
|
||||
.description(grid_socket_description);
|
||||
b.add_input<decl::Float>("Grid", "Grid_Float")
|
||||
.field_on_all()
|
||||
.hide_value()
|
||||
.description(grid_socket_description);
|
||||
b.add_input<decl::Bool>("Grid", "Grid_Bool")
|
||||
.field_on_all()
|
||||
.hide_value()
|
||||
.description(grid_socket_description);
|
||||
b.add_input<decl::Int>("Grid", "Grid_Int")
|
||||
.field_on_all()
|
||||
.hide_value()
|
||||
.description(grid_socket_description);
|
||||
|
||||
b.add_input<decl::Vector>("Position").implicit_field(implicit_field_inputs::position);
|
||||
|
||||
b.add_output<decl::Vector>("Value", "Value_Vector").dependent_field({5});
|
||||
b.add_output<decl::Float>("Value", "Value_Float").dependent_field({5});
|
||||
b.add_output<decl::Bool>("Value", "Value_Bool").dependent_field({5});
|
||||
b.add_output<decl::Int>("Value", "Value_Int").dependent_field({5});
|
||||
}
|
||||
|
||||
static std::optional<eCustomDataType> other_socket_type_to_grid_type(
|
||||
const eNodeSocketDatatype type)
|
||||
{
|
||||
switch (type) {
|
||||
case SOCK_FLOAT:
|
||||
return CD_PROP_FLOAT;
|
||||
case SOCK_VECTOR:
|
||||
case SOCK_RGBA:
|
||||
return CD_PROP_FLOAT3;
|
||||
case SOCK_BOOLEAN:
|
||||
return CD_PROP_BOOL;
|
||||
case SOCK_INT:
|
||||
return CD_PROP_INT32;
|
||||
default:
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
static void search_link_ops(GatherLinkSearchOpParams ¶ms)
|
||||
{
|
||||
if (!U.experimental.use_new_volume_nodes) {
|
||||
return;
|
||||
}
|
||||
const NodeDeclaration &declaration = *params.node_type().static_declaration;
|
||||
search_link_ops_for_declarations(params, declaration.inputs.as_span().take_back(1));
|
||||
search_link_ops_for_declarations(params, declaration.inputs.as_span().take_front(1));
|
||||
|
||||
const std::optional<eCustomDataType> type = other_socket_type_to_grid_type(
|
||||
eNodeSocketDatatype(params.other_socket().type));
|
||||
if (!type) {
|
||||
return;
|
||||
}
|
||||
/* The input and output sockets have the same name. */
|
||||
params.add_item(IFACE_("Grid"), [type](LinkSearchOpParams ¶ms) {
|
||||
bNode &node = params.add_node("GeometryNodeSampleVolume");
|
||||
node_storage(node).grid_type = *type;
|
||||
params.update_and_connect_available_socket(node, "Grid");
|
||||
});
|
||||
}
|
||||
|
||||
static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
|
||||
{
|
||||
uiLayoutSetPropSep(layout, true);
|
||||
uiLayoutSetPropDecorate(layout, false);
|
||||
uiItemR(layout, ptr, "grid_type", UI_ITEM_NONE, "", ICON_NONE);
|
||||
uiItemR(layout, ptr, "interpolation_mode", UI_ITEM_NONE, "", ICON_NONE);
|
||||
}
|
||||
|
||||
static void node_init(bNodeTree * /*tree*/, bNode *node)
|
||||
{
|
||||
NodeGeometrySampleVolume *data = MEM_cnew<NodeGeometrySampleVolume>(__func__);
|
||||
data->grid_type = CD_PROP_FLOAT;
|
||||
data->interpolation_mode = GEO_NODE_SAMPLE_VOLUME_INTERPOLATION_MODE_TRILINEAR;
|
||||
node->storage = data;
|
||||
}
|
||||
|
||||
static void node_update(bNodeTree *ntree, bNode *node)
|
||||
{
|
||||
const NodeGeometrySampleVolume &storage = node_storage(*node);
|
||||
const eCustomDataType grid_type = eCustomDataType(storage.grid_type);
|
||||
|
||||
bNodeSocket *socket_value_geometry = static_cast<bNodeSocket *>(node->inputs.first);
|
||||
bNodeSocket *socket_value_vector = socket_value_geometry->next;
|
||||
bNodeSocket *socket_value_float = socket_value_vector->next;
|
||||
bNodeSocket *socket_value_boolean = socket_value_float->next;
|
||||
bNodeSocket *socket_value_int32 = socket_value_boolean->next;
|
||||
|
||||
bke::nodeSetSocketAvailability(ntree, socket_value_vector, grid_type == CD_PROP_FLOAT3);
|
||||
bke::nodeSetSocketAvailability(ntree, socket_value_float, grid_type == CD_PROP_FLOAT);
|
||||
bke::nodeSetSocketAvailability(ntree, socket_value_boolean, grid_type == CD_PROP_BOOL);
|
||||
bke::nodeSetSocketAvailability(ntree, socket_value_int32, grid_type == CD_PROP_INT32);
|
||||
|
||||
bNodeSocket *out_socket_value_vector = static_cast<bNodeSocket *>(node->outputs.first);
|
||||
bNodeSocket *out_socket_value_float = out_socket_value_vector->next;
|
||||
bNodeSocket *out_socket_value_boolean = out_socket_value_float->next;
|
||||
bNodeSocket *out_socket_value_int32 = out_socket_value_boolean->next;
|
||||
|
||||
bke::nodeSetSocketAvailability(ntree, out_socket_value_vector, grid_type == CD_PROP_FLOAT3);
|
||||
bke::nodeSetSocketAvailability(ntree, out_socket_value_float, grid_type == CD_PROP_FLOAT);
|
||||
bke::nodeSetSocketAvailability(ntree, out_socket_value_boolean, grid_type == CD_PROP_BOOL);
|
||||
bke::nodeSetSocketAvailability(ntree, out_socket_value_int32, grid_type == CD_PROP_INT32);
|
||||
}
|
||||
|
||||
#ifdef WITH_OPENVDB
|
||||
|
||||
static const StringRefNull get_grid_name(GField &field)
|
||||
{
|
||||
if (const auto *attribute_field_input = dynamic_cast<const AttributeFieldInput *>(&field.node()))
|
||||
{
|
||||
return attribute_field_input->attribute_name();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static const blender::CPPType *vdb_grid_type_to_cpp_type(const VolumeGridType grid_type)
|
||||
{
|
||||
switch (grid_type) {
|
||||
case VOLUME_GRID_FLOAT:
|
||||
return &CPPType::get<float>();
|
||||
case VOLUME_GRID_VECTOR_FLOAT:
|
||||
return &CPPType::get<float3>();
|
||||
case VOLUME_GRID_INT:
|
||||
return &CPPType::get<int>();
|
||||
case VOLUME_GRID_BOOLEAN:
|
||||
return &CPPType::get<bool>();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename GridT>
|
||||
void sample_grid(openvdb::GridBase::ConstPtr base_grid,
|
||||
const Span<float3> positions,
|
||||
const IndexMask &mask,
|
||||
GMutableSpan dst,
|
||||
const GeometryNodeSampleVolumeInterpolationMode interpolation_mode)
|
||||
{
|
||||
using ValueT = typename GridT::ValueType;
|
||||
using AccessorT = typename GridT::ConstAccessor;
|
||||
const typename GridT::ConstPtr grid = openvdb::gridConstPtrCast<GridT>(base_grid);
|
||||
AccessorT accessor = grid->getConstAccessor();
|
||||
|
||||
auto sample_data = [&](auto sampler) {
|
||||
mask.foreach_index([&](const int64_t i) {
|
||||
const float3 &pos = positions[i];
|
||||
ValueT value = sampler.wsSample(openvdb::Vec3R(pos.x, pos.y, pos.z));
|
||||
|
||||
/* Special case for vector. */
|
||||
if constexpr (std::is_same_v<GridT, openvdb::VectorGrid>) {
|
||||
openvdb::Vec3f vec = static_cast<openvdb::Vec3f>(value);
|
||||
dst.typed<float3>()[i] = float3(vec.asV());
|
||||
}
|
||||
else {
|
||||
dst.typed<ValueT>()[i] = value;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
switch (interpolation_mode) {
|
||||
case GEO_NODE_SAMPLE_VOLUME_INTERPOLATION_MODE_TRILINEAR: {
|
||||
openvdb::tools::GridSampler<AccessorT, openvdb::tools::BoxSampler> sampler(
|
||||
accessor, grid->transform());
|
||||
sample_data(sampler);
|
||||
break;
|
||||
}
|
||||
case GEO_NODE_SAMPLE_VOLUME_INTERPOLATION_MODE_TRIQUADRATIC: {
|
||||
openvdb::tools::GridSampler<AccessorT, openvdb::tools::QuadraticSampler> sampler(
|
||||
accessor, grid->transform());
|
||||
sample_data(sampler);
|
||||
break;
|
||||
}
|
||||
case GEO_NODE_SAMPLE_VOLUME_INTERPOLATION_MODE_NEAREST:
|
||||
default: {
|
||||
openvdb::tools::GridSampler<AccessorT, openvdb::tools::PointSampler> sampler(
|
||||
accessor, grid->transform());
|
||||
sample_data(sampler);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SampleVolumeFunction : public mf::MultiFunction {
|
||||
openvdb::GridBase::ConstPtr base_grid_;
|
||||
VolumeGridType grid_type_;
|
||||
GeometryNodeSampleVolumeInterpolationMode interpolation_mode_;
|
||||
mf::Signature signature_;
|
||||
|
||||
public:
|
||||
SampleVolumeFunction(openvdb::GridBase::ConstPtr base_grid,
|
||||
GeometryNodeSampleVolumeInterpolationMode interpolation_mode)
|
||||
: base_grid_(std::move(base_grid)), interpolation_mode_(interpolation_mode)
|
||||
{
|
||||
grid_type_ = BKE_volume_grid_type_openvdb(*base_grid_);
|
||||
const CPPType *grid_cpp_type = vdb_grid_type_to_cpp_type(grid_type_);
|
||||
BLI_assert(grid_cpp_type != nullptr);
|
||||
mf::SignatureBuilder builder{"Sample Volume", signature_};
|
||||
builder.single_input<float3>("Position");
|
||||
builder.single_output("Value", *grid_cpp_type);
|
||||
this->set_signature(&signature_);
|
||||
}
|
||||
|
||||
void call(const IndexMask &mask, mf::Params params, mf::Context /*context*/) const override
|
||||
{
|
||||
const VArraySpan<float3> positions = params.readonly_single_input<float3>(0, "Position");
|
||||
GMutableSpan dst = params.uninitialized_single_output(1, "Value");
|
||||
|
||||
switch (grid_type_) {
|
||||
case VOLUME_GRID_FLOAT:
|
||||
sample_grid<openvdb::FloatGrid>(base_grid_, positions, mask, dst, interpolation_mode_);
|
||||
break;
|
||||
case VOLUME_GRID_INT:
|
||||
sample_grid<openvdb::Int32Grid>(base_grid_, positions, mask, dst, interpolation_mode_);
|
||||
break;
|
||||
case VOLUME_GRID_BOOLEAN:
|
||||
sample_grid<openvdb::BoolGrid>(base_grid_, positions, mask, dst, interpolation_mode_);
|
||||
break;
|
||||
case VOLUME_GRID_VECTOR_FLOAT:
|
||||
sample_grid<openvdb::VectorGrid>(base_grid_, positions, mask, dst, interpolation_mode_);
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static GField get_input_attribute_field(GeoNodeExecParams ¶ms, const eCustomDataType data_type)
|
||||
{
|
||||
switch (data_type) {
|
||||
case CD_PROP_FLOAT:
|
||||
return params.extract_input<Field<float>>("Grid_Float");
|
||||
case CD_PROP_FLOAT3:
|
||||
return params.extract_input<Field<float3>>("Grid_Vector");
|
||||
case CD_PROP_BOOL:
|
||||
return params.extract_input<Field<bool>>("Grid_Bool");
|
||||
case CD_PROP_INT32:
|
||||
return params.extract_input<Field<int>>("Grid_Int");
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
static void output_attribute_field(GeoNodeExecParams ¶ms, GField field)
|
||||
{
|
||||
switch (bke::cpp_type_to_custom_data_type(field.cpp_type())) {
|
||||
case CD_PROP_FLOAT:
|
||||
params.set_output("Value_Float", Field<float>(field));
|
||||
break;
|
||||
case CD_PROP_FLOAT3:
|
||||
params.set_output("Value_Vector", Field<float3>(field));
|
||||
break;
|
||||
case CD_PROP_BOOL:
|
||||
params.set_output("Value_Bool", Field<bool>(field));
|
||||
break;
|
||||
case CD_PROP_INT32:
|
||||
params.set_output("Value_Int", Field<int>(field));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* WITH_OPENVDB */
|
||||
|
||||
static void node_geo_exec(GeoNodeExecParams params)
|
||||
{
|
||||
#ifdef WITH_OPENVDB
|
||||
GeometrySet geometry_set = params.extract_input<GeometrySet>("Volume");
|
||||
if (!geometry_set.has_volume()) {
|
||||
params.set_default_remaining_outputs();
|
||||
return;
|
||||
}
|
||||
const NodeGeometrySampleVolume &storage = node_storage(params.node());
|
||||
const eCustomDataType output_field_type = eCustomDataType(storage.grid_type);
|
||||
auto interpolation_mode = GeometryNodeSampleVolumeInterpolationMode(storage.interpolation_mode);
|
||||
|
||||
GField grid_field = get_input_attribute_field(params, output_field_type);
|
||||
const StringRefNull grid_name = get_grid_name(grid_field);
|
||||
if (grid_name == "") {
|
||||
params.error_message_add(NodeWarningType::Error, TIP_("Grid name needs to be specified"));
|
||||
params.set_default_remaining_outputs();
|
||||
return;
|
||||
}
|
||||
|
||||
const VolumeComponent *component = geometry_set.get_component<VolumeComponent>();
|
||||
const Volume *volume = component->get();
|
||||
BKE_volume_load(volume, DEG_get_bmain(params.depsgraph()));
|
||||
const VolumeGrid *volume_grid = BKE_volume_grid_find_for_read(volume, grid_name.c_str());
|
||||
if (volume_grid == nullptr) {
|
||||
params.set_default_remaining_outputs();
|
||||
return;
|
||||
}
|
||||
openvdb::GridBase::ConstPtr base_grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid);
|
||||
const VolumeGridType grid_type = BKE_volume_grid_type_openvdb(*base_grid);
|
||||
|
||||
/* Check that the grid type is supported. */
|
||||
const CPPType *grid_cpp_type = vdb_grid_type_to_cpp_type(grid_type);
|
||||
if (grid_cpp_type == nullptr) {
|
||||
params.set_default_remaining_outputs();
|
||||
params.error_message_add(NodeWarningType::Error, TIP_("The grid type is unsupported"));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Use to the Nearest Neighbor sampler for Bool grids (no interpolation). */
|
||||
if (grid_type == VOLUME_GRID_BOOLEAN &&
|
||||
interpolation_mode != GEO_NODE_SAMPLE_VOLUME_INTERPOLATION_MODE_NEAREST)
|
||||
{
|
||||
interpolation_mode = GEO_NODE_SAMPLE_VOLUME_INTERPOLATION_MODE_NEAREST;
|
||||
}
|
||||
|
||||
Field<float3> position_field = params.extract_input<Field<float3>>("Position");
|
||||
auto fn = std::make_shared<SampleVolumeFunction>(std::move(base_grid), interpolation_mode);
|
||||
auto op = FieldOperation::Create(std::move(fn), {position_field});
|
||||
GField output_field = GField(std::move(op));
|
||||
|
||||
output_field = bke::get_implicit_type_conversions().try_convert(
|
||||
output_field, *bke::custom_data_type_to_cpp_type(output_field_type));
|
||||
|
||||
output_attribute_field(params, std::move(output_field));
|
||||
#else
|
||||
params.set_default_remaining_outputs();
|
||||
params.error_message_add(NodeWarningType::Error,
|
||||
TIP_("Disabled, Blender was compiled without OpenVDB"));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void node_rna(StructRNA *srna)
|
||||
{
|
||||
static const EnumPropertyItem interpolation_mode_items[] = {
|
||||
{GEO_NODE_SAMPLE_VOLUME_INTERPOLATION_MODE_NEAREST, "NEAREST", 0, "Nearest Neighbor", ""},
|
||||
{GEO_NODE_SAMPLE_VOLUME_INTERPOLATION_MODE_TRILINEAR, "TRILINEAR", 0, "Trilinear", ""},
|
||||
{GEO_NODE_SAMPLE_VOLUME_INTERPOLATION_MODE_TRIQUADRATIC,
|
||||
"TRIQUADRATIC",
|
||||
0,
|
||||
"Triquadratic",
|
||||
""},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
static const EnumPropertyItem grid_type_items[] = {
|
||||
{CD_PROP_FLOAT, "FLOAT", 0, "Float", "Floating-point value"},
|
||||
{CD_PROP_FLOAT3, "FLOAT_VECTOR", 0, "Vector", "3D vector with floating-point values"},
|
||||
{CD_PROP_INT32, "INT", 0, "Integer", "32-bit integer"},
|
||||
{CD_PROP_BOOL, "BOOLEAN", 0, "Boolean", "True or false"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
RNA_def_node_enum(srna,
|
||||
"grid_type",
|
||||
"Grid Type",
|
||||
"Type of grid to sample data from",
|
||||
grid_type_items,
|
||||
NOD_storage_enum_accessors(grid_type),
|
||||
CD_PROP_FLOAT);
|
||||
|
||||
RNA_def_node_enum(srna,
|
||||
"interpolation_mode",
|
||||
"Interpolation Mode",
|
||||
"How to interpolate the values from neighboring voxels",
|
||||
interpolation_mode_items,
|
||||
NOD_storage_enum_accessors(interpolation_mode),
|
||||
GEO_NODE_SAMPLE_VOLUME_INTERPOLATION_MODE_TRILINEAR);
|
||||
}
|
||||
|
||||
static void node_register()
|
||||
{
|
||||
static bNodeType ntype;
|
||||
|
||||
geo_node_type_base(&ntype, GEO_NODE_SAMPLE_VOLUME, "Sample Volume", NODE_CLASS_CONVERTER);
|
||||
node_type_storage(
|
||||
&ntype, "NodeGeometrySampleVolume", node_free_standard_storage, node_copy_standard_storage);
|
||||
ntype.initfunc = node_init;
|
||||
ntype.updatefunc = node_update;
|
||||
ntype.declare = node_declare;
|
||||
ntype.geometry_node_execute = node_geo_exec;
|
||||
ntype.draw_buttons = node_layout;
|
||||
ntype.gather_link_search_ops = search_link_ops;
|
||||
ntype.geometry_node_execute = node_geo_exec;
|
||||
nodeRegisterType(&ntype);
|
||||