def build(self): # configure beamer self.set_arena_mode('greenHDMI') self.cylinder_height, self.cylinder_radius, self.cylinder = tools.standard_cylinder(self.parent.mainNode) self.cylinder.setColor(self.bg_intensity/255.,self.bg_intensity/255.,self.bg_intensity/255.,1) 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. self.ts_window = pcore.TextureStage('ts_bar') tex_window = tools.create_window_texture(self.dphi, self.dz, self.bar_intensity, self.bg_intensity) self.cylinder.clearColor() self.cylinder.setTexture(self.ts_window, tex_window) # set starting point of bar depending if it will go rightwards or leftwards if self.velocity > 0: self.phi0 = -(90. + self.dphi/2.) elif self.velocity <= 0: self.phi0 = +(90. + self.dphi/2.) self.cylinder.setTexOffset(self.ts_window, -0.25 + self.dphi/2./360. - self.phi0/360., 0.5 - self.dz/2./26. - self.z/26.) self.T = (180. + self.dphi)/math.fabs(self.velocity)
def build(self): # configure beamer self.set_arena_mode('greenHDMI') self.cylinder_height, self.cylinder_radius, self.cylinder = tools.standard_cylinder(self.parent.mainNode) self.cylinder.setColor(self.bg_intensity/255.,self.bg_intensity/255.,self.bg_intensity/255.,1) # scale cylinder up in height in case the window texture is overlapping the edges self.cylinder_height = self.cylinder_height + self.dz * 2 self.cylinder.setScale(self.cylinder_radius,self.cylinder_radius,self.cylinder_height) self.dz = self.dz * 10/5. self.velocity = self.velocity * 10/5. if self.dz > 26.: self.dz = 26. if self.dphi > 360.: self.dphi = 360. self.ts_window = pcore.TextureStage('ts_bar') tex_window = tools.create_window_texture_set_size(self.dphi, self.dz, self.bar_intensity, self.bg_intensity, 360, int(self.cylinder_height/0.1)) self.cylinder.clearColor() self.cylinder.setTexture(self.ts_window, tex_window) # set starting point depending whether direction is downwards or upwards if self.velocity > 0: self.z0 = -(13 + self.dz/2.) elif self.velocity <= 0: self.z0 = (13 + self.dz/2.) self.cylinder.setTexOffset(self.ts_window, -0.25 + self.dphi/2./360. - self.phi/360., 0.5 - self.dz/2./self.cylinder_height - self.z0/self.cylinder_height) self.T = (26. + self.dz)/math.fabs(self.velocity)
def build(self): # configure beamer self.set_arena_mode('greenHDMI') self.cylinder_height, self.cylinder_radius, self.cylinder = tools.standard_cylinder( self.parent.mainNode) self.cylinder.setScale(10, 10, 50) self.cylinder_height = 50 self.cylinder_radius = 10 chess_image = pcore.PNMImage(2, 2) chess_image.setXelA(0, 0, 0, 0, 0, 1) chess_image.setXelA(1, 1, 0, 0, 0, 1) chess_image.setXelA(0, 1, 1, 1, 1, 1) chess_image.setXelA(1, 0, 1, 1, 1, 1) chess_tex = pcore.Texture() chess_tex.load(chess_image) chess_tex.setMagfilter(pcore.Texture.FTNearest) N_vertical = self.cylinder_height / ( 2 * math.pi * self.cylinder_radius / self.N_horizontal ) #1./(2*math.pi/N_horizontal) self.cylinder.setTexScale(pcore.TextureStage.getDefault(), self.N_horizontal, N_vertical) self.cylinder.setTexture(chess_tex) self.v_tex_offset_count = 0 self.h_tex_offset_count = 0 self.fov_right_diff = [0.0, 0.0] self.fov_left_diff = [0.0, 0.0] self.T = self.duration
def build(self): # configure beamer if self.color == 'b': self.set_arena_mode('optoblueHDMI') elif self.color == 'r': self.set_arena_mode('optoredHDMI') elif self.color == 'g': self.set_arena_mode('optogreenHDMI') self.cylinder_height, self.cylinder_radius, self.cylinder = tools.standard_cylinder(self.parent.mainNode) self.cylinder.setColor(self.min_intensity/255.,self.min_intensity/255.,self.min_intensity/255.,1) # set background color self.min_intensity = (self.min_intensity)/255. self.max_intensity = (self.max_intensity)/255. self.bg_intensity = self.min_intensity # create window self.ts_window = pcore.TextureStage('ts_window') #self.ts_window.setMode(pcore.TextureStage.MBlend) self.worlds_share(self.cylinder) # store cylinder in shared space to change its color synchronously in all color worlds self.pulse_done = False self.pulse_end = False
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): self.trigger_pixel.setColor(0, 0, 0, 1) # configure beamer self.set_arena_mode('greenHDMI') self.cylinder_height, self.cylinder_radius, self.cylinder = tools.standard_cylinder( self.parent.mainNode) self.cylinder.setColor(self.intensity / 255., self.intensity / 255., self.intensity / 255., 1)
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
def build(self): # configure beamer self.set_arena_mode('greenHDMI') self.cylinder_height, self.cylinder_radius, self.cylinder = tools.standard_cylinder( self.parent.mainNode) self.cylinder_height = self.cylinder_height + self.dz * 2 self.cylinder.setScale(self.cylinder_radius, self.cylinder_radius, self.cylinder_height) self.ts_window = pcore.TextureStage('ts_window') self.plain_tex = tools.create_plain_texture(self.bg_intensity) self.cylinder.setTexture(self.ts_window, self.plain_tex) self.nr_before = 0 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. self.tex_windowA = tools.create_window_texture_set_size( self.dphi, self.dz, self.max_intensity, self.bg_intensity, 360, int(self.cylinder_height / 0.1)) self.tex_windowB = tools.create_window_texture_set_size( self.dphi, self.dz, self.min_intensity, self.bg_intensity, 360, int(self.cylinder_height / 0.1)) 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 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)
def build(self): # configure beamer self.set_arena_mode('greenHDMI') self.cylinder_height, self.cylinder_radius, self.cylinder = tools.standard_cylinder( self.parent.mainNode) self.tex = tools.create_plain_texture(255) self.cylinder.setTexture(self.tex) self.cylinder.setColor(self.min_intensity, self.min_intensity, self.min_intensity, 1) # initialize binary variable to memorize the current phase of the flicker self.nr_before = 0
def build(self): N_z = self.N_z N_phi = self.N_phi self.N = N_z * N_phi # Texture: Background self.bg_tex_shape = (N_z, N_phi) # set inital condition for lowpass filter np.random.seed(0) self.frame_memory = np.random.normal(0, self.scaling_fac, self.bg_tex_shape) np.random.seed(0) # configure beamer self.set_arena_mode('greenHDMI') # generate standard cylinder self.cylinder_height, self.cylinder_radius, self.cylinder = tools.standard_cylinder( self.parent.mainNode) self.cylinder.setScale(self.cylinder_radius, self.cylinder_radius, self.cylinder_height * 1) # like in default.PDNDgrating self.T = self.T # INITIALIZE CYLINDER TEXTURE for the start frame (first N samples counting from random seed 0) self.framecount = 0 np.random.seed(0) try: self.tex = self.shared.texture except: ### #self.shared.control_values = np.zeros( (1000,) + self.bg_tex_shape ) ### self.shared.texture = self.generate_texture(0) # leading color world gets initialized again and jumps N random numbers (because the start frame was already generated) if self.first: np.random.seed(0) self.generate_texture(0) self.framecount = 1 # set texture in all color worlds self.tex = self.shared.texture self.cylinder.setTexture(pcore.TextureStage.getDefault(), self.tex) self.cylinder.setTexScale(pcore.TextureStage.getDefault(), 2., 1.)
def build(self): # configure beamer self.set_arena_mode('greenHDMI') self.cylinder_height, self.cylinder_radius, self.cylinder = tools.standard_cylinder(self.parent.mainNode) # paint the cylinder black on the ground tex_ground = tools.create_plain_texture(0) self.ts_ground = pcore.TextureStage('ts_ground') self.cylinder.setTexture(self.ts_ground, tex_ground) # generate textures 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 # unfortunately, MAdd Texture mode does not work together with the setColorScale - command from base.py # this means, that those textures that are added onto another one cannot be tinted in a certain color # hence, here we generate differently coloured texture from the beginning, depending on the temporal offset of the Stimulus World if self.t_offset == 0.: color_vector = [0,0,1] # blue elif self.t_offset == 1.: color_vector = [1,0,0] # red elif self.t_offset == 2.: color_vector = [0,1,0] # green # generate two sine gratings that are anti-phasic # then in the beginning everything is gray and on the left edge (phi = 0) the first polarity is dark self.tex = tools.create_coloured_sine_grating_texture(anti_alias_texture_size, self.min_intensity, self.max_intensity, color_vector=color_vector) self.tex2 = tools.create_coloured_sine_grating_texture(anti_alias_texture_size, self.max_intensity, self.min_intensity, color_vector=color_vector) # add the two sine gratings onto each other to generate a counterphase flicker self.ts1 = pcore.TextureStage('ts1') self.ts1.setMode(pcore.TextureStage.MAdd) self.ts2 = pcore.TextureStage('ts2') self.ts2.setMode(pcore.TextureStage.MAdd) self.cylinder.setTexture(self.ts1, self.tex) self.cylinder.setTexScale(self.ts1, 360.0/self.wave_length, math.degrees(math.atan(self.cylinder_height/2./self.cylinder_radius))*2/self.wave_length) self.cylinder.setTexRotate(self.ts1, -self.rotation) self.cylinder.setTexture(self.ts2, self.tex2) self.cylinder.setTexScale(self.ts2, 360.0/self.wave_length, math.degrees(math.atan(self.cylinder_height/2./self.cylinder_radius))*2/self.wave_length) self.cylinder.setTexRotate(self.ts2, -self.rotation) self.tex_offset = 0. self.cylinder.setTexOffset(self.ts1, (self.tex_offset + self.angle_function(0))/self.wave_length % 1, 0) self.cylinder.setTexOffset(self.ts2, (self.tex_offset - self.angle_function(0))/self.wave_length % 1, 0)
def build(self): # configure beamer self.set_arena_mode('greenHDMI') # generate standard cylinder self.cylinder_height, self.cylinder_radius, self.cylinder = tools.standard_cylinder( self.parent.mainNode) self.cylinder.setScale(self.cylinder_radius, self.cylinder_radius, self.cylinder_height * 1) ## PRE-RENDER background texture for all steps self.bg_tex_shape = (self.N_z, self.N_phi, self.N_steps + 1) self.bg_tex_npy = np.ones(self.bg_tex_shape) * ( self.c_bg ) # initialize as negative number (important to set BG color later) x0 = self.phi0 / self.sampling_phi # find x,y values for the center of the first box y0 = 0.5 * self.N_z + self.N_z / 13.0 * self.z0 width = self.width / self.sampling_phi # width and height of the box height = self.height / self.sampling_phi mask_list = [] for i in range(1, self.bg_tex_npy.shape[2]): n0 = np.array([ np.sin(np.radians(self.direction)), np.cos(np.radians(self.direction)) ]) # normal vector yn, xn = self.step_length / self.sampling_phi * n0 * ( i - 1) + np.array([y0, x0]) # center coordinates for n-th box mask = self.get_box_mask( self.N_phi, self.N_z, xn, yn, width / 2., height / 2., self.direction) # get pixels inside the box mask_list.append( mask) # remember each pixel mask for each time step for i in range( 1, self.bg_tex_npy.shape[2] ): # first, color all pixel during times where the box is OFF with c_off mask = mask_list[i - 1] self.bg_tex_npy[mask, :i] = self.c_off self.bg_tex_npy[mask, i + 1:] = self.c_off for i in range( 1, self.bg_tex_npy.shape[2] ): # second, color all pixel during times where the box is ON with c_on mask = mask_list[i - 1] self.bg_tex_npy[mask, i] = self.c_on self.texture_list = [ ] # convert the numpy array to actual panda3D textures and store them in a list for each time step for i in range(0, self.bg_tex_npy.shape[2]): self.texture_list.append( self.convert_npy_to_texture(self.bg_tex_npy[:, :, i])) # INITIALIZE CYLINDER TEXTURE for the start frame self.n_before = -1 self.tex = self.texture_list[0] self.cylinder.setTexture(pcore.TextureStage.getDefault(), self.tex) self.cylinder.setTexScale(pcore.TextureStage.getDefault(), 2., 1.)
def build(self): self.N_phi = self.N_pixels # configure beamer if self.color == 'b': self.set_arena_mode('optoblueHDMI') elif self.color == 'r': self.set_arena_mode('optoredHDMI') elif self.color == 'g': self.set_arena_mode('optogreenHDMI') # generate background cylinder _, _, self.bg_cylinder = tools.standard_cylinder(self.parent.mainNode) bg_cylinder_radius = 10 bg_cylinder_height = 50 self.bg_cylinder.setScale(bg_cylinder_radius, bg_cylinder_radius, bg_cylinder_height) phi_width = 180. / self.N_phi z_height = phi_width / 360. * 2 * np.pi * bg_cylinder_radius self.N_z = np.ceil(bg_cylinder_height / z_height) # take only one and the same noise for all color copys of this world!! try: self.bg_noise = self.shared.noise except: self.bg_noise = (np.random.randint( size=(int(self.N_phi * 2), int(self.N_z)), low=0, high=2)) * (self.c_on - self.c_off) + self.c_off self.shared.noise = self.bg_noise self.noise_tex = tools.make_matrix_to_texture(self.bg_noise) self.bg_cylinder.setTexture(self.noise_tex) cylinder_radius = 10 # generate first cylinder segment self.obj = tools.create_cylinder_segment(self.parent.mainNode, self.dphi) self.obj.setScale(cylinder_radius, cylinder_radius, self.dz * 2) self.obj.setHpr(90, 0, 0) N_phi = np.ceil(self.dphi / phi_width).astype(np.int) N_z = np.ceil(self.dz * 2 / z_height).astype(np.int) # take only one and the same noise for all color copys of this world!! try: self.obj_noise = self.shared.obj_noise except: self.obj_noise = (np.random.randint( size=(N_phi, N_z), low=0, high=2)) * (self.c_on - self.c_off) + self.c_off self.shared.obj_noise = self.obj_noise self.obj_tex = tools.make_matrix_to_texture(self.obj_noise) #baum_tex = loader.loadTexture("../stimuli/default/baum.jpg") #self.obj.setTexture(baum_tex) self.obj.setTexture(self.obj_tex) self.obj.setBin( "fixed", 20) # render object first (even before trigger_pixel! <40!) self.obj.setDepthTest(False) self.obj.setDepthWrite(False) # set starting point of bar depending if it will go rightwards or leftwards if self.velocity > 0: self.phi0 = -self.dphi / 2. elif self.velocity <= 0: self.phi0 = 180. + self.dphi / 2. self.setPos(self.phi0, self.z) self.T = (180. + self.dphi) / np.abs(self.velocity)
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)