You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python在Blender中实现GLB模型图片的两种适配模式

GLB相框图片等比例适配实现方案

核心思路

利用Blender内置API获取图片尺寸与相框UV区域比例,无需依赖PIL。通过计算两种适配模式的缩放因子与偏移量,调整纹理映射节点的参数,实现图片的等比例适配。

实现步骤

1. 编写Blender处理脚本(frame_image_fit.py)

import bpy
import sys

def fit_frame_image(image_path, fitting_mode):
    # 清除默认场景对象(若已有导入的GLB模型可跳过此步骤)
    bpy.ops.object.select_all(action='SELECT')
    bpy.ops.object.delete()

    # 导入GLB模型(替换为你的模型实际路径)
    glb_path = "path/to/your/frame.glb"
    bpy.ops.import_scene.gltf(filepath=glb_path)

    # 获取相框对象(替换为你的相框对象名称)
    frame_obj = bpy.data.objects.get("Frame")
    if not frame_obj:
        print("未找到相框对象")
        return

    # 获取相框UV区域的宽高比例
    mesh = frame_obj.data
    uv_layer = mesh.uv_layers.active
    if not uv_layer:
        print("相框无UV图层")
        return

    # 提取相框面的UV坐标(假设为四边形面,取前4个UV点)
    uv_coords = [uv.uv for uv in uv_layer.data[:4]]
    min_u = min(uv[0] for uv in uv_coords)
    max_u = max(uv[0] for uv in uv_coords)
    min_v = min(uv[1] for uv in uv_coords)
    max_v = max(uv[1] for uv in uv_coords)
    frame_width = max_u - min_u
    frame_height = max_v - min_v
    frame_aspect = frame_width / frame_height

    # 加载目标图片
    try:
        img = bpy.data.images.load(image_path)
    except:
        print(f"无法加载图片: {image_path}")
        return
    img_width, img_height = img.size
    img_aspect = img_width / img_height

    # 计算缩放与偏移量
    scale_x = 1.0
    scale_y = 1.0
    offset_x = 0.0
    offset_y = 0.0

    if fitting_mode == "max":
        # 最大化填满相框,裁剪超出部分
        scale_factor = max(frame_aspect / img_aspect, img_aspect / frame_aspect)
        scale_x = frame_width / (img_width / scale_factor)
        scale_y = frame_height / (img_height / scale_factor)
        # 居中偏移
        offset_x = (frame_width - (img_width / scale_factor)) / (2 * frame_width)
        offset_y = (frame_height - (img_height / scale_factor)) / (2 * frame_height)
    elif fitting_mode == "fit":
        # 最小化完全放入相框,留空白边
        scale_factor = min(frame_width / img_width, frame_height / img_height)
        scale_x = scale_factor
        scale_y = scale_factor
        # 居中偏移
        offset_x = (frame_width - img_width * scale_factor) / (2 * frame_width)
        offset_y = (frame_height - img_height * scale_factor) / (2 * frame_height)
    else:
        print("无效的适配模式,仅支持'max'或'fit'")
        return

    # 调整纹理节点
    material = frame_obj.active_material
    if not material:
        print("相框无材质")
        return

    nodes = material.node_tree.nodes
    links = material.node_tree.links

    # 查找或创建纹理映射节点
    mapping_node = next((n for n in nodes if n.type == 'MAPPING'), None)
    if not mapping_node:
        mapping_node = nodes.new(type='ShaderNodeMapping')
        # 连接UV节点到映射节点
        uv_node = next((n for n in nodes if n.type == 'UVMAP'), None)
        if not uv_node:
            uv_node = nodes.new(type='ShaderNodeUVMap')
        links.new(uv_node.outputs['UV'], mapping_node.inputs['Vector'])
        # 连接映射节点到图片纹理节点
        texture_node = next((n for n in nodes if n.type == 'TEX_IMAGE'), None)
        if texture_node:
            links.new(mapping_node.outputs['Vector'], texture_node.inputs['Vector'])

    # 替换图片并设置参数
    texture_node = next((n for n in nodes if n.type == 'TEX_IMAGE'), None)
    if texture_node:
        texture_node.image = img
        mapping_node.inputs['Scale'].default_value = (scale_x, scale_y, 1.0)
        mapping_node.inputs['Location'].default_value = (offset_x, offset_y, 0.0)

    # 导出处理后的GLB(替换为你的实际导出路径)
    output_path = "path/to/output/frame_with_image.glb"
    bpy.ops.export_scene.gltf(filepath=output_path, export_format='GLB')
    print(f"处理完成,导出路径: {output_path}")

if __name__ == "__main__":
    # 从命令行获取参数
    if len(sys.argv) < 4:
        print("用法: blender --background --python frame_image_fit.py -- <image_path> <fitting_mode>")
        sys.exit(1)
    image_path = sys.argv[-2]
    fitting_mode = sys.argv[-1]
    fit_frame_image(image_path, fitting_mode)

2. 通过subprocess后台调用Blender

在你的主Python脚本中,使用subprocess调用上述Blender脚本:

import subprocess

def process_frame_image(image_path, fitting_mode):
    blender_path = "blender"  # 若Blender不在环境变量中,需指定完整路径,如"C:/Program Files/Blender Foundation/Blender 3.6/blender.exe"
    script_path = "frame_image_fit.py"
    # 构造命令
    cmd = [
        blender_path,
        "--background",
        "--python", script_path,
        "--",
        image_path,
        fitting_mode
    ]
    # 后台执行
    result = subprocess.run(cmd, capture_output=True, text=True)
    if result.returncode == 0:
        print(result.stdout)
    else:
        print("处理失败:", result.stderr)

# 调用示例
process_frame_image("test.jpg", "max")
process_frame_image("test.png", "fit")

关键说明

  • 替换脚本中的GLB模型路径、相框对象名称为你实际的资源信息。
  • 若相框的UV不是四边形,需调整UV坐标提取逻辑,确保正确获取相框的显示区域比例。
  • 无需依赖PIL,所有尺寸计算均通过Blender内置的bpy.data.images和UV数据完成。

内容的提问来源于stack exchange,提问作者Abdulkader Khateeb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 22:05:28