【问题标题】:How do I animate multiple objects simultaneously with each having a different KeyFrameTrack in pythreejs?如何在pythreejs中同时为多个对象设置动画,每个对象都有不同的KeyFrameTrack?
【发布时间】:2019-11-23 19:59:47
【问题描述】:

随着时间的推移,我为场景中的每个对象生成 4x4 变换矩阵,并使用 VectorKeyframeTrack 在 Mesh 对象上设置变换矩阵。我可以为每个对象分别使用AnimateAction 为对象设置动画,但无法弄清楚如何通过单个.play() 调用让所有对象同时动画并保持它们同步。据我所知,希望从第二个循环开始,对象将是时间同步的,但它们不是:

import pythreejs as pjs

rod_mesh = pjs.Mesh(
    pjs.CylinderBufferGeometry(0.005, 0.005, sys.constants[lB] - sys.constants[h] / 2,),
    pjs.MeshStandardMaterial(color='red')
)

plate_mesh = pjs.Mesh(pjs.PlaneBufferGeometry(sys.constants[h], sys.constants[w]),
                      pjs.MeshStandardMaterial(color='blue', side='DoubleSide'))
# Animation will not update without this set.
rod_mesh.matrixAutoUpdate = False
plate_mesh.matrixAutoUpdate = False
# Set initial position/orientation
rod_mesh.matrix = rod_matrices[0]
plate_mesh.matrix = plate_matrices[0]

# Setup scene
view_width = 600
view_height = 400
camera = pjs.PerspectiveCamera(position=[0.25, 0.25, 0.25], aspect=view_width/view_height)
key_light = pjs.DirectionalLight(position=[0, 10, 10])
ambient_light = pjs.AmbientLight()
scene_pjs = pjs.Scene(children=[rod_mesh, plate_mesh, camera, key_light, ambient_light])
controller = pjs.OrbitControls(controlling=camera)
renderer = pjs.Renderer(camera=camera, scene=scene_pjs, controls=[controller], width=view_width, height=view_height)

# Specify KeyframeTracks
rod_track = pjs.VectorKeyframeTrack(name='.matrix', times=list(sys.times), values=rod_matrices)
plate_track = pjs.VectorKeyframeTrack(name='.matrix', times=list(sys.times), values=plate_matrices)

rod_clip = pjs.AnimationClip(tracks=[rod_track])
plate_clip = pjs.AnimationClip(tracks=[plate_track])

rod_mixer = pjs.AnimationMixer(rod_mesh)
plate_mixer = pjs.AnimationMixer(plate_mesh)

rod_action = pjs.AnimationAction(rod_mixer, rod_clip, rod_mesh)
plate_action = pjs.AnimationAction(plate_mixer, plate_clip, plate_mesh)

# Try to enforce syncronization among actions at each loop start
plate_action.exec_three_obj_method('syncWith', 'IPY_MODEL_' + rod_action.get_view_spec()['model_id'])
rod_action.exec_three_obj_method('syncWith', 'IPY_MODEL_' + plate_action.get_view_spec()['model_id'])

listener_func = '() => {{ {}.syncWith({}); }}'.format('IPY_MODEL_' + plate_action.get_view_spec()['model_id'], 'IPY_MODEL_' + rod_action.get_view_spec()['model_id'])

rod_mixer.exec_three_obj_method('addEventListener', 'loop', listener_func)

syncWith() 必须在每个帧转换时调用,但我不确定如何影响 pythreejs 的动画帧循环。

【问题讨论】:

    标签: python three.js jupyter pythreejs


    【解决方案1】:

    这里给出了解决方案:

    https://github.com/jupyter-widgets/pythreejs/issues/262

    关键是动画场景而不是单个网格,这样做的技巧是命名网格,然后在设置 KeyFrameTracks 时使用scene/<mesh name>.<attribute to change>。这是我重新设计的示例:

    rod_mesh = pjs.Mesh(pjs.CylinderBufferGeometry(0.005, 0.005, sys.constants[lB] - sys.constants[h] / 2),
                        pjs.MeshStandardMaterial(color='red'),
                        name='rod'  # name each mesh!
    )
    
    plate_mesh = pjs.Mesh(pjs.PlaneBufferGeometry(sys.constants[h], sys.constants[w]),
                          pjs.MeshStandardMaterial(color='blue', side='DoubleSide'),
                          name="plate"  # name each mesh!
    )
    
    # For updating the transform matrices directly set:
    rod_mesh.matrixAutoUpdate = False
    plate_mesh.matrixAutoUpdate = False
    
    # Scene setup
    view_width = 600
    view_height = 400
    camera = pjs.PerspectiveCamera(position=[0.25, 0.25, 0.25], aspect=view_width/view_height)
    key_light = pjs.DirectionalLight(position=[0, 10, 10])
    ambient_light = pjs.AmbientLight()
    scene_pjs = pjs.Scene(children=[rod_mesh, plate_mesh, camera, key_light, ambient_light])
    controller = pjs.OrbitControls(controlling=camera)
    renderer = pjs.Renderer(camera=camera, scene=scene_pjs, controls=[controller], width=view_width, height=view_height)
    
    # Key thing here is to set the attribute you want to change as a sub-item of the scene. Use the names of the meshes above.
    rod_track = pjs.VectorKeyframeTrack(name='scene/rod.matrix',
                                        times=list(sys.times),
                                        values=rod_matrices)
    plate_track = pjs.VectorKeyframeTrack(name='scene/plate.matrix',
                                          times=list(sys.times),
                                          values=plate_matrices)
    
    # Now create a single clip with both tracks and animate the scene:
    clip = pjs.AnimationClip(tracks=[rod_track, plate_track], duration=sys.times[-1])
    action = pjs.AnimationAction(pjs.AnimationMixer(scene_pjs), clip, scene_pjs)
    

    这是我的完整工作示例:

    https://gist.github.com/moorepants/c5ebb846499c4002744b8c101705015f

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-12
      • 2019-10-12
      • 1970-01-01
      • 1970-01-01
      • 2023-03-08
      相关资源
      最近更新 更多