This is a plugin which tries hard to make Unreal Editor Tools As Easy As Possible.
TAPython is an editor plugin for Unreal Engine. It provides a framework for creating python editor tools in Unreal Engine, and live Slate editing for developers, which makes creating menus and UE native Slate UI much easier and faster(without any compiling time or restart editor). The plugin also provides 200+ editor tool interfaces to use, making developing UE editor tools very simple and efficient.
Thank you, TAPython's stargazers✨.😄
Support UE 5.4.4
SCircularThrobber
SProperty
apply_world_offset
for applying world offsetdelete_umap
for deleting UMapget_weightmap_data
for getting the weight map used by the specified layer of the terrainget_weightmap_data
for getting the weight map used by the specified layer of the terrainset_weightmap_data
for setting the weight map used by the specified layer of the terrainget_layer_names
for getting the names of the layers used by the terrainclear_layer
for clearing the specified layer of the terrainclear_all_layers
for clearing all layers of the terrainget_visibility_data
for getting the visibility data of the specified layer of the terrainassign_layer_info
for specifying the layer information of the terrainrecalculate_normals
for recalculating the normals of the terrainget_used_paint_layers
for getting the names of the layers already used by the terrainAdd Aliases
field in the json
file to set aliases. For example, in the following settings, you can use $this_tool
in the settings to replace PCG_Bridge.PCG_Bridge.PCG_Bridge()
later, and you can use $this_tool
in the Json file settings to replace the content after it.
"Aliases": {
"$this_tool": "PCG_Bridge.PCG_Bridge.PCG_Bridge()"
},
BorderBackgroundColor
not being set for SExpandableArea
Add the following settings to control the behavior of DetailPanelCustomization
.
[DetailPanelCustomization]
IsDetailCustomizationEnabled=True
IsForceAddDetailCustomization=False
IsReusingWidget=False
ClassName=SomeClassA
ClassName=SomeClassB
DetailPanelCustomization
DetailPanelCustomization
, which need to be set in the config first, and then set their specific content in the editoradd_detail_customization
to add DetailPanelCustomization
to the specified objectclear_detail_customization
to clear DetailPanelCustomization
get_customized_object
to get the CustomizationPanel of the specified object through UniqueIDlog_all_saved_detail_customization
to print all saved Customizationget_detail_panel_customized_class_names
to get all UClass that have been added CustomizationGetUniqueID
to get the UniqueID of the specified objectSupport UE5.4.1
Unreal Engine 5.4 uses Python 3.11.8, so we need to install the third-party library of Python 3.11.8.
If you are using the default resources provided by the old TAPython, some of the code in the old ObjectDetailViewer is incompatible with 3.11.8. You can find the corresponding file in the DefaultResources of TAPython v1.2.2 and replace the original file. Or you can also find the corresponding file here
The menu items created through the "MenuEntries" field will be automatically sorted
SOverlay
field 'unhandled' messageBelow is Experimental. It is only recorded here. There may be major changes later, and it is not recommended to use it in official tools.
Add the ability to modify the content of TextureArray (Experimental)
Add Define menu entry directly in Chameleon Tool's Json file
feature. (In contrast, previous versions required defining menu entries in MenuConfig.json
)
This feature is similar to the way Unity's MenuItem works, eliminating the need to define menu entries in MenuConfig.json
. It is undoubtedly a great help for the migration and merging of tools.
Add menu entries for the tool through the MenuEntries
field in the ChameleonTools json file. For example, in the following example, a menu entry Tools/Image Compare
is defined for "Chameleon Tool". Clicking this menu entry will open the Image Compare
tool.
{
"TabLabel": "Image Compare",
"InitTabSize": [1000, 650],
"InitTabPosition": [200, 100],
"MenuEntries": ["Tools/Image Compare"],
"Icon": {"style": "ChameleonStyle", "name": "Picture" },
"InitPyCmd": "..."
}
This tool has been added to Default Python Source and can be used directly.
The menu items are separated by /
, for example Tools/Image Comparison
, which means that Tools
is a menu group and Image Compare
is a menu item under the menu group.
The MenuEntries field supports multiple menu entries, although in most cases, a tool only needs one menu entry. Currently, this feature supports adding menu items to the blue Chameleon button in the toolbar, and will support adding menu items to other locations in the future.
The Icon
field can be used to add icons to menu items, and the specific method is similar to the method of adding icons to menu items in MenuConfig.json
.
A new configuration item MenuFromToolsJsonEnabled
has been added to Config.ini to control whether to enable the function of reading menu entries from Json files. The default value is True
.
SDPIScaler
.The SDPIScaler
widget can control the scaling ratio of its child components. The usage is as follows:
"SDPIScaler":
{
"Aka": "Scaler",
"DPIScaler": 1.0,
"Content": {
...
}
}
SDIPScaler
is similar to widgets such as SBox
that have a child widget, and also has a Content
field to specify its child widget.
Within ChameleonData
, the scaling ratio of the SDPIScaler widget can be set through the newly added set_dpi_scale
method.
SDropTarget
adds the OverrideBackgroundImagePadding
field to set the Padding of the SDropTarget
background image.
SComboBox
adds the keyword: InitiallySelectedItem
, which specifies the initially selected item of the SCoboBox
.
SEditableText
, SEditableTextBox
adds the IsPassword
field to specify whether it is a password input box.
SImage
adds support for the Tile
field to specify the SImage in repeat mode. The optional values are:
Add set_image_data_base64
Set the SImage's image data from base64 string
Add set_image_data_from_memory
Set the SImage's image data from memory
Optimize the performance of set_image_data
in UE5
set_image_data
, set_image_data_from_memory
, set_image_from_path
, set_image_from
and other methods add two new parameters: Tint and Tiling, used to set the color and repeat mode of SImage
Add set_image_data_from_texture2d
to directly set the image of the SImage
in the UI through the Texture2D
in the project
Added set_desired_size_override
to set the desired size of SImage
Added get_chameleon_desired_size
to get the desired size of the entire interface of Chameleon Tool.
A new module has been added to use RBF (Radial Basis Function) interpolation in Python
get_texture2d_content
to get the content of the 8-bit texture and return a byte arrayAdd debug command TAPython.OverrideEnable 1
Enter this command in the CMD debug window, and the contents of the DefaultResource
directory in the default resource of the plugin will replace the contents of the TA/TAPython
directory in the current project.
CAUTION
This command will overwrite the contents of the TA/Python
directory and will not delete the contents of the directory. Please make a backup before using it.
{: .alert .alert-warning}
Compare the differences between two images, such as comparing the rendering content of the scene and the rendering content of the wireframe mode
Or compare two different textures
SSplitter
and SDPI
widgetsAdd icons
Set LogOnTickWarnings
of config.ini
default value to False
set_image_data
The first parameter raw_data of set_image_data supports compressed data in Zlib formatFor example, the code used to fill SImage before is:
self.data.set_image_data(self.ui_image, img.data.tobytes(), width, height, channel_num)
change to:
self.data.set_image_data(self.ui_image, zlib.compress(img.data.tobytes()), w, h, channel_num)
with the same result, you will get a faster execution speed, which will be 1/3~20 times faster, depending on the image content.
Note:
compressor = zlib.compressobj(level=1) # use fast compression or use zlib.compress()
compressed_data = compressor.compress(im.tobytes()) + compressor.flush()
self.data.set_image_data(self.ui_image, compressed_data, w, h, channel_num)
Add more viewport and projection matrix related interfaces
set_level_viewport_camera_fov
Set the fov of level viewport cameraget_level_viewport_camera_aspect
Get the aspect of level viewport cameraget_level_viewport_size
Get the size of level viewportget_viewport_pixels_as_texture
Get the content of first active viewport as Texture2D. UE5 only.get_viewport_pixels_as_data
Get the raw pixels from first active viewport as RawDatacalculate_projection_matrix
Calculate the Projection Matrix by fov and near planecalculate_view_matrix
Calculate the View Matrix by ViewLocation and ViewRotation.calculate_vp_matrix
Calculate the ViewProjection Matrix by ViewLocation, ViewRotation, fov and near plane.calculate_inv_view_projection_matrix
Calculate the inverse ViewProjection Matrix by ViewLocation, ViewRotation, fov and near plane.project_world_to_view
Project world position to view position.frustum_trace
Trace rays against the world using a specific profile in a gird in Frustum and return the hits. UE5 only.unreal.TAPythonPrimitiveHitResult is used to add more return data for HitResult.
component
(PrimitiveComponent): [Read-Write]hit_locations
(Array[Vector]): [Read-Write]hit_normals
(Array[Vector]): [Read-Write]is_this_triangles_vertex_all_visible
(Array[bool]): [Read-Write]screen_normals
(Array[Vector]): [Read-Write]screen_positions
(Array[Vector2D]): [Read-Write]transform
(Transform): [Read-Write]triangle_ids
(Array[int32]): [Read-Write] The index of output in the expressionAdd more interfaces for DynamicMesh
set_uvs_from_camera_projection
Project the DynamicMesh to specified UVSet in current view. UE5 only.get_visible_triangles
Get the visible triangles of DynamicMesh in current view. UE5 only.rasterize_and_trace_triangles_uv
Trace the visibility of DynamicMesh in current view.(Experimental). UE5 only.trace_dynamic_mesh_triangles_visibility
Trace the visibility of DynamicMesh's triangles in current view. UE5 only.get_triangles_face_normal_in_view
Get the face normal of DynamicMesh in current view. (Experimental). UE5 only.cal_triangles_derivatives
Calculate the merged ddxy of DynamicMesh's triangles in current view. UE5 only.export_normal_and_derivatives
Export the current normal and mip of DynamicMesh in current view as raw data. (Experimental). UE5 only.create_texture2d
Create a Texture2D with specified size which has no uasset file. UE5 only.finish_compilation_texture
Wait for the texture to finish compiling. UE5 only.create_texture2d_from_raw
, default is FalseAdd menu items for Blueprint Editor
OnBlueprintEditorMenu
Add menu items to Blueprint Editor "OnBlueprintEditorMenu": {
"name": "Python Menu On Control BP",
"items":
[
{
"name": "TA Python Blurprint Example",
"items": [
{
"name": "Print Blueprint",
"command": "print(%asset_paths)"
}
]
}
]
}
The configuration items in Config.ini: MenuConfigFilePath
and PythonContentFolder
support absolute paths Request from. Now we can share Chameleon Tools in different projects.
Add two default menu items to the global Context menu of the Chameleon tool. (UE5 only)
Add guess_instance_name
method to guess the instance variable name of the current Chameleon tool in Python
Below is Experimental. It is only recorded here. There may be major changes later, and it is not recommended to use it in official tools.
Add support for SGraphPanel (Experimental), and EdGraphSchema_K2 is used by default.
Add SGraphPanel related methods (Experimental):
Note: The following methods are "Experimental" functions, which may be removed later. It is only recorded here.
spawn_to_graph_by_class
spawn_function_to_graph
Spawn a specified function of a module in SGraphPanel.spawn_function_to_graph_with_spawner
Spawn a specified function of a module in SGraphPanel through a BPFunctionSpawner.get_graph_panel_nodes
Get all nodes in SGraphPanel.clear_graph_panel
Clear all nodes in SGraphPanel.get_graph_selected_node
Get the selected nodes in SGraphPanel.get_graph_panel_content_as_json
Get the content of SGraphPanel as JSON stringset_graph_panel_content_from_json
Set the content of SGraphPanel from JSON string.Add a new BPLib to process Blueprint related content
get_selected_nodes
log_schema
log_all_k2_nodes
log_all_schemas
Log all available Schemas, and return UClass arrayget_graph_node_by_name
get_all_k2_nodes
get_children_classes
Get the children classes from the specified UClassget_classes_from_module
Get the UClass from the specified module nameget_bp_functions_spawners
Get the UFunction from the specified UClassget_bp_function_spawner
Get the Spawner of the specified Blueprint function name, used to create nodes in SGraphPanelThe expample project of the "Splinter_Button" above is here:
https://github.com/cgerchenhp/TAPython_ButtonDivision_Example
The biggest change in TAPython v1.1 is the addition of a feature that allows widgets to be directly added, inserted, and deleted through Python code. With this feature, we can dynamically add widgets to the tool during runtime. This function is particularly useful for displaying widgets of an unknown quantity.
chameleon_data_instance.set_content_from_json
, which is used to set sub-widgets for SBox
, SBorder
, SCheckBox
, SBox
, and SButton
components.chameleon_data_instance.append_slot_from_json
, which is used to add sub-widgets to Slots for SHorizontalBox
, SVerticalBox
, SScrollBox
, SGridPanel
, SUniformGridPanel
, SUniformWrapPanel
, SOverlay
, SCanvas
, and SSplitter
.chameleon_data_instance.insert_slot_from_json
, which is used to add sub-widgets at a specified Slot index for SHorizontalBox
, SVerticalBox
.chameleon_data_instance.remove_widget_at
, which is used to remove the widget at the specified location. This is applicable to all the widgets mentioned above.chameleon_data_instance.get_all_akas
, which is used to get all Aka names in the chameleon tool.chameleon_data_instance.get_widget_path
, which is used to get the Slate path of the widget through its Aka name.In the past two months, TAPython has completed the update of the initial version of the document, and the subsequent documents will be iterated on the existing basis.
The document address in the plugin is updated to the new url: https://www.tacolor.xyz/tapython/welcome_to_tapython.html
VAlign
of the middle element in SHeader to Center
OnTick
to 60hzVAlign
and HAlign
in SCanvasAdd unreal.ChameleonData.snapshot_sketch
command for capturing the current Sketch panel
Add chameleon_data_instance.get_top_scroll_box_offsets(json_path)
for getting the offset of the top scroll box in Chameleon Tool.
Add chameleon_data_instance.get_scroll_box_offsets(aka_name)
for getting the offset of the scroll box in Chameleon Tool with the given name.
chameleon_data_instance::set_image_from_path(aka_name, image_file_path)
supports using absolute paths
Add SetMinAspectRatio/SetMaxAspectRatio for SBox
Add chameleon_data_instance.set_min_aspect_ratio
and chameleon_data_instance.set_max_aspect_ratio
for setting the min/max aspect ratio of the given SBox
unreal.PythonBPLib.get_class_path_name
for getting the path name of the given object's classunreal.PythonBPLib.get_viewport_linear_color_pixels
for getting the pixels of the viewport as a linear color arrayunreal.PythonBPLib.exec_python_command
, add force_game_thread
option to allow Python code to execute on the main thread. When we execute code in a sub-thread, if we need to modify the UI content, we can specify to modify it in the main thread through the force_game_thread
option (the UI content can only be modified in the Game thread).unreal.PythonBPLib.get_modifier_keys_state()
The Intermediate directory is added to the package and includes UnrealEditor-TAPython.lib (UE4Editor-TAPython.lib in UE4) to make compatibility with the automated build system. At the same time, add the corresponding .dll for DebugGame mode.
Adding support for SWebBrowser allows you to embed WebBrowser in the tool window, which can be helpful in some situations, such as embedding the internal pipeline tool in the python tool in Unreal Editor.
Using the SWebBrowser widget, the web browser plug-in is required. It is disabled by default. We must enable the plug-in before using it
Added "SizeRule" attribute for the SSplitter widget. Optional values are "FractionOfParent" and "SizeToContent",
And more attributes for SColorBlock and SColorPicker
Get the current visibility status of the widget.
They are used for getting and setting the color of the widget.
More APIs for SWebBrowser widget though ChameleonData.
If IsModalWindow is set to True, Tab is still a nomad type and we can still dock to other Windows.
Known issue: the maximize button reappears after the window is floated from the docked window.
As the Material Editor, we can add custom menus for Physics Asset Editor and Control Rig Editor now.
"OnPhysicsAssetEditorMenu": {
"name": "Python Menu On Physics Asset Editor",
"items":
[
{
"name": "TA Python Physics Asset Example",
"items": [
{
"name": "Print Physics Asset",
"command": "print(%f)"
}
]
}
]
}
We can add a TAPython menu where the UE ToolMenus can.
"ControlRigEditor.RigHierarchy.ContextMenu": {
"name": "Python Menu On Control Rig Editor",
"items": [
{
"name": "Rigging Tools",
"command": "print('Rigging Tools')",
"icon": {
"style": "ChameleonStyle",
"name": "Resources.Chameleon_32x_png"
}
}
]
}
And we can add a context menu for object's component in Detail views.
Kismet.SubobjectEditorContextMenu: {
...
}
TAPython.RefreshToolMenus
"TAPython.RefreshToolMenus" can be used to refresh the "ToolMenus" menus, other menus will be auto-refreshed and not need this command
GetModifierKeyState Get the modifier key states(Ctrl, Shift, Alt, etc.), so we used it to display an optional dialog or menu.
We can tank a snapshot of the entire Details window via 'snapshot_details'. The file will be saved to
Cancel the specified DelayCall by ID.
We got a new editor library: PhysicsAssetLib, as its name, it's for PhysicsAsset Editing.
Function Name | Description | |
---|---|---|
get_selected_bodies_indexes | Get the indexes of the selected bodies in Physics Asset Editor | |
rotate_selected_body | Set the rotation of the selected body in Physics Asset Editor | |
rotate_selected_constraint | Set the rotation of the selected constraint in Physics Asset Editor | |
get_body_center | Get the center value of the specified body | |
set_body_center | Set the center value of the specified body | |
get_body_rotation | Get the rotation value of the first body | |
get_bodies_rotations | Get the rotation value of the first body | |
set_body_rotation | Set the rotation value of the specified body | |
get_body_radius | Get the Radius value of the body | |
set_body_radius | Set the Radius value of the body | |
get_body_length | Get the rotation value of the first body | |
set_body_length | Get the rotation value of the first body | |
get_body_size | Get the Size value of the box body | |
set_body_size | Set the Size value of the box body | |
scale_body | Scale the specified body | |
get_edited_physics_assets | Get all PhysicsAsset currently being tracked with open editors | |
get_physics_asset_from_top_window | Get the PhysicsAsset from the top opened editor window. | |
get_selected_item_names | Get all the selected items name in PhysicsAsset editor window. | |
select_body_by_name | Select the Body by name in PhysicsAsset editor window. | |
select_body_by_names | Select the Bodies by name in PhysicsAsset editor window. | |
select_shape_by_name | Select the Shape by name in PhysicsAsset editor window. | |
select_shape_by_names | Select the Shapes by name in PhysicsAsset editor window. | |
select_constraint_by_name | Select the constraint by name in PhysicsAsset editor window. | |
select_constraint_by_names | Select the constraints by name in PhysicsAsset editor window. | |
add_constraints | Add constraint to specified bodies | |
get_skeleton_hierarchy | Get the bones hierarchy | |
get_bodies_hierarchy | Get all the bodies names and their parent bone's index | |
get_constraints_names | Get all the constraint's display names of PhysicsAsset | |
get_bone_indexes_of_constraint | Get the parent and child bone's indexes of the specified Constraint | |
get_bone_index_from_body | Get the first Body under the specified bone | |
get_bodies_from_bone | Get the Bodies under the specified bone | |
get_constraint_instance_accessor | Get the ConstraintInstanceAccessor from PhysicsAsset | |
reset_constraint_properties | Reset the specified Constraint's values | |
update_profile_instance | Update the Profile according to the specified Constraint | |
break_constraint_accessor | Get the Owner and Constraint Index from ConstraintInstanceAccessor |
A new editor lib PythonTestLib has been added to TAPython to complete the test cases of all the extended APIs.
In the test cases repo UE_TAPython_Plugin_TestCases, more than 200 PythonLib APIs has been tested.
Now we can get the contents of the Output Log, which we can use to validate the operation result from the editor.
Note that Logs are the same content as Output Log in the editor, but they are separate. Clearing Log in Output Log will not affect what PythonTestLib.get_log() returns, and vice visa
A new setting parameters LogNumberLimit in Config.ini will limit the maximum number of log buffers. The default size is 10240.
In the test case, I used delay_call, pushing the python scripting, then waiting for the editor to complete its asynchronous tasks, or waiting for the window to refresh, and so on.
Add "OnMapChangedCmd" to the Chameleon tool for executing Python commands when changing maps.
Usage:
For example, I fixed the crash when using ObjectDetailViewer tool and then loading another level, as the queried object will referenced by ObjectDetailViewer. :-(
"OnMapChangedCmd": "chemeleon_objectDetailViewer.on_map_changed(%map_change_type)",
def on_map_changed(self, map_change_type_str):
# remove the reference, avoid memory leaking when load another map.
if map_change_type_str == "TearDownWorld":
self.reset(bResetParameter=False)
else:
pass # skip: LoadMap, SaveMap, NewMap
%world: Get the world of map operation
%map_change_type: Get the operation type of changing map, "LoadMap", "SaveMap", "NewMap" or "TearDownWorld"
We can use SDetailViewer for showing the object properties.
Add "AlwaysShowScrollbars" bool field in SMultiLineEditableTextBox
Add ScrollTo function, for scrolling the scroll bar to the specified location
Add SetColorAndOpacity support for SScrollBox/SImage/STextBlock/SEditableText
TAPython released its first version of MacOS Monterey (v1.0.8 for UE 5.0.3), although there are far fewer Unreal developers on the MAC than PC. If you have any problems, please let me know.
Now, we can add the global context menu of the Chameleon Tool by adding "OnTabContextMenu" in the MenuConfig.json.
For example, the following example adds a menu item named "Reload This Tool" to all Chameleon Tools. The tool will re-launch when the user clicks the menu. If we use this method to reload the python module when we open the tool, we can quickly reload both the interface and python logic, which is very convenient when developing the tools.
MenuConfig.json:
"OnTabContextMenu":{
"name": "TA Python Tab",
"items": [
{
"name": "Reload This tool",
"command": "unreal.ChameleonData.request_close(%tool_path); unreal.ChameleonData.launch_chameleon_tool(%tool_path)"
}
]
}
Each Chameleon Tool can also add its own context menu. The way of adding menu is similar to the Global Context Menu: add the "OnTabContextMenu" subitem in the Json file of tool's json file, and add the menu content to it.
For example, add a custom context menu for MinimalExample
{
"TabLabel": "Example",
"InitTabSize": [200, 123],
"InitTabPosition": [180, 200],
"InitPyCmd": "import Example; chameleon_example = Example.MinimalExample.MinimalExample(%JsonPath)",
"Root":
{
...
},
"OnTabContextMenu":{
"items": [
{
"name": "Reset Click Count",
"command": "chameleon_example.reset_click_count()"
}
]
}
}
Or a menu item that switches the tool to "Development Mode" for your tool.
Tips:
One of the most important features in this release is the addition of support for the Material Editor.
Now we can add custom menu items directly to the material editor and pass the material instance that we are currently editing to the python script so that we can "play with" the material nodes directly in python.
The %asset_paths in the following example will be replaced by the TAPython with an array of paths to the material currently being edited, which usually has only one element.
With the APIs added to PythonMaterialLib in this release, we can fully script the material expression nodes via Python.
MenuConfig.json:
"OnMaterialEditorMenu": {
"name": "Python Menu On Material Editor",
"items":
[
{
"name": "TA Python Material Example",
"items": [
{
"name": "Print Editing Material / MF",
"command": "print(%asset_paths)"
},
{
"name": "Log Editing Nodes",
"command": "editing_asset = unreal.load_asset(%asset_paths[0]); unreal.PythonMaterialLib.log_editing_nodes(editing_asset)"
},
{
"name": "Selected Nodes --> global variable _r",
"command": "_r = unreal.PythonMaterialLib.get_selected_nodes_in_material_editor(unreal.load_asset(%asset_paths[0]))"
}
]
}
]
},
Now we can calculate the size of all content in the whole ScrollBox from the Offset, ScrollOffsetOfEnd,ViewFraction,ViewOffsetFraction, etc. Then use SnapshotChameleonWindow to capture the contents of the entire tool window, including the parts of ScrollBox that are not shown.
Add %widgetPath keyword in JSON
It will pass the widget path of the current clicked button to python code, so we can figure out which SButton was clicked, when we import the External JONS file multi-times.
When we need to remind the user to a specified tool, we can use the flash_chameleon_window.
We can capture the contents of the entire chameleon tool window, including the parts of ScrollBox that are not shown.
For example, the ChameleonGallery tool that comes with the plugin is over 3,000 pixels height and wrapped in ScrollBox, which we can also save as an image at once.
The following code will calculate the size of the contents in the entire tool window, then take the snapshot.
def get_full_size_of_this_chameleon(self):
current_size = unreal.ChameleonData.get_chameleon_window_size(self.jsonPath)
scrollbox_offsets = self.data.get_scroll_box_offsets(self.ui_scrollbox)
height_full = scrollbox_offsets["ScrollOffsetOfEnd"] / (1.0 - scrollbox_offsets["viewFraction"])
height_full += 48 # add title bar
return current_size.x, round(height_full)
def on_button_Snapshot_click(self):
full_size = self.get_full_size_of_this_chameleon()
saved_file_path = unreal.ChameleonData.snapshot_chameleon_window(self.jsonPath, unreal.Vector2D(*full_size))
if saved_file_path:
unreal.PythonBPLib.notification(f"UI Snapshot Saved:", hyperlink_text = saved_file_path
, on_hyperlink_click_command = f'chameleon_gallery.explorer("{saved_file_path}")')
else:
unreal.PythonBPLib.notification(f"Save UI snapshot failed.", info_level = 1)
Now we can iterate, create, and modify Material Expression nodes of Material and Material Function with Python. Including the nodes that cannot be created or modified in the MaterialEditingLibrary. For example, connect properties to World Position Offset, add Get/SetMaterialAttribute nodes, etc.
For more details and examples of material expressions can be found here: How to manipulate Material Expressions Node in Material with Python in Unreal Engine
PythonMaterialLib | Description | Is New added |
---|---|---|
get_static_switch_parameter_values | Get the Static Switch Infos of material instance | |
set_static_switch_parameter_value | Set the Static Switch Infos of material instance | |
set_static_switch_parameters_values | Batch set the Static Switch's status of material instance. | |
get_mf_static_switch_parameter | Get the Static Switch Infos of material function. | |
get_static_parameters_summary | Get the numbers of each StaticSwitchParameter of material instance. | |
log_mat | Log out all the connections in the material | Yes |
get_material_expressions | Log out all the Material Expressions in the material | Yes |
get_all_referenced_expressions | Get Material Expressions in the material with specified feature level | Yes |
get_material_connections | Get all the connections in the material | Yes |
get_material_function_connections | Get all the connections in the material function | Yes |
get_material_expression_input_names | Get the input pin's names of the material expression | Yes |
get_material_expression_output_names | Get the output pin's names of the material expression | Yes |
get_material_expression_captions | The captions of the material expression | Yes |
set_shading_model | Set the shading model of the material, for the hidden shading model | Yes |
get_material_expression_id | Get the ParameterExpressionId of the material expression. | Yes |
log_mf | Log out all the connections in the material function | Yes |
get_material_function_expressions | Get all the expressions in the Material Function | Yes |
get_material_function_output_expressions | Get all the output expressions in the Material Function | Yes |
get_selected_material_nodes | Get the selected nodes in material editor. | Yes |
log_material_expression | Log Detail information of the MaterialExpression, include inputs, outputs etc. | Yes |
log_editing_nodes | Log Detail information of the Material or Material Function | Yes |
get_selected_nodes_in_material_editor | Get the selected nodes in material editor. | Yes |
get_hlsl_code | Get the HLSL code of the Material | Yes |
get_shader_map_info | Get the ShaderMaps infos in string format. | Yes |
get_material_content | Get the material's content in JSON Format | Yes |
get_material_function_content | Get the material function's content in JSON Format | Yes |
connect_material_expressions | Create connection between two material expressions | Yes |
disconnect_expression | Disconnection the material expression's input | Yes |
connect_material_property | Connect a material expression output to one of the material property inputs (e.g. diffuse color, world position offset etc) | Yes |
disconnect_material_property | Disconnect the material property input | Yes |
get_material_proper_str_from_guid | Get EMaterialProperty in string format from a guid | Yes |
gen_guid_from_material_property_str | Generate a Guid from EMaterialProperty | Yes |
add_input_at_expression_set_material_attributes | Add an Attribute Get Type pin for material expression "GetMaterialAttributes" | Yes |
add_output_at_expression_get_material_attributes | Add an Attribute Get Type pin for material expression "GetMaterialAttributes" | Yes |
Add Mouse Event for SImage
With the three mouse events, our python code can use them to perform more complex operations based on the user's mouse input in SImage.
The %uv, %mouse_flags in the following example will be automatically replaced with the UV coordinates of the mouse in SImage and the pressed state of the left, middle and right mouse button
{
"SImage": {
"DesiredSizeOverride": [200, 200],
"Aka": "ImageCanvas",
"OnTick": "your_tool.on_tick()",
"OnMouseLeave": "your_tool.on_mouse_leave(%mouse_flags)",
"OnMouseMove": "your_tool.on_mouse_move(%uv, %mouse_flags)"
}
}
The user's operation in SImage is taken as Stable Fluid function's input, then using result drive the volume cloud with set_render_target_data function of PythonTextureLibs.
Two new optional parameters in notifications were added, for adding a specify hyperlinks and the custom python function that executes when click. So we can quickly jump to a specific location or open a hyperlink.
More information and example about modify RenderTexture2D and SImage can be found here.
Added:
Fixed:
PythonEnumLib and PythonStructLib has been added to Python Editor Libs, PythonDataTableLib also adds more python/blueprint callable functions.
In short, we can use Python to do almost everything you did manually in the editor with User defined ENum, User Defined Struct and DataTable. More details and examples can be found here.
Support more slates:
Two APIs was added in ChameleonData for SExpandableArea:
void SetIsExpanded(const FName AkaName, bool bExpanded, bool bAnimated=false)
data.get_is_expanded(aka_name) -> bool
Get the Expanded state of Specified SExpandableArea
note: Supported widgets: SExpandableArea.
note: added in v1.0.4
Args:
aka_name (Name): The aka name of the widget
Returns:
bool: Is Expanded or not.
data.set_is_expanded(aka_name, expanded, animated=False) -> None
Set the Expanded state of Specified SExpandableArea
note: Supported widgets: SExpandableArea.
note: added in v1.0.4
Args:
aka_name (Name): The aka name of the widget
expanded (bool): Is Expanded or not.
animated (bool): Expanded with animation or not.
Now we can add context menu in Outline window, with the "OnOutlineMenu" field in MenuConfig.ini.
"OnOutlineMenu": {
"name:": "Python Menu On OutlineMenu",
"items":
[
{
"name": "Print selected actors",
"command": "print(unreal.get_editor_subsystem(unreal.EditorActorSubsystem).get_selected_level_actors())"
}
]
},
The .png and.svg files in the plugin resource directory will be added to "ChameleonStyle" automatically. Then we can use it for menu items.
{
"name": "Chameleon Shelf Tool",
"ChameleonTools": "../Python/ShelfTools/Shelf.json",
"icon": {
"ImagePathInPlugin": "Resources/briefcase_32x.png"
}
},
{
"name": "Minimal Example",
"ChameleonTools": "../Python/Example/MinimalExample.json",
"icon": {
"style": "ChameleonStyle",
"name": "Flash"
}
}
Now the Chameleon UI json file can reference other Json files. Nested references are supported, but circular references need to be avoided
{
"autoWidth": true,
"SBox": {
"WidthOverride": 480,
"Content": {
"ExternalJson": "ZeldaWorldMapEditor_Buttons.json"
}
}
}
The number of shortcuts that can be configured in ExitorSettings has now been increased to 10. It will be a configurable number in later version.
{
"SBorder": {
"BorderBackgroundColor": [1, 0.5, 0, 1],
"BorderImage":
{
"Style": "FEditorStyle",
"Brush": "ErrorReporting.EmptyBox"
}
}
}
Or send it to other device, for example, I send the viewport content to my MacroKeyboard. I think this is the smallest screen which displays Unreal Engine viewport content :D
Force the viewport Redraw
We can get the EObjectFlags of a UObject.
GetLevelViewportCameraFov
GetActorsFromFolder Get the actors in Specified folder in outline
FindActorsByLabelName
Find the actor by it's "label name" not the "actor name"
LogOnTickWarnings=True
This option controls whether a warning is printed when the user uses the keyword OnTick.
ChameleonTools has a hidden keyword that has not been mentioned: "OnTick". The python code in it is executed during Slate updates, which are much more frequent than viewPort updates, So the py code can easily lower the editor's FPS.
"OnTick" is hidden because 99.9% of the time it is not needed and there are better ways to do it if there is a "real" need. So I don't recommend using OnTick and changing the LogOnTickWarnings setting.
Fixed RequestClose failing after Chameleon dock to another window.
Fixed unreal.PythonBp.get_all_objects crash, when some objects don't have "world"
Fixed the incorrect display of the Breadcrumb in Python Tool: ObjectDetailViewer
Fixed chameleonData.get_float_value failed with SSpinBox
Fixed incorrect Padding setting in SBox
This plugin use UE native Python Script Plugin. The Scripting the Editor using Python is also very useful.
Download from TAPython release repo @github and unzip the plugin to <Your_UE_Project>\Plugins
Your_UE_Project
├── Content
├── ...
└── Plugins
└── TAPython # <--- Put Plugin Here
├── Binaries
├── Config
└── Content
└─ ...
Laungch project, open Project settings - Plugin Python - additional path, add <Your_UE_Project>/TA/TAPython/Python to additional path. then restart the editor.
Green sign and text "Python Path Ready" will showing at the top of gallery.
If a Red Cross is displayed, check the Project Setting above.
The plug-in package contains several menu items and four demo tools by default.
The latest DefaultResources is here: DefaultResources@github
The Sketch Tool is a special ui design tool. When the<Your_UE_Project>\TA\TAPython\Python\ChameleonSketch\ChameleonSketch.json file is modified, the content of the ui will be updated immediately(see below gif). This can be very useful when writing tool interfaces, and will save a lot of time when tweaking the interface layout or parameters.
The default sketch tool looks like below. Try to modify the content of ChameleonSketch.json with any text editor, and save it. Don't worry about the json keywords and syntax, it's easy to learn and has lots of examples, will be described below.
All the 4 Example tools, are written with python, without any single line of c++ code.
This is a tool demonstrating the creation of a standard UE Slate UI with python and a json file. The Button calls Python code, then the python code sends the results(click count) back to the UI.
The tool includes a 30-lines Json file and a 15-lines Python file. In fact, it can be shorter.
I will call this kind of tool which creates Slate interfaces in this way "Chameleon Tools"
MinimalExample.json:
{
"TabLabel": "Example",
"InitTabSize": [200, 123],
"InitTabPosition": [680, 150],
"InitPyCmd": "import Example; chameleon_example = Example.MinimalExample.MinimalExample(%JsonPath)",
"Root":
{
"SVerticalBox":
{
"Slots": [
{
"SButton": {
"Text": "Click Me",
"HAlign": "Center",
"VAlign": "Center",
"OnClick": "chameleon_example.on_button_click()"
}
},
{
"SEditableTextBox":
{
"IsReadOnly": true,
"Aka": "InfoOutput",
"Text": ""
}
}
]
}
}
}
MinimalExample.py
# -*- coding: utf-8 -*-
import unreal
from Utilities.Utils import Singleton
class MinimalExample(metaclass=Singleton):
def __init__(self, jsonPath:str):
self.jsonPath = jsonPath
self.data = unreal.PythonBPLib.get_chameleon_data(self.jsonPath)
self.ui_output = "InfoOutput"
self.clickCount = 0
def on_button_click(self):
self.clickCount += 1
self.data.set_text(self.ui_output, "Clicked {} time(s)".format(self.clickCount))
Shelf is a Maya-like shortcut shelf tool, showing how to set visibility of widget and the usage of SDropTarget widget.
Users can drag and drop items to the shelf, and execute custom Python Code, launch Chameleon tool when clicking the item on the shelf.
Type | Action |
---|---|
assets | select saved assets in content Brower |
folder | enter saved folder in Content Brower |
actors | select saved actors in level |
text(python snippet) | execute as python code |
chamelon tool json file | launch the Chameleon tool |
You can modify the python code, and make it better.
Object Detail Viewer is an inspector Tool for UE object. It shows all the functions and property in any UObject. Double click the property will query the child property. The image above shows the detail values of Floor_14(actor).static_mesh_component.static_mesh.static_materials[0].
In compare mode, the differences of two UObjects will be highlighted. It's very useful for being familiar with all kinds of UObject.
Chameleon Gallery shows the most common widgets, and how to describe them in a json file. All the supported widgets and API documents can be found here
A: Yes, at the beginning this plugin was developed with UE 4.21. We have released this plugin for UE 4.26, 4.27, UE5.0EA, UE5.0Preview1.
This Plugin: TAPython is Free for use. The PythonDefaultResource is under MIT license.