如何用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
相关产品推荐
相关产品推荐

