Beispiel #1
0
    def build(self):

        # configure beamer
        self.set_arena_mode('greenHDMI')

        self.cylinder_height, self.cylinder_radius, self.cylinder = tools.standard_cylinder(
            self.parent.mainNode)

        # load texture
        # for horizontal gratings the edge is at the left edge of the arena (phi = 0)
        # for vertical gratings the edge is at the bottom edge of the arena (z = -6.5)
        anti_alias_texture_size = int(
            math.ceil(608. / (math.degrees(
                math.atan(self.cylinder_height / 2. / self.cylinder_radius)) *
                              2 / self.wave_length / 0.9) - 2 * 4) / 2. +
            2)  # empirically
        if self.mode == 'sin':
            # starts always at the edge of the texture with phase = 0 of the sine wave (rescaled to the range between max_intensity and min_intensity)
            self.tex = tools.create_sine_grating_texture(
                anti_alias_texture_size, self.min_intensity,
                self.max_intensity)
        elif self.mode == 'sq':
            # starts always at the edge of the texture with the black stripe
            self.tex = tools.create_grating_texture(anti_alias_texture_size,
                                                    self.min_intensity,
                                                    self.max_intensity)

        # generate wavelength by rescaling the texture ( which contains exact one period of the grating) in relation to the desired wavelength
        # for the horizontal component the scaling factor is given by the ratio between the cylinder width (360 degree) and the wavelength
        # for the vertical component the scaling factor is given by the ratio between 180 degree (because we would see the whole texture if the scaling factor would be 1)
        #       and the wavelength times the aspect ratio of the arena screen (such that 45 degree remains 45 degree)
        #
        # NOTE: Using this convention the vertical scaling factor is given by the requirement that 45 degree generates exactly 45 degree on the arena screen
        #       This scaling factor also defines how wide the bars will be in vertical direction.
        #       Hence, the wavelength is strictly speaking defined only for horizontal gratings moving along the azimuth

        self.cylinder.setTexture(self.tex)
        #self.cylinder.setTexScale(pcore.TextureStage.getDefault(), 360.0/self.wave_length, math.degrees(math.atan(self.cylinder_height/2./self.cylinder_radius))*2/self.wave_length)
        self.cylinder.setTexScale(
            pcore.TextureStage.getDefault(), 360.0 / self.wave_length,
            360.0 / self.wave_length / 2. / (10. * math.pi / 26.))
        self.cylinder.setTexRotate(pcore.TextureStage.getDefault(),
                                   -self.rotation)

        self.tex_offset = 0.
        self.cylinder.setTexOffset(pcore.TextureStage.getDefault(),
                                   (self.tex_offset + self.angle_function(0)) /
                                   self.wave_length % 1, 0)

        # set up shared variables for synchronizing all color worlds
        self.shared.rotation = self.rotation

        # set up keyboard commands for moving the window
        base.accept("arrow_up", self.increase_rot)
        base.accept("arrow_down", self.decrease_rot)
        base.accept("arrow_up-repeat", self.increase_rot)
        base.accept("arrow_down-repeat", self.decrease_rot)
    def build(self):  #, old_geometry):

        # configure beamer
        self.set_arena_mode('greenHDMI')

        self.cylinder_height, self.cylinder_radius, self.cylinder = tools.standard_cylinder(
            self.parent.mainNode)

        self.T = self.motion_T * 2 + self.pause

        # load texture (same as in default.Grating)
        anti_alias_texture_size = int(
            math.ceil(608. / (math.degrees(
                math.atan(self.cylinder_height / 2. / self.cylinder_radius)) *
                              2 / self.wave_length / 0.9) - 2 * 4) / 2. +
            2)  # empirically
        if self.mode == 'sin':
            self.tex = tools.create_sine_grating_texture(
                anti_alias_texture_size, self.min_intensity,
                self.max_intensity)
        elif self.mode == 'sq':
            self.tex = tools.create_grating_texture(anti_alias_texture_size,
                                                    self.min_intensity,
                                                    self.max_intensity)

        # generate wavelength by rescaling the texture ( which contains exact one period of the grating) in relation to the desired wavelength
        # for the horizontal component the scaling factor is given by the ratio between the cylinder width (360 degree) and the wavelength
        # for the vertical component the scaling factor is given by the ratio between 180 degree (because we would see the whole texture if the scaling factor would be 1)
        #       and the wavelength times the aspect ratio of the arena screen (such that 45 degree remains 45 degree)
        #
        # NOTE: Using this convention the vertical scaling factor is given by the requirement that 45 degree generates exactly 45 degree on the arena screen
        #       This scaling factor also defines how wide the bars will be in vertical direction.
        #       Hence, the wavelength is strictly speaking defined only for horizontal gratings moving along the azimuth

        self.cylinder.setTexture(self.tex)
        #self.cylinder.setTexScale(pcore.TextureStage.getDefault(), 360.0/self.wave_length, math.degrees(math.atan(self.cylinder_height/2./self.cylinder_radius))*2/self.wave_length)
        self.cylinder.setTexScale(
            pcore.TextureStage.getDefault(), 360.0 / self.wave_length,
            360.0 / self.wave_length / 2. / (10. * math.pi / 26.))
        self.cylinder.setTexRotate(pcore.TextureStage.getDefault(),
                                   -self.rotation)
        self.velocity = -self.velocity

        self.tex_offset = 0.
        self.cylinder.setTexOffset(pcore.TextureStage.getDefault(),
                                   (self.tex_offset + self.angle_function(0)) /
                                   self.wave_length % 1, 0)

        # set up variables to memorize which triggers have been made already
        self.stop1stdirection_trigger = True
        self.start2ndirection_trigger = True
