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 bpy.types import Menu
|
|
|
|
|
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
|
|
|
|
2022-09-26 12:36:13 -05:00
|
|
|
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
|
2022-09-29 11:08:21 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeAttributeStatistic")
|
2023-01-09 18:09:22 +01:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeAttributeDomainSize")
|
|
|
|
|
layout.separator()
|
2022-12-07 18:22:44 +01:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeBlurAttribute")
|
2022-09-26 12:36:13 -05:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeCaptureAttribute")
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeRemoveAttribute")
|
2024-04-22 18:22:05 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeStoreNamedAttribute", search_weight=1.0)
|
2022-11-01 16:09:49 +01:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2022-09-26 12:36:13 -05:00
|
|
|
class NODE_MT_geometry_node_GEO_COLOR(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_geometry_node_GEO_COLOR"
|
|
|
|
|
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
|
2023-12-13 10:10:06 +01:00
|
|
|
node_add_menu.add_node_type(layout, "ShaderNodeBlackbody")
|
2025-08-20 08:46:34 +02:00
|
|
|
node_add_menu.add_node_type(layout, "ShaderNodeGamma")
|
2022-09-29 11:08:21 +02:00
|
|
|
node_add_menu.add_node_type(layout, "ShaderNodeValToRGB")
|
2023-01-09 18:09:22 +01:00
|
|
|
node_add_menu.add_node_type(layout, "ShaderNodeRGBCurve")
|
|
|
|
|
layout.separator()
|
2022-09-29 11:08:21 +02:00
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeCombineColor")
|
2025-05-09 04:02:50 +02:00
|
|
|
node_add_menu.add_color_mix_node(context, layout)
|
2022-09-26 12:36:13 -05:00
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeSeparateColor")
|
2024-05-29 05:44:47 +02:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Utilities/Color")
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2022-09-26 12:36:13 -05:00
|
|
|
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
|
2023-01-09 18:09:22 +01:00
|
|
|
layout.menu("NODE_MT_geometry_node_GEO_CURVE_READ")
|
2023-02-03 16:26:30 -05:00
|
|
|
layout.menu("NODE_MT_geometry_node_GEO_CURVE_SAMPLE")
|
2023-01-09 18:09:22 +01:00
|
|
|
layout.menu("NODE_MT_geometry_node_GEO_CURVE_WRITE")
|
2022-09-26 12:36:13 -05:00
|
|
|
layout.separator()
|
2023-01-09 18:09:22 +01:00
|
|
|
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
|
2022-09-26 12:36:13 -05:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeInputCurveHandlePositions")
|
2023-01-09 18:09:22 +01:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeCurveLength")
|
2022-09-26 12:36:13 -05:00
|
|
|
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")
|
2023-09-26 17:01:30 -04:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Curve/Read")
|
2023-01-09 18:09:22 +01:00
|
|
|
|
2023-01-16 14:39:10 +01:00
|
|
|
|
2023-02-03 16:26:30 -05:00
|
|
|
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")
|
2023-09-26 17:01:30 -04:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Curve/Sample")
|
2023-02-03 16:26:30 -05:00
|
|
|
|
|
|
|
|
|
2023-01-09 18:09:22 +01:00
|
|
|
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
|
2022-10-03 15:50:21 -05:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeSetCurveNormal")
|
2022-09-26 12:36:13 -05:00
|
|
|
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")
|
2023-09-26 17:01:30 -04:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Curve/Write")
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2023-01-09 18:09:22 +01:00
|
|
|
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, "GeometryNodeCurveToMesh")
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeCurveToPoints")
|
2025-06-10 15:49:31 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeCurvesToGreasePencil")
|
2023-01-09 18:09:22 +01:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeDeformCurvesOnSurface")
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeFillCurve")
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeFilletCurve")
|
2023-01-20 12:09:29 +01:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeInterpolateCurves")
|
2023-01-09 18:09:22 +01:00
|
|
|
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")
|
2023-09-26 17:01:30 -04:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Curve/Operations")
|
2023-01-09 18:09:22 +01:00
|
|
|
|
|
|
|
|
|
2022-09-26 12:36:13 -05:00
|
|
|
class NODE_MT_geometry_node_GEO_PRIMITIVES_CURVE(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_geometry_node_GEO_PRIMITIVES_CURVE"
|
2023-01-09 18:09:22 +01:00
|
|
|
bl_label = "Primitives"
|
2022-09-26 12:36:13 -05:00
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2022-09-29 11:08:21 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeCurveArc")
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeCurvePrimitiveBezierSegment")
|
2022-09-26 12:36:13 -05:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeCurvePrimitiveCircle")
|
2022-09-29 11:08:21 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeCurvePrimitiveLine")
|
2022-09-26 12:36:13 -05:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeCurveSpiral")
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeCurveQuadraticBezier")
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeCurvePrimitiveQuadrilateral")
|
2022-09-29 11:08:21 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeCurveStar")
|
2023-09-26 17:01:30 -04:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Curve/Primitives")
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2022-09-28 14:38:27 -05:00
|
|
|
class NODE_MT_geometry_node_curve_topology(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_geometry_node_curve_topology"
|
2023-01-09 18:09:22 +01:00
|
|
|
bl_label = "Topology"
|
2022-09-28 14:38:27 -05:00
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeCurveOfPoint")
|
2023-08-24 16:09:58 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeOffsetPointInCurve")
|
2022-09-28 14:38:27 -05:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodePointsOfCurve")
|
2023-09-26 17:05:36 -04:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Curve/Topology")
|
2022-09-28 14:38:27 -05:00
|
|
|
|
|
|
|
|
|
2025-04-08 09:51:28 -04:00
|
|
|
class NODE_MT_geometry_node_grease_pencil_read(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_geometry_node_grease_pencil_read"
|
2025-03-25 16:38:18 +01:00
|
|
|
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")
|
|
|
|
|
|
|
|
|
|
|
2025-04-08 09:51:28 -04:00
|
|
|
class NODE_MT_geometry_node_grease_pencil_write(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_geometry_node_grease_pencil_write"
|
2025-04-05 12:11:26 +02:00
|
|
|
bl_label = "Write"
|
|
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeSetGreasePencilColor")
|
2025-04-08 15:24:51 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeSetGreasePencilDepth")
|
2025-05-23 07:30:23 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeSetGreasePencilSoftness")
|
2025-04-05 12:11:26 +02:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Grease Pencil/Write")
|
|
|
|
|
|
|
|
|
|
|
2025-04-08 09:51:28 -04:00
|
|
|
class NODE_MT_geometry_node_grease_pencil_operations(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_geometry_node_grease_pencil_operations"
|
2025-03-25 16:38:18 +01:00
|
|
|
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")
|
|
|
|
|
|
|
|
|
|
|
2025-04-08 09:51:28 -04:00
|
|
|
class NODE_MT_geometry_node_grease_pencil(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_geometry_node_grease_pencil"
|
2025-03-25 16:38:18 +01:00
|
|
|
bl_label = "Grease Pencil"
|
|
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-04-08 09:51:28 -04:00
|
|
|
layout.menu("NODE_MT_geometry_node_grease_pencil_read")
|
|
|
|
|
layout.menu("NODE_MT_geometry_node_grease_pencil_write")
|
2025-03-25 16:38:18 +01:00
|
|
|
layout.separator()
|
2025-04-08 09:51:28 -04:00
|
|
|
layout.menu("NODE_MT_geometry_node_grease_pencil_operations")
|
2025-03-25 16:38:18 +01:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
|
|
|
|
|
|
|
|
|
|
|
2022-09-26 12:36:13 -05:00
|
|
|
class NODE_MT_geometry_node_GEO_GEOMETRY(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_geometry_node_GEO_GEOMETRY"
|
|
|
|
|
bl_label = "Geometry"
|
|
|
|
|
|
2023-01-09 18:09:22 +01:00
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
|
|
|
|
layout.menu("NODE_MT_geometry_node_GEO_GEOMETRY_READ")
|
2023-02-03 16:26:30 -05:00
|
|
|
layout.menu("NODE_MT_geometry_node_GEO_GEOMETRY_SAMPLE")
|
2023-01-09 18:09:22 +01:00
|
|
|
layout.menu("NODE_MT_geometry_node_GEO_GEOMETRY_WRITE")
|
2023-01-16 12:23:50 +01:00
|
|
|
layout.separator()
|
2023-01-09 18:09:22 +01:00
|
|
|
layout.menu("NODE_MT_geometry_node_GEO_GEOMETRY_OPERATIONS")
|
|
|
|
|
layout.separator()
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeGeometryToInstance")
|
2024-04-16 12:18:45 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeJoinGeometry", search_weight=1.0)
|
2023-01-09 18:09:22 +01:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
|
|
|
|
|
|
2023-01-16 14:39:10 +01:00
|
|
|
|
2023-01-09 18:09:22 +01:00
|
|
|
class NODE_MT_geometry_node_GEO_GEOMETRY_READ(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_geometry_node_GEO_GEOMETRY_READ"
|
|
|
|
|
bl_label = "Read"
|
|
|
|
|
|
2023-08-24 13:34:15 +02:00
|
|
|
def draw(self, context):
|
2023-01-09 18:09:22 +01:00
|
|
|
layout = self.layout
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeInputID")
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeInputIndex")
|
2024-04-22 18:22:05 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeInputNamedAttribute", search_weight=1.0)
|
2023-01-09 18:09:22 +01:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeInputNormal")
|
2024-04-22 18:22:05 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeInputPosition", search_weight=1.0)
|
2023-01-09 18:09:22 +01:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeInputRadius")
|
2025-08-21 09:04:13 +02:00
|
|
|
if context.space_data.node_tree_sub_type == 'TOOL':
|
2023-08-24 13:34:15 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeToolSelection")
|
2024-05-20 21:01:30 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeToolActiveElement")
|
2023-09-26 17:01:30 -04:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Geometry/Read")
|
2023-01-09 18:09:22 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class NODE_MT_geometry_node_GEO_GEOMETRY_WRITE(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_geometry_node_GEO_GEOMETRY_WRITE"
|
|
|
|
|
bl_label = "Write"
|
|
|
|
|
|
2023-08-24 13:34:15 +02:00
|
|
|
def draw(self, context):
|
2023-01-09 18:09:22 +01:00
|
|
|
layout = self.layout
|
2024-07-09 17:03:54 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeSetGeometryName")
|
2023-01-09 18:09:22 +01:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeSetID")
|
2024-04-22 18:22:05 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeSetPosition", search_weight=1.0)
|
2025-08-21 09:04:13 +02:00
|
|
|
if context.space_data.node_tree_sub_type == 'TOOL':
|
2023-08-24 13:34:15 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeToolSetSelection")
|
2023-09-26 17:01:30 -04:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Geometry/Write")
|
2023-01-09 18:09:22 +01:00
|
|
|
|
2023-01-16 14:39:10 +01:00
|
|
|
|
2023-01-09 18:09:22 +01:00
|
|
|
class NODE_MT_geometry_node_GEO_GEOMETRY_OPERATIONS(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_geometry_node_GEO_GEOMETRY_OPERATIONS"
|
|
|
|
|
bl_label = "Operations"
|
|
|
|
|
|
2022-09-26 12:36:13 -05:00
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2023-12-18 13:01:06 +01:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeBake")
|
2022-09-26 12:36:13 -05:00
|
|
|
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")
|
2024-01-12 14:30:34 +01:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeSortElements")
|
2024-04-16 12:18:45 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeTransform", search_weight=1.0)
|
2023-01-09 18:09:22 +01:00
|
|
|
layout.separator()
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeSeparateComponents")
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeSeparateGeometry")
|
2023-10-18 10:26:23 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeSplitToInstances")
|
2023-09-26 17:01:30 -04:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Geometry/Operations")
|
2023-01-09 18:09:22 +01:00
|
|
|
|
2023-01-16 14:39:10 +01:00
|
|
|
|
2023-01-09 18:09:22 +01:00
|
|
|
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")
|
2023-04-22 13:11:51 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeIndexOfNearest")
|
2022-09-26 12:36:13 -05:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeRaycast")
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeSampleIndex")
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeSampleNearest")
|
2023-09-26 17:01:30 -04:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Geometry/Sample")
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2022-09-26 12:36:13 -05:00
|
|
|
class NODE_MT_geometry_node_GEO_INPUT(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_geometry_node_GEO_INPUT"
|
|
|
|
|
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
|
|
|
|
|
layout.menu("NODE_MT_geometry_node_GEO_INPUT_CONSTANT")
|
2025-08-21 09:04:13 +02:00
|
|
|
if context.space_data.node_tree_sub_type != 'TOOL':
|
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.menu("NODE_MT_geometry_node_GEO_INPUT_GIZMO")
|
2023-01-09 18:09:22 +01:00
|
|
|
layout.menu("NODE_MT_geometry_node_GEO_INPUT_GROUP")
|
2025-03-17 13:54:48 +01:00
|
|
|
layout.menu("NODE_MT_category_import")
|
2023-01-09 18:09:22 +01:00
|
|
|
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"
|
2023-03-03 14:44:21 +01:00
|
|
|
bl_translation_context = i18n_contexts.id_nodetree
|
2023-01-09 18:09:22 +01:00
|
|
|
|
2022-09-26 12:36:13 -05:00
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
|
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeInputBool")
|
2024-12-04 15:01:44 +01:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeInputCollection")
|
2022-09-26 12:36:13 -05:00
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeInputColor")
|
2022-12-09 15:50:00 -06:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeInputImage")
|
2022-09-26 12:36:13 -05:00
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeInputInt")
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeInputMaterial")
|
2024-12-04 15:01:44 +01:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeInputObject")
|
2024-05-06 19:04:30 +02:00
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeInputRotation")
|
2022-09-26 12:36:13 -05:00
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeInputString")
|
|
|
|
|
node_add_menu.add_node_type(layout, "ShaderNodeValue")
|
|
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeInputVector")
|
2023-09-26 17:01:30 -04:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Input/Constant")
|
2023-01-09 18:09:22 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
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")
|
2023-09-26 17:01:30 -04:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Input/Group")
|
2023-01-09 18:09:22 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class NODE_MT_geometry_node_GEO_INPUT_SCENE(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_geometry_node_GEO_INPUT_SCENE"
|
|
|
|
|
bl_label = "Scene"
|
|
|
|
|
|
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':
|
2023-08-24 13:34:15 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeTool3DCursor")
|
2023-12-12 19:11:06 +01:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeInputActiveCamera")
|
2025-07-11 16:43:13 +10:00
|
|
|
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",
|
|
|
|
|
],
|
|
|
|
|
)
|
2023-01-09 18:09:22 +01:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeCollectionInfo")
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeImageInfo")
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeIsViewport")
|
2025-08-21 09:04:13 +02:00
|
|
|
if context.space_data.node_tree_sub_type == 'TOOL':
|
Nodes: support searching for outputs of various input nodes directly
Previously, one had to search for the name of an input node (Geometry, Light
Path, etc.) instead of for the actual desired values.
This patch makes it possible to search for the output names of various input
nodes directly. All other outputs of the input node are hidden automatically.
This was partially support for the Scene Time before.
Supported nodes:
* Compositor: Scene Time
* Geometry Nodes: Camera Info, Mouse Position, Scene Time, Viewport Transform
* Shader Nodes: Camera Data, Curves Info, Geometry, Volume Info, Light Path,
Object Info, Particle Info
Right now, the output names are hardcoded in the menu. We don't have a great way
to access those without an actual node instance currently. For that we'll need
to make the node declarations available in Python, which is a good project but
out of scope for this this feature. It also does not seem too bad to have more
explicit control over what's shown in the search.
Pull Request: https://projects.blender.org/blender/blender/pulls/139477
2025-05-28 05:41:37 +02:00
|
|
|
node_add_menu.add_node_type_with_outputs(
|
2025-07-11 16:43:13 +10:00
|
|
|
context, layout, "GeometryNodeToolMousePosition",
|
|
|
|
|
["Mouse X", "Mouse Y", "Region Width", "Region Height"],
|
|
|
|
|
)
|
2023-01-09 18:09:22 +01:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeObjectInfo")
|
Nodes: support searching for outputs of various input nodes directly
Previously, one had to search for the name of an input node (Geometry, Light
Path, etc.) instead of for the actual desired values.
This patch makes it possible to search for the output names of various input
nodes directly. All other outputs of the input node are hidden automatically.
This was partially support for the Scene Time before.
Supported nodes:
* Compositor: Scene Time
* Geometry Nodes: Camera Info, Mouse Position, Scene Time, Viewport Transform
* Shader Nodes: Camera Data, Curves Info, Geometry, Volume Info, Light Path,
Object Info, Particle Info
Right now, the output names are hardcoded in the menu. We don't have a great way
to access those without an actual node instance currently. For that we'll need
to make the node declarations available in Python, which is a good project but
out of scope for this this feature. It also does not seem too bad to have more
explicit control over what's shown in the search.
Pull Request: https://projects.blender.org/blender/blender/pulls/139477
2025-05-28 05:41:37 +02:00
|
|
|
node_add_menu.add_node_type_with_outputs(context, layout, "GeometryNodeInputSceneTime", ["Frame", "Seconds"])
|
2023-08-24 16:09:58 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeSelfObject")
|
2025-08-21 09:04:13 +02:00
|
|
|
if context.space_data.node_tree_sub_type == 'TOOL':
|
Nodes: support searching for outputs of various input nodes directly
Previously, one had to search for the name of an input node (Geometry, Light
Path, etc.) instead of for the actual desired values.
This patch makes it possible to search for the output names of various input
nodes directly. All other outputs of the input node are hidden automatically.
This was partially support for the Scene Time before.
Supported nodes:
* Compositor: Scene Time
* Geometry Nodes: Camera Info, Mouse Position, Scene Time, Viewport Transform
* Shader Nodes: Camera Data, Curves Info, Geometry, Volume Info, Light Path,
Object Info, Particle Info
Right now, the output names are hardcoded in the menu. We don't have a great way
to access those without an actual node instance currently. For that we'll need
to make the node declarations available in Python, which is a good project but
out of scope for this this feature. It also does not seem too bad to have more
explicit control over what's shown in the search.
Pull Request: https://projects.blender.org/blender/blender/pulls/139477
2025-05-28 05:41:37 +02:00
|
|
|
node_add_menu.add_node_type_with_outputs(
|
2025-07-11 16:43:13 +10:00
|
|
|
context, layout, "GeometryNodeViewportTransform",
|
|
|
|
|
["Projection", "View", "Is Orthographic"],
|
|
|
|
|
)
|
2023-09-26 17:01:30 -04:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Input/Scene")
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2022-09-27 16:36:27 +10:00
|
|
|
|
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
|
|
|
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")
|
2025-05-14 16:12:29 +02:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "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
|
|
|
|
|
|
|
|
|
2022-09-26 12:36:13 -05:00
|
|
|
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
|
2024-04-22 18:22:05 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeInstanceOnPoints", search_weight=2.0)
|
2022-09-26 12:36:13 -05:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeInstancesToPoints")
|
2023-01-09 18:09:22 +01:00
|
|
|
layout.separator()
|
2024-04-22 18:22:05 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeRealizeInstances", search_weight=1.0)
|
2022-09-26 12:36:13 -05:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeRotateInstances")
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeScaleInstances")
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeTranslateInstances")
|
2024-05-28 16:34:37 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeSetInstanceTransform")
|
2022-09-26 12:36:13 -05:00
|
|
|
layout.separator()
|
2025-04-17 13:34:26 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeInputInstanceBounds")
|
2024-05-31 12:55:40 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeInstanceTransform")
|
2022-09-26 12:36:13 -05:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeInputInstanceRotation")
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeInputInstanceScale")
|
2022-11-01 16:09:49 +01:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2022-09-26 12:36:13 -05:00
|
|
|
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()
|
2024-04-22 18:22:05 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeSetMaterial", search_weight=1.0)
|
2022-09-26 12:36:13 -05:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeSetMaterialIndex")
|
2022-11-01 16:09:49 +01:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2022-09-26 12:36:13 -05:00
|
|
|
class NODE_MT_geometry_node_GEO_MESH(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_geometry_node_GEO_MESH"
|
|
|
|
|
bl_label = "Mesh"
|
|
|
|
|
|
2023-01-09 18:09:22 +01:00
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
|
|
|
|
layout.menu("NODE_MT_geometry_node_GEO_MESH_READ")
|
2023-02-03 16:26:30 -05:00
|
|
|
layout.menu("NODE_MT_geometry_node_GEO_MESH_SAMPLE")
|
2023-01-09 18:09:22 +01:00
|
|
|
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"
|
|
|
|
|
|
2023-08-24 13:34:15 +02:00
|
|
|
def draw(self, context):
|
2023-01-09 18:09:22 +01:00
|
|
|
layout = self.layout
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeInputMeshEdgeAngle")
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeInputMeshEdgeNeighbors")
|
2023-08-24 16:09:58 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeInputMeshEdgeVertices")
|
2023-08-24 16:15:43 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeEdgesToFaceGroups")
|
2023-01-09 18:09:22 +01:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeInputMeshFaceArea")
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeMeshFaceSetBoundaries")
|
2023-08-24 16:09:58 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeInputMeshFaceNeighbors")
|
2025-08-21 09:04:13 +02:00
|
|
|
if context.space_data.node_tree_sub_type == 'TOOL':
|
2023-08-24 13:34:15 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeToolFaceSet")
|
2023-01-09 18:09:22 +01:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeInputMeshFaceIsPlanar")
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeInputShadeSmooth")
|
2023-09-06 17:12:27 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeInputEdgeSmooth")
|
2023-01-09 18:09:22 +01:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeInputMeshIsland")
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeInputShortestEdgePaths")
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeInputMeshVertexNeighbors")
|
2023-09-26 17:01:30 -04:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Mesh/Read")
|
2023-01-09 18:09:22 +01:00
|
|
|
|
|
|
|
|
|
2023-02-03 16:26:30 -05:00
|
|
|
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")
|
2023-09-26 17:01:30 -04:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Mesh/Sample")
|
2023-02-03 16:26:30 -05:00
|
|
|
|
|
|
|
|
|
2023-01-09 18:09:22 +01:00
|
|
|
class NODE_MT_geometry_node_GEO_MESH_WRITE(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_geometry_node_GEO_MESH_WRITE"
|
|
|
|
|
bl_label = "Write"
|
|
|
|
|
|
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':
|
2023-08-24 13:34:15 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeToolSetFaceSet")
|
Mesh: Add "free" custom normals
Add a "dumb vector" storage option for custom normals, with the
"custom_normal" attribute. Adjust the mesh normals caching to
provide this attribute if it's available, and add a geometry node to
store custom normals.
## Free Normals
They're called "free" in the sense that they're just direction vectors
in the object's local space, rather than the existing "smooth corner
fan space" storage. They're also "free" in that they make further
normals calculation very inexpensive, since we just use the custom
normals instead. That's a big improvement from the existing custom
normals storage, which usually significantly decreases
viewport performance. For example, in a simple test file just storing
the vertex normals on a UV sphere, using free normals gives 25 times
better playback performance and 10% lower memory usage.
Free normals are adjusted when applying a transformation to the entire
mesh or when realizing instances, but in general they're not updated for
vertex deformations.
## Set Mesh Normal Node
The new geometry node allows storing free custom normals as well as
the existing corner fan space normals. When free normals are chosen,
free normals can be stored on vertices, faces, or face corners. Using
the face corner domain is necessary to bake existing mixed sharp and
smooth edges into the custom normal vectors.
The node also has a mode for storing edge and mesh sharpness, meant
as a "soft" replacement to the "Set Shade Smooth" node that's a bit
more convenient.
## Normal Input Node
The normal node outputs free custom normals mixed to whatever domain is
requested. A "true normal" output that ignores custom normals and
sharpness is added as well.
Across Blender, custom normals are generally accessed via face and
vertex normals, when "true normals" are not requested explicitly.
In many cases that means they are mixed from the face corner domain.
## Future Work
1. There are many places where propagation of free normals could be
improved. They should probably be normalized after mixing, and it
may be useful to not just use 0 vectors for new elements. To keep
the scope of this change smaller, that sort of thing generally isn't
handled here. Searching `CD_NORMAL` gives a hint of where better
propagation could be useful.
2. Free normals are displayed properly in edit mode, but the existing
custom normal editing operators don't work with free normals yet.
This will hopefully be fairly straightforward since custom normals
are usually converted to `float3` for editing anyway. Edit mode
changes aren't included here because they're unnecessary for the
procedural custom normals use cases.
3. Most importers can probably switch to using free normals instead,
or at least provide an option for it. That will give a significant
import performance improvement, and an improvement of Blender's
FPS for imported scenes too.
Pull Request: https://projects.blender.org/blender/blender/pulls/132583
2025-04-04 19:16:51 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeSetMeshNormal")
|
2023-11-04 11:02:59 +01:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeSetShadeSmooth")
|
2023-09-26 17:01:30 -04:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Mesh/Write")
|
2023-01-09 18:09:22 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class NODE_MT_geometry_node_GEO_MESH_OPERATIONS(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_geometry_node_GEO_MESH_OPERATIONS"
|
|
|
|
|
bl_label = "Operations"
|
|
|
|
|
|
2023-03-23 15:31:14 +11:00
|
|
|
def draw(self, context):
|
2022-09-26 12:36:13 -05:00
|
|
|
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")
|
2024-02-28 22:15:10 +01:00
|
|
|
if context.preferences.experimental.use_new_volume_nodes:
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeMeshToDensityGrid")
|
2022-09-26 12:36:13 -05:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeMeshToPoints")
|
2024-02-28 22:15:10 +01:00
|
|
|
if context.preferences.experimental.use_new_volume_nodes:
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeMeshToSDFGrid")
|
2022-09-26 12:36:13 -05:00
|
|
|
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")
|
2023-09-26 17:01:30 -04:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Mesh/Operations")
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2022-09-26 12:36:13 -05:00
|
|
|
class NODE_MT_category_PRIMITIVES_MESH(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_category_PRIMITIVES_MESH"
|
2023-01-09 18:09:22 +01:00
|
|
|
bl_label = "Primitives"
|
2022-09-26 12:36:13 -05:00
|
|
|
|
|
|
|
|
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")
|
2022-09-29 11:08:21 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeMeshCircle")
|
2022-09-26 12:36:13 -05:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeMeshLine")
|
2022-10-05 10:53:12 -05:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeMeshUVSphere")
|
2023-09-26 17:01:30 -04:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Mesh/Primitives")
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2024-06-10 15:38:43 -04:00
|
|
|
|
|
|
|
|
class NODE_MT_category_import(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_category_import"
|
2024-06-10 20:47:37 +02:00
|
|
|
bl_label = "Import"
|
|
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2025-03-17 13:54:48 +01:00
|
|
|
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)")
|
2025-05-06 04:13:11 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeImportVDB", label="OpenVDB (.vdb)")
|
2024-06-10 20:47:37 +02:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Input/Import")
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2024-06-10 15:38:43 -04:00
|
|
|
|
2022-09-28 14:38:27 -05:00
|
|
|
class NODE_MT_geometry_node_mesh_topology(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_geometry_node_mesh_topology"
|
2023-01-09 18:09:22 +01:00
|
|
|
bl_label = "Topology"
|
2022-09-28 14:38:27 -05:00
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2023-05-31 15:25:48 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeCornersOfEdge")
|
2023-04-13 13:14:05 +10:00
|
|
|
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")
|
2023-09-26 17:01:30 -04:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Mesh/Topology")
|
2022-09-28 14:38:27 -05:00
|
|
|
|
|
|
|
|
|
2022-09-26 12:36:13 -05:00
|
|
|
class NODE_MT_category_GEO_OUTPUT(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_category_GEO_OUTPUT"
|
|
|
|
|
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
|
2023-01-09 18:09:22 +01:00
|
|
|
node_add_menu.add_node_type(layout, "NodeGroupOutput")
|
2022-09-26 12:36:13 -05:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeViewer")
|
2025-05-27 09:01:54 +02:00
|
|
|
node_add_menu.add_node_type_with_searchable_enum(context, layout, "GeometryNodeWarning", "warning_type")
|
2022-11-01 16:09:49 +01:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2022-09-26 12:36:13 -05:00
|
|
|
class NODE_MT_category_GEO_POINT(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_category_GEO_POINT"
|
|
|
|
|
bl_label = "Point"
|
|
|
|
|
|
2023-03-23 15:31:14 +11:00
|
|
|
def draw(self, context):
|
2022-09-26 12:36:13 -05:00
|
|
|
layout = self.layout
|
2024-03-05 16:11:01 -05:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeDistributePointsInVolume")
|
2024-02-29 01:20:27 +01:00
|
|
|
if context.preferences.experimental.use_new_volume_nodes:
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeDistributePointsInGrid")
|
2022-09-26 12:36:13 -05:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeDistributePointsOnFaces")
|
2023-01-09 18:09:22 +01:00
|
|
|
layout.separator()
|
2022-09-26 12:36:13 -05:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodePoints")
|
2023-08-29 16:52:20 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodePointsToCurves")
|
2024-02-28 22:15:10 +01:00
|
|
|
if context.preferences.experimental.use_new_volume_nodes:
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodePointsToSDFGrid")
|
2022-09-26 12:36:13 -05:00
|
|
|
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")
|
2022-11-01 16:09:49 +01:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2022-09-27 16:36:27 +10:00
|
|
|
|
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
|
|
|
class NODE_MT_category_simulation(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_category_simulation"
|
|
|
|
|
bl_label = "Simulation"
|
|
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2024-09-30 17:09:00 +02:00
|
|
|
node_add_menu.add_simulation_zone(layout, label="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
|
|
|
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
|
|
|
|
|
|
|
|
|
|
|
2022-09-26 12:36:13 -05:00
|
|
|
class NODE_MT_category_GEO_TEXT(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_category_GEO_TEXT"
|
|
|
|
|
bl_label = "Text"
|
|
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
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
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeFormatString")
|
2022-09-26 12:36:13 -05:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeStringJoin")
|
2025-04-03 02:57:39 +02:00
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeMatchString")
|
2022-09-26 12:36:13 -05:00
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeReplaceString")
|
2022-09-29 11:08:21 +02:00
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeSliceString")
|
2023-01-09 18:09:22 +01:00
|
|
|
layout.separator()
|
2024-12-24 17:12:19 +01:00
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeFindInString")
|
2025-06-10 15:49:31 +02:00
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeStringLength")
|
2022-09-26 12:36:13 -05:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeStringToCurves")
|
2025-09-05 08:51:38 +02:00
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeStringToValue")
|
2022-09-29 11:08:21 +02:00
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeValueToString")
|
2022-09-26 12:36:13 -05:00
|
|
|
layout.separator()
|
|
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeInputSpecialCharacters")
|
2023-09-26 17:01:30 -04:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Utilities/Text")
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2022-09-26 12:36:13 -05:00
|
|
|
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")
|
2024-08-14 08:48:17 +02:00
|
|
|
node_add_menu.add_node_type(layout, "ShaderNodeTexGabor")
|
2022-09-26 12:36:13 -05:00
|
|
|
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")
|
2022-11-01 16:09:49 +01:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2022-09-26 12:36:13 -05:00
|
|
|
class NODE_MT_category_GEO_UTILITIES(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_category_GEO_UTILITIES"
|
|
|
|
|
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
|
|
|
|
|
layout.menu("NODE_MT_geometry_node_GEO_COLOR")
|
|
|
|
|
layout.menu("NODE_MT_category_GEO_TEXT")
|
|
|
|
|
layout.menu("NODE_MT_category_GEO_VECTOR")
|
|
|
|
|
layout.separator()
|
2025-08-08 13:48:02 +02:00
|
|
|
layout.menu("NODE_MT_category_utilities_bundle")
|
|
|
|
|
layout.menu("NODE_MT_category_utilities_closure")
|
2023-01-09 18:09:22 +01:00
|
|
|
layout.menu("NODE_MT_category_GEO_UTILITIES_FIELD")
|
2025-07-24 16:16:40 +02:00
|
|
|
if context.preferences.experimental.use_geometry_nodes_lists:
|
|
|
|
|
layout.menu("NODE_MT_category_utilities_list")
|
2025-07-31 21:08:47 +02:00
|
|
|
layout.menu("NODE_MT_category_GEO_UTILITIES_MATH")
|
2024-04-17 10:34:13 +02:00
|
|
|
layout.menu("NODE_MT_category_utilities_matrix")
|
2023-01-09 18:09:22 +01:00
|
|
|
layout.menu("NODE_MT_category_GEO_UTILITIES_ROTATION")
|
2024-02-06 19:08:01 +01:00
|
|
|
layout.menu("NODE_MT_category_GEO_UTILITIES_DEPRECATED")
|
2023-01-09 18:09:22 +01:00
|
|
|
layout.separator()
|
2024-09-30 17:09:00 +02:00
|
|
|
node_add_menu.add_foreach_geometry_element_zone(layout, label="For Each Element")
|
2024-01-29 14:17:10 -05:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeIndexSwitch")
|
2024-01-26 12:40:01 +01:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeMenuSwitch")
|
2023-01-09 18:09:22 +01:00
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeRandomValue")
|
2024-09-30 17:09:00 +02:00
|
|
|
node_add_menu.add_repeat_zone(layout, label="Repeat")
|
2023-01-09 18:09:22 +01:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeSwitch")
|
|
|
|
|
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
|
|
|
|
|
|
|
|
|
|
|
2024-02-06 19:08:01 +01:00
|
|
|
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
|
2024-04-30 15:52:11 +02:00
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeAlignEulerToVector")
|
2024-02-06 19:08:01 +01:00
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeRotateEuler")
|
2024-06-06 23:39:00 +02:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Utilities/Deprecated")
|
2024-02-06 19:08:01 +01:00
|
|
|
|
|
|
|
|
|
2023-01-09 18:09:22 +01:00
|
|
|
class NODE_MT_category_GEO_UTILITIES_FIELD(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_category_GEO_UTILITIES_FIELD"
|
|
|
|
|
bl_label = "Field"
|
|
|
|
|
|
2022-09-26 12:36:13 -05:00
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeAccumulateField")
|
2023-01-09 18:09:22 +01:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeFieldAtIndex")
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeFieldOnDomain")
|
2025-04-08 17:12:08 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeFieldAverage")
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeFieldMinAndMax")
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeFieldVariance")
|
2024-05-29 05:44:47 +02:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Utilities/Field")
|
2023-01-09 18:09:22 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
2024-04-30 15:52:11 +02:00
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeAlignRotationToVector")
|
2024-05-08 13:34:14 +02:00
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeAxesToRotation")
|
2023-08-24 14:58:55 +02:00
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeAxisAngleToRotation")
|
|
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeEulerToRotation")
|
|
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeInvertRotation")
|
2024-02-01 14:29:30 +01:00
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeRotateRotation")
|
2023-08-24 14:58:55 +02:00
|
|
|
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")
|
2023-09-26 17:01:30 -04:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Utilities/Rotation")
|
2023-01-09 18:09:22 +01:00
|
|
|
|
2023-01-16 14:39:10 +01:00
|
|
|
|
2024-02-13 18:59:36 +01:00
|
|
|
class NODE_MT_category_utilities_matrix(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_category_utilities_matrix"
|
|
|
|
|
bl_label = "Matrix"
|
|
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
2024-05-01 21:31:08 +02:00
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeCombineMatrix")
|
2024-02-13 18:59:36 +01:00
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeCombineTransform")
|
2024-09-30 21:30:10 +02:00
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeMatrixDeterminant", label="Determinant")
|
2024-02-13 18:59:36 +01:00
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeInvertMatrix")
|
|
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeMatrixMultiply")
|
2024-04-24 15:56:33 +02:00
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeProjectPoint")
|
2024-05-01 21:31:08 +02:00
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeSeparateMatrix")
|
2024-02-13 18:59:36 +01:00
|
|
|
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")
|
|
|
|
|
|
|
|
|
|
|
2025-07-31 21:08:47 +02:00
|
|
|
class NODE_MT_category_utilities_bundle(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_category_utilities_bundle"
|
|
|
|
|
bl_label = "Bundle"
|
|
|
|
|
|
|
|
|
|
def draw(self, context):
|
|
|
|
|
layout = self.layout
|
2025-08-02 10:17:39 +02:00
|
|
|
node_add_menu.add_node_type(layout, "NodeCombineBundle")
|
|
|
|
|
node_add_menu.add_node_type(layout, "NodeSeparateBundle")
|
2025-07-31 21:08:47 +02:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Utilities/Bundle")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class NODE_MT_category_utilities_closure(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_category_utilities_closure"
|
|
|
|
|
bl_label = "Closure"
|
|
|
|
|
|
|
|
|
|
def draw(self, context):
|
|
|
|
|
layout = self.layout
|
|
|
|
|
node_add_menu.add_closure_zone(layout, label="Closure")
|
2025-08-02 10:17:39 +02:00
|
|
|
node_add_menu.add_node_type(layout, "NodeEvaluateClosure")
|
2025-07-31 21:08:47 +02:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Utilities/Closure")
|
|
|
|
|
|
|
|
|
|
|
2025-07-24 16:16:40 +02:00
|
|
|
class NODE_MT_category_utilities_list(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_category_utilities_list"
|
|
|
|
|
bl_label = "List"
|
|
|
|
|
|
|
|
|
|
def draw(self, _context):
|
|
|
|
|
layout = self.layout
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeList")
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeListGetItem")
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeListLength")
|
|
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Utilities/List")
|
|
|
|
|
|
|
|
|
|
|
2023-01-09 18:09:22 +01:00
|
|
|
class NODE_MT_category_GEO_UTILITIES_MATH(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_category_GEO_UTILITIES_MATH"
|
|
|
|
|
bl_label = "Math"
|
|
|
|
|
|
2025-05-08 04:28:22 +02:00
|
|
|
def draw(self, context):
|
2023-01-09 18:09:22 +01:00
|
|
|
layout = self.layout
|
Nodes: add Bit Math node
This adds a new Bit Math node which supports the following operations: `and`,
`or`, `xor`, `not`, `shift` and `rotate`.
For the `shift` and `rotate` operations, a posititive shift is a left shift and
a negative shift is a right shift.
Currently, the node always works on 32-bit integers which is what Geometry Nodes
uses internally for integers. If required, this can be extended to work on other
bit widths in the future.
The need for this came up every now and then. It can be useful when encoding
specific bits in integer attributes (for efficiency or because the geometry is
exported to other software that expects a certain format). Also, this node is
useful for some people doing crazy but fun things with Geometry Nodes like
emulating hardware. Even if the use-cases are not common, if they arise, it's
hard to work around and the cost of having this node is quite low for us.
Co-authored-by: Charlie Jolly <charliejolly@noreply.localhost>
Pull Request: https://projects.blender.org/blender/blender/pulls/138290
2025-05-19 18:03:05 +02:00
|
|
|
node_add_menu.add_node_type_with_searchable_enum(
|
2025-07-11 16:43:13 +10:00
|
|
|
context, layout, "FunctionNodeBitMath", "operation", search_weight=-1.0,
|
|
|
|
|
)
|
2025-05-08 04:28:22 +02:00
|
|
|
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")
|
2022-09-29 11:08:21 +02:00
|
|
|
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")
|
2024-08-30 16:42:29 +02:00
|
|
|
node_add_menu.add_node_type(layout, "FunctionNodeHashValue")
|
2022-09-26 12:36:13 -05:00
|
|
|
node_add_menu.add_node_type(layout, "ShaderNodeMapRange")
|
2025-05-08 04:28:22 +02:00
|
|
|
node_add_menu.add_node_type_with_searchable_enum(context, layout, "ShaderNodeMath", "operation")
|
2022-09-26 12:36:13 -05:00
|
|
|
node_add_menu.add_node_type(layout, "ShaderNodeMix")
|
2023-09-26 17:01:30 -04:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Utilities/Math")
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2022-09-26 12:36:13 -05:00
|
|
|
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")
|
2023-09-26 17:01:30 -04:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Mesh/UV")
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2022-09-26 12:36:13 -05:00
|
|
|
class NODE_MT_category_GEO_VECTOR(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_category_GEO_VECTOR"
|
|
|
|
|
bl_label = "Vector"
|
|
|
|
|
|
2025-05-08 04:28:22 +02:00
|
|
|
def draw(self, context):
|
2022-09-26 12:36:13 -05:00
|
|
|
layout = self.layout
|
|
|
|
|
node_add_menu.add_node_type(layout, "ShaderNodeVectorCurve")
|
2025-05-08 04:28:22 +02:00
|
|
|
node_add_menu.add_node_type_with_searchable_enum(context, layout, "ShaderNodeVectorMath", "operation")
|
2022-09-26 12:36:13 -05:00
|
|
|
node_add_menu.add_node_type(layout, "ShaderNodeVectorRotate")
|
2023-01-09 18:09:22 +01:00
|
|
|
layout.separator()
|
|
|
|
|
node_add_menu.add_node_type(layout, "ShaderNodeCombineXYZ")
|
I18n: Translate GN Add > Input > Import menu items
Geometry Nodes' Add > Input > Import menu includes file format items
such as "Standford PLY (.ply)", "STL (.stl)", "Text (.txt)". The
latter needs to be translated because "Text" is a generic format.
These items are declared using a custom function
`node_add_menu.add_node_type`, with a `label` argument. This commit
adds the `label` argument to the function arguments that can be
extracted from specific node declaration functions, and specifies the
argument position for each:
"add_node_type", "add_node_type_with_outputs", "add_simulation_zone",
"add_repeat_zone", "add_foreach_geometry_element_zone",
"add_closure_zone".
There is currently no facility to specify a translation context but it
could be easily added if the need arises.
Most of these functions do not actually declare new, unique messages,
but it could happen in the future. In addition, two messages were
extracted using manual `iface_()` calls, which are no longer needed
after this change.
Reported by Ye Gui in #43295.
2025-06-30 11:31:45 +02:00
|
|
|
props = node_add_menu.add_node_type(layout, "ShaderNodeMix", label="Mix Vector")
|
2023-01-09 18:09:22 +01:00
|
|
|
ops = props.settings.add()
|
|
|
|
|
ops.name = "data_type"
|
|
|
|
|
ops.value = "'VECTOR'"
|
|
|
|
|
node_add_menu.add_node_type(layout, "ShaderNodeSeparateXYZ")
|
2023-09-26 17:01:30 -04:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Utilities/Vector")
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2022-09-26 12:36:13 -05:00
|
|
|
class NODE_MT_category_GEO_VOLUME(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_category_GEO_VOLUME"
|
|
|
|
|
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
|
2023-12-20 22:33:17 +01:00
|
|
|
if context.preferences.experimental.use_new_volume_nodes:
|
|
|
|
|
layout.menu("NODE_MT_geometry_node_GEO_VOLUME_READ")
|
2024-02-22 17:58:09 +01:00
|
|
|
layout.menu("NODE_MT_geometry_node_volume_sample")
|
2023-12-20 22:33:17 +01:00
|
|
|
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")
|
2022-11-01 16:09:49 +01:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2023-12-20 22:33:17 +01:00
|
|
|
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")
|
2025-05-12 13:46:40 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeGridInfo")
|
2023-12-20 22:33:17 +01:00
|
|
|
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")
|
|
|
|
|
|
|
|
|
|
|
2024-02-22 17:58:09 +01:00
|
|
|
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")
|
2024-05-07 21:53:22 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeSampleGridIndex")
|
2024-02-22 17:58:09 +01:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, "Volume/Sample")
|
|
|
|
|
|
|
|
|
|
|
2023-12-20 22:33:17 +01:00
|
|
|
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")
|
2024-02-29 01:20:27 +01:00
|
|
|
if context.preferences.experimental.use_new_volume_nodes:
|
|
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeGridToMesh")
|
2024-04-23 14:48:59 +02:00
|
|
|
node_add_menu.add_node_type(layout, "GeometryNodeSDFGridBoolean")
|
2023-12-20 22:33:17 +01:00
|
|
|
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")
|
|
|
|
|
|
|
|
|
|
|
2022-09-26 12:36:13 -05:00
|
|
|
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)
|
2022-11-01 16:09:49 +01:00
|
|
|
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
|
2022-09-26 12:36:13 -05:00
|
|
|
|
2022-09-27 16:36:27 +10:00
|
|
|
|
2022-09-26 12:36:13 -05:00
|
|
|
class NODE_MT_geometry_node_add_all(Menu):
|
|
|
|
|
bl_idname = "NODE_MT_geometry_node_add_all"
|
|
|
|
|
bl_label = ""
|
|
|
|
|
|
2023-08-04 20:59:04 +02:00
|
|
|
def draw(self, context):
|
2022-09-26 12:36:13 -05:00
|
|
|
layout = self.layout
|
|
|
|
|
layout.menu("NODE_MT_geometry_node_GEO_ATTRIBUTE")
|
|
|
|
|
layout.menu("NODE_MT_geometry_node_GEO_INPUT")
|
2023-01-09 18:09:22 +01:00
|
|
|
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")
|
2025-04-08 09:51:28 -04:00
|
|
|
layout.menu("NODE_MT_geometry_node_grease_pencil")
|
2022-09-26 12:36:13 -05:00
|
|
|
layout.menu("NODE_MT_geometry_node_GEO_INSTANCE")
|
|
|
|
|
layout.menu("NODE_MT_geometry_node_GEO_MESH")
|
|
|
|
|
layout.menu("NODE_MT_category_GEO_POINT")
|
2023-01-09 18:09:22 +01:00
|
|
|
layout.menu("NODE_MT_category_GEO_VOLUME")
|
|
|
|
|
layout.separator()
|
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.menu("NODE_MT_category_simulation")
|
|
|
|
|
layout.separator()
|
2023-01-09 18:09:22 +01:00
|
|
|
layout.menu("NODE_MT_geometry_node_GEO_MATERIAL")
|
2022-09-26 12:36:13 -05:00
|
|
|
layout.menu("NODE_MT_category_GEO_TEXTURE")
|
|
|
|
|
layout.menu("NODE_MT_category_GEO_UTILITIES")
|
2023-01-09 18:09:22 +01:00
|
|
|
layout.separator()
|
2022-09-26 12:36:13 -05:00
|
|
|
layout.menu("NODE_MT_category_GEO_GROUP")
|
2023-09-01 20:46:12 +02:00
|
|
|
layout.menu("NODE_MT_category_layout")
|
2022-11-01 16:09:49 +01:00
|
|
|
node_add_menu.draw_root_assets(layout)
|
2022-09-26 12:36:13 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
classes = (
|
|
|
|
|
NODE_MT_geometry_node_add_all,
|
|
|
|
|
NODE_MT_geometry_node_GEO_ATTRIBUTE,
|
2023-01-09 18:09:22 +01:00
|
|
|
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,
|
2022-09-26 12:36:13 -05:00
|
|
|
NODE_MT_geometry_node_GEO_CURVE,
|
2023-01-09 18:09:22 +01:00
|
|
|
NODE_MT_geometry_node_GEO_CURVE_READ,
|
2023-02-03 16:26:30 -05:00
|
|
|
NODE_MT_geometry_node_GEO_CURVE_SAMPLE,
|
2023-01-09 18:09:22 +01:00
|
|
|
NODE_MT_geometry_node_GEO_CURVE_WRITE,
|
|
|
|
|
NODE_MT_geometry_node_GEO_CURVE_OPERATIONS,
|
2022-09-26 12:36:13 -05:00
|
|
|
NODE_MT_geometry_node_GEO_PRIMITIVES_CURVE,
|
2022-09-28 14:38:27 -05:00
|
|
|
NODE_MT_geometry_node_curve_topology,
|
2025-04-08 09:51:28 -04:00
|
|
|
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,
|
2022-09-26 12:36:13 -05:00
|
|
|
NODE_MT_geometry_node_GEO_GEOMETRY,
|
2023-01-09 18:09:22 +01:00
|
|
|
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,
|
2022-09-26 12:36:13 -05:00
|
|
|
NODE_MT_geometry_node_GEO_INSTANCE,
|
|
|
|
|
NODE_MT_geometry_node_GEO_MESH,
|
2023-01-09 18:09:22 +01:00
|
|
|
NODE_MT_geometry_node_GEO_MESH_READ,
|
2023-02-03 16:26:30 -05:00
|
|
|
NODE_MT_geometry_node_GEO_MESH_SAMPLE,
|
2023-01-09 18:09:22 +01:00
|
|
|
NODE_MT_geometry_node_GEO_MESH_WRITE,
|
|
|
|
|
NODE_MT_geometry_node_GEO_MESH_OPERATIONS,
|
|
|
|
|
NODE_MT_category_GEO_UV,
|
2022-09-26 12:36:13 -05:00
|
|
|
NODE_MT_category_PRIMITIVES_MESH,
|
2024-06-10 15:38:43 -04:00
|
|
|
NODE_MT_category_import,
|
2022-09-28 14:38:27 -05:00
|
|
|
NODE_MT_geometry_node_mesh_topology,
|
2022-09-26 12:36:13 -05:00
|
|
|
NODE_MT_category_GEO_POINT,
|
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
|
|
|
NODE_MT_category_simulation,
|
2023-01-09 18:09:22 +01:00
|
|
|
NODE_MT_category_GEO_VOLUME,
|
2023-12-20 22:33:17 +01:00
|
|
|
NODE_MT_geometry_node_GEO_VOLUME_READ,
|
2024-02-22 17:58:09 +01:00
|
|
|
NODE_MT_geometry_node_volume_sample,
|
2023-12-20 22:33:17 +01:00
|
|
|
NODE_MT_geometry_node_GEO_VOLUME_WRITE,
|
|
|
|
|
NODE_MT_geometry_node_GEO_VOLUME_OPERATIONS,
|
|
|
|
|
NODE_MT_geometry_node_GEO_VOLUME_PRIMITIVES,
|
2023-01-09 18:09:22 +01:00
|
|
|
NODE_MT_geometry_node_GEO_MATERIAL,
|
2022-09-26 12:36:13 -05:00
|
|
|
NODE_MT_category_GEO_TEXTURE,
|
|
|
|
|
NODE_MT_category_GEO_UTILITIES,
|
2023-01-09 18:09:22 +01:00
|
|
|
NODE_MT_geometry_node_GEO_COLOR,
|
|
|
|
|
NODE_MT_category_GEO_TEXT,
|
2022-09-26 12:36:13 -05:00
|
|
|
NODE_MT_category_GEO_VECTOR,
|
2023-01-09 18:09:22 +01:00
|
|
|
NODE_MT_category_GEO_UTILITIES_FIELD,
|
|
|
|
|
NODE_MT_category_GEO_UTILITIES_MATH,
|
|
|
|
|
NODE_MT_category_GEO_UTILITIES_ROTATION,
|
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
|
|
|
NODE_MT_geometry_node_GEO_INPUT_GIZMO,
|
2025-07-24 16:16:40 +02:00
|
|
|
NODE_MT_category_utilities_list,
|
2024-02-13 18:59:36 +01:00
|
|
|
NODE_MT_category_utilities_matrix,
|
2025-07-31 21:08:47 +02:00
|
|
|
NODE_MT_category_utilities_bundle,
|
|
|
|
|
NODE_MT_category_utilities_closure,
|
2024-02-06 19:08:01 +01:00
|
|
|
NODE_MT_category_GEO_UTILITIES_DEPRECATED,
|
2022-09-26 12:36:13 -05:00
|
|
|
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)
|