mirror of
https://github.com/blender/blender
synced 2026-09-29 04:37:17 +03:00
Geometry Nodes: Implement Import SPZ node
A straightforward node that accepts file path to an SPZ file and outputs point cloud of type 3D Gaussian Splats. The node performs conversion from the SPZ coordinate convention to Blender coordinate convention. Note that this convention is not always followed by all assets on the Internet. The unfortunate part is that it is not trivial to convert the coordinate systems as the spherical harmonics attribute requires special handling. For the efficiency extra parameters might need to be added to the node. Or, alternatively, spherical harmonics need to become a native attribute type, so that we can have transform nodes applied on them. Ref #159470
This commit is contained in:
parent
330ef38ef3
commit
1be8f41103
6 changed files with 117 additions and 1 deletions
|
|
@ -595,6 +595,7 @@ class NODE_MT_gn_input_import_base(node_add_menu.NodeMenu):
|
|||
self.node_operator(layout, "GeometryNodeImportCSV", label="CSV (.csv)")
|
||||
self.node_operator(layout, "GeometryNodeImportOBJ", label="Wavefront (.obj)")
|
||||
self.node_operator(layout, "GeometryNodeImportPLY", label="Stanford PLY (.ply)")
|
||||
self.node_operator(layout, "GeometryNodeImportSPZ", label="SPZ (.spz)")
|
||||
self.node_operator(layout, "GeometryNodeImportSTL", label="STL (.stl)")
|
||||
self.node_operator(layout, "GeometryNodeImportText", label="Text (.txt)")
|
||||
self.node_operator(layout, "GeometryNodeImportVDB", label="OpenVDB (.vdb)")
|
||||
|
|
|
|||
|
|
@ -1252,6 +1252,9 @@ static wmOperatorStatus node_add_import_node_exec(bContext *C, wmOperator *op)
|
|||
else if (is_geometry_tree && path.endswith(".ply")) {
|
||||
node = add_node(*C, "GeometryNodeImportPLY"_ustr, snode->runtime->cursor);
|
||||
}
|
||||
else if (is_geometry_tree && path.endswith(".spz")) {
|
||||
node = add_node(*C, "GeometryNodeImportSPZ"_ustr, snode->runtime->cursor);
|
||||
}
|
||||
else if (is_geometry_tree && path.endswith(".stl")) {
|
||||
node = add_node(*C, "GeometryNodeImportSTL"_ustr, snode->runtime->cursor);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1117,7 +1117,7 @@ static bool node_import_file_drop_poll(bContext *C, wmDrag *drag, const wmEvent
|
|||
}
|
||||
if (is_geometry_tree &&
|
||||
(path.endswith(".csv") || path.endswith(".obj") || path.endswith(".ply") ||
|
||||
path.endswith(".stl") || path.endswith(".vdb")))
|
||||
path.endswith(".stl") || path.endswith(".vdb") || path.endswith(".spz")))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11151,6 +11151,7 @@ static void rna_def_nodes(BlenderRNA *brna)
|
|||
define("GeometryNode", "GeometryNodeImportCSV");
|
||||
define("GeometryNode", "GeometryNodeImportOBJ");
|
||||
define("GeometryNode", "GeometryNodeImportPLY");
|
||||
define("GeometryNode", "GeometryNodeImportSPZ");
|
||||
define("GeometryNode", "GeometryNodeImportSTL");
|
||||
define("GeometryNode", "GeometryNodeImportText");
|
||||
define("GeometryNode", "GeometryNodeImportVDB");
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ set(INC
|
|||
../../io/common
|
||||
../../io/csv
|
||||
../../io/ply
|
||||
../../io/spz
|
||||
../../io/stl
|
||||
../../io/wavefront_obj
|
||||
# RNA_prototypes.hh
|
||||
|
|
@ -138,6 +139,7 @@ set(SRC
|
|||
nodes/node_geo_image_texture.cc
|
||||
nodes/node_geo_import_csv.cc
|
||||
nodes/node_geo_import_obj.cc
|
||||
nodes/node_geo_import_spz.cc
|
||||
nodes/node_geo_import_ply.cc
|
||||
nodes/node_geo_import_stl.cc
|
||||
nodes/node_geo_import_text.cc
|
||||
|
|
@ -360,6 +362,14 @@ set(LIB
|
|||
PRIVATE bf::dependencies::optional::bullet
|
||||
)
|
||||
|
||||
if(WITH_IO_SPZ)
|
||||
list(APPEND LIB
|
||||
PRIVATE bf_io_common
|
||||
PRIVATE bf_io_spz
|
||||
)
|
||||
add_definitions(-DWITH_IO_SPZ)
|
||||
endif()
|
||||
|
||||
if(WITH_IO_STL)
|
||||
list(APPEND LIB
|
||||
PRIVATE bf_io_common
|
||||
|
|
|
|||
101
source/blender/nodes/geometry/nodes/node_geo_import_spz.cc
Normal file
101
source/blender/nodes/geometry/nodes/node_geo_import_spz.cc
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/* SPDX-FileCopyrightText: 2026 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
#include "BLI_generic_key_string.hh"
|
||||
#include "BLI_listbase.hh"
|
||||
#include "BLI_memory_cache_file_load.hh"
|
||||
#include "BLI_string.hh"
|
||||
|
||||
#include "BKE_report.hh"
|
||||
|
||||
#include "IO_spz.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_import_spz {
|
||||
|
||||
static void node_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
b.add_input<decl::String>("Path"_ustr)
|
||||
.subtype(PROP_FILEPATH)
|
||||
.path_filter("*.spz")
|
||||
.optional_label()
|
||||
.description("Path to a SPZ file");
|
||||
|
||||
b.add_output<decl::Geometry>("Points"_ustr);
|
||||
}
|
||||
|
||||
class LoadSpzCache : public memory_cache::CachedValue {
|
||||
public:
|
||||
GeometrySet geometry;
|
||||
Vector<NodeWarning> warnings;
|
||||
|
||||
void count_memory(MemoryCounter &counter) const override
|
||||
{
|
||||
this->geometry.count_memory(counter);
|
||||
}
|
||||
};
|
||||
|
||||
static void node_geo_exec(GeoNodeExecParams params)
|
||||
{
|
||||
#ifdef WITH_IO_SPZ
|
||||
const std::optional<std::string> path = params.ensure_absolute_path(
|
||||
params.extract_input<std::string>("Path"_ustr));
|
||||
if (!path) {
|
||||
params.set_default_remaining_outputs();
|
||||
return;
|
||||
}
|
||||
|
||||
std::shared_ptr<const LoadSpzCache> cached_value = memory_cache::get_loaded<LoadSpzCache>(
|
||||
GenericStringKey{"import_spz_node"}, {StringRefNull(*path)}, [&]() {
|
||||
SPZImportParams import_params;
|
||||
import_params.filepath = *path;
|
||||
|
||||
ReportList reports;
|
||||
BKE_reports_init(&reports, RPT_STORE);
|
||||
BLI_SCOPED_DEFER([&]() { BKE_reports_free(&reports); })
|
||||
import_params.reports = &reports;
|
||||
|
||||
PointCloud *point_cloud = SPZ_import_point_cloud(&import_params);
|
||||
|
||||
auto cached_value = std::make_unique<LoadSpzCache>();
|
||||
cached_value->geometry = GeometrySet::from_pointcloud(point_cloud);
|
||||
|
||||
for (Report &report : (import_params.reports)->list) {
|
||||
cached_value->warnings.append_as(report);
|
||||
}
|
||||
|
||||
return cached_value;
|
||||
});
|
||||
|
||||
for (const NodeWarning &warning : cached_value->warnings) {
|
||||
params.error_message_add(warning.type, warning.message);
|
||||
}
|
||||
|
||||
params.set_output("Points"_ustr, cached_value->geometry);
|
||||
|
||||
#else
|
||||
params.error_message_add(NodeWarningType::Error,
|
||||
TIP_("Disabled, Blender was compiled without SPZ I/O"));
|
||||
params.set_default_remaining_outputs();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void node_register()
|
||||
{
|
||||
static bke::bNodeType ntype;
|
||||
|
||||
geo_node_type_base(&ntype, "GeometryNodeImportSPZ"_ustr);
|
||||
ntype.ui_name = "Import SPZ";
|
||||
ntype.ui_description =
|
||||
"Import a point cloud object that is rendered as gaussian splat from an SPZ file";
|
||||
ntype.nclass = NODE_CLASS_INPUT;
|
||||
ntype.geometry_node_execute = node_geo_exec;
|
||||
ntype.declare = node_declare;
|
||||
|
||||
bke::node_register_type(ntype);
|
||||
}
|
||||
NOD_REGISTER_NODE(node_register)
|
||||
|
||||
} // namespace blender::nodes::node_geo_import_spz
|
||||
Loading…
Add table
Add a link
Reference in a new issue