Files
test/scripts/startup/bl_ui/node_add_menu_geometry.py
Jacques Lucke 182797ea61 Geometry Nodes: new Format String node
This adds a new Format String node which simplifies constructing strings from
multiple values. The node takes a format string and a dynamic number of
additional parameters as input. The format string determines how the other
inputs are inserted into the string. Only integer, float and string inputs are
supported for now.

It supports two different format syntaxes:
* Python compatible format syntax which also mostly matches the behavior of the
  `fmt` C++ library. Most of this is supported, but there are some small
  limitations.
* Syntax of the form `###.##` where each `#` stands for a digit. This is the
  syntax that was introduced in #134860.

This node greatly simplifies common string operations which would have required
potentially many nodes before to convert numbers to strings and to concatenate
them. It also makes new conversions possible that were not supported before.
This node can also be used to insert e.g. frame numbers into a file path which
was surprisingly complex before.

This node has special behavior for the name of new inputs. For the purpose of
the node, the name of the inputs must be valid identifiers and it's usually
helpful when they are short. New names are therefore initialized to be single
characters. If possible, the first character of the linked input is used. This
works well when connecting e.g. a Separate Vector/Color node. Otherwise, inputs
are named `a` to `z` by default. If that's not possible, the source socket name
is used instead (converted to be a valid identifier). If that still doesn't
work, the name is made unique using the normal `.001` mechanism except that `_`
instead of `.` is used as separator to make the name a valid identifier.

Python Syntax references:
* Python: https://docs.python.org/3/library/string.html#formatspec
* `fmt`: https://fmt.dev/latest/syntax/

More detailed notes about compatibility with the above syntax specifications:
* Conversion using e.g. `!r` like in Python is not supported (maybe the future).
* Sub-attribute access like `{vector.x}` is not supported (maybe the future).
* Using `%` like in Python is not supported (maybe in future).
* Using `#` for an alternate form is not supported. This might help in the
  future to make the syntax compatible with #134860.
* Using `L` like in the `fmt` library is not supported because it depends on the
  locale which is not good for determinism.
* Grouping with e.g. thousands separators using e.g. `,` or `_` like in Python
  is not supported (maybe in future). Need to think about the locale here too.
* Mixing of unnamed (`{}`) and named (`{x} or {0}`) specifiers is allowed.
  However, all unnamed specifiers must come before any named specifier.

The implementation uses the `fmt` library for the actual formatting. However,
the inputs are preprocessed to give us more control over the exact supported
syntax and error messages. The code is already somewhat written so that many
strings could be formatted with the same format but that's not actually used yet
because we don't have string fields yet.

Error messages are propagated using a new mechanism that allows a limited form
of error propagation from multi-functions to the node that evaluates them.
Currently, this only works in fairly limited circumstances, e.g. it does not
work during field evaluation. Since this node is never part of field evaluation
yet, that limitation seems ok, but it's something to work on at some point.
Properly supporting that requires some more changes to propagate enough context
information everywhere. Also showing errors of field evaluation on the field
node itself (instead of on the evaluation node) requires even more work because
our current logging system is not setup to support that yet.

This node comes with a few new requirements for the socket items system: names
must be valid identifiers and they are initialized in a non-trivial way.
Overall, this was fairly straight forward to implement but currently it requires
to adding a bunch of new members to all the accessors that don't really need it.
This is something that we should simplify at some point even if I'm not entirely
sure how yet. The same new requirements used in this node would probably also
exist in a potential future expression node.

Pull Request: https://projects.blender.org/blender/blender/pulls/138860
2025-05-29 13:17:03 +02:00

967 lines
44 KiB
Python

