likes
comments
collection
share

如何用脚本在 Blender UI 中显示图像?

作者站长头像
站长
· 阅读数 11

前言

一共有两种方法

  1. 代码量少,需要提前手动将图像导入 Blender 当中,在 属性面板 中显示;
  2. 代码量稍多,如果所需的图像质量不是很重要的话,以下技术(图标)可能会派上用场,这个脚本将在 n 面板 中显示指定文件夹内所有的 .jpg 文件(自动加载)。

方法1 的关键函数

效果图

如何用脚本在 Blender UI 中显示图像?

1. template_preview 方法

声明

template_preview(id, show_buttons=True, parent=None, slot=None, preview_id='' )

材质、纹理、灯光或世界的预览窗口

参数

  • id (ID) – ID 数据块
  • show_buttons (boolean , ( optional ) ) – 显示预览按钮
  • parent (ID, (optional)) – ID 数据块
  • slot (TextureSlot, (optional)) – 纹理槽
  • preview_id (string , ( optional , never None ) ) – 此预览小部件的标识符,如果没有设置则将使用 ID 类型 (即 所有没有明确 ID 的材质预览将具有相同的大小)

举例

row = layout.row()
row.template_preview(bpy.data.textures['previewTexture'])

完整代码与注释

import bpy


class HelloWorldPanel(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "Hello World Panel"
    bl_idname = "OBJECT_PT_hello"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"
    
    # 图像
    img = bpy.data.images.load("D:\\本地素材库\\杂设计\\BlenderSecrets.png", check_existing=True) # 从磁盘加载图像
    img = bpy.data.images['Secrets'] # 在 blend 文件内加载
    # 纹理
    texture = bpy.data.textures.new(name="previewTexture", type="IMAGE")
    texture.image = img
    tex = bpy.data.textures['previewTexture']
    tex.extension = 'CLIP'  #EXTEND # CLIP # CLIP_CUBE # REPEAT # CHECKER

    def draw(self, context):
        layout = self.layout

        obj = context.object

        row = layout.row()
        row.label(text="Hello world!", icon='WORLD_DATA')

        row = layout.row()
        row.label(text="Active object is: " + obj.name)
        row = layout.row()
        row.prop(obj, "name")

        row = layout.row()
        row.operator("mesh.primitive_cube_add")
        
        # 显示图像
        row = layout.row()
        row.template_preview(bpy.data.textures['previewTexture'])
        
def register():
    bpy.utils.register_class(HelloWorldPanel)

def unregister():
    bpy.utils.unregister_class(HelloWorldPanel)

if __name__ == "__main__":
    register()

方法2 的关键函数

效果图

如何用脚本在 Blender UI 中显示图像?

如何用脚本在 Blender UI 中显示图像?

1. bpy.utils.user_resource 方法

声明

bpy.utils.user_resource(resource_type,  * , path='' , create=False)

返回用户资源路径(通常来自用户的主目录)。

参数

  • type (string) – 资源类型,可选的类型有 [DATAFILES, CONFIG, SCRIPTS, AUTOSAVE].
  • path (string) – 可选的子目录.
  • create (boolean) – 将路径视为目录,如果它不存在就创建它。

返回值

字符串类型的路径

举例

directory   = os.path.join(bpy.utils.user_resource('SCRIPTS'), "presets", "scatter_presets_custom\\")

本例中所使用的是 SCRIPTS 资源类型,返回的目录如下图所示(我将需要展示的图片放置在该目录)

如何用脚本在 Blender UI 中显示图像?

2. template_icon 方法

声明

template_icon(icon_value, scale=1.0)

显示一张大图标

参数

  • icon_value (int in [ 0 , inf ] ) – 显示的图标 id
  • scale (float in [ 1 , 100 ] , ( optional ) ) – 缩放,缩放图标大小(根据按钮大小)

举例

# 在 draw 方法中
self.layout.template_icon(icon_value=custom_icons[z[:-4]].icon_id, scale=10)

3. bpy.utils.previews.new 方法

声明

bpy.utils.previews.new()

返回一个新的预览集合。

返回值

类型为 ImagePreviewCollection

举例

global custom_icons 
custom_icons = bpy.utils.previews.new()

4. bpy.utils.previews.remove 方法

声明

bpy.utils.previews.remove(pcoll)

删除指定的预览集合。

参数

举例

global custom_icons 
bpy.utils.previews.remove(custom_icons)

5. ImagePreviewCollection 的 load 方法

声明

load(name, filepath, filetype, force_reload=False)

从给定的文件路径生成一个新的预览。

参数

  • name (string) – 标识预览的名称(唯一 id)。
  • filepath (string) – 要从中生成预览的文件路径。
  • filetype (string) – 生成预览所需的文件类型,比如 [IMAGE, MOVIE, BLEND, FONT].
  • force_reload (bool) – 如果为 True,则强制运行缩略图管理器,即使预览已经存在于缓存中。

返回值

预览匹配给定的名称,或一个新的空名称。

返回值类型为 bpy.types.ImagePreview

抛出异常

  • KeyError – 如果 name 已经存在。

举例

custom_icons.load(z[:-4], os.path.join(directory, z), 'IMAGE')

完整代码与注释

import os
import bpy
import bpy.utils.previews

# 获取指定的图像文件路径
directory   = os.path.join(bpy.utils.user_resource('SCRIPTS'), "presets", "scatter_presets_custom\\")
list_raw = []

from os import listdir
from os.path import isfile, join
# 过滤出文件,并凑成完整路径
onlyfiles = [f for f in listdir(directory) if isfile(join(directory, f))]

# 仅加载以 `.jpg` 结尾的文件
for f in onlyfiles:
    if f[-4:] == ".jpg":
        list_raw.append(f)

class Panel(bpy.types.Panel):

    """在 3D 视图工具面板中创建一个面板"""
    bl_idname = "TEST_PT_Panel" 
    bl_label = "Scatter Icon test"
    bl_category = "Scatter BETA"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_context = "objectmode"

    def draw(self, context):
        global custom_icons

        for z in list_raw:
            # 显示一张大图标
            self.layout.template_icon(icon_value=custom_icons[z[:-4]].icon_id, scale=10)

# 存储图标的全局变量
custom_icons = None

def register():
    global custom_icons
    custom_icons = bpy.utils.previews.new()

    for z in list_raw:
        custom_icons.load(z[:-4], os.path.join(directory, z), 'IMAGE')

    bpy.utils.register_class(Panel)

def unregister():
    global custom_icons
    bpy.utils.previews.remove(custom_icons)

    bpy.utils.unregister_class(Panel)

if __name__ == "__main__":
    register()