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

Blender脚本无限循环卡顿及Redis订阅场景解决方案咨询

解决Blender通过Redis订阅更新物体位置的问题

问题根源分析

  • 直接用无限循环:会阻塞Blender的主事件循环,导致UI卡顿、无法响应操作——因为Blender的界面刷新、事件处理都在主线程执行,被循环占用后完全无法运转。
  • 用子进程实现:Blender的bpy API只能在主进程的主线程中调用,子进程无法访问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秒之间,平衡实时性和性能消耗。
  • 线程安全:永远不要在子线程中直接调用bpy API(创建物体、修改属性等),必须通过队列将数据传递到主线程处理。
  • Redis订阅:使用ignore_subscribe_messages=True可以过滤订阅成功的系统消息,只处理业务位置数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 21:47:11