Files
test2/scripts/startup/bl_ui/node_add_menu_compositor.py
Omar Emara 5841cb21f7 Fix #146759: Radial Tilling node crashes in the compositor
The Radial Tilling node crashes in the compositor in GPU mode. This is
because the compositor does not yet support 2D vectors in shader code
generation, but properly supports and expects them in the interface,
which the Radial Tilling node declares. This results in a bad shader
which crashes Blender.

To properly fix this, we need to:

- Support 2D vectors in compositor GPU material shader code generation.
- Support 2D vectors in shader node GPU stack construction.
- Adjust the interface of radial tilling to actually use 2D vectors.

This seems risky for 5.0, so this patch temporarily drops support for
the node in the compositor in 5.0. Then once 2D vectors are supported,
it can be enabled again.

Pull Request: https://projects.blender.org/blender/blender/pulls/147627
2025-10-09 17:23:12 +02:00

438 lines
17 KiB
Python

# SPDX-FileCopyrightText: 2022-2023 Blender Authors
#
# SPDX-License-Identifier: GPL-2.0-or-later
from bl_ui import node_add_menu
from bpy.app.translations import (
contexts as i18n_contexts,
)
class NODE_MT_compositor_node_input_base(node_add_menu.NodeMenu):
bl_label = "Input"
def draw(self, context):
del context
layout = self.layout
self.draw_menu(layout, path="Input/Constant")
layout.separator()
self.node_operator(layout, "NodeGroupInput")
self.node_operator(layout, "CompositorNodeBokehImage")
self.node_operator(layout, "CompositorNodeImage")
self.node_operator(layout, "CompositorNodeImageInfo")
self.node_operator(layout, "CompositorNodeImageCoordinates")
self.node_operator(layout, "CompositorNodeMask")
self.node_operator(layout, "CompositorNodeMovieClip")
layout.separator()
self.draw_menu(layout, path="Input/Scene")
self.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_compositor_node_input_constant_base(node_add_menu.NodeMenu):
bl_label = "Constant"
menu_path = "Input/Constant"
def draw(self, _context):
layout = self.layout
self.node_operator(layout, "CompositorNodeRGB")
self.node_operator(layout, "ShaderNodeValue")
self.node_operator(layout, "CompositorNodeNormal")
self.draw_assets_for_catalog(layout, self.menu_path)
class NODE_MT_compositor_node_input_scene_base(node_add_menu.NodeMenu):
bl_label = "Scene"
menu_path = "Input/Scene"
def draw(self, context):
layout = self.layout
if context.space_data.node_tree_sub_type == 'SCENE':
self.node_operator(layout, "CompositorNodeRLayers")
self.node_operator_with_outputs(context, layout, "CompositorNodeSceneTime", ["Frame", "Seconds"])
self.node_operator(layout, "CompositorNodeTime")
self.draw_assets_for_catalog(layout, self.menu_path)
class NODE_MT_compositor_node_output_base(node_add_menu.NodeMenu):
bl_label = "Output"
def draw(self, context):
layout = self.layout
self.node_operator(layout, "NodeEnableOutput")
self.node_operator(layout, "NodeGroupOutput")
self.node_operator(layout, "CompositorNodeViewer")
if context.space_data.node_tree_sub_type == 'SCENE':
layout.separator()
self.node_operator(layout, "CompositorNodeOutputFile")
self.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_compositor_node_color_base(node_add_menu.NodeMenu):
bl_label = "Color"
def draw(self, context):
layout = self.layout
self.draw_menu(layout, path="Color/Adjust")
layout.separator()
self.node_operator(layout, "CompositorNodePremulKey")
self.node_operator(layout, "CompositorNodeAlphaOver")
self.node_operator(layout, "CompositorNodeSetAlpha")
layout.separator()
self.node_operator(layout, "CompositorNodeCombineColor")
self.node_operator(layout, "CompositorNodeSeparateColor")
layout.separator()
self.node_operator(layout, "CompositorNodeZcombine")
self.color_mix_node(context, layout)
layout.separator()
self.node_operator(layout, "ShaderNodeBlackbody")
self.node_operator(layout, "ShaderNodeValToRGB")
self.node_operator(layout, "CompositorNodeConvertColorSpace")
self.node_operator(layout, "CompositorNodeConvertToDisplay")
layout.separator()
self.node_operator(layout, "CompositorNodeInvert")
self.node_operator(layout, "CompositorNodeRGBToBW")
self.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_compositor_node_color_adjust_base(node_add_menu.NodeMenu):
bl_label = "Adjust"
menu_path = "Color/Adjust"
def draw(self, _context):
layout = self.layout
self.node_operator(layout, "CompositorNodeBrightContrast")
self.node_operator(layout, "CompositorNodeColorBalance")
self.node_operator(layout, "CompositorNodeColorCorrection")
self.node_operator(layout, "CompositorNodeExposure")
self.node_operator(layout, "ShaderNodeGamma")
self.node_operator(layout, "CompositorNodeHueCorrect")
self.node_operator(layout, "CompositorNodeHueSat")
self.node_operator(layout, "CompositorNodeCurveRGB")
self.node_operator(layout, "CompositorNodeTonemap")
self.draw_assets_for_catalog(layout, self.menu_path)
class NODE_MT_compositor_node_color_mix_base(node_add_menu.NodeMenu):
bl_label = "Mix"
menu_path = "Color/Mix"
def draw(self, context):
del context
layout = self.layout
self.draw_assets_for_catalog(layout, self.menu_path)
class NODE_MT_compositor_node_filter_base(node_add_menu.NodeMenu):
bl_label = "Filter"
def draw(self, context):
layout = self.layout
self.draw_menu(layout, path="Filter/Blur")
layout.separator()
self.node_operator(layout, "CompositorNodeAntiAliasing")
self.node_operator(layout, "CompositorNodeConvolve")
self.node_operator(layout, "CompositorNodeDenoise")
self.node_operator(layout, "CompositorNodeDespeckle")
layout.separator()
self.node_operator(layout, "CompositorNodeDilateErode")
self.node_operator(layout, "CompositorNodeInpaint")
layout.separator()
self.node_operator_with_searchable_enum_socket(
context, layout, "CompositorNodeFilter", "Type", [
"Soften", "Box Sharpen", "Diamond Sharpen", "Laplace", "Sobel", "Prewitt", "Kirsch", "Shadow"])
self.node_operator_with_searchable_enum_socket(
context, layout, "CompositorNodeGlare", "Type", [
"Bloom", "Ghosts", "Streaks", "Fog Glow", "Simple Star", "Sun Beams", "Kernel"])
self.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_compositor_node_filter_blur_base(node_add_menu.NodeMenu):
bl_label = "Blur"
menu_path = "Filter/Blur"
def draw(self, _context):
layout = self.layout
self.node_operator(layout, "CompositorNodeBilateralblur")
self.node_operator(layout, "CompositorNodeBlur")
self.node_operator(layout, "CompositorNodeBokehBlur")
self.node_operator(layout, "CompositorNodeDefocus")
self.node_operator(layout, "CompositorNodeDBlur")
self.node_operator(layout, "CompositorNodeVecBlur")
self.draw_assets_for_catalog(layout, self.menu_path)
class NODE_MT_compositor_node_keying_base(node_add_menu.NodeMenu):
bl_label = "Keying"
def draw(self, _context):
layout = self.layout
self.node_operator(layout, "CompositorNodeChannelMatte")
self.node_operator(layout, "CompositorNodeChromaMatte")
self.node_operator(layout, "CompositorNodeColorMatte")
self.node_operator(layout, "CompositorNodeColorSpill")
self.node_operator(layout, "CompositorNodeDiffMatte")
self.node_operator(layout, "CompositorNodeDistanceMatte")
self.node_operator(layout, "CompositorNodeKeying")
self.node_operator(layout, "CompositorNodeKeyingScreen")
self.node_operator(layout, "CompositorNodeLumaMatte")
self.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_compositor_node_mask_base(node_add_menu.NodeMenu):
bl_label = "Mask"
def draw(self, _context):
layout = self.layout
self.node_operator(layout, "CompositorNodeCryptomatteV2")
self.node_operator(layout, "CompositorNodeCryptomatte")
layout.separator()
self.node_operator(layout, "CompositorNodeBoxMask")
self.node_operator(layout, "CompositorNodeEllipseMask")
layout.separator()
self.node_operator(layout, "CompositorNodeDoubleEdgeMask")
self.node_operator(layout, "CompositorNodeIDMask")
self.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_compositor_node_tracking_base(node_add_menu.NodeMenu):
bl_label = "Tracking"
bl_translation_context = i18n_contexts.id_movieclip
def draw(self, _context):
layout = self.layout
self.node_operator(layout, "CompositorNodePlaneTrackDeform")
self.node_operator(layout, "CompositorNodeStabilize")
self.node_operator(layout, "CompositorNodeTrackPos")
self.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_compositor_node_transform_base(node_add_menu.NodeMenu):
bl_label = "Transform"
def draw(self, _context):
layout = self.layout
self.node_operator(layout, "CompositorNodeRotate")
self.node_operator(layout, "CompositorNodeScale")
self.node_operator(layout, "CompositorNodeTransform")
self.node_operator(layout, "CompositorNodeTranslate")
layout.separator()
self.node_operator(layout, "CompositorNodeCornerPin")
self.node_operator(layout, "CompositorNodeCrop")
layout.separator()
self.node_operator(layout, "CompositorNodeDisplace")
self.node_operator(layout, "CompositorNodeFlip")
self.node_operator(layout, "CompositorNodeMapUV")
layout.separator()
self.node_operator(layout, "CompositorNodeLensdist")
self.node_operator(layout, "CompositorNodeMovieDistortion")
self.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_compositor_node_texture_base(node_add_menu.NodeMenu):
bl_label = "Texture"
def draw(self, _context):
layout = self.layout
self.node_operator(layout, "ShaderNodeTexBrick")
self.node_operator(layout, "ShaderNodeTexChecker")
self.node_operator(layout, "ShaderNodeTexGabor")
self.node_operator(layout, "ShaderNodeTexGradient")
self.node_operator(layout, "ShaderNodeTexMagic")
self.node_operator(layout, "ShaderNodeTexNoise")
self.node_operator(layout, "ShaderNodeTexVoronoi")
self.node_operator(layout, "ShaderNodeTexWave")
self.node_operator(layout, "ShaderNodeTexWhiteNoise")
self.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_compositor_node_utilities_base(node_add_menu.NodeMenu):
bl_label = "Utilities"
def draw(self, context):
del context
layout = self.layout
self.draw_menu(layout, path="Utilities/Math")
self.draw_menu(layout, path="Utilities/Vector")
layout.separator()
self.node_operator(layout, "CompositorNodeLevels")
self.node_operator(layout, "CompositorNodeNormalize")
layout.separator()
self.node_operator(layout, "CompositorNodeSplit")
self.node_operator(layout, "CompositorNodeSwitch")
self.node_operator(layout, "GeometryNodeMenuSwitch")
self.node_operator(
layout, "CompositorNodeSwitchView",
label="Switch Stereo View")
layout.separator()
self.node_operator(layout, "CompositorNodeRelativeToPixel")
self.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_compositor_node_vector_base(node_add_menu.NodeMenu):
bl_label = "Vector"
menu_path = "Utilities/Vector"
def draw(self, context):
layout = self.layout
self.node_operator(layout, "ShaderNodeCombineXYZ")
props = self.node_operator(layout, "ShaderNodeMapRange")
ops = props.settings.add()
ops.name = "data_type"
ops.value = "'FLOAT_VECTOR'"
props = self.node_operator(layout, "ShaderNodeMix", label="Mix Vector")
ops = props.settings.add()
ops.name = "data_type"
ops.value = "'VECTOR'"
self.node_operator(layout, "ShaderNodeSeparateXYZ")
layout.separator()
self.node_operator(layout, "ShaderNodeVectorCurve")
self.node_operator_with_searchable_enum(context, layout, "ShaderNodeVectorMath", "operation")
self.node_operator(layout, "ShaderNodeVectorRotate")
self.draw_assets_for_catalog(layout, self.menu_path)
class NODE_MT_compositor_node_math_base(node_add_menu.NodeMenu):
bl_label = "Math"
menu_path = "Utilities/Math"
def draw(self, context):
layout = self.layout
self.node_operator(layout, "ShaderNodeClamp")
self.node_operator(layout, "ShaderNodeFloatCurve")
self.node_operator(layout, "ShaderNodeMapRange")
self.node_operator_with_searchable_enum(context, layout, "ShaderNodeMath", "operation")
self.node_operator(layout, "ShaderNodeMix")
self.draw_assets_for_catalog(layout, self.menu_path)
class NODE_MT_compositor_node_creative_base(node_add_menu.NodeMenu):
bl_label = "Creative"
def draw(self, _context):
layout = self.layout
self.node_operator(layout, "CompositorNodeKuwahara")
self.node_operator(layout, "CompositorNodePixelate")
self.node_operator(layout, "CompositorNodePosterize")
self.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_compositor_node_all_base(node_add_menu.NodeMenu):
bl_label = ""
menu_path = "Root"
bl_translation_context = i18n_contexts.operator_default
# NOTE: Menus are looked up via their label, this is so that both the Add
# & Swap menus can share the same layout while each using their
# corresponding menus
def draw(self, context):
del context
layout = self.layout
self.draw_menu(layout, "Input")
self.draw_menu(layout, "Output")
layout.separator()
self.draw_menu(layout, "Color")
self.draw_menu(layout, "Creative")
self.draw_menu(layout, "Filter")
layout.separator()
self.draw_menu(layout, "Keying")
self.draw_menu(layout, "Mask")
layout.separator()
self.draw_menu(layout, "Tracking")
layout.separator()
self.draw_menu(layout, "Texture")
self.draw_menu(layout, "Transform")
self.draw_menu(layout, "Utilities")
layout.separator()
self.draw_root_assets(layout)
layout.separator()
self.draw_menu(layout, "Group")
self.draw_menu(layout, "Layout")
add_menus = {
# menu bl_idname: baseclass
"NODE_MT_category_compositor_input": NODE_MT_compositor_node_input_base,
"NODE_MT_category_compositor_input_constant": NODE_MT_compositor_node_input_constant_base,
"NODE_MT_category_compositor_input_scene": NODE_MT_compositor_node_input_scene_base,
"NODE_MT_category_compositor_output": NODE_MT_compositor_node_output_base,
"NODE_MT_category_compositor_color": NODE_MT_compositor_node_color_base,
"NODE_MT_category_compositor_color_adjust": NODE_MT_compositor_node_color_adjust_base,
"NODE_MT_category_compositor_filter": NODE_MT_compositor_node_filter_base,
"NODE_MT_category_compositor_filter_blur": NODE_MT_compositor_node_filter_blur_base,
"NODE_MT_category_compositor_creative": NODE_MT_compositor_node_creative_base,
"NODE_MT_category_compositor_texture": NODE_MT_compositor_node_texture_base,
"NODE_MT_category_compositor_keying": NODE_MT_compositor_node_keying_base,
"NODE_MT_category_compositor_mask": NODE_MT_compositor_node_mask_base,
"NODE_MT_category_compositor_tracking": NODE_MT_compositor_node_tracking_base,
"NODE_MT_category_compositor_transform": NODE_MT_compositor_node_transform_base,
"NODE_MT_category_compositor_utilities": NODE_MT_compositor_node_utilities_base,
"NODE_MT_category_compositor_vector": NODE_MT_compositor_node_vector_base,
"NODE_MT_category_compositor_math": NODE_MT_compositor_node_math_base,
"NODE_MT_compositor_node_add_all": NODE_MT_compositor_node_all_base,
}
add_menus = node_add_menu.generate_menus(
add_menus,
template=node_add_menu.AddNodeMenu,
base_dict=node_add_menu.add_base_pathing_dict
)
swap_menus = {
# menu bl_idname: baseclass
"NODE_MT_compositor_node_input_swap": NODE_MT_compositor_node_input_base,
"NODE_MT_compositor_node_input_constant_swap": NODE_MT_compositor_node_input_constant_base,
"NODE_MT_compositor_node_input_scene_swap": NODE_MT_compositor_node_input_scene_base,
"NODE_MT_compositor_node_output_swap": NODE_MT_compositor_node_output_base,
"NODE_MT_compositor_node_color_swap": NODE_MT_compositor_node_color_base,
"NODE_MT_compositor_node_color_adjust_swap": NODE_MT_compositor_node_color_adjust_base,
"NODE_MT_compositor_node_filter_swap": NODE_MT_compositor_node_filter_base,
"NODE_MT_compositor_node_filter_blur_swap": NODE_MT_compositor_node_filter_blur_base,
"NODE_MT_category_compositor_creative_swap": NODE_MT_compositor_node_creative_base,
"NODE_MT_compositor_node_texture_swap": NODE_MT_compositor_node_texture_base,
"NODE_MT_compositor_node_keying_swap": NODE_MT_compositor_node_keying_base,
"NODE_MT_compositor_node_mask_swap": NODE_MT_compositor_node_mask_base,
"NODE_MT_compositor_node_tracking_swap": NODE_MT_compositor_node_tracking_base,
"NODE_MT_compositor_node_transform_swap": NODE_MT_compositor_node_transform_base,
"NODE_MT_compositor_node_utilities_swap": NODE_MT_compositor_node_utilities_base,
"NODE_MT_compositor_node_vector_swap": NODE_MT_compositor_node_vector_base,
"NODE_MT_compositor_node_math_swap": NODE_MT_compositor_node_math_base,
"NODE_MT_compositor_node_swap_all": NODE_MT_compositor_node_all_base,
}
swap_menus = node_add_menu.generate_menus(
swap_menus,
template=node_add_menu.SwapNodeMenu,
base_dict=node_add_menu.swap_base_pathing_dict
)
classes = (
*add_menus,
*swap_menus,
)
if __name__ == "__main__": # only for live edit.
from bpy.utils import register_class
for cls in classes:
register_class(cls)