Bootstrap Chameleon Logo

Use Images and Image Brush

创建SImage

Editor Style

如果使用EditorStyle中已有的图片,可以通过"Brush"指定。例如:

"SImage": {
    "Image": {
        "Style": "FEditorStyle",
        "Brush": "AutomationTools.TestAutomation"
    }
}

NOTE
TAPython中支持的EditorStyle有:"FEditorStyle", "FCoreStyle","FAppStyle events"

ImagePath

通过"ImagePath"字段,可以指定图片的路径。该路径是图片相对于当前工具的UI json文件的路径。

例如:

An SImage assigned with the field 'ImagePath'

"SImage": {
    "Aka": "AUniqueName",
    "ColorAndOpacity": [1, 1, 1, 1],
    "ImagePath": "../ChameleonGallery/Images/cartoon_game_map.png",
    "ToolTipText": "'ImagePath' is a relative path with the local ui json file.",
    "OnMouseButtonDown": "print('clicked')"
}

对于当前工具中使用的图片,将其放在工具所在目录中或其中的子目录中,是比较方便的做法。

ImagePathInPlugin

如果是使用放置在插件目录中的图片,可以通过"ImagePathInPlugin"指定,路径同样相对路径,是相对于TAPython目录的路径。例如:

"ImagePathInPlugin": "Resources/Icon128.png",实际指向的路径是<Your_Project>\Plugins\TAPython\Resources/Icon128.png

An SImage assigned with the field 'ImagePathInPlugin'

"SImage": {
    "Aka": "AUniqueName",
    "ImagePathInPlugin": "Resources/Icon128.png",
    "DesiredSizeOverride": [64, 64]
}

CAUTION
在SImage中通过"ImagePath", "ImagePathInPlugin"指定图片内容的时候,也需要指定"Aka"控件名。

SetImageFromPath

unreal.ChameleonData.set_image_from_path(aka_name, image_file_path, brush_width, brush_height),可以通过图片路径SImage的图片内容。

  • aka_name:SImage控件的名字。
  • image_file_path:图片的绝对路径。(如果提供了一个相对路径,它是相对于Plugin目录中的Resource目录的)
  • brush_width:生成的Brush的宽度
  • brush_height:生成的Brush的高度

CAUTION
image_file_path中的相对路径方式增加了开发者的记忆成本,建议在使用set_image_from_path的时候,使用绝对路径。

Fill SImage

除了下面介绍的内容以外,关于SImage填充和修改的内容,更多的细节可以查看这里:Image and Render Target

set_image_pixel

chameleon_instance.set_image_pixels(aka_name, pixel_colors, width, height),可以通过像素的方式填充SImage的图片内容。

chameleon_instance:ChameleonData的实例。

例如下面带代码,将SImage的图片内容设置为一个64x64的随机的黑白噪声图。

def set_random_image_data(self):
    width = 64
    height = 64
    colors = [unreal.LinearColor(1, 1, 1, 1)  if random.randint(0, 1) else unreal.LinearColor(0, 0, 0, 1) for _ in range(width * height)]
    self.data.set_image_pixels(self.ui_image, colors, width, height)

set_image_data

使用像素填充SImage的方式很符合我们的直觉,但是在实际的使用中,我们更多的是使用"raw_data"来填充SImage的内容。它的执行速度相对更快。

`chameleon_instance.set_image_data(aka_name, raw_data, width, height, channel_num=4, bgr=True)

  • raw_data: The flatten raw data of image, len(RawDataIn) == Height * Width * ChannelNum

例如在TAPython_Taichi_StableFluid_UE5中,使用了numpy来作为图片的数据结构,我们可以通过下面的代码将其填充到SImage中。

import numpy as np
...
self.image_im = np.ones((self.height, self.width, 4), dtype=np.uint8) * 255
...
self.data.set_image_data(self.ui_image, self.image_im.data.tobytes(), width=self.width, height=self.height)

再如: 我们从网络端获取了回的一个图片的base64编码的字符串,我们可以通过下面的代码将其填充到SImage中。

from PIL import Image

def on_timer(self, count):
    if count != 0 and count != -1:
        progress_json = self.api.get_progress()
        progress = progress_json.get("progress", None)
        current_image = progress_json.get("current_image", None)
        if progress:
            self._set_progress(progress)
        if current_image:
            img = Image.open(io.BytesIO(base64.b64decode(current_image)))
            self.data.set_image_data(self.ui_image, img.tobytes(), img.width, img.height, channel_num=3, bgr=False)

A stable-diffusion Unreal Editor snapshot

TIP
numpy,PIL等三方库可以大大加速图片的计算,gpu计算可以考虑Taichi。此外通过UE自身的RenderTarget和Material,也可以高效得修改图片。

细心的开发者可能已经注意到了,TAPython中并没有提供对SImage的所谓get_image_data方法。实际上这是有意为之的,因为TAPython操作的SImage都是我们自己创建的,其中的内容也是由我们填充的。因此我们在python端,也一定有一份的image内容的数据。因此,“避免从界面控件中反复获取Image内容,而直接从python数据中获取”,这是更为合理的做法

Event

SImage 控件支持以下三个鼠标事件:方便用户在界面中与SImage进行交互操作。

  • OnMouseMove
  • OnMouseEnter
  • OnMouseLeave events

下面例子中的变量占位符%uv, %mouse_flags在运行是会被实际的uv值和鼠标按键flag所替换。

{
    "SImage": {
        "DesiredSizeOverride": [200, 200],
        "Aka": "ImageCanvas",
        "OnMouseLeave": "your_tool.on_mouse_leave(%mouse_flags)",
        "OnMouseMove": "your_tool.on_mouse_move(%uv, %mouse_flags)"
    }
}
  • %uv: tuple, (u, v)
  • %mouse_flags: 标志位。其中,第0位,1位,2位分别表示鼠标左键,中键状态,右键状态。三者数值取或。
def on_mouse_move(self, uv, mouse_flags):
    self.cursor_pos_x, self.cursor_pos_y = uv
    self.bLMB = (mouse_flags % 2)
    self.bMMB = (mouse_flags>>1 % 2)
    self.bRMB = (mouse_flags>>2 % 2)

Painter on a slate removing the coverage of the Background Image

例如,我们在Image中获取了用户的鼠标输入,然后将其传递给StableFluid做计算,具体详细内容可见:Modify SImage content and Set Pixels to RenderTarget in Unreal Engine. 示例仓库在TAPython_Taichi_StableFluid_UE5

GIF showing modification of volumetric clouds using only Python through TAPython plugin and Taichi-lang

参考

PythonTextureLib