# SPDX-FileCopyrightText: 2022-2023 Blender Authors
#
# SPDX-License-Identifier: GPL-2.0-or-later
import bpy
from bpy.types import Menu
from bl_ui import node_add_menu
from bpy.app.translations import (
pgettext_iface as iface_,
contexts as i18n_contexts,
)
class NODE_MT_geometry_node_GEO_ATTRIBUTE(Menu):
bl_idname = "NODE_MT_geometry_node_GEO_ATTRIBUTE"
bl_label = "Attribute"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeAttributeStatistic")
node_add_menu.add_node_type(layout, "GeometryNodeAttributeDomainSize")
layout.separator()
node_add_menu.add_node_type(layout, "GeometryNodeBlurAttribute")
node_add_menu.add_node_type(layout, "GeometryNodeCaptureAttribute")
node_add_menu.add_node_type(layout, "GeometryNodeRemoveAttribute")
node_add_menu.add_node_type(layout, "GeometryNodeStoreNamedAttribute", search_weight=1.0)
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_geometry_node_GEO_COLOR(Menu):
bl_idname = "NODE_MT_geometry_node_GEO_COLOR"
bl_label = "Color"
def draw(self, context):
layout = self.layout
node_add_menu.add_node_type(layout, "ShaderNodeBlackbody")
node_add_menu.add_node_type(layout, "ShaderNodeValToRGB")
node_add_menu.add_node_type(layout, "ShaderNodeRGBCurve")
layout.separator()
node_add_menu.add_node_type(layout, "FunctionNodeCombineColor")
node_add_menu.add_color_mix_node(context, layout)
node_add_menu.add_node_type(layout, "FunctionNodeSeparateColor")
node_add_menu.draw_assets_for_catalog(layout, "Utilities/Color")
class NODE_MT_geometry_node_GEO_CURVE(Menu):
bl_idname = "NODE_MT_geometry_node_GEO_CURVE"
bl_label = "Curve"
def draw(self, _context):
layout = self.layout
layout.menu("NODE_MT_geometry_node_GEO_CURVE_READ")
layout.menu("NODE_MT_geometry_node_GEO_CURVE_SAMPLE")
layout.menu("NODE_MT_geometry_node_GEO_CURVE_WRITE")
layout.separator()
layout.menu("NODE_MT_geometry_node_GEO_CURVE_OPERATIONS")
layout.menu("NODE_MT_geometry_node_GEO_PRIMITIVES_CURVE")
layout.menu("NODE_MT_geometry_node_curve_topology")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_geometry_node_GEO_CURVE_READ(Menu):
bl_idname = "NODE_MT_geometry_node_GEO_CURVE_READ"
bl_label = "Read"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeInputCurveHandlePositions")
node_add_menu.add_node_type(layout, "GeometryNodeCurveLength")
node_add_menu.add_node_type(layout, "GeometryNodeInputTangent")
node_add_menu.add_node_type(layout, "GeometryNodeInputCurveTilt")
node_add_menu.add_node_type(layout, "GeometryNodeCurveEndpointSelection")
node_add_menu.add_node_type(layout, "GeometryNodeCurveHandleTypeSelection")
node_add_menu.add_node_type(layout, "GeometryNodeInputSplineCyclic")
node_add_menu.add_node_type(layout, "GeometryNodeSplineLength")
node_add_menu.add_node_type(layout, "GeometryNodeSplineParameter")
node_add_menu.add_node_type(layout, "GeometryNodeInputSplineResolution")
node_add_menu.draw_assets_for_catalog(layout, "Curve/Read")
class NODE_MT_geometry_node_GEO_CURVE_SAMPLE(Menu):
bl_idname = "NODE_MT_geometry_node_GEO_CURVE_SAMPLE"
bl_label = "Sample"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeSampleCurve")
node_add_menu.draw_assets_for_catalog(layout, "Curve/Sample")
class NODE_MT_geometry_node_GEO_CURVE_WRITE(Menu):
bl_idname = "NODE_MT_geometry_node_GEO_CURVE_WRITE"
bl_label = "Write"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeSetCurveNormal")
node_add_menu.add_node_type(layout, "GeometryNodeSetCurveRadius")
node_add_menu.add_node_type(layout, "GeometryNodeSetCurveTilt")
node_add_menu.add_node_type(layout, "GeometryNodeSetCurveHandlePositions")
node_add_menu.add_node_type(layout, "GeometryNodeCurveSetHandles")
node_add_menu.add_node_type(layout, "GeometryNodeSetSplineCyclic")
node_add_menu.add_node_type(layout, "GeometryNodeSetSplineResolution")
node_add_menu.add_node_type(layout, "GeometryNodeCurveSplineType")
node_add_menu.draw_assets_for_catalog(layout, "Curve/Write")
class NODE_MT_geometry_node_GEO_CURVE_OPERATIONS(Menu):
bl_idname = "NODE_MT_geometry_node_GEO_CURVE_OPERATIONS"
bl_label = "Operations"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeCurvesToGreasePencil")
node_add_menu.add_node_type(layout, "GeometryNodeCurveToMesh")
node_add_menu.add_node_type(layout, "GeometryNodeCurveToPoints")
node_add_menu.add_node_type(layout, "GeometryNodeDeformCurvesOnSurface")
node_add_menu.add_node_type(layout, "GeometryNodeFillCurve")
node_add_menu.add_node_type(layout, "GeometryNodeFilletCurve")
node_add_menu.add_node_type(layout, "GeometryNodeInterpolateCurves")
node_add_menu.add_node_type(layout, "GeometryNodeResampleCurve")
node_add_menu.add_node_type(layout, "GeometryNodeReverseCurve")
node_add_menu.add_node_type(layout, "GeometryNodeSubdivideCurve")
node_add_menu.add_node_type(layout, "GeometryNodeTrimCurve")
node_add_menu.draw_assets_for_catalog(layout, "Curve/Operations")
class NODE_MT_geometry_node_GEO_PRIMITIVES_CURVE(Menu):
bl_idname = "NODE_MT_geometry_node_GEO_PRIMITIVES_CURVE"
bl_label = "Primitives"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeCurveArc")
node_add_menu.add_node_type(layout, "GeometryNodeCurvePrimitiveBezierSegment")
node_add_menu.add_node_type(layout, "GeometryNodeCurvePrimitiveCircle")
node_add_menu.add_node_type(layout, "GeometryNodeCurvePrimitiveLine")
node_add_menu.add_node_type(layout, "GeometryNodeCurveSpiral")
node_add_menu.add_node_type(layout, "GeometryNodeCurveQuadraticBezier")
node_add_menu.add_node_type(layout, "GeometryNodeCurvePrimitiveQuadrilateral")
node_add_menu.add_node_type(layout, "GeometryNodeCurveStar")
node_add_menu.draw_assets_for_catalog(layout, "Curve/Primitives")
class NODE_MT_geometry_node_curve_topology(Menu):
bl_idname = "NODE_MT_geometry_node_curve_topology"
bl_label = "Topology"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeCurveOfPoint")
node_add_menu.add_node_type(layout, "GeometryNodeOffsetPointInCurve")
node_add_menu.add_node_type(layout, "GeometryNodePointsOfCurve")
node_add_menu.draw_assets_for_catalog(layout, "Curve/Topology")
class NODE_MT_geometry_node_grease_pencil_read(Menu):
bl_idname = "NODE_MT_geometry_node_grease_pencil_read"
bl_label = "Read"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeInputNamedLayerSelection")
node_add_menu.draw_assets_for_catalog(layout, "Grease Pencil/Read")
class NODE_MT_geometry_node_grease_pencil_write(Menu):
bl_idname = "NODE_MT_geometry_node_grease_pencil_write"
bl_label = "Write"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeSetGreasePencilColor")
node_add_menu.add_node_type(layout, "GeometryNodeSetGreasePencilDepth")
node_add_menu.add_node_type(layout, "GeometryNodeSetGreasePencilSoftness")
node_add_menu.draw_assets_for_catalog(layout, "Grease Pencil/Write")
class NODE_MT_geometry_node_grease_pencil_operations(Menu):
bl_idname = "NODE_MT_geometry_node_grease_pencil_operations"
bl_label = "Operations"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeGreasePencilToCurves")
node_add_menu.add_node_type(layout, "GeometryNodeMergeLayers")
node_add_menu.draw_assets_for_catalog(layout, "Grease Pencil/Operations")
class NODE_MT_geometry_node_grease_pencil(Menu):
bl_idname = "NODE_MT_geometry_node_grease_pencil"
bl_label = "Grease Pencil"
def draw(self, _context):
layout = self.layout
layout.menu("NODE_MT_geometry_node_grease_pencil_read")
layout.menu("NODE_MT_geometry_node_grease_pencil_write")
layout.separator()
layout.menu("NODE_MT_geometry_node_grease_pencil_operations")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_geometry_node_GEO_GEOMETRY(Menu):
bl_idname = "NODE_MT_geometry_node_GEO_GEOMETRY"
bl_label = "Geometry"
def draw(self, _context):
layout = self.layout
layout.menu("NODE_MT_geometry_node_GEO_GEOMETRY_READ")
layout.menu("NODE_MT_geometry_node_GEO_GEOMETRY_SAMPLE")
layout.menu("NODE_MT_geometry_node_GEO_GEOMETRY_WRITE")
layout.separator()
layout.menu("NODE_MT_geometry_node_GEO_GEOMETRY_OPERATIONS")
layout.separator()
node_add_menu.add_node_type(layout, "GeometryNodeGeometryToInstance")
node_add_menu.add_node_type(layout, "GeometryNodeJoinGeometry", search_weight=1.0)
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_geometry_node_GEO_GEOMETRY_READ(Menu):
bl_idname = "NODE_MT_geometry_node_GEO_GEOMETRY_READ"
bl_label = "Read"
def draw(self, context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeInputID")
node_add_menu.add_node_type(layout, "GeometryNodeInputIndex")
node_add_menu.add_node_type(layout, "GeometryNodeInputNamedAttribute", search_weight=1.0)
node_add_menu.add_node_type(layout, "GeometryNodeInputNormal")
node_add_menu.add_node_type(layout, "GeometryNodeInputPosition", search_weight=1.0)
node_add_menu.add_node_type(layout, "GeometryNodeInputRadius")
if context.space_data.geometry_nodes_type == 'TOOL':
node_add_menu.add_node_type(layout, "GeometryNodeToolSelection")
node_add_menu.add_node_type(layout, "GeometryNodeToolActiveElement")
node_add_menu.draw_assets_for_catalog(layout, "Geometry/Read")
class NODE_MT_geometry_node_GEO_GEOMETRY_WRITE(Menu):
bl_idname = "NODE_MT_geometry_node_GEO_GEOMETRY_WRITE"
bl_label = "Write"
def draw(self, context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeSetGeometryName")
node_add_menu.add_node_type(layout, "GeometryNodeSetID")
node_add_menu.add_node_type(layout, "GeometryNodeSetPosition", search_weight=1.0)
if context.space_data.geometry_nodes_type == 'TOOL':
node_add_menu.add_node_type(layout, "GeometryNodeToolSetSelection")
node_add_menu.draw_assets_for_catalog(layout, "Geometry/Write")
class NODE_MT_geometry_node_GEO_GEOMETRY_OPERATIONS(Menu):
bl_idname = "NODE_MT_geometry_node_GEO_GEOMETRY_OPERATIONS"
bl_label = "Operations"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeBake")
node_add_menu.add_node_type(layout, "GeometryNodeBoundBox")
node_add_menu.add_node_type(layout, "GeometryNodeConvexHull")
node_add_menu.add_node_type(layout, "GeometryNodeDeleteGeometry")
node_add_menu.add_node_type(layout, "GeometryNodeDuplicateElements")
node_add_menu.add_node_type(layout, "GeometryNodeMergeByDistance")
node_add_menu.add_node_type(layout, "GeometryNodeSortElements")
node_add_menu.add_node_type(layout, "GeometryNodeTransform", search_weight=1.0)
layout.separator()
node_add_menu.add_node_type(layout, "GeometryNodeSeparateComponents")
node_add_menu.add_node_type(layout, "GeometryNodeSeparateGeometry")
node_add_menu.add_node_type(layout, "GeometryNodeSplitToInstances")
node_add_menu.draw_assets_for_catalog(layout, "Geometry/Operations")
class NODE_MT_geometry_node_GEO_GEOMETRY_SAMPLE(Menu):
bl_idname = "NODE_MT_geometry_node_GEO_GEOMETRY_SAMPLE"
bl_label = "Sample"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeProximity")
node_add_menu.add_node_type(layout, "GeometryNodeIndexOfNearest")
node_add_menu.add_node_type(layout, "GeometryNodeRaycast")
node_add_menu.add_node_type(layout, "GeometryNodeSampleIndex")
node_add_menu.add_node_type(layout, "GeometryNodeSampleNearest")
node_add_menu.draw_assets_for_catalog(layout, "Geometry/Sample")
class NODE_MT_geometry_node_GEO_INPUT(Menu):
bl_idname = "NODE_MT_geometry_node_GEO_INPUT"
bl_label = "Input"
def draw(self, context):
layout = self.layout
layout.menu("NODE_MT_geometry_node_GEO_INPUT_CONSTANT")
if context.space_data.geometry_nodes_type != 'TOOL':
layout.menu("NODE_MT_geometry_node_GEO_INPUT_GIZMO")
layout.menu("NODE_MT_geometry_node_GEO_INPUT_GROUP")
layout.menu("NODE_MT_category_import")
layout.menu("NODE_MT_geometry_node_GEO_INPUT_SCENE")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_geometry_node_GEO_INPUT_CONSTANT(Menu):
bl_idname = "NODE_MT_geometry_node_GEO_INPUT_CONSTANT"
bl_label = "Constant"
bl_translation_context = i18n_contexts.id_nodetree
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "FunctionNodeInputBool")
node_add_menu.add_node_type(layout, "GeometryNodeInputCollection")
node_add_menu.add_node_type(layout, "FunctionNodeInputColor")
node_add_menu.add_node_type(layout, "GeometryNodeInputImage")
node_add_menu.add_node_type(layout, "FunctionNodeInputInt")
node_add_menu.add_node_type(layout, "GeometryNodeInputMaterial")
node_add_menu.add_node_type(layout, "GeometryNodeInputObject")
node_add_menu.add_node_type(layout, "FunctionNodeInputRotation")
node_add_menu.add_node_type(layout, "FunctionNodeInputString")
node_add_menu.add_node_type(layout, "ShaderNodeValue")
node_add_menu.add_node_type(layout, "FunctionNodeInputVector")
node_add_menu.draw_assets_for_catalog(layout, "Input/Constant")
class NODE_MT_geometry_node_GEO_INPUT_GROUP(Menu):
bl_idname = "NODE_MT_geometry_node_GEO_INPUT_GROUP"
bl_label = "Group"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "NodeGroupInput")
node_add_menu.draw_assets_for_catalog(layout, "Input/Group")
class NODE_MT_geometry_node_GEO_INPUT_SCENE(Menu):
bl_idname = "NODE_MT_geometry_node_GEO_INPUT_SCENE"
bl_label = "Scene"
def draw(self, context):
layout = self.layout
if context.space_data.geometry_nodes_type == 'TOOL':
node_add_menu.add_node_type(layout, "GeometryNodeTool3DCursor")
node_add_menu.add_node_type(layout, "GeometryNodeInputActiveCamera")
node_add_menu.add_node_type_with_outputs(context,
layout,
"GeometryNodeCameraInfo",
["Projection Matrix",
"Focal Length",
"Sensor",
"Shift",
"Clip Start",
"Clip End",
"Focus Distance",
"Is Orthographic",
"Orthographic Scale"])
node_add_menu.add_node_type(layout, "GeometryNodeCollectionInfo")
node_add_menu.add_node_type(layout, "GeometryNodeImageInfo")
node_add_menu.add_node_type(layout, "GeometryNodeIsViewport")
if context.space_data.geometry_nodes_type == 'TOOL':
node_add_menu.add_node_type_with_outputs(
context, layout, "GeometryNodeToolMousePosition", [
"Mouse X", "Mouse Y", "Region Width", "Region Height"])
node_add_menu.add_node_type(layout, "GeometryNodeObjectInfo")
node_add_menu.add_node_type_with_outputs(context, layout, "GeometryNodeInputSceneTime", ["Frame", "Seconds"])
node_add_menu.add_node_type(layout, "GeometryNodeSelfObject")
if context.space_data.geometry_nodes_type == 'TOOL':
node_add_menu.add_node_type_with_outputs(
context, layout, "GeometryNodeViewportTransform", [
"Projection", "View", "Is Orthographic"])
node_add_menu.draw_assets_for_catalog(layout, "Input/Scene")
class NODE_MT_geometry_node_GEO_INPUT_GIZMO(Menu):
bl_idname = "NODE_MT_geometry_node_GEO_INPUT_GIZMO"
bl_label = "Gizmo"
def draw(self, context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeGizmoDial")
node_add_menu.add_node_type(layout, "GeometryNodeGizmoLinear")
node_add_menu.add_node_type(layout, "GeometryNodeGizmoTransform")
node_add_menu.draw_assets_for_catalog(layout, "Input/Gizmo")
class NODE_MT_geometry_node_GEO_INSTANCE(Menu):
bl_idname = "NODE_MT_geometry_node_GEO_INSTANCE"
bl_label = "Instances"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeInstanceOnPoints", search_weight=2.0)
node_add_menu.add_node_type(layout, "GeometryNodeInstancesToPoints")
layout.separator()
node_add_menu.add_node_type(layout, "GeometryNodeRealizeInstances", search_weight=1.0)
node_add_menu.add_node_type(layout, "GeometryNodeRotateInstances")
node_add_menu.add_node_type(layout, "GeometryNodeScaleInstances")
node_add_menu.add_node_type(layout, "GeometryNodeTranslateInstances")
node_add_menu.add_node_type(layout, "GeometryNodeSetInstanceTransform")
layout.separator()
node_add_menu.add_node_type(layout, "GeometryNodeInputInstanceBounds")
node_add_menu.add_node_type(layout, "GeometryNodeInstanceTransform")
node_add_menu.add_node_type(layout, "GeometryNodeInputInstanceRotation")
node_add_menu.add_node_type(layout, "GeometryNodeInputInstanceScale")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_geometry_node_GEO_MATERIAL(Menu):
bl_idname = "NODE_MT_geometry_node_GEO_MATERIAL"
bl_label = "Material"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeReplaceMaterial")
layout.separator()
node_add_menu.add_node_type(layout, "GeometryNodeInputMaterialIndex")
node_add_menu.add_node_type(layout, "GeometryNodeMaterialSelection")
layout.separator()
node_add_menu.add_node_type(layout, "GeometryNodeSetMaterial", search_weight=1.0)
node_add_menu.add_node_type(layout, "GeometryNodeSetMaterialIndex")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_geometry_node_GEO_MESH(Menu):
bl_idname = "NODE_MT_geometry_node_GEO_MESH"
bl_label = "Mesh"
def draw(self, _context):
layout = self.layout
layout.menu("NODE_MT_geometry_node_GEO_MESH_READ")
layout.menu("NODE_MT_geometry_node_GEO_MESH_SAMPLE")
layout.menu("NODE_MT_geometry_node_GEO_MESH_WRITE")
layout.separator()
layout.menu("NODE_MT_geometry_node_GEO_MESH_OPERATIONS")
layout.menu("NODE_MT_category_PRIMITIVES_MESH")
layout.menu("NODE_MT_geometry_node_mesh_topology")
layout.menu("NODE_MT_category_GEO_UV")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_geometry_node_GEO_MESH_READ(Menu):
bl_idname = "NODE_MT_geometry_node_GEO_MESH_READ"
bl_label = "Read"
def draw(self, context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeInputMeshEdgeAngle")
node_add_menu.add_node_type(layout, "GeometryNodeInputMeshEdgeNeighbors")
node_add_menu.add_node_type(layout, "GeometryNodeInputMeshEdgeVertices")
node_add_menu.add_node_type(layout, "GeometryNodeEdgesToFaceGroups")
node_add_menu.add_node_type(layout, "GeometryNodeInputMeshFaceArea")
node_add_menu.add_node_type(layout, "GeometryNodeMeshFaceSetBoundaries")
node_add_menu.add_node_type(layout, "GeometryNodeInputMeshFaceNeighbors")
if context.space_data.geometry_nodes_type == 'TOOL':
node_add_menu.add_node_type(layout, "GeometryNodeToolFaceSet")
node_add_menu.add_node_type(layout, "GeometryNodeInputMeshFaceIsPlanar")
node_add_menu.add_node_type(layout, "GeometryNodeInputShadeSmooth")
node_add_menu.add_node_type(layout, "GeometryNodeInputEdgeSmooth")
node_add_menu.add_node_type(layout, "GeometryNodeInputMeshIsland")
node_add_menu.add_node_type(layout, "GeometryNodeInputShortestEdgePaths")
node_add_menu.add_node_type(layout, "GeometryNodeInputMeshVertexNeighbors")
node_add_menu.draw_assets_for_catalog(layout, "Mesh/Read")
class NODE_MT_geometry_node_GEO_MESH_SAMPLE(Menu):
bl_idname = "NODE_MT_geometry_node_GEO_MESH_SAMPLE"
bl_label = "Sample"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeSampleNearestSurface")
node_add_menu.add_node_type(layout, "GeometryNodeSampleUVSurface")
node_add_menu.draw_assets_for_catalog(layout, "Mesh/Sample")
class NODE_MT_geometry_node_GEO_MESH_WRITE(Menu):
bl_idname = "NODE_MT_geometry_node_GEO_MESH_WRITE"
bl_label = "Write"
def draw(self, context):
layout = self.layout
if context.space_data.geometry_nodes_type == 'TOOL':
node_add_menu.add_node_type(layout, "GeometryNodeToolSetFaceSet")
node_add_menu.add_node_type(layout, "GeometryNodeSetMeshNormal")
node_add_menu.add_node_type(layout, "GeometryNodeSetShadeSmooth")
node_add_menu.draw_assets_for_catalog(layout, "Mesh/Write")
class NODE_MT_geometry_node_GEO_MESH_OPERATIONS(Menu):
bl_idname = "NODE_MT_geometry_node_GEO_MESH_OPERATIONS"
bl_label = "Operations"
def draw(self, context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeDualMesh")
node_add_menu.add_node_type(layout, "GeometryNodeEdgePathsToCurves")
node_add_menu.add_node_type(layout, "GeometryNodeEdgePathsToSelection")
node_add_menu.add_node_type(layout, "GeometryNodeExtrudeMesh")
node_add_menu.add_node_type(layout, "GeometryNodeFlipFaces")
node_add_menu.add_node_type(layout, "GeometryNodeMeshBoolean")
node_add_menu.add_node_type(layout, "GeometryNodeMeshToCurve")
if context.preferences.experimental.use_new_volume_nodes:
node_add_menu.add_node_type(layout, "GeometryNodeMeshToDensityGrid")
node_add_menu.add_node_type(layout, "GeometryNodeMeshToPoints")
if context.preferences.experimental.use_new_volume_nodes:
node_add_menu.add_node_type(layout, "GeometryNodeMeshToSDFGrid")
node_add_menu.add_node_type(layout, "GeometryNodeMeshToVolume")
node_add_menu.add_node_type(layout, "GeometryNodeScaleElements")
node_add_menu.add_node_type(layout, "GeometryNodeSplitEdges")
node_add_menu.add_node_type(layout, "GeometryNodeSubdivideMesh")
node_add_menu.add_node_type(layout, "GeometryNodeSubdivisionSurface")
node_add_menu.add_node_type(layout, "GeometryNodeTriangulate")
node_add_menu.draw_assets_for_catalog(layout, "Mesh/Operations")
class NODE_MT_category_PRIMITIVES_MESH(Menu):
bl_idname = "NODE_MT_category_PRIMITIVES_MESH"
bl_label = "Primitives"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeMeshCone")
node_add_menu.add_node_type(layout, "GeometryNodeMeshCube")
node_add_menu.add_node_type(layout, "GeometryNodeMeshCylinder")
node_add_menu.add_node_type(layout, "GeometryNodeMeshGrid")
node_add_menu.add_node_type(layout, "GeometryNodeMeshIcoSphere")
node_add_menu.add_node_type(layout, "GeometryNodeMeshCircle")
node_add_menu.add_node_type(layout, "GeometryNodeMeshLine")
node_add_menu.add_node_type(layout, "GeometryNodeMeshUVSphere")
node_add_menu.draw_assets_for_catalog(layout, "Mesh/Primitives")
class NODE_MT_category_import(Menu):
bl_idname = "NODE_MT_category_import"
bl_label = "Import"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeImportCSV", label="CSV (.csv)")
node_add_menu.add_node_type(layout, "GeometryNodeImportOBJ", label="Wavefront (.obj)")
node_add_menu.add_node_type(layout, "GeometryNodeImportPLY", label="Stanford PLY (.ply)")
node_add_menu.add_node_type(layout, "GeometryNodeImportSTL", label="STL (.stl)")
node_add_menu.add_node_type(layout, "GeometryNodeImportText", label="Text (.txt)")
node_add_menu.add_node_type(layout, "GeometryNodeImportVDB", label="OpenVDB (.vdb)")
node_add_menu.draw_assets_for_catalog(layout, "Input/Import")
class NODE_MT_geometry_node_mesh_topology(Menu):
bl_idname = "NODE_MT_geometry_node_mesh_topology"
bl_label = "Topology"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeCornersOfEdge")
node_add_menu.add_node_type(layout, "GeometryNodeCornersOfFace")
node_add_menu.add_node_type(layout, "GeometryNodeCornersOfVertex")
node_add_menu.add_node_type(layout, "GeometryNodeEdgesOfCorner")
node_add_menu.add_node_type(layout, "GeometryNodeEdgesOfVertex")
node_add_menu.add_node_type(layout, "GeometryNodeFaceOfCorner")
node_add_menu.add_node_type(layout, "GeometryNodeOffsetCornerInFace")
node_add_menu.add_node_type(layout, "GeometryNodeVertexOfCorner")
node_add_menu.draw_assets_for_catalog(layout, "Mesh/Topology")
class NODE_MT_category_GEO_OUTPUT(Menu):
bl_idname = "NODE_MT_category_GEO_OUTPUT"
bl_label = "Output"
def draw(self, context):
layout = self.layout
node_add_menu.add_node_type(layout, "NodeGroupOutput")
node_add_menu.add_node_type(layout, "GeometryNodeViewer")
node_add_menu.add_node_type_with_searchable_enum(context, layout, "GeometryNodeWarning", "warning_type")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_category_GEO_POINT(Menu):
bl_idname = "NODE_MT_category_GEO_POINT"
bl_label = "Point"
def draw(self, context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeDistributePointsInVolume")
if context.preferences.experimental.use_new_volume_nodes:
node_add_menu.add_node_type(layout, "GeometryNodeDistributePointsInGrid")
node_add_menu.add_node_type(layout, "GeometryNodeDistributePointsOnFaces")
layout.separator()
node_add_menu.add_node_type(layout, "GeometryNodePoints")
node_add_menu.add_node_type(layout, "GeometryNodePointsToCurves")
if context.preferences.experimental.use_new_volume_nodes:
node_add_menu.add_node_type(layout, "GeometryNodePointsToSDFGrid")
node_add_menu.add_node_type(layout, "GeometryNodePointsToVertices")
node_add_menu.add_node_type(layout, "GeometryNodePointsToVolume")
layout.separator()
node_add_menu.add_node_type(layout, "GeometryNodeSetPointRadius")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_category_simulation(Menu):
bl_idname = "NODE_MT_category_simulation"
bl_label = "Simulation"
def draw(self, _context):
layout = self.layout
node_add_menu.add_simulation_zone(layout, label="Simulation")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_category_GEO_TEXT(Menu):
bl_idname = "NODE_MT_category_GEO_TEXT"
bl_label = "Text"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "FunctionNodeFormatString")
node_add_menu.add_node_type(layout, "GeometryNodeStringJoin")
node_add_menu.add_node_type(layout, "FunctionNodeMatchString")
node_add_menu.add_node_type(layout, "FunctionNodeReplaceString")
node_add_menu.add_node_type(layout, "FunctionNodeSliceString")
layout.separator()
node_add_menu.add_node_type(layout, "FunctionNodeStringLength")
node_add_menu.add_node_type(layout, "FunctionNodeFindInString")
node_add_menu.add_node_type(layout, "GeometryNodeStringToCurves")
node_add_menu.add_node_type(layout, "FunctionNodeValueToString")
layout.separator()
node_add_menu.add_node_type(layout, "FunctionNodeInputSpecialCharacters")
node_add_menu.draw_assets_for_catalog(layout, "Utilities/Text")
class NODE_MT_category_GEO_TEXTURE(Menu):
bl_idname = "NODE_MT_category_GEO_TEXTURE"
bl_label = "Texture"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "ShaderNodeTexBrick")
node_add_menu.add_node_type(layout, "ShaderNodeTexChecker")
node_add_menu.add_node_type(layout, "ShaderNodeTexGabor")
node_add_menu.add_node_type(layout, "ShaderNodeTexGradient")
node_add_menu.add_node_type(layout, "GeometryNodeImageTexture")
node_add_menu.add_node_type(layout, "ShaderNodeTexMagic")
node_add_menu.add_node_type(layout, "ShaderNodeTexNoise")
node_add_menu.add_node_type(layout, "ShaderNodeTexVoronoi")
node_add_menu.add_node_type(layout, "ShaderNodeTexWave")
node_add_menu.add_node_type(layout, "ShaderNodeTexWhiteNoise")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_category_GEO_UTILITIES(Menu):
bl_idname = "NODE_MT_category_GEO_UTILITIES"
bl_label = "Utilities"
def draw(self, context):
layout = self.layout
layout.menu("NODE_MT_geometry_node_GEO_COLOR")
layout.menu("NODE_MT_category_GEO_TEXT")
layout.menu("NODE_MT_category_GEO_VECTOR")
layout.separator()
layout.menu("NODE_MT_category_GEO_UTILITIES_FIELD")
layout.menu("NODE_MT_category_GEO_UTILITIES_MATH")
layout.menu("NODE_MT_category_utilities_matrix")
layout.menu("NODE_MT_category_GEO_UTILITIES_ROTATION")
layout.menu("NODE_MT_category_GEO_UTILITIES_DEPRECATED")
layout.separator()
if context.preferences.experimental.use_bundle_and_closure_nodes:
node_add_menu.add_closure_zone(layout, label="Closure")
node_add_menu.add_node_type(layout, "GeometryNodeEvaluateClosure")
node_add_menu.add_foreach_geometry_element_zone(layout, label="For Each Element")
node_add_menu.add_node_type(layout, "GeometryNodeIndexSwitch")
node_add_menu.add_node_type(layout, "GeometryNodeMenuSwitch")
node_add_menu.add_node_type(layout, "FunctionNodeRandomValue")
node_add_menu.add_repeat_zone(layout, label="Repeat")
node_add_menu.add_node_type(layout, "GeometryNodeSwitch")
if context.preferences.experimental.use_bundle_and_closure_nodes:
node_add_menu.add_node_type(layout, "GeometryNodeCombineBundle")
node_add_menu.add_node_type(layout, "GeometryNodeSeparateBundle")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_category_GEO_UTILITIES_DEPRECATED(Menu):
bl_idname = "NODE_MT_category_GEO_UTILITIES_DEPRECATED"
bl_label = "Deprecated"
def draw(self, context):
layout = self.layout
node_add_menu.add_node_type(layout, "FunctionNodeAlignEulerToVector")
node_add_menu.add_node_type(layout, "FunctionNodeRotateEuler")
node_add_menu.draw_assets_for_catalog(layout, "Utilities/Deprecated")
class NODE_MT_category_GEO_UTILITIES_FIELD(Menu):
bl_idname = "NODE_MT_category_GEO_UTILITIES_FIELD"
bl_label = "Field"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeAccumulateField")
node_add_menu.add_node_type(layout, "GeometryNodeFieldAtIndex")
node_add_menu.add_node_type(layout, "GeometryNodeFieldOnDomain")
node_add_menu.add_node_type(layout, "GeometryNodeFieldAverage")
node_add_menu.add_node_type(layout, "GeometryNodeFieldMinAndMax")
node_add_menu.add_node_type(layout, "GeometryNodeFieldVariance")
node_add_menu.draw_assets_for_catalog(layout, "Utilities/Field")
class NODE_MT_category_GEO_UTILITIES_ROTATION(Menu):
bl_idname = "NODE_MT_category_GEO_UTILITIES_ROTATION"
bl_label = "Rotation"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "FunctionNodeAlignRotationToVector")
node_add_menu.add_node_type(layout, "FunctionNodeAxesToRotation")
node_add_menu.add_node_type(layout, "FunctionNodeAxisAngleToRotation")
node_add_menu.add_node_type(layout, "FunctionNodeEulerToRotation")
node_add_menu.add_node_type(layout, "FunctionNodeInvertRotation")
node_add_menu.add_node_type(layout, "FunctionNodeRotateRotation")
node_add_menu.add_node_type(layout, "FunctionNodeRotateVector")
node_add_menu.add_node_type(layout, "FunctionNodeRotationToAxisAngle")
node_add_menu.add_node_type(layout, "FunctionNodeRotationToEuler")
node_add_menu.add_node_type(layout, "FunctionNodeRotationToQuaternion")
node_add_menu.add_node_type(layout, "FunctionNodeQuaternionToRotation")
node_add_menu.draw_assets_for_catalog(layout, "Utilities/Rotation")
class NODE_MT_category_utilities_matrix(Menu):
bl_idname = "NODE_MT_category_utilities_matrix"
bl_label = "Matrix"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "FunctionNodeCombineMatrix")
node_add_menu.add_node_type(layout, "FunctionNodeCombineTransform")
node_add_menu.add_node_type(layout, "FunctionNodeMatrixDeterminant", label="Determinant")
node_add_menu.add_node_type(layout, "FunctionNodeInvertMatrix")
node_add_menu.add_node_type(layout, "FunctionNodeMatrixMultiply")
node_add_menu.add_node_type(layout, "FunctionNodeProjectPoint")
node_add_menu.add_node_type(layout, "FunctionNodeSeparateMatrix")
node_add_menu.add_node_type(layout, "FunctionNodeSeparateTransform")
node_add_menu.add_node_type(layout, "FunctionNodeTransformDirection")
node_add_menu.add_node_type(layout, "FunctionNodeTransformPoint")
node_add_menu.add_node_type(layout, "FunctionNodeTransposeMatrix")
node_add_menu.draw_assets_for_catalog(layout, "Utilities/Matrix")
class NODE_MT_category_GEO_UTILITIES_MATH(Menu):
bl_idname = "NODE_MT_category_GEO_UTILITIES_MATH"
bl_label = "Math"
def draw(self, context):
layout = self.layout
node_add_menu.add_node_type_with_searchable_enum(
context, layout, "FunctionNodeBitMath", "operation", search_weight=-1.0)
node_add_menu.add_node_type_with_searchable_enum(context, layout, "FunctionNodeBooleanMath", "operation")
node_add_menu.add_node_type_with_searchable_enum(context, layout, "FunctionNodeIntegerMath", "operation")
node_add_menu.add_node_type(layout, "ShaderNodeClamp")
node_add_menu.add_node_type(layout, "FunctionNodeCompare")
node_add_menu.add_node_type(layout, "ShaderNodeFloatCurve")
node_add_menu.add_node_type(layout, "FunctionNodeFloatToInt")
node_add_menu.add_node_type(layout, "FunctionNodeHashValue")
node_add_menu.add_node_type(layout, "ShaderNodeMapRange")
node_add_menu.add_node_type_with_searchable_enum(context, layout, "ShaderNodeMath", "operation")
node_add_menu.add_node_type(layout, "ShaderNodeMix")
node_add_menu.draw_assets_for_catalog(layout, "Utilities/Math")
class NODE_MT_category_GEO_UV(Menu):
bl_idname = "NODE_MT_category_GEO_UV"
bl_label = "UV"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeUVPackIslands")
node_add_menu.add_node_type(layout, "GeometryNodeUVUnwrap")
node_add_menu.draw_assets_for_catalog(layout, "Mesh/UV")
class NODE_MT_category_GEO_VECTOR(Menu):
bl_idname = "NODE_MT_category_GEO_VECTOR"
bl_label = "Vector"
def draw(self, context):
layout = self.layout
node_add_menu.add_node_type(layout, "ShaderNodeVectorCurve")
node_add_menu.add_node_type_with_searchable_enum(context, layout, "ShaderNodeVectorMath", "operation")
node_add_menu.add_node_type(layout, "ShaderNodeVectorRotate")
layout.separator()
node_add_menu.add_node_type(layout, "ShaderNodeCombineXYZ")
props = node_add_menu.add_node_type(layout, "ShaderNodeMix", label=iface_("Mix Vector"))
ops = props.settings.add()
ops.name = "data_type"
ops.value = "'VECTOR'"
node_add_menu.add_node_type(layout, "ShaderNodeSeparateXYZ")
node_add_menu.draw_assets_for_catalog(layout, "Utilities/Vector")
class NODE_MT_category_GEO_VOLUME(Menu):
bl_idname = "NODE_MT_category_GEO_VOLUME"
bl_label = "Volume"
bl_translation_context = i18n_contexts.id_id
def draw(self, context):
layout = self.layout
if context.preferences.experimental.use_new_volume_nodes:
layout.menu("NODE_MT_geometry_node_GEO_VOLUME_READ")
layout.menu("NODE_MT_geometry_node_volume_sample")
layout.menu("NODE_MT_geometry_node_GEO_VOLUME_WRITE")
layout.separator()
layout.menu("NODE_MT_geometry_node_GEO_VOLUME_OPERATIONS")
layout.menu("NODE_MT_geometry_node_GEO_VOLUME_PRIMITIVES")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_geometry_node_GEO_VOLUME_READ(Menu):
bl_idname = "NODE_MT_geometry_node_GEO_VOLUME_READ"
bl_label = "Read"
def draw(self, context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeGetNamedGrid")
node_add_menu.add_node_type(layout, "GeometryNodeGridInfo")
node_add_menu.draw_assets_for_catalog(layout, "Volume/Read")
class NODE_MT_geometry_node_GEO_VOLUME_WRITE(Menu):
bl_idname = "NODE_MT_geometry_node_GEO_VOLUME_WRITE"
bl_label = "Write"
def draw(self, context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeStoreNamedGrid")
node_add_menu.draw_assets_for_catalog(layout, "Volume/Write")
class NODE_MT_geometry_node_volume_sample(Menu):
bl_idname = "NODE_MT_geometry_node_volume_sample"
bl_label = "Sample"
def draw(self, context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeSampleGrid")
node_add_menu.add_node_type(layout, "GeometryNodeSampleGridIndex")
node_add_menu.draw_assets_for_catalog(layout, "Volume/Sample")
class NODE_MT_geometry_node_GEO_VOLUME_OPERATIONS(Menu):
bl_idname = "NODE_MT_geometry_node_GEO_VOLUME_OPERATIONS"
bl_label = "Operations"
def draw(self, context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeVolumeToMesh")
if context.preferences.experimental.use_new_volume_nodes:
node_add_menu.add_node_type(layout, "GeometryNodeGridToMesh")
node_add_menu.add_node_type(layout, "GeometryNodeSDFGridBoolean")
node_add_menu.draw_assets_for_catalog(layout, "Volume/Operations")
class NODE_MT_geometry_node_GEO_VOLUME_PRIMITIVES(Menu):
bl_idname = "NODE_MT_geometry_node_GEO_VOLUME_PRIMITIVES"
bl_label = "Primitives"
def draw(self, context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeVolumeCube")
node_add_menu.draw_assets_for_catalog(layout, "Volume/Primitives")
class NODE_MT_category_GEO_GROUP(Menu):
bl_idname = "NODE_MT_category_GEO_GROUP"
bl_label = "Group"
def draw(self, context):
layout = self.layout
node_add_menu.draw_node_group_add_menu(context, layout)
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_geometry_node_add_all(Menu):
bl_idname = "NODE_MT_geometry_node_add_all"
bl_label = ""
def draw(self, context):
layout = self.layout
layout.menu("NODE_MT_geometry_node_GEO_ATTRIBUTE")
layout.menu("NODE_MT_geometry_node_GEO_INPUT")
layout.menu("NODE_MT_category_GEO_OUTPUT")
layout.separator()
layout.menu("NODE_MT_geometry_node_GEO_GEOMETRY")
layout.separator()
layout.menu("NODE_MT_geometry_node_GEO_CURVE")
layout.menu("NODE_MT_geometry_node_grease_pencil")
layout.menu("NODE_MT_geometry_node_GEO_INSTANCE")
layout.menu("NODE_MT_geometry_node_GEO_MESH")
layout.menu("NODE_MT_category_GEO_POINT")
layout.menu("NODE_MT_category_GEO_VOLUME")
layout.separator()
layout.menu("NODE_MT_category_simulation")
layout.separator()
layout.menu("NODE_MT_geometry_node_GEO_MATERIAL")
layout.menu("NODE_MT_category_GEO_TEXTURE")
layout.menu("NODE_MT_category_GEO_UTILITIES")
layout.separator()
layout.menu("NODE_MT_category_GEO_GROUP")
layout.menu("NODE_MT_category_layout")
node_add_menu.draw_root_assets(layout)
classes = (
NODE_MT_geometry_node_add_all,
NODE_MT_geometry_node_GEO_ATTRIBUTE,
NODE_MT_geometry_node_GEO_INPUT,
NODE_MT_geometry_node_GEO_INPUT_CONSTANT,
NODE_MT_geometry_node_GEO_INPUT_GROUP,
NODE_MT_geometry_node_GEO_INPUT_SCENE,
NODE_MT_category_GEO_OUTPUT,
NODE_MT_geometry_node_GEO_CURVE,
NODE_MT_geometry_node_GEO_CURVE_READ,
NODE_MT_geometry_node_GEO_CURVE_SAMPLE,
NODE_MT_geometry_node_GEO_CURVE_WRITE,
NODE_MT_geometry_node_GEO_CURVE_OPERATIONS,
NODE_MT_geometry_node_GEO_PRIMITIVES_CURVE,
NODE_MT_geometry_node_curve_topology,
NODE_MT_geometry_node_grease_pencil,
NODE_MT_geometry_node_grease_pencil_read,
NODE_MT_geometry_node_grease_pencil_write,
NODE_MT_geometry_node_grease_pencil_operations,
NODE_MT_geometry_node_GEO_GEOMETRY,
NODE_MT_geometry_node_GEO_GEOMETRY_READ,
NODE_MT_geometry_node_GEO_GEOMETRY_WRITE,
NODE_MT_geometry_node_GEO_GEOMETRY_OPERATIONS,
NODE_MT_geometry_node_GEO_GEOMETRY_SAMPLE,
NODE_MT_geometry_node_GEO_INSTANCE,
NODE_MT_geometry_node_GEO_MESH,
NODE_MT_geometry_node_GEO_MESH_READ,
NODE_MT_geometry_node_GEO_MESH_SAMPLE,
NODE_MT_geometry_node_GEO_MESH_WRITE,
NODE_MT_geometry_node_GEO_MESH_OPERATIONS,
NODE_MT_category_GEO_UV,
NODE_MT_category_PRIMITIVES_MESH,
NODE_MT_category_import,
NODE_MT_geometry_node_mesh_topology,
NODE_MT_category_GEO_POINT,
NODE_MT_category_simulation,
NODE_MT_category_GEO_VOLUME,
NODE_MT_geometry_node_GEO_VOLUME_READ,
NODE_MT_geometry_node_volume_sample,
NODE_MT_geometry_node_GEO_VOLUME_WRITE,
NODE_MT_geometry_node_GEO_VOLUME_OPERATIONS,
NODE_MT_geometry_node_GEO_VOLUME_PRIMITIVES,
NODE_MT_geometry_node_GEO_MATERIAL,
NODE_MT_category_GEO_TEXTURE,
NODE_MT_category_GEO_UTILITIES,
NODE_MT_geometry_node_GEO_COLOR,
NODE_MT_category_GEO_TEXT,
NODE_MT_category_GEO_VECTOR,
NODE_MT_category_GEO_UTILITIES_FIELD,
NODE_MT_category_GEO_UTILITIES_MATH,
NODE_MT_category_GEO_UTILITIES_ROTATION,
NODE_MT_geometry_node_GEO_INPUT_GIZMO,
NODE_MT_category_utilities_matrix,
NODE_MT_category_GEO_UTILITIES_DEPRECATED,
NODE_MT_category_GEO_GROUP,
)
if __name__ == "__main__": # only for live edit.
from bpy.utils import register_class
for cls in classes:
register_class(cls)