Blender脚本无限循环卡顿及Redis订阅场景解决方案咨询
解决Blender通过Redis订阅更新物体位置的问题
问题根源分析
- 直接用无限循环:会阻塞Blender的主事件循环,导致UI卡顿、无法响应操作——因为Blender的界面刷新、事件处理都在主线程执行,被循环占用后完全无法运转。
- 用子进程实现:Blender的
bpyAPI只能在主进程的主线程中调用,子进程无法访问Blender的上下文和数据,所以创建球体失败,也无法修改主进程中的物体属性。
方案一:Blender定时器 + Redis非阻塞监听
利用Blender的定时器机制,在主循环间隙周期性轮询Redis消息,既不阻塞UI,又能实时更新物体位置。
import bpy import redis import ast # 初始化Redis连接与订阅 r = redis.StrictRedis(host='localhost', port=6379, db=0) pubsub = r.pubsub() pubsub.subscribe('positions') # 创建球体(在主线程执行) bpy.ops.mesh.primitive_uv_sphere_add(radius=0.005, location=(0, 0, 0)) ball = bpy.context.object ball.name = 'sphere' def update_sphere_position(): # 非阻塞获取消息,超时0.1秒避免空转 message = pubsub.get_message(ignore_subscribe_messages=True, timeout=0.1) if message: position_str = message['data'].decode('utf-8') position = ast.literal_eval(position_str) print(f"Received position: {position}") ball.location = position # 返回True保持定时器持续运行 return True # 注册定时器,每0.05秒执行一次(可根据需求调整间隔) bpy.app.timers.register(update_sphere_position, first_interval=0.05)
方案二:线程 + 消息队列(适合高消息量场景)
用子线程处理Redis订阅,通过消息队列将位置数据传递到主线程,再由定时器更新物体属性,避免线程安全问题(Blender API不支持子线程直接调用)。
import bpy import redis import ast import threading import queue # 创建线程安全的消息队列,用于传递位置数据 msg_queue = queue.Queue() # Redis订阅子线程 def redis_subscribe_thread(): r = redis.StrictRedis(host='localhost', port=6379, db=0) pubsub = r.pubsub() pubsub.subscribe('positions') for message in pubsub.listen(): if message['type'] == 'message': position_str = message['data'].decode('utf-8') position = ast.literal_eval(position_str) msg_queue.put(position) # 创建球体(主线程执行) bpy.ops.mesh.primitive_uv_sphere_add(radius=0.005, location=(0, 0, 0)) ball = bpy.context.object ball.name = 'sphere' # 主线程更新函数:从队列取数据并修改物体位置 def update_from_queue(): while not msg_queue.empty(): position = msg_queue.get() print(f"Received position: {position}") ball.location = position return True # 启动订阅线程(设为守护线程,随Blender关闭自动退出) threading.Thread(target=redis_subscribe_thread, daemon=True).start() # 注册定时器轮询队列 bpy.app.timers.register(update_from_queue, first_interval=0.05)
注意事项
- 定时器间隔:建议设置在0.05-0.1秒之间,平衡实时性和性能消耗。
- 线程安全:永远不要在子线程中直接调用
bpyAPI(创建物体、修改属性等),必须通过队列将数据传递到主线程处理。 - Redis订阅:使用
ignore_subscribe_messages=True可以过滤订阅成功的系统消息,只处理业务位置数据。
内容的提问来源于stack exchange,提问作者kevinlinxc
相关产品推荐
相关产品推荐

