2023-08-16 00:20:26 +10:00
|
|
|
# SPDX-FileCopyrightText: 2022-2023 Blender Authors
|
2023-06-15 13:09:04 +10:00
|
|
|
#
|
2022-09-26 12:36:13 -05:00
|
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
2023-06-15 13:09:04 +10:00
|
|
|
|
2025-05-08 04:28:22 +02:00
|
|
|
import bpy
|
2022-09-26 12:36:13 -05:00
|
|
|
from bl_ui import node_add_menu
|
2023-03-03 14:44:21 +01:00
|
|
|
from bpy.app.translations import (
|
|
|
|
|
contexts as i18n_contexts,
|
|
|
|
|
)
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
class NODE_MT_gn_attribute_base(node_add_menu.NodeMenu):
|
2022-09-26 12:36:13 -05:00
|
|
|
bl_label = "Attribute"
|
|
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeAttributeStatistic")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeAttributeDomainSize")
|
2023-01-09 18:09:22 +01:00
|
|
|
layout.separator()
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeBlurAttribute")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeCaptureAttribute")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeRemoveAttribute")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeStoreNamedAttribute", search_weight=1.0)
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_assets_for_catalog(layout, self.bl_label)
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
|
2025-10-02 11:07:25 +02:00
|
|
|
class NODE_MT_gn_color_base(node_add_menu.NodeMenu):
|
2022-09-26 12:36:13 -05:00
|
|
|
bl_label = "Color"
|
|
|
|
|
|
2025-05-09 04:02:50 +02:00
|
|
|
def draw(self, context):
|
2022-09-26 12:36:13 -05:00
|
|
|
layout = self.layout
|
2025-10-02 11:07:25 +02:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "ShaderNodeBlackbody")
|
|
|
|
|
self.node_operator(layout, "ShaderNodeGamma")
|
|
|
|
|
self.node_operator(layout, "ShaderNodeValToRGB")
|
|
|
|
|
self.node_operator(layout, "ShaderNodeRGBCurve")
|
2025-10-02 11:07:25 +02:00
|
|
|
self.color_mix_node(context, layout)
|
2023-01-09 18:09:22 +01:00
|
|
|
layout.separator()
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "FunctionNodeCombineColor")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeSeparateColor")
|
|
|
|
|
|
2025-10-02 11:07:25 +02:00
|
|
|
self.draw_assets_for_catalog(layout, self.bl_label)
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
class NODE_MT_gn_curve_base(node_add_menu.NodeMenu):
|
2022-09-26 12:36:13 -05:00
|
|
|
bl_label = "Curve"
|
|
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_menu(layout, path="Curve/Read")
|
|
|
|
|
self.draw_menu(layout, path="Curve/Sample")
|
|
|
|
|
self.draw_menu(layout, path="Curve/Write")
|
2022-09-26 12:36:13 -05:00
|
|
|
layout.separator()
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_menu(layout, path="Curve/Operations")
|
|
|
|
|
self.draw_menu(layout, path="Curve/Primitives")
|
|
|
|
|
self.draw_menu(layout, path="Curve/Topology")
|
|
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.bl_label)
|
2023-01-09 18:09:22 +01:00
|
|
|
|
|
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
class NODE_MT_gn_curve_read_base(node_add_menu.NodeMenu):
|
2023-01-09 18:09:22 +01:00
|
|
|
bl_label = "Read"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Curve/Read"
|
2023-01-09 18:09:22 +01:00
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeInputCurveHandlePositions")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeCurveLength")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeInputTangent")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeInputCurveTilt")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeCurveEndpointSelection")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeCurveHandleTypeSelection")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeInputSplineCyclic")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSplineLength")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSplineParameter")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeInputSplineResolution")
|
2023-01-09 18:09:22 +01:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2023-01-16 14:39:10 +01:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
|
|
|
|
|
class NODE_MT_gn_curve_sample_base(node_add_menu.NodeMenu):
|
2023-02-03 16:26:30 -05:00
|
|
|
bl_label = "Sample"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Curve/Sample"
|
2023-02-03 16:26:30 -05:00
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeSampleCurve")
|
|
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2023-02-03 16:26:30 -05:00
|
|
|
|
|
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
class NODE_MT_gn_curve_write_base(node_add_menu.NodeMenu):
|
2023-01-09 18:09:22 +01:00
|
|
|
bl_label = "Write"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Curve/Write"
|
2023-01-09 18:09:22 +01:00
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeSetCurveNormal")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSetCurveRadius")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSetCurveTilt")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSetCurveHandlePositions")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeCurveSetHandles")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSetSplineCyclic")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSetSplineResolution")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeCurveSplineType")
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
|
|
|
|
|
class NODE_MT_gn_curve_operations_base(node_add_menu.NodeMenu):
|
2023-01-09 18:09:22 +01:00
|
|
|
bl_label = "Operations"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Curve/Operations"
|
2023-01-09 18:09:22 +01:00
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeCurveToMesh")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeCurveToPoints")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeCurvesToGreasePencil")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeDeformCurvesOnSurface")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeFillCurve")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeFilletCurve")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeInterpolateCurves")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeResampleCurve")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeReverseCurve")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSubdivideCurve")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeTrimCurve")
|
|
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class NODE_MT_gn_curve_primitives_base(node_add_menu.NodeMenu):
|
2023-01-09 18:09:22 +01:00
|
|
|
bl_label = "Primitives"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Curve/Primitives"
|
2022-09-26 12:36:13 -05:00
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeCurveArc")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeCurvePrimitiveBezierSegment")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeCurvePrimitiveCircle")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeCurvePrimitiveLine")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeCurveSpiral")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeCurveQuadraticBezier")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeCurvePrimitiveQuadrilateral")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeCurveStar")
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
|
|
|
|
|
class NODE_MT_gn_curve_topology_base(node_add_menu.NodeMenu):
|
2023-01-09 18:09:22 +01:00
|
|
|
bl_label = "Topology"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Curve/Topology"
|
2022-09-28 14:38:27 -05:00
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeCurveOfPoint")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeOffsetPointInCurve")
|
|
|
|
|
self.node_operator(layout, "GeometryNodePointsOfCurve")
|
|
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2022-09-28 14:38:27 -05:00
|
|
|
|
|
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
class NODE_MT_gn_grease_pencil_read_base(node_add_menu.NodeMenu):
|
2025-03-25 16:38:18 +01:00
|
|
|
bl_label = "Read"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Grease Pencil/Read"
|
2025-03-25 16:38:18 +01:00
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeInputNamedLayerSelection")
|
2025-03-25 16:38:18 +01:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2025-03-25 16:38:18 +01:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
|
|
|
|
|
class NODE_MT_gn_grease_pencil_write_base(node_add_menu.NodeMenu):
|
2025-04-05 12:11:26 +02:00
|
|
|
bl_label = "Write"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Grease Pencil/Write"
|
2025-04-05 12:11:26 +02:00
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeSetGreasePencilColor")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSetGreasePencilDepth")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSetGreasePencilSoftness")
|
|
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2025-04-05 12:11:26 +02:00
|
|
|
|
|
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
class NODE_MT_gn_grease_pencil_operations_base(node_add_menu.NodeMenu):
|
2025-03-25 16:38:18 +01:00
|
|
|
bl_label = "Operations"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Grease Pencil/Operations"
|
2025-03-25 16:38:18 +01:00
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeGreasePencilToCurves")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeMergeLayers")
|
|
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2025-03-25 16:38:18 +01:00
|
|
|
|
|
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
class NODE_MT_gn_grease_pencil_base(node_add_menu.NodeMenu):
|
2025-03-25 16:38:18 +01:00
|
|
|
bl_label = "Grease Pencil"
|
|
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_menu(layout, path="Grease Pencil/Read")
|
|
|
|
|
self.draw_menu(layout, path="Grease Pencil/Write")
|
2025-03-25 16:38:18 +01:00
|
|
|
layout.separator()
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_menu(layout, path="Grease Pencil/Operations")
|
2025-03-25 16:38:18 +01:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_assets_for_catalog(layout, self.bl_label)
|
2025-03-25 16:38:18 +01:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
|
|
|
|
|
class NODE_MT_gn_geometry_base(node_add_menu.NodeMenu):
|
2022-09-26 12:36:13 -05:00
|
|
|
bl_label = "Geometry"
|
|
|
|
|
|
2023-01-09 18:09:22 +01:00
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_menu(layout, path="Geometry/Read")
|
|
|
|
|
self.draw_menu(layout, path="Geometry/Sample")
|
|
|
|
|
self.draw_menu(layout, path="Geometry/Write")
|
2023-01-16 12:23:50 +01:00
|
|
|
layout.separator()
|
2025-10-02 11:07:25 +02:00
|
|
|
self.draw_menu(layout, path="Geometry/Material")
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_menu(layout, path="Geometry/Operations")
|
2023-01-09 18:09:22 +01:00
|
|
|
layout.separator()
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeGeometryToInstance")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeJoinGeometry", search_weight=1.0)
|
|
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.bl_label)
|
2023-01-09 18:09:22 +01:00
|
|
|
|
2023-01-16 14:39:10 +01:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
class NODE_MT_gn_geometry_read_base(node_add_menu.NodeMenu):
|
2023-01-09 18:09:22 +01:00
|
|
|
bl_label = "Read"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Geometry/Read"
|
2023-01-09 18:09:22 +01:00
|
|
|
|
2023-08-24 13:34:15 +02:00
|
|
|
def draw(self, context):
|
2023-01-09 18:09:22 +01:00
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeInputID")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeInputIndex")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeInputNamedAttribute", search_weight=1.0)
|
|
|
|
|
self.node_operator(layout, "GeometryNodeInputNormal")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeInputPosition", search_weight=1.0)
|
|
|
|
|
self.node_operator(layout, "GeometryNodeInputRadius")
|
2025-08-21 09:04:13 +02:00
|
|
|
if context.space_data.node_tree_sub_type == 'TOOL':
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeToolSelection")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeToolActiveElement")
|
2023-01-09 18:09:22 +01:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2023-01-09 18:09:22 +01:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
|
|
|
|
|
class NODE_MT_gn_geometry_write_base(node_add_menu.NodeMenu):
|
2023-01-09 18:09:22 +01:00
|
|
|
bl_label = "Write"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Geometry/Write"
|
2023-01-09 18:09:22 +01:00
|
|
|
|
2023-08-24 13:34:15 +02:00
|
|
|
def draw(self, context):
|
2023-01-09 18:09:22 +01:00
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeSetGeometryName")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSetID")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSetPosition", search_weight=1.0)
|
2025-08-21 09:04:13 +02:00
|
|
|
if context.space_data.node_tree_sub_type == 'TOOL':
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeToolSetSelection")
|
|
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2023-01-09 18:09:22 +01:00
|
|
|
|
2023-01-16 14:39:10 +01:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
class NODE_MT_gn_geometry_operations_base(node_add_menu.NodeMenu):
|
2023-01-09 18:09:22 +01:00
|
|
|
bl_label = "Operations"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Geometry/Operations"
|
2023-01-09 18:09:22 +01:00
|
|
|
|
2022-09-26 12:36:13 -05:00
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeBake")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeBoundBox")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeConvexHull")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeDeleteGeometry")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeDuplicateElements")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeMergeByDistance")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSortElements")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeTransform", search_weight=1.0)
|
2023-01-09 18:09:22 +01:00
|
|
|
layout.separator()
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeSeparateComponents")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSeparateGeometry")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSplitToInstances")
|
2023-01-09 18:09:22 +01:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2023-01-16 14:39:10 +01:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
|
|
|
|
|
class NODE_MT_gn_geometry_sample_base(node_add_menu.NodeMenu):
|
2023-01-09 18:09:22 +01:00
|
|
|
bl_label = "Sample"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Geometry/Sample"
|
2023-01-09 18:09:22 +01:00
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeProximity")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeIndexOfNearest")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeRaycast")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSampleIndex")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSampleNearest")
|
|
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
class NODE_MT_gn_input_base(node_add_menu.NodeMenu):
|
2022-09-26 12:36:13 -05:00
|
|
|
bl_label = "Input"
|
|
|
|
|
|
2024-06-10 20:47:37 +02:00
|
|
|
def draw(self, context):
|
2023-01-09 18:09:22 +01:00
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_menu(layout, path="Input/Constant")
|
2025-08-21 09:04:13 +02:00
|
|
|
if context.space_data.node_tree_sub_type != 'TOOL':
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_menu(layout, path="Input/Gizmo")
|
|
|
|
|
self.draw_menu(layout, path="Input/Group")
|
|
|
|
|
self.draw_menu(layout, path="Input/Import")
|
|
|
|
|
self.draw_menu(layout, path="Input/Scene")
|
2023-01-09 18:09:22 +01:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_assets_for_catalog(layout, self.bl_label)
|
2023-01-09 18:09:22 +01:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
|
|
|
|
|
class NODE_MT_gn_input_constant_base(node_add_menu.NodeMenu):
|
2023-01-09 18:09:22 +01:00
|
|
|
bl_label = "Constant"
|
2023-03-03 14:44:21 +01:00
|
|
|
bl_translation_context = i18n_contexts.id_nodetree
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Input/Constant"
|
2023-01-09 18:09:22 +01:00
|
|
|
|
2022-09-26 12:36:13 -05:00
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "FunctionNodeInputBool")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeInputCollection")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeInputColor")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeInputImage")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeInputInt")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeInputMaterial")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeInputObject")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeInputRotation")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeInputString")
|
|
|
|
|
self.node_operator(layout, "ShaderNodeValue")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeInputVector")
|
|
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class NODE_MT_gn_input_group_base(node_add_menu.NodeMenu):
|
2023-01-09 18:09:22 +01:00
|
|
|
bl_label = "Group"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Input/Group"
|
2023-01-09 18:09:22 +01:00
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "NodeGroupInput")
|
2023-01-09 18:09:22 +01:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2023-01-09 18:09:22 +01:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
|
|
|
|
|
class NODE_MT_gn_input_scene_base(node_add_menu.NodeMenu):
|
2023-01-09 18:09:22 +01:00
|
|
|
bl_label = "Scene"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Input/Scene"
|
2023-01-09 18:09:22 +01:00
|
|
|
|
2023-08-24 13:34:15 +02:00
|
|
|
def draw(self, context):
|
2023-01-09 18:09:22 +01:00
|
|
|
layout = self.layout
|
2025-08-21 09:04:13 +02:00
|
|
|
if context.space_data.node_tree_sub_type == 'TOOL':
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeTool3DCursor")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeInputActiveCamera")
|
|
|
|
|
self.node_operator_with_outputs(
|
2025-07-11 16:43:13 +10:00
|
|
|
context,
|
|
|
|
|
layout,
|
|
|
|
|
"GeometryNodeCameraInfo",
|
|
|
|
|
[
|
|
|
|
|
"Projection Matrix",
|
|
|
|
|
"Focal Length",
|
|
|
|
|
"Sensor",
|
|
|
|
|
"Shift",
|
|
|
|
|
"Clip Start",
|
|
|
|
|
"Clip End",
|
|
|
|
|
"Focus Distance",
|
|
|
|
|
"Is Orthographic",
|
|
|
|
|
"Orthographic Scale",
|
|
|
|
|
],
|
|
|
|
|
)
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeCollectionInfo")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeImageInfo")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeIsViewport")
|
2025-08-21 09:04:13 +02:00
|
|
|
if context.space_data.node_tree_sub_type == 'TOOL':
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator_with_outputs(
|
2025-07-11 16:43:13 +10:00
|
|
|
context, layout, "GeometryNodeToolMousePosition",
|
|
|
|
|
["Mouse X", "Mouse Y", "Region Width", "Region Height"],
|
|
|
|
|
)
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeObjectInfo")
|
|
|
|
|
self.node_operator_with_outputs(context, layout, "GeometryNodeInputSceneTime", ["Frame", "Seconds"])
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSelfObject")
|
2025-08-21 09:04:13 +02:00
|
|
|
if context.space_data.node_tree_sub_type == 'TOOL':
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator_with_outputs(
|
2025-07-11 16:43:13 +10:00
|
|
|
context, layout, "GeometryNodeViewportTransform",
|
|
|
|
|
["Projection", "View", "Is Orthographic"],
|
|
|
|
|
)
|
2025-09-25 16:12:02 +02:00
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
class NODE_MT_gn_input_gizmo_base(node_add_menu.NodeMenu):
|
Geometry Nodes: support attaching gizmos to input values
This adds support for attaching gizmos for input values. The goal is to make it
easier for users to set input values intuitively in the 3D viewport.
We went through multiple different possible designs until we settled on the one
implemented here. We picked it for it's flexibility and ease of use when using
geometry node assets. The core principle in the design is that **gizmos are
attached to existing input values instead of being the input value themselves**.
This actually fits the existing concept of gizmos in Blender well, but may be a
bit unintutitive in a node setup at first. The attachment is done using links in
the node editor.
The most basic usage of the node is to link a Value node to the new Linear Gizmo
node. This attaches the gizmo to the input value and allows you to change it
from the 3D view. The attachment is indicated by the gizmo icon in the sockets
which are controlled by a gizmo as well as the back-link (notice the double
link) when the gizmo is active.
The core principle makes it straight forward to control the same node setup from
the 3D view with gizmos, or by manually changing input values, or by driving the
input values procedurally.
If the input value is controlled indirectly by other inputs, it's often possible
to **automatically propagate** the gizmo to the actual input.
Backpropagation does not work for all nodes, although more nodes can be
supported over time.
This patch adds the first three gizmo nodes which cover common use cases:
* **Linear Gizmo**: Creates a gizmo that controls a float or integer value using
a linear movement of e.g. an arrow in the 3D viewport.
* **Dial Gizmo**: Creates a circular gizmo in the 3D viewport that can be
rotated to change the attached angle input.
* **Transform Gizmo**: Creates a simple gizmo for location, rotation and scale.
In the future, more built-in gizmos and potentially the ability for custom
gizmos could be added.
All gizmo nodes have a **Transform** geometry output. Using it is optional but
it is recommended when the gizmo is used to control inputs that affect a
geometry. When it is used, Blender will automatically transform the gizmos
together with the geometry that they control. To achieve this, the output should
be merged with the generated geometry using the *Join Geometry* node. The data
contained in *Transform* output is not visible geometry, but just internal
information that helps Blender to give a better user experience when using
gizmos.
The gizmo nodes have a multi-input socket. This allows **controlling multiple
values** with the same gizmo.
Only a small set of **gizmo shapes** is supported initially. It might be
extended in the future but one goal is to give the gizmos used by different node
group assets a familiar look and feel. A similar constraint exists for
**colors**. Currently, one can choose from a fixed set of colors which can be
modified in the theme settings.
The set of **visible gizmos** is determined by a multiple factors because it's
not really feasible to show all possible gizmos at all times. To see any of the
geometry nodes gizmos, the "Active Modifier" option has to be enabled in the
"Viewport Gizmos" popover. Then all gizmos are drawn for which at least one of
the following is true:
* The gizmo controls an input of the active modifier of the active object.
* The gizmo controls a value in a selected node in an open node editor.
* The gizmo controls a pinned value in an open node editor. Pinning works by
clicking the gizmo icon next to the value.
Pull Request: https://projects.blender.org/blender/blender/pulls/112677
2024-07-10 16:18:47 +02:00
|
|
|
bl_label = "Gizmo"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Input/Gizmo"
|
Geometry Nodes: support attaching gizmos to input values
This adds support for attaching gizmos for input values. The goal is to make it
easier for users to set input values intuitively in the 3D viewport.
We went through multiple different possible designs until we settled on the one
implemented here. We picked it for it's flexibility and ease of use when using
geometry node assets. The core principle in the design is that **gizmos are
attached to existing input values instead of being the input value themselves**.
This actually fits the existing concept of gizmos in Blender well, but may be a
bit unintutitive in a node setup at first. The attachment is done using links in
the node editor.
The most basic usage of the node is to link a Value node to the new Linear Gizmo
node. This attaches the gizmo to the input value and allows you to change it
from the 3D view. The attachment is indicated by the gizmo icon in the sockets
which are controlled by a gizmo as well as the back-link (notice the double
link) when the gizmo is active.
The core principle makes it straight forward to control the same node setup from
the 3D view with gizmos, or by manually changing input values, or by driving the
input values procedurally.
If the input value is controlled indirectly by other inputs, it's often possible
to **automatically propagate** the gizmo to the actual input.
Backpropagation does not work for all nodes, although more nodes can be
supported over time.
This patch adds the first three gizmo nodes which cover common use cases:
* **Linear Gizmo**: Creates a gizmo that controls a float or integer value using
a linear movement of e.g. an arrow in the 3D viewport.
* **Dial Gizmo**: Creates a circular gizmo in the 3D viewport that can be
rotated to change the attached angle input.
* **Transform Gizmo**: Creates a simple gizmo for location, rotation and scale.
In the future, more built-in gizmos and potentially the ability for custom
gizmos could be added.
All gizmo nodes have a **Transform** geometry output. Using it is optional but
it is recommended when the gizmo is used to control inputs that affect a
geometry. When it is used, Blender will automatically transform the gizmos
together with the geometry that they control. To achieve this, the output should
be merged with the generated geometry using the *Join Geometry* node. The data
contained in *Transform* output is not visible geometry, but just internal
information that helps Blender to give a better user experience when using
gizmos.
The gizmo nodes have a multi-input socket. This allows **controlling multiple
values** with the same gizmo.
Only a small set of **gizmo shapes** is supported initially. It might be
extended in the future but one goal is to give the gizmos used by different node
group assets a familiar look and feel. A similar constraint exists for
**colors**. Currently, one can choose from a fixed set of colors which can be
modified in the theme settings.
The set of **visible gizmos** is determined by a multiple factors because it's
not really feasible to show all possible gizmos at all times. To see any of the
geometry nodes gizmos, the "Active Modifier" option has to be enabled in the
"Viewport Gizmos" popover. Then all gizmos are drawn for which at least one of
the following is true:
* The gizmo controls an input of the active modifier of the active object.
* The gizmo controls a value in a selected node in an open node editor.
* The gizmo controls a pinned value in an open node editor. Pinning works by
clicking the gizmo icon next to the value.
Pull Request: https://projects.blender.org/blender/blender/pulls/112677
2024-07-10 16:18:47 +02:00
|
|
|
|
|
|
|
|
def draw(self, context):
|
2025-09-26 14:28:46 +10:00
|
|
|
del context
|
Geometry Nodes: support attaching gizmos to input values
This adds support for attaching gizmos for input values. The goal is to make it
easier for users to set input values intuitively in the 3D viewport.
We went through multiple different possible designs until we settled on the one
implemented here. We picked it for it's flexibility and ease of use when using
geometry node assets. The core principle in the design is that **gizmos are
attached to existing input values instead of being the input value themselves**.
This actually fits the existing concept of gizmos in Blender well, but may be a
bit unintutitive in a node setup at first. The attachment is done using links in
the node editor.
The most basic usage of the node is to link a Value node to the new Linear Gizmo
node. This attaches the gizmo to the input value and allows you to change it
from the 3D view. The attachment is indicated by the gizmo icon in the sockets
which are controlled by a gizmo as well as the back-link (notice the double
link) when the gizmo is active.
The core principle makes it straight forward to control the same node setup from
the 3D view with gizmos, or by manually changing input values, or by driving the
input values procedurally.
If the input value is controlled indirectly by other inputs, it's often possible
to **automatically propagate** the gizmo to the actual input.
Backpropagation does not work for all nodes, although more nodes can be
supported over time.
This patch adds the first three gizmo nodes which cover common use cases:
* **Linear Gizmo**: Creates a gizmo that controls a float or integer value using
a linear movement of e.g. an arrow in the 3D viewport.
* **Dial Gizmo**: Creates a circular gizmo in the 3D viewport that can be
rotated to change the attached angle input.
* **Transform Gizmo**: Creates a simple gizmo for location, rotation and scale.
In the future, more built-in gizmos and potentially the ability for custom
gizmos could be added.
All gizmo nodes have a **Transform** geometry output. Using it is optional but
it is recommended when the gizmo is used to control inputs that affect a
geometry. When it is used, Blender will automatically transform the gizmos
together with the geometry that they control. To achieve this, the output should
be merged with the generated geometry using the *Join Geometry* node. The data
contained in *Transform* output is not visible geometry, but just internal
information that helps Blender to give a better user experience when using
gizmos.
The gizmo nodes have a multi-input socket. This allows **controlling multiple
values** with the same gizmo.
Only a small set of **gizmo shapes** is supported initially. It might be
extended in the future but one goal is to give the gizmos used by different node
group assets a familiar look and feel. A similar constraint exists for
**colors**. Currently, one can choose from a fixed set of colors which can be
modified in the theme settings.
The set of **visible gizmos** is determined by a multiple factors because it's
not really feasible to show all possible gizmos at all times. To see any of the
geometry nodes gizmos, the "Active Modifier" option has to be enabled in the
"Viewport Gizmos" popover. Then all gizmos are drawn for which at least one of
the following is true:
* The gizmo controls an input of the active modifier of the active object.
* The gizmo controls a value in a selected node in an open node editor.
* The gizmo controls a pinned value in an open node editor. Pinning works by
clicking the gizmo icon next to the value.
Pull Request: https://projects.blender.org/blender/blender/pulls/112677
2024-07-10 16:18:47 +02:00
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeGizmoDial")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeGizmoLinear")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeGizmoTransform")
|
Geometry Nodes: support attaching gizmos to input values
This adds support for attaching gizmos for input values. The goal is to make it
easier for users to set input values intuitively in the 3D viewport.
We went through multiple different possible designs until we settled on the one
implemented here. We picked it for it's flexibility and ease of use when using
geometry node assets. The core principle in the design is that **gizmos are
attached to existing input values instead of being the input value themselves**.
This actually fits the existing concept of gizmos in Blender well, but may be a
bit unintutitive in a node setup at first. The attachment is done using links in
the node editor.
The most basic usage of the node is to link a Value node to the new Linear Gizmo
node. This attaches the gizmo to the input value and allows you to change it
from the 3D view. The attachment is indicated by the gizmo icon in the sockets
which are controlled by a gizmo as well as the back-link (notice the double
link) when the gizmo is active.
The core principle makes it straight forward to control the same node setup from
the 3D view with gizmos, or by manually changing input values, or by driving the
input values procedurally.
If the input value is controlled indirectly by other inputs, it's often possible
to **automatically propagate** the gizmo to the actual input.
Backpropagation does not work for all nodes, although more nodes can be
supported over time.
This patch adds the first three gizmo nodes which cover common use cases:
* **Linear Gizmo**: Creates a gizmo that controls a float or integer value using
a linear movement of e.g. an arrow in the 3D viewport.
* **Dial Gizmo**: Creates a circular gizmo in the 3D viewport that can be
rotated to change the attached angle input.
* **Transform Gizmo**: Creates a simple gizmo for location, rotation and scale.
In the future, more built-in gizmos and potentially the ability for custom
gizmos could be added.
All gizmo nodes have a **Transform** geometry output. Using it is optional but
it is recommended when the gizmo is used to control inputs that affect a
geometry. When it is used, Blender will automatically transform the gizmos
together with the geometry that they control. To achieve this, the output should
be merged with the generated geometry using the *Join Geometry* node. The data
contained in *Transform* output is not visible geometry, but just internal
information that helps Blender to give a better user experience when using
gizmos.
The gizmo nodes have a multi-input socket. This allows **controlling multiple
values** with the same gizmo.
Only a small set of **gizmo shapes** is supported initially. It might be
extended in the future but one goal is to give the gizmos used by different node
group assets a familiar look and feel. A similar constraint exists for
**colors**. Currently, one can choose from a fixed set of colors which can be
modified in the theme settings.
The set of **visible gizmos** is determined by a multiple factors because it's
not really feasible to show all possible gizmos at all times. To see any of the
geometry nodes gizmos, the "Active Modifier" option has to be enabled in the
"Viewport Gizmos" popover. Then all gizmos are drawn for which at least one of
the following is true:
* The gizmo controls an input of the active modifier of the active object.
* The gizmo controls a value in a selected node in an open node editor.
* The gizmo controls a pinned value in an open node editor. Pinning works by
clicking the gizmo icon next to the value.
Pull Request: https://projects.blender.org/blender/blender/pulls/112677
2024-07-10 16:18:47 +02:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
Geometry Nodes: support attaching gizmos to input values
This adds support for attaching gizmos for input values. The goal is to make it
easier for users to set input values intuitively in the 3D viewport.
We went through multiple different possible designs until we settled on the one
implemented here. We picked it for it's flexibility and ease of use when using
geometry node assets. The core principle in the design is that **gizmos are
attached to existing input values instead of being the input value themselves**.
This actually fits the existing concept of gizmos in Blender well, but may be a
bit unintutitive in a node setup at first. The attachment is done using links in
the node editor.
The most basic usage of the node is to link a Value node to the new Linear Gizmo
node. This attaches the gizmo to the input value and allows you to change it
from the 3D view. The attachment is indicated by the gizmo icon in the sockets
which are controlled by a gizmo as well as the back-link (notice the double
link) when the gizmo is active.
The core principle makes it straight forward to control the same node setup from
the 3D view with gizmos, or by manually changing input values, or by driving the
input values procedurally.
If the input value is controlled indirectly by other inputs, it's often possible
to **automatically propagate** the gizmo to the actual input.
Backpropagation does not work for all nodes, although more nodes can be
supported over time.
This patch adds the first three gizmo nodes which cover common use cases:
* **Linear Gizmo**: Creates a gizmo that controls a float or integer value using
a linear movement of e.g. an arrow in the 3D viewport.
* **Dial Gizmo**: Creates a circular gizmo in the 3D viewport that can be
rotated to change the attached angle input.
* **Transform Gizmo**: Creates a simple gizmo for location, rotation and scale.
In the future, more built-in gizmos and potentially the ability for custom
gizmos could be added.
All gizmo nodes have a **Transform** geometry output. Using it is optional but
it is recommended when the gizmo is used to control inputs that affect a
geometry. When it is used, Blender will automatically transform the gizmos
together with the geometry that they control. To achieve this, the output should
be merged with the generated geometry using the *Join Geometry* node. The data
contained in *Transform* output is not visible geometry, but just internal
information that helps Blender to give a better user experience when using
gizmos.
The gizmo nodes have a multi-input socket. This allows **controlling multiple
values** with the same gizmo.
Only a small set of **gizmo shapes** is supported initially. It might be
extended in the future but one goal is to give the gizmos used by different node
group assets a familiar look and feel. A similar constraint exists for
**colors**. Currently, one can choose from a fixed set of colors which can be
modified in the theme settings.
The set of **visible gizmos** is determined by a multiple factors because it's
not really feasible to show all possible gizmos at all times. To see any of the
geometry nodes gizmos, the "Active Modifier" option has to be enabled in the
"Viewport Gizmos" popover. Then all gizmos are drawn for which at least one of
the following is true:
* The gizmo controls an input of the active modifier of the active object.
* The gizmo controls a value in a selected node in an open node editor.
* The gizmo controls a pinned value in an open node editor. Pinning works by
clicking the gizmo icon next to the value.
Pull Request: https://projects.blender.org/blender/blender/pulls/112677
2024-07-10 16:18:47 +02:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
|
|
|
|
|
class NODE_MT_gn_instance_base(node_add_menu.NodeMenu):
|
2022-09-26 12:36:13 -05:00
|
|
|
bl_label = "Instances"
|
|
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeInstanceOnPoints", search_weight=2.0)
|
|
|
|
|
self.node_operator(layout, "GeometryNodeInstancesToPoints")
|
2023-01-09 18:09:22 +01:00
|
|
|
layout.separator()
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeRealizeInstances", search_weight=1.0)
|
|
|
|
|
self.node_operator(layout, "GeometryNodeRotateInstances")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeScaleInstances")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeTranslateInstances")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSetInstanceTransform")
|
2022-09-26 12:36:13 -05:00
|
|
|
layout.separator()
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeInputInstanceBounds")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeInstanceTransform")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeInputInstanceRotation")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeInputInstanceScale")
|
|
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.bl_label)
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
class NODE_MT_gn_material_base(node_add_menu.NodeMenu):
|
2022-09-26 12:36:13 -05:00
|
|
|
bl_label = "Material"
|
2025-10-02 11:07:25 +02:00
|
|
|
menu_path = "Geometry/Material"
|
2022-09-26 12:36:13 -05:00
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeReplaceMaterial")
|
2022-09-26 12:36:13 -05:00
|
|
|
layout.separator()
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeInputMaterialIndex")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeMaterialSelection")
|
2022-09-26 12:36:13 -05:00
|
|
|
layout.separator()
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeSetMaterial", search_weight=1.0)
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSetMaterialIndex")
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2025-10-02 11:07:25 +02:00
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
|
|
|
|
|
class NODE_MT_gn_mesh_base(node_add_menu.NodeMenu):
|
2022-09-26 12:36:13 -05:00
|
|
|
bl_label = "Mesh"
|
|
|
|
|
|
2023-01-09 18:09:22 +01:00
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_menu(layout, path="Mesh/Read")
|
|
|
|
|
self.draw_menu(layout, path="Mesh/Sample")
|
|
|
|
|
self.draw_menu(layout, path="Mesh/Write")
|
2023-01-09 18:09:22 +01:00
|
|
|
layout.separator()
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_menu(layout, path="Mesh/Operations")
|
|
|
|
|
self.draw_menu(layout, path="Mesh/Primitives")
|
|
|
|
|
self.draw_menu(layout, path="Mesh/Topology")
|
|
|
|
|
self.draw_menu(layout, path="Mesh/UV")
|
|
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.bl_label)
|
2023-01-09 18:09:22 +01:00
|
|
|
|
|
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
class NODE_MT_gn_mesh_read_base(node_add_menu.NodeMenu):
|
2023-01-09 18:09:22 +01:00
|
|
|
bl_label = "Read"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Mesh/Read"
|
2023-01-09 18:09:22 +01:00
|
|
|
|
2023-08-24 13:34:15 +02:00
|
|
|
def draw(self, context):
|
2023-01-09 18:09:22 +01:00
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeInputMeshEdgeAngle")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeInputMeshEdgeNeighbors")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeInputMeshEdgeVertices")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeEdgesToFaceGroups")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeInputMeshFaceArea")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeMeshFaceSetBoundaries")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeInputMeshFaceNeighbors")
|
2025-08-21 09:04:13 +02:00
|
|
|
if context.space_data.node_tree_sub_type == 'TOOL':
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeToolFaceSet")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeInputMeshFaceIsPlanar")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeInputShadeSmooth")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeInputEdgeSmooth")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeInputMeshIsland")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeInputShortestEdgePaths")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeInputMeshVertexNeighbors")
|
|
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class NODE_MT_gn_mesh_sample_base(node_add_menu.NodeMenu):
|
2023-02-03 16:26:30 -05:00
|
|
|
bl_label = "Sample"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Mesh/Sample"
|
2023-02-03 16:26:30 -05:00
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeSampleNearestSurface")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSampleUVSurface")
|
2023-02-03 16:26:30 -05:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2023-02-03 16:26:30 -05:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
|
|
|
|
|
class NODE_MT_gn_mesh_write_base(node_add_menu.NodeMenu):
|
2023-01-09 18:09:22 +01:00
|
|
|
bl_label = "Write"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Mesh/Write"
|
2023-01-09 18:09:22 +01:00
|
|
|
|
2023-08-24 13:34:15 +02:00
|
|
|
def draw(self, context):
|
2023-01-09 18:09:22 +01:00
|
|
|
layout = self.layout
|
2025-08-21 09:04:13 +02:00
|
|
|
if context.space_data.node_tree_sub_type == 'TOOL':
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeToolSetFaceSet")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSetMeshNormal")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSetShadeSmooth")
|
|
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2023-01-09 18:09:22 +01:00
|
|
|
|
|
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
class NODE_MT_gn_mesh_operations_base(node_add_menu.NodeMenu):
|
2023-01-09 18:09:22 +01:00
|
|
|
bl_label = "Operations"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Mesh/Operations"
|
2023-01-09 18:09:22 +01:00
|
|
|
|
2023-03-23 15:31:14 +11:00
|
|
|
def draw(self, context):
|
2025-10-07 09:15:20 +11:00
|
|
|
del context
|
2022-09-26 12:36:13 -05:00
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeDualMesh")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeEdgePathsToCurves")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeEdgePathsToSelection")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeExtrudeMesh")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeFlipFaces")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeMeshBoolean")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeMeshToCurve")
|
2025-10-03 15:04:55 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeMeshToDensityGrid")
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeMeshToPoints")
|
2025-10-03 15:04:55 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeMeshToSDFGrid")
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeMeshToVolume")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeScaleElements")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSplitEdges")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSubdivideMesh")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSubdivisionSurface")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeTriangulate")
|
|
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class NODE_MT_gn_mesh_primitives_base(node_add_menu.NodeMenu):
|
2023-01-09 18:09:22 +01:00
|
|
|
bl_label = "Primitives"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Mesh/Primitives"
|
2022-09-26 12:36:13 -05:00
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeMeshCone")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeMeshCube")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeMeshCylinder")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeMeshGrid")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeMeshIcoSphere")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeMeshCircle")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeMeshLine")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeMeshUVSphere")
|
|
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2024-06-10 15:38:43 -04:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
class NODE_MT_gn_input_import_base(node_add_menu.NodeMenu):
|
2024-06-10 20:47:37 +02:00
|
|
|
bl_label = "Import"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Input/Import"
|
2024-06-10 20:47:37 +02:00
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
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, "GeometryNodeImportSTL", label="STL (.stl)")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeImportText", label="Text (.txt)")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeImportVDB", label="OpenVDB (.vdb)")
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2024-06-10 15:38:43 -04:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
|
|
|
|
|
class NODE_MT_gn_mesh_topology_base(node_add_menu.NodeMenu):
|
2023-01-09 18:09:22 +01:00
|
|
|
bl_label = "Topology"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Mesh/Topology"
|
2022-09-28 14:38:27 -05:00
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeCornersOfEdge")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeCornersOfFace")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeCornersOfVertex")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeEdgesOfCorner")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeEdgesOfVertex")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeFaceOfCorner")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeOffsetCornerInFace")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeVertexOfCorner")
|
|
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2022-09-28 14:38:27 -05:00
|
|
|
|
|
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
class NODE_MT_gn_output_base(node_add_menu.NodeMenu):
|
2022-09-26 12:36:13 -05:00
|
|
|
bl_label = "Output"
|
|
|
|
|
|
2025-05-27 09:01:54 +02:00
|
|
|
def draw(self, context):
|
2022-09-26 12:36:13 -05:00
|
|
|
layout = self.layout
|
2025-09-27 10:09:48 +02:00
|
|
|
self.node_operator(layout, "NodeEnableOutput")
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "NodeGroupOutput")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeViewer")
|
|
|
|
|
self.node_operator_with_searchable_enum(context, layout, "GeometryNodeWarning", "warning_type")
|
|
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.bl_label)
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
class NODE_MT_gn_point_base(node_add_menu.NodeMenu):
|
2022-09-26 12:36:13 -05:00
|
|
|
bl_label = "Point"
|
|
|
|
|
|
2023-03-23 15:31:14 +11:00
|
|
|
def draw(self, context):
|
2025-10-07 09:15:20 +11:00
|
|
|
del context
|
2022-09-26 12:36:13 -05:00
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeDistributePointsInVolume")
|
2025-10-03 15:04:55 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeDistributePointsInGrid")
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeDistributePointsOnFaces")
|
2023-01-09 18:09:22 +01:00
|
|
|
layout.separator()
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodePoints")
|
|
|
|
|
self.node_operator(layout, "GeometryNodePointsToCurves")
|
2025-10-03 15:04:55 +02:00
|
|
|
self.node_operator(layout, "GeometryNodePointsToSDFGrid")
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodePointsToVertices")
|
|
|
|
|
self.node_operator(layout, "GeometryNodePointsToVolume")
|
2022-09-26 12:36:13 -05:00
|
|
|
layout.separator()
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeSetPointRadius")
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_assets_for_catalog(layout, self.bl_label)
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
|
|
|
|
|
class NODE_MT_gn_simulation_base(node_add_menu.NodeMenu):
|
Geometry Nodes: add simulation support
This adds support for building simulations with geometry nodes. A new
`Simulation Input` and `Simulation Output` node allow maintaining a
simulation state across multiple frames. Together these two nodes form
a `simulation zone` which contains all the nodes that update the simulation
state from one frame to the next.
A new simulation zone can be added via the menu
(`Simulation > Simulation Zone`) or with the node add search.
The simulation state contains a geometry by default. However, it is possible
to add multiple geometry sockets as well as other socket types. Currently,
field inputs are evaluated and stored for the preceding geometry socket in
the order that the sockets are shown. Simulation state items can be added
by linking one of the empty sockets to something else. In the sidebar, there
is a new panel that allows adding, removing and reordering these sockets.
The simulation nodes behave as follows:
* On the first frame, the inputs of the `Simulation Input` node are evaluated
to initialize the simulation state. In later frames these sockets are not
evaluated anymore. The `Delta Time` at the first frame is zero, but the
simulation zone is still evaluated.
* On every next frame, the `Simulation Input` node outputs the simulation
state of the previous frame. Nodes in the simulation zone can edit that
data in arbitrary ways, also taking into account the `Delta Time`. The new
simulation state has to be passed to the `Simulation Output` node where it
is cached and forwarded.
* On a frame that is already cached or baked, the nodes in the simulation
zone are not evaluated, because the `Simulation Output` node can return
the previously cached data directly.
It is not allowed to connect sockets from inside the simulation zone to the
outside without going through the `Simulation Output` node. This is a necessary
restriction to make caching and sub-frame interpolation work. Links can go into
the simulation zone without problems though.
Anonymous attributes are not propagated by the simulation nodes unless they
are explicitly stored in the simulation state. This is unfortunate, but
currently there is no practical and reliable alternative. The core problem
is detecting which anonymous attributes will be required for the simulation
and afterwards. While we can detect this for the current evaluation, we can't
look into the future in time to see what data will be necessary. We intend to
make it easier to explicitly pass data through a simulation in the future,
even if the simulation is in a nested node group.
There is a new `Simulation Nodes` panel in the physics tab in the properties
editor. It allows baking all simulation zones on the selected objects. The
baking options are intentially kept at a minimum for this MVP. More features
for simulation baking as well as baking in general can be expected to be added
separately.
All baked data is stored on disk in a folder next to the .blend file. #106937
describes how baking is implemented in more detail. Volumes can not be baked
yet and materials are lost during baking for now. Packing the baked data into
the .blend file is not yet supported.
The timeline indicates which frames are currently cached, baked or cached but
invalidated by user-changes.
Simulation input and output nodes are internally linked together by their
`bNode.identifier` which stays the same even if the node name changes. They
are generally added and removed together. However, there are still cases where
"dangling" simulation nodes can be created currently. Those generally don't
cause harm, but would be nice to avoid this in more cases in the future.
Co-authored-by: Hans Goudey <h.goudey@me.com>
Co-authored-by: Lukas Tönne <lukas@blender.org>
Pull Request: https://projects.blender.org/blender/blender/pulls/104924
2023-05-03 13:18:51 +02:00
|
|
|
bl_label = "Simulation"
|
|
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.simulation_zone(layout, label="Simulation")
|
|
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.bl_label)
|
Geometry Nodes: add simulation support
This adds support for building simulations with geometry nodes. A new
`Simulation Input` and `Simulation Output` node allow maintaining a
simulation state across multiple frames. Together these two nodes form
a `simulation zone` which contains all the nodes that update the simulation
state from one frame to the next.
A new simulation zone can be added via the menu
(`Simulation > Simulation Zone`) or with the node add search.
The simulation state contains a geometry by default. However, it is possible
to add multiple geometry sockets as well as other socket types. Currently,
field inputs are evaluated and stored for the preceding geometry socket in
the order that the sockets are shown. Simulation state items can be added
by linking one of the empty sockets to something else. In the sidebar, there
is a new panel that allows adding, removing and reordering these sockets.
The simulation nodes behave as follows:
* On the first frame, the inputs of the `Simulation Input` node are evaluated
to initialize the simulation state. In later frames these sockets are not
evaluated anymore. The `Delta Time` at the first frame is zero, but the
simulation zone is still evaluated.
* On every next frame, the `Simulation Input` node outputs the simulation
state of the previous frame. Nodes in the simulation zone can edit that
data in arbitrary ways, also taking into account the `Delta Time`. The new
simulation state has to be passed to the `Simulation Output` node where it
is cached and forwarded.
* On a frame that is already cached or baked, the nodes in the simulation
zone are not evaluated, because the `Simulation Output` node can return
the previously cached data directly.
It is not allowed to connect sockets from inside the simulation zone to the
outside without going through the `Simulation Output` node. This is a necessary
restriction to make caching and sub-frame interpolation work. Links can go into
the simulation zone without problems though.
Anonymous attributes are not propagated by the simulation nodes unless they
are explicitly stored in the simulation state. This is unfortunate, but
currently there is no practical and reliable alternative. The core problem
is detecting which anonymous attributes will be required for the simulation
and afterwards. While we can detect this for the current evaluation, we can't
look into the future in time to see what data will be necessary. We intend to
make it easier to explicitly pass data through a simulation in the future,
even if the simulation is in a nested node group.
There is a new `Simulation Nodes` panel in the physics tab in the properties
editor. It allows baking all simulation zones on the selected objects. The
baking options are intentially kept at a minimum for this MVP. More features
for simulation baking as well as baking in general can be expected to be added
separately.
All baked data is stored on disk in a folder next to the .blend file. #106937
describes how baking is implemented in more detail. Volumes can not be baked
yet and materials are lost during baking for now. Packing the baked data into
the .blend file is not yet supported.
The timeline indicates which frames are currently cached, baked or cached but
invalidated by user-changes.
Simulation input and output nodes are internally linked together by their
`bNode.identifier` which stays the same even if the node name changes. They
are generally added and removed together. However, there are still cases where
"dangling" simulation nodes can be created currently. Those generally don't
cause harm, but would be nice to avoid this in more cases in the future.
Co-authored-by: Hans Goudey <h.goudey@me.com>
Co-authored-by: Lukas Tönne <lukas@blender.org>
Pull Request: https://projects.blender.org/blender/blender/pulls/104924
2023-05-03 13:18:51 +02:00
|
|
|
|
|
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
class NODE_MT_gn_utilities_text_base(node_add_menu.NodeMenu):
|
2022-09-26 12:36:13 -05:00
|
|
|
bl_label = "Text"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Utilities/Text"
|
2022-09-26 12:36:13 -05:00
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "FunctionNodeFormatString")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeStringJoin")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeMatchString")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeReplaceString")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeSliceString")
|
2023-01-09 18:09:22 +01:00
|
|
|
layout.separator()
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "FunctionNodeFindInString")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeStringLength")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeStringToCurves")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeStringToValue")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeValueToString")
|
2022-09-26 12:36:13 -05:00
|
|
|
layout.separator()
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "FunctionNodeInputSpecialCharacters")
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
|
|
|
|
|
class NODE_MT_gn_texture_base(node_add_menu.NodeMenu):
|
2022-09-26 12:36:13 -05:00
|
|
|
bl_label = "Texture"
|
|
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "ShaderNodeTexBrick")
|
|
|
|
|
self.node_operator(layout, "ShaderNodeTexChecker")
|
|
|
|
|
self.node_operator(layout, "ShaderNodeTexGabor")
|
|
|
|
|
self.node_operator(layout, "ShaderNodeTexGradient")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeImageTexture")
|
|
|
|
|
self.node_operator(layout, "ShaderNodeTexMagic")
|
|
|
|
|
self.node_operator(layout, "ShaderNodeTexNoise")
|
|
|
|
|
self.node_operator(layout, "ShaderNodeTexVoronoi")
|
|
|
|
|
self.node_operator(layout, "ShaderNodeTexWave")
|
|
|
|
|
self.node_operator(layout, "ShaderNodeTexWhiteNoise")
|
|
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.bl_label)
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
class NODE_MT_gn_utilities_base(node_add_menu.NodeMenu):
|
2022-09-26 12:36:13 -05:00
|
|
|
bl_label = "Utilities"
|
|
|
|
|
|
2024-02-13 18:59:36 +01:00
|
|
|
def draw(self, context):
|
2023-01-09 18:09:22 +01:00
|
|
|
layout = self.layout
|
2025-10-02 11:07:25 +02:00
|
|
|
self.draw_menu(layout, path="Utilities/Math")
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_menu(layout, path="Utilities/Text")
|
|
|
|
|
self.draw_menu(layout, path="Utilities/Vector")
|
2023-01-09 18:09:22 +01:00
|
|
|
layout.separator()
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_menu(layout, path="Utilities/Bundle")
|
|
|
|
|
self.draw_menu(layout, path="Utilities/Closure")
|
|
|
|
|
self.draw_menu(layout, path="Utilities/Field")
|
2025-07-24 16:16:40 +02:00
|
|
|
if context.preferences.experimental.use_geometry_nodes_lists:
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_menu(layout, path="Utilities/List")
|
|
|
|
|
self.draw_menu(layout, path="Utilities/Matrix")
|
|
|
|
|
self.draw_menu(layout, path="Utilities/Rotation")
|
2023-01-09 18:09:22 +01:00
|
|
|
layout.separator()
|
2025-09-25 16:12:02 +02:00
|
|
|
self.for_each_element_zone(layout, label="For Each Element")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeIndexSwitch")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeMenuSwitch")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeRandomValue")
|
|
|
|
|
self.repeat_zone(layout, label="Repeat")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSwitch")
|
2025-10-02 11:07:25 +02:00
|
|
|
layout.separator()
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_assets_for_catalog(layout, self.bl_label)
|
2025-10-02 11:07:25 +02:00
|
|
|
layout.separator()
|
|
|
|
|
self.draw_menu(layout, path="Utilities/Deprecated")
|
2023-01-09 18:09:22 +01:00
|
|
|
|
|
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
class NODE_MT_gn_utilities_deprecated_base(node_add_menu.NodeMenu):
|
2024-02-06 19:08:01 +01:00
|
|
|
bl_label = "Deprecated"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Utilities/Deprecated"
|
2024-02-06 19:08:01 +01:00
|
|
|
|
|
|
|
|
def draw(self, context):
|
2025-09-26 14:28:46 +10:00
|
|
|
del context
|
2024-02-06 19:08:01 +01:00
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "FunctionNodeAlignEulerToVector")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeRotateEuler")
|
2024-02-06 19:08:01 +01:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2024-02-06 19:08:01 +01:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
|
|
|
|
|
class NODE_MT_gn_utilities_field_base(node_add_menu.NodeMenu):
|
2023-01-09 18:09:22 +01:00
|
|
|
bl_label = "Field"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Utilities/Field"
|
2023-01-09 18:09:22 +01:00
|
|
|
|
2022-09-26 12:36:13 -05:00
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeAccumulateField")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeFieldAtIndex")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeFieldOnDomain")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeFieldAverage")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeFieldMinAndMax")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeFieldVariance")
|
|
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2023-01-09 18:09:22 +01:00
|
|
|
|
|
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
class NODE_MT_gn_utilities_rotation_base(node_add_menu.NodeMenu):
|
2023-01-09 18:09:22 +01:00
|
|
|
bl_label = "Rotation"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Utilities/Rotation"
|
2023-01-09 18:09:22 +01:00
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "FunctionNodeAlignRotationToVector")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeAxesToRotation")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeAxisAngleToRotation")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeEulerToRotation")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeInvertRotation")
|
2025-09-28 14:20:14 +02:00
|
|
|
props = self.node_operator(layout, "ShaderNodeMix", label="Mix Rotation")
|
|
|
|
|
ops = props.settings.add()
|
|
|
|
|
ops.name = "data_type"
|
|
|
|
|
ops.value = "'ROTATION'"
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "FunctionNodeRotateRotation")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeRotateVector")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeRotationToAxisAngle")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeRotationToEuler")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeRotationToQuaternion")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeQuaternionToRotation")
|
|
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class NODE_MT_gn_utilities_matrix_base(node_add_menu.NodeMenu):
|
2024-02-13 18:59:36 +01:00
|
|
|
bl_label = "Matrix"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Utilities/Matrix"
|
2024-02-13 18:59:36 +01:00
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "FunctionNodeCombineMatrix")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeCombineTransform")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeMatrixDeterminant", label="Determinant")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeInvertMatrix")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeMatrixMultiply")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeProjectPoint")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeSeparateMatrix")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeSeparateTransform")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeTransformDirection")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeTransformPoint")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeTransposeMatrix")
|
|
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class NODE_MT_category_utilities_bundle_base(node_add_menu.NodeMenu):
|
2025-07-31 21:08:47 +02:00
|
|
|
bl_label = "Bundle"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Utilities/Bundle"
|
2025-07-31 21:08:47 +02:00
|
|
|
|
|
|
|
|
def draw(self, context):
|
2025-09-26 14:28:46 +10:00
|
|
|
del context
|
2025-07-31 21:08:47 +02:00
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "NodeCombineBundle")
|
|
|
|
|
self.node_operator(layout, "NodeSeparateBundle")
|
2025-10-01 09:20:11 +02:00
|
|
|
self.node_operator(layout, "NodeJoinBundle")
|
2025-09-25 16:12:02 +02:00
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2025-07-31 21:08:47 +02:00
|
|
|
|
|
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
class NODE_MT_category_utilities_closure_base(node_add_menu.NodeMenu):
|
2025-07-31 21:08:47 +02:00
|
|
|
bl_label = "Closure"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Utilities/Closure"
|
2025-07-31 21:08:47 +02:00
|
|
|
|
|
|
|
|
def draw(self, context):
|
2025-09-26 14:28:46 +10:00
|
|
|
del context
|
2025-07-31 21:08:47 +02:00
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.closure_zone(layout, label="Closure")
|
|
|
|
|
self.node_operator(layout, "NodeEvaluateClosure")
|
2025-07-31 21:08:47 +02:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2025-07-31 21:08:47 +02:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
|
|
|
|
|
class NODE_MT_gn_utilities_list_base(node_add_menu.NodeMenu):
|
2025-07-24 16:16:40 +02:00
|
|
|
bl_label = "List"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Utilities/List"
|
2025-07-24 16:16:40 +02:00
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeList")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeListGetItem")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeListLength")
|
|
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2025-07-24 16:16:40 +02:00
|
|
|
|
|
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
class NODE_MT_gn_utilities_math_base(node_add_menu.NodeMenu):
|
2023-01-09 18:09:22 +01:00
|
|
|
bl_label = "Math"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Utilities/Math"
|
2023-01-09 18:09:22 +01:00
|
|
|
|
2025-05-08 04:28:22 +02:00
|
|
|
def draw(self, context):
|
2023-01-09 18:09:22 +01:00
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator_with_searchable_enum(
|
2025-07-11 16:43:13 +10:00
|
|
|
context, layout, "FunctionNodeBitMath", "operation", search_weight=-1.0,
|
|
|
|
|
)
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator_with_searchable_enum(context, layout, "FunctionNodeBooleanMath", "operation")
|
|
|
|
|
self.node_operator_with_searchable_enum(context, layout, "FunctionNodeIntegerMath", "operation")
|
|
|
|
|
self.node_operator(layout, "ShaderNodeClamp")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeCompare")
|
|
|
|
|
self.node_operator(layout, "ShaderNodeFloatCurve")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeFloatToInt")
|
|
|
|
|
self.node_operator(layout, "FunctionNodeHashValue")
|
|
|
|
|
self.node_operator(layout, "ShaderNodeMapRange")
|
|
|
|
|
self.node_operator_with_searchable_enum(context, layout, "ShaderNodeMath", "operation")
|
|
|
|
|
self.node_operator(layout, "ShaderNodeMix")
|
|
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class NODE_MT_gn_mesh_uv_base(node_add_menu.NodeMenu):
|
2022-09-26 12:36:13 -05:00
|
|
|
bl_label = "UV"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Mesh/UV"
|
2022-09-26 12:36:13 -05:00
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeUVPackIslands")
|
2025-09-27 18:57:18 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeUVTangent")
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeUVUnwrap")
|
|
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
class NODE_MT_gn_utilities_vector_base(node_add_menu.NodeMenu):
|
2022-09-26 12:36:13 -05:00
|
|
|
bl_label = "Vector"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Utilities/Vector"
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2025-05-08 04:28:22 +02:00
|
|
|
def draw(self, context):
|
2022-09-26 12:36:13 -05:00
|
|
|
layout = self.layout
|
2025-10-02 11:07:25 +02:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "ShaderNodeCombineXYZ")
|
2025-10-02 11:07:25 +02:00
|
|
|
props = self.node_operator(layout, "ShaderNodeMapRange")
|
|
|
|
|
ops = props.settings.add()
|
|
|
|
|
ops.name = "data_type"
|
|
|
|
|
ops.value = "'FLOAT_VECTOR'"
|
2025-09-25 16:12:02 +02:00
|
|
|
props = self.node_operator(layout, "ShaderNodeMix", label="Mix Vector")
|
2023-01-09 18:09:22 +01:00
|
|
|
ops = props.settings.add()
|
|
|
|
|
ops.name = "data_type"
|
|
|
|
|
ops.value = "'VECTOR'"
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "ShaderNodeSeparateXYZ")
|
2025-10-06 19:09:01 +02:00
|
|
|
layout.separator()
|
2025-10-02 11:07:25 +02:00
|
|
|
self.node_operator(layout, "ShaderNodeRadialTiling")
|
|
|
|
|
self.node_operator(layout, "ShaderNodeVectorCurve")
|
|
|
|
|
self.node_operator_with_searchable_enum(context, layout, "ShaderNodeVectorMath", "operation")
|
|
|
|
|
self.node_operator(layout, "ShaderNodeVectorRotate")
|
2025-09-25 16:12:02 +02:00
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
class NODE_MT_gn_volume_base(node_add_menu.NodeMenu):
|
2022-09-26 12:36:13 -05:00
|
|
|
bl_label = "Volume"
|
2023-02-23 22:00:57 +01:00
|
|
|
bl_translation_context = i18n_contexts.id_id
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2023-03-23 15:31:14 +11:00
|
|
|
def draw(self, context):
|
2022-09-26 12:36:13 -05:00
|
|
|
layout = self.layout
|
2025-10-03 15:04:55 +02:00
|
|
|
self.draw_menu(layout, path="Volume/Read")
|
|
|
|
|
self.draw_menu(layout, path="Volume/Sample")
|
|
|
|
|
self.draw_menu(layout, path="Volume/Write")
|
|
|
|
|
layout.separator()
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_menu(layout, path="Volume/Operations")
|
|
|
|
|
self.draw_menu(layout, path="Volume/Primitives")
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_assets_for_catalog(layout, self.bl_label)
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
|
|
|
|
|
class NODE_MT_gn_volume_read_base(node_add_menu.NodeMenu):
|
2023-12-20 22:33:17 +01:00
|
|
|
bl_label = "Read"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Volume/Read"
|
2023-12-20 22:33:17 +01:00
|
|
|
|
|
|
|
|
def draw(self, context):
|
2025-09-26 14:28:46 +10:00
|
|
|
del context
|
2023-12-20 22:33:17 +01:00
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeGetNamedGrid")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeGridInfo")
|
2025-10-03 14:25:14 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeInputVoxelIndex")
|
2025-09-25 16:12:02 +02:00
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2023-12-20 22:33:17 +01:00
|
|
|
|
|
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
class NODE_MT_gn_volume_write_base(node_add_menu.NodeMenu):
|
2023-12-20 22:33:17 +01:00
|
|
|
bl_label = "Write"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Volume/Write"
|
2023-12-20 22:33:17 +01:00
|
|
|
|
|
|
|
|
def draw(self, context):
|
|
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeStoreNamedGrid")
|
2025-10-02 21:25:11 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeSetGridBackground")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSetGridTransform")
|
2023-12-20 22:33:17 +01:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2023-12-20 22:33:17 +01:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
|
|
|
|
|
class NODE_MT_gn_volume_sample_base(node_add_menu.NodeMenu):
|
2024-02-22 17:58:09 +01:00
|
|
|
bl_label = "Sample"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Volume/Sample"
|
2024-02-22 17:58:09 +01:00
|
|
|
|
|
|
|
|
def draw(self, context):
|
2025-09-26 14:28:46 +10:00
|
|
|
del context
|
2024-02-22 17:58:09 +01:00
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeSampleGrid")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSampleGridIndex")
|
2025-10-07 16:19:19 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeGridAdvect")
|
2025-10-02 16:28:46 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeGridCurl")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeGridDivergence")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeGridGradient")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeGridLaplacian")
|
2025-09-25 16:12:02 +02:00
|
|
|
|
|
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2024-02-22 17:58:09 +01:00
|
|
|
|
|
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
class NODE_MT_gn_volume_operations_base(node_add_menu.NodeMenu):
|
2023-12-20 22:33:17 +01:00
|
|
|
bl_label = "Operations"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Volume/Operations"
|
2023-12-20 22:33:17 +01:00
|
|
|
|
|
|
|
|
def draw(self, context):
|
2025-10-07 09:15:20 +11:00
|
|
|
del context
|
2023-12-20 22:33:17 +01:00
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeVolumeToMesh")
|
2025-10-03 15:04:55 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeGridToMesh")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSDFGridBoolean")
|
2025-10-06 17:54:25 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeSDFGridFillet")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSDFGridLaplacian")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSDFGridMean")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSDFGridMeanCurvature")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSDFGridMedian")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeSDFGridOffset")
|
2025-10-03 15:04:55 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeFieldToGrid")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeGridPrune")
|
|
|
|
|
self.node_operator(layout, "GeometryNodeGridVoxelize")
|
2023-12-20 22:33:17 +01:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2023-12-20 22:33:17 +01:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
|
|
|
|
|
class NODE_MT_gn_volume_primitives_base(node_add_menu.NodeMenu):
|
2023-12-20 22:33:17 +01:00
|
|
|
bl_label = "Primitives"
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Volume/Primitives"
|
2023-12-20 22:33:17 +01:00
|
|
|
|
|
|
|
|
def draw(self, context):
|
2025-09-26 14:28:46 +10:00
|
|
|
del context
|
2023-12-20 22:33:17 +01:00
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.node_operator(layout, "GeometryNodeVolumeCube")
|
2023-12-20 22:33:17 +01:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_assets_for_catalog(layout, self.menu_path)
|
2022-09-26 12:36:13 -05:00
|
|
|
|
|
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
class NODE_MT_gn_all_base(node_add_menu.NodeMenu):
|
2022-09-26 12:36:13 -05:00
|
|
|
bl_label = ""
|
2025-09-25 16:12:02 +02:00
|
|
|
menu_path = "Root"
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
# NOTE: Menus are looked up via their label, this is so that both the Add
|
|
|
|
|
# & Swap menus can share the same layout while each using their
|
|
|
|
|
# corresponding menus
|
2023-08-04 20:59:04 +02:00
|
|
|
def draw(self, context):
|
2025-09-26 14:28:46 +10:00
|
|
|
del context
|
2022-09-26 12:36:13 -05:00
|
|
|
layout = self.layout
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_menu(layout, "Input")
|
|
|
|
|
self.draw_menu(layout, "Output")
|
2023-01-09 18:09:22 +01:00
|
|
|
layout.separator()
|
2025-10-02 11:07:25 +02:00
|
|
|
self.draw_menu(layout, "Attribute")
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_menu(layout, "Geometry")
|
2023-01-09 18:09:22 +01:00
|
|
|
layout.separator()
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_menu(layout, "Curve")
|
|
|
|
|
self.draw_menu(layout, "Grease Pencil")
|
|
|
|
|
self.draw_menu(layout, "Instances")
|
|
|
|
|
self.draw_menu(layout, "Mesh")
|
|
|
|
|
self.draw_menu(layout, "Point")
|
|
|
|
|
self.draw_menu(layout, "Volume")
|
2023-01-09 18:09:22 +01:00
|
|
|
layout.separator()
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_menu(layout, "Simulation")
|
Geometry Nodes: add simulation support
This adds support for building simulations with geometry nodes. A new
`Simulation Input` and `Simulation Output` node allow maintaining a
simulation state across multiple frames. Together these two nodes form
a `simulation zone` which contains all the nodes that update the simulation
state from one frame to the next.
A new simulation zone can be added via the menu
(`Simulation > Simulation Zone`) or with the node add search.
The simulation state contains a geometry by default. However, it is possible
to add multiple geometry sockets as well as other socket types. Currently,
field inputs are evaluated and stored for the preceding geometry socket in
the order that the sockets are shown. Simulation state items can be added
by linking one of the empty sockets to something else. In the sidebar, there
is a new panel that allows adding, removing and reordering these sockets.
The simulation nodes behave as follows:
* On the first frame, the inputs of the `Simulation Input` node are evaluated
to initialize the simulation state. In later frames these sockets are not
evaluated anymore. The `Delta Time` at the first frame is zero, but the
simulation zone is still evaluated.
* On every next frame, the `Simulation Input` node outputs the simulation
state of the previous frame. Nodes in the simulation zone can edit that
data in arbitrary ways, also taking into account the `Delta Time`. The new
simulation state has to be passed to the `Simulation Output` node where it
is cached and forwarded.
* On a frame that is already cached or baked, the nodes in the simulation
zone are not evaluated, because the `Simulation Output` node can return
the previously cached data directly.
It is not allowed to connect sockets from inside the simulation zone to the
outside without going through the `Simulation Output` node. This is a necessary
restriction to make caching and sub-frame interpolation work. Links can go into
the simulation zone without problems though.
Anonymous attributes are not propagated by the simulation nodes unless they
are explicitly stored in the simulation state. This is unfortunate, but
currently there is no practical and reliable alternative. The core problem
is detecting which anonymous attributes will be required for the simulation
and afterwards. While we can detect this for the current evaluation, we can't
look into the future in time to see what data will be necessary. We intend to
make it easier to explicitly pass data through a simulation in the future,
even if the simulation is in a nested node group.
There is a new `Simulation Nodes` panel in the physics tab in the properties
editor. It allows baking all simulation zones on the selected objects. The
baking options are intentially kept at a minimum for this MVP. More features
for simulation baking as well as baking in general can be expected to be added
separately.
All baked data is stored on disk in a folder next to the .blend file. #106937
describes how baking is implemented in more detail. Volumes can not be baked
yet and materials are lost during baking for now. Packing the baked data into
the .blend file is not yet supported.
The timeline indicates which frames are currently cached, baked or cached but
invalidated by user-changes.
Simulation input and output nodes are internally linked together by their
`bNode.identifier` which stays the same even if the node name changes. They
are generally added and removed together. However, there are still cases where
"dangling" simulation nodes can be created currently. Those generally don't
cause harm, but would be nice to avoid this in more cases in the future.
Co-authored-by: Hans Goudey <h.goudey@me.com>
Co-authored-by: Lukas Tönne <lukas@blender.org>
Pull Request: https://projects.blender.org/blender/blender/pulls/104924
2023-05-03 13:18:51 +02:00
|
|
|
layout.separator()
|
2025-10-02 11:07:25 +02:00
|
|
|
self.draw_menu(layout, "Color")
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_menu(layout, "Texture")
|
|
|
|
|
self.draw_menu(layout, "Utilities")
|
2023-01-09 18:09:22 +01:00
|
|
|
layout.separator()
|
2025-10-02 11:07:25 +02:00
|
|
|
self.draw_root_assets(layout)
|
|
|
|
|
layout.separator()
|
2025-09-25 16:12:02 +02:00
|
|
|
self.draw_menu(layout, "Group")
|
|
|
|
|
self.draw_menu(layout, "Layout")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
add_menus = {
|
|
|
|
|
# menu bl_idname: baseclass
|
|
|
|
|
"NODE_MT_geometry_node_GEO_ATTRIBUTE": NODE_MT_gn_attribute_base,
|
|
|
|
|
"NODE_MT_geometry_node_GEO_INPUT": NODE_MT_gn_input_base,
|
|
|
|
|
"NODE_MT_geometry_node_GEO_INPUT_CONSTANT": NODE_MT_gn_input_constant_base,
|
|
|
|
|
"NODE_MT_geometry_node_GEO_INPUT_GIZMO": NODE_MT_gn_input_gizmo_base,
|
|
|
|
|
"NODE_MT_geometry_node_GEO_INPUT_GROUP": NODE_MT_gn_input_group_base,
|
|
|
|
|
"NODE_MT_category_import": NODE_MT_gn_input_import_base,
|
|
|
|
|
"NODE_MT_geometry_node_GEO_INPUT_SCENE": NODE_MT_gn_input_scene_base,
|
|
|
|
|
"NODE_MT_category_GEO_OUTPUT": NODE_MT_gn_output_base,
|
|
|
|
|
"NODE_MT_geometry_node_GEO_CURVE": NODE_MT_gn_curve_base,
|
|
|
|
|
"NODE_MT_geometry_node_GEO_CURVE_READ": NODE_MT_gn_curve_read_base,
|
|
|
|
|
"NODE_MT_geometry_node_GEO_CURVE_SAMPLE": NODE_MT_gn_curve_sample_base,
|
|
|
|
|
"NODE_MT_geometry_node_GEO_CURVE_WRITE": NODE_MT_gn_curve_write_base,
|
|
|
|
|
"NODE_MT_geometry_node_GEO_CURVE_OPERATIONS": NODE_MT_gn_curve_operations_base,
|
|
|
|
|
"NODE_MT_geometry_node_GEO_PRIMITIVES_CURVE": NODE_MT_gn_curve_primitives_base,
|
|
|
|
|
"NODE_MT_geometry_node_curve_topology": NODE_MT_gn_curve_topology_base,
|
|
|
|
|
"NODE_MT_geometry_node_grease_pencil": NODE_MT_gn_grease_pencil_base,
|
|
|
|
|
"NODE_MT_geometry_node_grease_pencil_read": NODE_MT_gn_grease_pencil_read_base,
|
|
|
|
|
"NODE_MT_geometry_node_grease_pencil_write": NODE_MT_gn_grease_pencil_write_base,
|
|
|
|
|
"NODE_MT_geometry_node_grease_pencil_operations": NODE_MT_gn_grease_pencil_operations_base,
|
|
|
|
|
"NODE_MT_geometry_node_GEO_GEOMETRY": NODE_MT_gn_geometry_base,
|
|
|
|
|
"NODE_MT_geometry_node_GEO_GEOMETRY_READ": NODE_MT_gn_geometry_read_base,
|
|
|
|
|
"NODE_MT_geometry_node_GEO_GEOMETRY_WRITE": NODE_MT_gn_geometry_write_base,
|
|
|
|
|
"NODE_MT_geometry_node_GEO_GEOMETRY_OPERATIONS": NODE_MT_gn_geometry_operations_base,
|
|
|
|
|
"NODE_MT_geometry_node_GEO_GEOMETRY_SAMPLE": NODE_MT_gn_geometry_sample_base,
|
|
|
|
|
"NODE_MT_geometry_node_GEO_INSTANCE": NODE_MT_gn_instance_base,
|
|
|
|
|
"NODE_MT_geometry_node_GEO_MESH": NODE_MT_gn_mesh_base,
|
|
|
|
|
"NODE_MT_geometry_node_GEO_MESH_READ": NODE_MT_gn_mesh_read_base,
|
|
|
|
|
"NODE_MT_geometry_node_GEO_MESH_SAMPLE": NODE_MT_gn_mesh_sample_base,
|
|
|
|
|
"NODE_MT_geometry_node_GEO_MESH_WRITE": NODE_MT_gn_mesh_write_base,
|
|
|
|
|
"NODE_MT_geometry_node_GEO_MESH_OPERATIONS": NODE_MT_gn_mesh_operations_base,
|
|
|
|
|
"NODE_MT_category_PRIMITIVES_MESH": NODE_MT_gn_mesh_uv_base,
|
|
|
|
|
"NODE_MT_geometry_node_mesh_topology": NODE_MT_gn_mesh_topology_base,
|
|
|
|
|
"NODE_MT_category_GEO_UV": NODE_MT_gn_mesh_primitives_base,
|
|
|
|
|
"NODE_MT_category_GEO_POINT": NODE_MT_gn_point_base,
|
|
|
|
|
"NODE_MT_category_simulation": NODE_MT_gn_simulation_base,
|
|
|
|
|
"NODE_MT_category_GEO_VOLUME": NODE_MT_gn_volume_base,
|
|
|
|
|
"NODE_MT_geometry_node_GEO_VOLUME_READ": NODE_MT_gn_volume_read_base,
|
|
|
|
|
"NODE_MT_geometry_node_volume_sample": NODE_MT_gn_volume_sample_base,
|
|
|
|
|
"NODE_MT_geometry_node_GEO_VOLUME_WRITE": NODE_MT_gn_volume_write_base,
|
|
|
|
|
"NODE_MT_geometry_node_GEO_VOLUME_OPERATIONS": NODE_MT_gn_volume_operations_base,
|
|
|
|
|
"NODE_MT_geometry_node_GEO_VOLUME_PRIMITIVES": NODE_MT_gn_volume_primitives_base,
|
2025-10-02 11:07:25 +02:00
|
|
|
"NODE_MT_geometry_node_GEO_COLOR": NODE_MT_gn_color_base,
|
2025-09-25 16:12:02 +02:00
|
|
|
"NODE_MT_geometry_node_GEO_MATERIAL": NODE_MT_gn_material_base,
|
|
|
|
|
"NODE_MT_category_GEO_TEXTURE": NODE_MT_gn_texture_base,
|
|
|
|
|
"NODE_MT_category_GEO_UTILITIES": NODE_MT_gn_utilities_base,
|
|
|
|
|
"NODE_MT_category_GEO_TEXT": NODE_MT_gn_utilities_text_base,
|
|
|
|
|
"NODE_MT_category_GEO_VECTOR": NODE_MT_gn_utilities_vector_base,
|
|
|
|
|
"NODE_MT_category_utilities_bundle": NODE_MT_category_utilities_bundle_base,
|
|
|
|
|
"NODE_MT_category_utilities_closure": NODE_MT_category_utilities_closure_base,
|
|
|
|
|
"NODE_MT_category_GEO_UTILITIES_FIELD": NODE_MT_gn_utilities_field_base,
|
|
|
|
|
"NODE_MT_category_GEO_UTILITIES_MATH": NODE_MT_gn_utilities_math_base,
|
|
|
|
|
"NODE_MT_category_GEO_UTILITIES_ROTATION": NODE_MT_gn_utilities_rotation_base,
|
|
|
|
|
"NODE_MT_category_utilities_list": NODE_MT_gn_utilities_list_base,
|
|
|
|
|
"NODE_MT_category_utilities_matrix": NODE_MT_gn_utilities_matrix_base,
|
|
|
|
|
"NODE_MT_category_GEO_UTILITIES_DEPRECATED": NODE_MT_gn_utilities_deprecated_base,
|
|
|
|
|
"NODE_MT_geometry_node_add_all": NODE_MT_gn_all_base,
|
|
|
|
|
}
|
|
|
|
|
add_menus = node_add_menu.generate_menus(
|
|
|
|
|
add_menus,
|
|
|
|
|
template=node_add_menu.AddNodeMenu,
|
|
|
|
|
base_dict=node_add_menu.add_base_pathing_dict
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
swap_menus = {
|
|
|
|
|
# menu bl_idname: baseclass
|
|
|
|
|
"NODE_MT_gn_attribute_swap": NODE_MT_gn_attribute_base,
|
|
|
|
|
"NODE_MT_gn_input_swap": NODE_MT_gn_input_base,
|
|
|
|
|
"NODE_MT_gn_input_constant_swap": NODE_MT_gn_input_constant_base,
|
|
|
|
|
"NODE_MT_gn_input_gizmo_swap": NODE_MT_gn_input_gizmo_base,
|
|
|
|
|
"NODE_MT_gn_input_group_swap": NODE_MT_gn_input_group_base,
|
|
|
|
|
"NODE_MT_gn_input_import_swap": NODE_MT_gn_input_import_base,
|
|
|
|
|
"NODE_MT_gn_input_scene_swap": NODE_MT_gn_input_scene_base,
|
|
|
|
|
"NODE_MT_gn_output_swap": NODE_MT_gn_output_base,
|
|
|
|
|
"NODE_MT_gn_curve_swap": NODE_MT_gn_curve_base,
|
|
|
|
|
"NODE_MT_gn_curve_read_swap": NODE_MT_gn_curve_read_base,
|
|
|
|
|
"NODE_MT_gn_curve_sample_swap": NODE_MT_gn_curve_sample_base,
|
|
|
|
|
"NODE_MT_gn_curve_write_swap": NODE_MT_gn_curve_write_base,
|
|
|
|
|
"NODE_MT_gn_curve_operations_swap": NODE_MT_gn_curve_operations_base,
|
|
|
|
|
"NODE_MT_gn_curve_primitives_swap": NODE_MT_gn_curve_primitives_base,
|
|
|
|
|
"NODE_MT_gn_curve_topology_swap": NODE_MT_gn_curve_topology_base,
|
|
|
|
|
"NODE_MT_gn_grease_pencil_swap": NODE_MT_gn_grease_pencil_base,
|
|
|
|
|
"NODE_MT_gn_grease_pencil_read_swap": NODE_MT_gn_grease_pencil_read_base,
|
|
|
|
|
"NODE_MT_gn_grease_pencil_write_swap": NODE_MT_gn_grease_pencil_write_base,
|
|
|
|
|
"NODE_MT_gn_grease_pencil_operations_swap": NODE_MT_gn_grease_pencil_operations_base,
|
|
|
|
|
"NODE_MT_gn_geometry_swap": NODE_MT_gn_geometry_base,
|
|
|
|
|
"NODE_MT_gn_geometry_read_swap": NODE_MT_gn_geometry_read_base,
|
|
|
|
|
"NODE_MT_gn_geometry_write_swap": NODE_MT_gn_geometry_write_base,
|
|
|
|
|
"NODE_MT_gn_geometry_operations_swap": NODE_MT_gn_geometry_operations_base,
|
|
|
|
|
"NODE_MT_gn_geometry_sample_swap": NODE_MT_gn_geometry_sample_base,
|
|
|
|
|
"NODE_MT_gn_instance_swap": NODE_MT_gn_instance_base,
|
|
|
|
|
"NODE_MT_gn_mesh_swap": NODE_MT_gn_mesh_base,
|
|
|
|
|
"NODE_MT_gn_mesh_read_swap": NODE_MT_gn_mesh_read_base,
|
|
|
|
|
"NODE_MT_gn_mesh_sample_swap": NODE_MT_gn_mesh_sample_base,
|
|
|
|
|
"NODE_MT_gn_mesh_write_swap": NODE_MT_gn_mesh_write_base,
|
|
|
|
|
"NODE_MT_gn_mesh_operations_swap": NODE_MT_gn_mesh_operations_base,
|
|
|
|
|
"NODE_MT_gn_mesh_uv_swap": NODE_MT_gn_mesh_uv_base,
|
|
|
|
|
"NODE_MT_gn_mesh_topology_swap": NODE_MT_gn_mesh_topology_base,
|
|
|
|
|
"NODE_MT_gn_mesh_primitives_swap": NODE_MT_gn_mesh_primitives_base,
|
|
|
|
|
"NODE_MT_gn_point_swap": NODE_MT_gn_point_base,
|
|
|
|
|
"NODE_MT_gn_simulation_swap": NODE_MT_gn_simulation_base,
|
|
|
|
|
"NODE_MT_gn_volume_swap": NODE_MT_gn_volume_base,
|
|
|
|
|
"NODE_MT_gn_volume_read_swap": NODE_MT_gn_volume_read_base,
|
|
|
|
|
"NODE_MT_gn_volume_sample_swap": NODE_MT_gn_volume_sample_base,
|
|
|
|
|
"NODE_MT_gn_volume_write_swap": NODE_MT_gn_volume_write_base,
|
|
|
|
|
"NODE_MT_gn_volume_operations_swap": NODE_MT_gn_volume_operations_base,
|
|
|
|
|
"NODE_MT_gn_volume_primitives_swap": NODE_MT_gn_volume_primitives_base,
|
2025-10-02 11:07:25 +02:00
|
|
|
"NODE_MT_gn_color_swap": NODE_MT_gn_color_base,
|
2025-09-25 16:12:02 +02:00
|
|
|
"NODE_MT_gn_material_swap": NODE_MT_gn_material_base,
|
|
|
|
|
"NODE_MT_gn_texture_swap": NODE_MT_gn_texture_base,
|
|
|
|
|
"NODE_MT_gn_utilities_swap": NODE_MT_gn_utilities_base,
|
|
|
|
|
"NODE_MT_gn_utilities_text_swap": NODE_MT_gn_utilities_text_base,
|
|
|
|
|
"NODE_MT_gn_utilities_vector_swap": NODE_MT_gn_utilities_vector_base,
|
|
|
|
|
"NODE_MT_gn_utilities_bundle_swap": NODE_MT_category_utilities_bundle_base,
|
|
|
|
|
"NODE_MT_gn_utilities_closure_swap": NODE_MT_category_utilities_closure_base,
|
|
|
|
|
"NODE_MT_gn_utilities_field_swap": NODE_MT_gn_utilities_field_base,
|
|
|
|
|
"NODE_MT_gn_utilities_math_swap": NODE_MT_gn_utilities_math_base,
|
|
|
|
|
"NODE_MT_gn_utilities_rotation_swap": NODE_MT_gn_utilities_rotation_base,
|
|
|
|
|
"NODE_MT_gn_utilities_list_swap": NODE_MT_gn_utilities_list_base,
|
|
|
|
|
"NODE_MT_gn_utilities_matrix_swap": NODE_MT_gn_utilities_matrix_base,
|
|
|
|
|
"NODE_MT_gn_utilities_deprecated_swap": NODE_MT_gn_utilities_deprecated_base,
|
|
|
|
|
"NODE_MT_geometry_node_swap_all": NODE_MT_gn_all_base,
|
|
|
|
|
}
|
|
|
|
|
swap_menus = node_add_menu.generate_menus(
|
|
|
|
|
swap_menus,
|
|
|
|
|
template=node_add_menu.SwapNodeMenu,
|
|
|
|
|
base_dict=node_add_menu.swap_base_pathing_dict
|
|
|
|
|
)
|
2022-09-26 12:36:13 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
classes = (
|
2025-09-25 16:12:02 +02:00
|
|
|
*add_menus,
|
|
|
|
|
*swap_menus,
|
2022-09-26 12:36:13 -05:00
|
|
|
)
|
|
|
|
|
|
2025-09-25 16:12:02 +02:00
|
|
|
|
2022-09-26 12:36:13 -05:00
|
|
|
if __name__ == "__main__": # only for live edit.
|
|
|
|
|
from bpy.utils import register_class
|
|
|
|
|
for cls in classes:
|
|
|
|
|
register_class(cls)
|