Beispiel #3
0
    def build(self):

        # configure beamer
        self.set_arena_mode('greenHDMI')

        self.cylinder_height, self.cylinder_radius, self.cylinder = tools.standard_cylinder(
            self.parent.mainNode)

        # define 4 quadrants for the rotation angle phi:
        #   a) 0 < phi < 90:
        #       standard configuration, edge starts from lower left
        #   b) 90 < phi < 180:
        #       rotate the cylinder AND flip it, edge starts from lower right
        #   c) 180 < phi < 270:
        #       rotate the cylinder, edge starts from upper right
        #   d) 270 < phi < 360:
        #       flip the cylinder, edge starts from upper left
        #
        # for each case define a new rotation angle phi_ (flip the sign if necessary)

        phi = self.rotation % 360.
        if (0. <= phi) and (phi < 90.):
            phi_ = phi % 90.
        elif (90. <= phi) and (phi < 180.):
            self.cylinder.setHpr(90, 180, 0)
            self.cylinder.setScale(self.cylinder_radius, self.cylinder_radius,
                                   -self.cylinder_height)
            self.cylinder.setAttrib(pcore.CullFaceAttrib.makeReverse())
            phi_ = 90 - (phi % 90.)
        elif (180. <= phi) and (phi < 270.):
            self.cylinder.setHpr(90, 180, 0)
            phi_ = phi % 90.
        elif (270. <= phi) and (phi < 360.):
            self.cylinder.setScale(self.cylinder_radius, self.cylinder_radius,
                                   -self.cylinder_height)
            self.cylinder.setAttrib(pcore.CullFaceAttrib.makeReverse())
            phi_ = 90 - (phi % 90.)

        # load texture
        self.wave_length = 600.  # big enough that even at 50.38 degree (when the grating is oriented along the diagonal of the arena) one phase can cover the whole screen
        anti_alias_texture_size = int(
            math.ceil(608. / (math.degrees(
                math.atan(self.cylinder_height / 2. / self.cylinder_radius)) *
                              2 / self.wave_length / 0.9) - 2 * 4) / 2. +
            2)  # empirically
        self.tex = tools.create_grating_texture(anti_alias_texture_size,
                                                self.bg_intensity,
                                                self.edge_intensity)

        # use the same scaling and rotation convention as for gratings
        self.cylinder.setTexture(self.tex)
        self.cylinder.setTexScale(
            pcore.TextureStage.getDefault(), 360.0 / self.wave_length,
            360.0 / self.wave_length / 2. / (10. * math.pi / 26.))
        #self.cylinder.setTexRotate(pcore.TextureStage.getDefault(), -self.rotation)
        self.cylinder.setTexRotate(pcore.TextureStage.getDefault(), -phi_)

        self.tex_offset = 0.0
        self.cylinder.setTexOffset(pcore.TextureStage.getDefault(),
                                   self.tex_offset, 0)

        # Define stimulus length as the time an edge travels across the whole azimuth times the ratio
        # between the length of the diagonal and the azimuthal length plus 0.5 seconds
        # In this way the stimulus is longh enough for all orientations and the start and end trigger not too close to each other
        self.max_T = 180. / math.fabs(
            self.velocity) * (math.sqrt(26.**2 + (10. * math.pi)**2) /
                              (10. * math.pi))
        self.T = self.max_T + 0.5
    def build(self):  #, old_geometry):

        # configure beamer
        self.set_arena_mode('greenHDMI')

        self.cylinder_height, self.cylinder_radius, self.cylinder = tools.standard_cylinder(
            self.parent.mainNode)

        # make cylinder bigger in case the window is overlapping the edges and needs more space
        self.cylinder_height = self.cylinder_height + self.dz * 2
        self.cylinder.setScale(self.cylinder_radius, self.cylinder_radius,
                               self.cylinder_height)

        # like in default.PDNDgrating
        self.period = self.motion_T * 2 + self.pause * 2
        self.T = 100000  # go on for eternity
        self.count_period = 0

        # load texture
        anti_alias_texture_size = int(
            math.ceil(608. / (math.degrees(
                math.atan(self.cylinder_height / 2. / self.cylinder_radius)) *
                              2 / self.wave_length / 0.9) - 2 * 4) / 2. +
            2)  # empirically
        if self.mode == 'sin':
            self.tex = tools.create_sine_grating_texture(
                anti_alias_texture_size, self.min_intensity,
                self.max_intensity)
        elif self.mode == 'sq':
            self.tex = tools.create_grating_texture(anti_alias_texture_size,
                                                    self.min_intensity,
                                                    self.max_intensity)
        self.cylinder.setTexture(self.tex)

        # scale like in the normal PDNDgrating and then scale down even more by the factor between the bigger cylinder and the "normal" cylinder of height 26.
        #factor_visible = math.degrees(math.atan(26/2./self.cylinder_radius))*2/self.wave_length * self.cylinder_height/26.
        #self.cylinder.setTexScale(pcore.TextureStage.getDefault(), 360.0/self.wave_length, factor_visible) # visible cylinder height is 26

        # generate wavelength by rescaling the texture ( which contains exact one period of the grating) in relation to the desired wavelength
        # for the horizontal component the scaling factor is given by the ratio between the cylinder width (360 degree) and the wavelength
        # for the vertical component the scaling factor is given by the ratio between 180 degree (because we would see the whole texture if the scaling factor would be 1)
        #       and the wavelength times the aspect ratio of the arena screen (such that 45 degree remains 45 degree)
        #
        # NOTE: Using this convention the vertical scaling factor is given by the requirement that 45 degree generates exactly 45 degree on the arena screen
        #       This scaling factor also defines how wide the bars will be in vertical direction.
        #       Hence, the wavelength is strictly speaking defined only for horizontal gratings moving along the azimuth

        self.cylinder.setTexture(self.tex)
        #self.cylinder.setTexScale(pcore.TextureStage.getDefault(), 360.0/self.wave_length, math.degrees(math.atan(self.cylinder_height/2./self.cylinder_radius))*2/self.wave_length)
        self.cylinder.setTexScale(
            pcore.TextureStage.getDefault(), 360.0 / self.wave_length, 360.0 /
            self.wave_length / 2. / (10. * math.pi / self.cylinder_height))

        self.cylinder.setTexRotate(pcore.TextureStage.getDefault(),
                                   -self.rotation)
        self.velocity = -self.velocity

        self.tex_offset = 0.
        self.cylinder.setTexOffset(pcore.TextureStage.getDefault(),
                                   (self.tex_offset + self.angle_function(0)) /
                                   self.wave_length % 1, 0)

        # create window
        self.z = self.z * 10 / 5.
        self.dz = self.dz * 10 / 5.
        if self.dz > 26:
            self.dz = 26
        if self.dphi > 360.:
            self.dphi = 360.

        # create black/white mask for transparent area
        self.ts_window = pcore.TextureStage('ts_window')
        self.ts_window.setMode(pcore.TextureStage.MBlend)
        tex_window = tools.create_window_texture_set_size(
            self.dphi, self.dz, 0, 255, 360, int(self.cylinder_height / 0.1))
        self.cylinder.setTexture(self.ts_window, tex_window)
        self.cylinder.setTexOffset(
            self.ts_window, -(-self.dphi / 2. / 360. + self.phi / 360.),
            0.5 - self.dz / 2. / self.cylinder_height -
            self.z / self.cylinder_height)

        # set color of the background around the window
        self.ts_window.setColor(
            pcore.Vec4(self.bg_intensity / 255., self.bg_intensity / 255.,
                       self.bg_intensity / 255., 1))

        # initialize variables to memorize phase of the stimulus
        self.stop1stdirection_trigger = True
        self.start2ndirection_trigger = True

        # set up shared variables for synchronizing all color worlds
        self.shared.phi = self.phi
        self.shared.z = self.z
        self.shared.factor = 1

        # set up keyboard commands for moving the window
        base.accept("arrow_right", self.increase_phi)
        base.accept("arrow_left", self.decrease_phi)
        base.accept("arrow_up", self.increase_z)
        base.accept("arrow_down", self.decrease_z)
        base.accept("arrow_right-repeat", self.increase_phi)
        base.accept("arrow_left-repeat", self.decrease_phi)
        base.accept("arrow_up-repeat", self.increase_z)
        base.accept("arrow_down-repeat", self.decrease_z)