gpt4 book ai didi

python - 在 Shady 中控制逐帧绘制

转载 作者:太空宇宙 更新时间:2023-11-04 04:10:34 24 4
gpt4 key购买 nike

我正在努力理解如何控制 Shady 在屏幕上绘制的内容的流程。我习惯了 Psychtoolbox,您可以在其中通过在后台缓冲区上绘图来不断添加帧,然后通过调用 flip() 将其显式推送到屏幕上。使用 Shady,事情似乎会自动发生,因此当您将 Stimulus 对象添加到 World 时,它会尽快绘制。但是,如果我必须添加多个刺激,我如何保证在它们全部被绘制之前屏幕上不会更新任何内容?

例如,假设我想绘制一个空白屏幕,并在其上左上角绘制一个小方 block 。我可以做类似的事情:

w = Shady.World()
s1 = w.Stimulus(None, 'blank', envelopeSize=[1920, 1200], backgroundColor=[0, 0, 0], z=0)
s2 = w.Stimulus(None, 'square', envelopeSize=[20, 20], x=-950, y=590, backgroundColor=[1, 1, 1], z=1)

但是我如何保证我最终不会从第 n 帧开始绘制 s1,而从第 n+1 帧开始绘制 s2?也许它们可以组合成一个 Stimulus 对象,但我想让它们分开(在我的真实案例问题中,小方 block 实际上是用来触发光电管的,所以我需要能够让它闪烁一次框架,在任务期间的不同时间)。

最佳答案

首先最好阅读关于 Concurrency 的 Shady 文档.前两个示例(在“运行单线程”标题下)没有您担心的问题,因为 Stimulus 实例是在实际渲染单个帧之前创建的。这是一个简单的例子:

import Shady
w = Shady.World(threaded=False)
# s1 = ...
# s2 = ...
# ...
w.Run()

除此之外,Shady 固有的范式转换之一是您从不自己调用任何等效的 flip(),这是对的。一开始可能会觉得不熟悉,但请放心:在我们基于 Shady 构建的应用程序中,我们不会错过自己调用 flip() 的日子。刺激参数的更新在回调中完成,例如:

  • 所谓的“动画回调”,您可以选择将其安装到每个 WorldStimulus 实例中;

  • 您可以分配给任何 WorldStimulus 属性的动态(可调用)值(这些在任何动画后立即得到评估回调);

  • 响应按键等的事件回调

您在同一回调中所做的更改保证在同一帧上呈现 — 这就是我们如何保持严格控制时间的答案,即使不是运行单线程。的确,如果您运行多线程并发出一个接一个的 w.Stimulus() 调用,它们不能保证出现在同一帧上(事实上,它们保证出现在 < em>不同 帧,因为非绘图线程中的 .Stimulus() 调用实际上将刺激创建的实际工作推迟到绘图线程中,然后等待直到在返回之前完成)。可能的解毒剂是(1)运行单线程; (2) 在专用的 Prepare() 方法中执行所有 w.Stimulus() 创建调用,如文档的第二个示例;或 (3) 确保刺激物在创建时具有 visible=False,并且仅在稍后使它们可见。在所有这些情况下,我们都小心地将刺激的创建(可能很慢)与其属性的操纵分开。

前两种回调类型与您所描述的内容最相关。它们包含在 Shady 关于 "Making properties dynamic" 的文档中.在他们提供的框架内,有许多不同的方法来实现您描述的目标(在 Python 和 Shady 中总是如此)。就个人而言,我喜欢使用 StateMachine实例作为我的动画回调。以下是我将如何创建一个简单的重复呈现的刺激,其开始由传感器贴片闪烁单帧预示:

import random
import Shady

w = Shady.World(canvas=True, gamma=2.2)


# STIMULI

Shady.Stimulus.SetDefault(visible=False)
# let all stimuli be invisible by default when created

gabor = w.Sine(pp=0)
sensorPatch = w.Stimulus(
size = 100, # small,
color = 1, # bright,
anchor = Shady.UPPER_LEFT, # with its top-left corner stuck...
position = w.Place(Shady.UPPER_LEFT), # to the top-left corner of the screen
)


# STATE MACHINE

sm = Shady.StateMachine()

@sm.AddState
class InterTrialInterval(sm.State):
# state names should be descriptive but can be anything you want

def duration(self):
return random.uniform(1.0, 3.0)

next = 'PresentGabor'

@sm.AddState
class PresentGabor(sm.State):

def onset(self):
gabor.visible = True
sensorPatch.visible = Shady.Impulse() # a dynamic object: returns 1.0 the first time it is evaluated, then 0.0 thereafter

duration = 2.0

def offset(self):
gabor.visible = False

next = 'InterTrialInterval'


w.SetAnimationCallback( sm )
# now sm(t) will be called at every new time `t`, i.e. on every frame,
# and this will in turn call `onset()` and `offset()` whenever appropriate

关于python - 在 Shady 中控制逐帧绘制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56349120/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com