![]() |
|
#1
|
|||
|
|||
|
I am creating a 3d flanker task using sightlab and vizard. I added the environment and objects (flanker and target arrows) in sightlab, and am now finetuning the trials and manipulating the positioning of arrows in vizard.
I want to link the 4 flanker arrows as a group so they move as one from trial to trial, as they will always be manipulated in the same way at the same time per trial. I am a beginner with python and don't have much experience coding. I tried to use the sightlab AI to create code to do this, but was unsuccessful. This is the code that sightlab VR assistant gave me: #position flankers and target at same depth and height: import vizfx #group flankers so they move and rotate as one, keep target separate: flankerNames = ['L1_group', 'L2_group', 'R1_group', 'R2_group'] targetName = 'C_group' flankerArrows = [vizfx.addChild(name) for name in flankerNames] targetArrow = [vizfx.addChild(targetName)] flankerGroup = vizfx.addGroup() for arrow in flankerArrows: arrow.setParent(flankerGroup) #arrange flankers and a target in a line spacing = 0.4 positions = { 'L2': -2*spacing, 'L1': -spacing, 'R1': spacing, 'R2': 2*spacing, } for arrow in flankerArrows: arrow.setPosition(positions[arrow.getName()], 0, 0, mode=viz.REL_LOCAL) #position of flankers relative to participant depthZ = 2.0 heightY = 1.5 centerX = 0 flankerGroup.setPosition(centerX, heightY, depthZ) targetArrow.setPosition(centerX, heightY, depthZ) #face participant flankerGroup.setEuler(0,0,0) targetArrow.setEuler(0,0,0) The error code I am getting is: AttributeError: module 'vizfx' has no attribute 'addGroup'. Just wondering if anyone has any idea how I could group objects as one, or how to adjust this code so that it runs? |
|
#2
|
|||
|
|||
|
There's a few ways to approach this:
You could still use the GUI, but then would need to create copies of your environment with the stimuli rotated or moved and then add that modified environment to each trial. An example that uses this method is the Visual Search Single Object GUI SightLab Projects\ExampleScripts\VisualSearch\VisualSearch1 _SingleObject_GUI https://help.worldviz.com/sightlab/v...e-manipulation Also, using mostly the GUI you can just access the arrow objects if they are added in Inspector by using env,.getChild('nameOfObject'), so like this: def sightLabExperiment(): yield viztask.waitEvent(EXPERIMENT_START) viz.callback(viz.getEventID('ResetPosition'), sightlab.resetViewPoint) env = sightlab.getEnvironment() arrow1 = env.getChild('nameofArrow') arrow1.setPosition([0,1,0]) arrow1.setEuler([180,0,0]) You could definitely use a STIM file, you would then also need either just the objects rotated or moved differently or the full environment and modify which one to present via the STIM file https://help.worldviz.com/sightlab/stim-files/ You could fully create this with code. For help with coding I would recommend first trying with the SightLab GPT Assistant (can change this to GPT 5.2 for more thinking/better responses). You just need an OpenAI account (a free one works as well) and can access that here: https://chatgpt.com/g/g-tgG8cOR5i-sightlab-vr-assistant For example here is what I got from the Assistant. You just need to press trigger to start, then A or D for right or left and then trigger to start the next trial import random import math import viz import vizfx import vizshape import viztask import vizact import sightlab_utils.sightlab as sl from sightlab_utils.settings import * # ------------------------------------------------------------ # 1) Initialize SightLab # ------------------------------------------------------------ # NOTE: vizshape objects need headlight=True so they render nicely. sightlab = sl.SightLab(gui=False, headlight=True) sightlab.setStartText('press Trigger to Start') # If you're not using the GUI, you must set an environment in code: env = vizfx.addChild('sightlab_resources/environments/whiteroom.osgb') sightlab.setEnvironment(env) # ------------------------------------------------------------ # 2) Helper: build a simple 3D "arrow" out of vizshape primitives # ------------------------------------------------------------ def makeArrow(scale=0.12): """ Creates a right-pointing arrow (points +X by default). Returns a viz.Group node you can position/rotate as one object. """ g = viz.addGroup() # Shaft shaft = vizshape.addBox(size=(0.35, 0.08, 0.08)) shaft.setParent(g) shaft.setPosition(0.0, 0.0, 0.0) # Head (cone) head = vizshape.addCone(height=0.18, radius=0.09, slices=20) head.setParent(g) head.setPosition(0.22, 0.0, 0.0) # Cone points +Z by default in many cases; rotate so it points +X head.setEuler(0, 0, -90) # Scale the whole arrow g.setScale(scale, scale, scale) # Optional: give a neutral color g.color(viz.WHITE) return g def setArrowDirection(arrowNode, direction): """ direction: 'L' or 'R' Arrow is modeled pointing +X (Right). Left is 180° about Y. """ if direction.upper() == 'R': arrowNode.setEuler(0, 0, 0) else: arrowNode.setEuler(180, 0, 0) # ------------------------------------------------------------ # 3) Create flanker layout: 4 flankers + 1 target (center) # ------------------------------------------------------------ # Positions are in meters (SightLab uses meters) Y_HEIGHT = 1.5 # roughly eye level in many setups BASE_Z_NEAR = 1.0 # near depth BASE_Z_FAR = 2.0 # far depth # Horizontal spacing of arrows (meters) X_SPACING = 0.18 # Make nodes flanker1 = makeArrow() flanker2 = makeArrow() target = makeArrow() flanker3 = makeArrow() flanker4 = makeArrow() # Parent them to the environment so their positions are in environment space for n in [flanker1, flanker2, target, flanker3, flanker4]: n.setParent(env) # Base positions (Z will be set per trial) flanker1.setPosition(-2*X_SPACING, Y_HEIGHT, BASE_Z_NEAR) flanker2.setPosition(-1*X_SPACING, Y_HEIGHT, BASE_Z_NEAR) target.setPosition(0*X_SPACING, Y_HEIGHT, BASE_Z_NEAR) flanker3.setPosition(1*X_SPACING, Y_HEIGHT, BASE_Z_NEAR) flanker4.setPosition(2*X_SPACING, Y_HEIGHT, BASE_Z_NEAR) # IMPORTANT: Add objects to SightLab for data collection. # If you want gaze data on them, set gaze=True. sightlab.addSceneObject('flanker1', flanker1, gaze=True) sightlab.addSceneObject('flanker2', flanker2, gaze=True) sightlab.addSceneObject('target', target, gaze=True) sightlab.addSceneObject('flanker3', flanker3, gaze=True) sightlab.addSceneObject('flanker4', flanker4, gaze=True) # ------------------------------------------------------------ # 4) Define "STIM-like" trial table in code # (In a real project, you’d often read this from a CSV/STIM file.) # ------------------------------------------------------------ TRIALS = [] n_trials = 20 for i in range(n_trials): congruency = random.choice(['congruent', 'incongruent']) depth = random.choice(['near', 'far']) target_dir = random.choice(['L', 'R']) if congruency == 'congruent': flanker_dir = target_dir else: flanker_dir = 'L' if target_dir == 'R' else 'R' z = BASE_Z_NEAR if depth == 'near' else BASE_Z_FAR TRIALS.append({ 'congruency': congruency, 'depth': depth, 'target_dir': target_dir, 'flanker_dir': flanker_dir, 'z': z }) sightlab.setTrialCount(len(TRIALS)) # ------------------------------------------------------------ # 5) Optional: simple response collection + RT (keyboard) # ------------------------------------------------------------ RESPONSE_LEFT_KEY = 'a' RESPONSE_RIGHT_KEY = 'd' def applyTrialConfig(cfg): # Set directions setArrowDirection(target, cfg['target_dir']) for f in [flanker1, flanker2, flanker3, flanker4]: setArrowDirection(f, cfg['flanker_dir']) # Set depth (same z for all arrows in this simple example) z = cfg['z'] flanker1.setPosition(-2*X_SPACING, Y_HEIGHT, z) flanker2.setPosition(-1*X_SPACING, Y_HEIGHT, z) target.setPosition(0*X_SPACING, Y_HEIGHT, z) flanker3.setPosition(1*X_SPACING, Y_HEIGHT, z) flanker4.setPosition(2*X_SPACING, Y_HEIGHT, z) # ------------------------------------------------------------ # 6) Main trial loop # ------------------------------------------------------------ def sightLabExperiment(): yield viztask.waitEvent(EXPERIMENT_START) for t in range(sightlab.getTrialCount()): cfg = TRIALS[t] applyTrialConfig(cfg) # Show trial-start text (SightLab will use trigger/left-click by default to continue) msg = ( f"Flanker Task\n\n" f"Respond to the CENTER arrow only.\n" f"Press '{RESPONSE_LEFT_KEY.upper()}' for LEFT, '{RESPONSE_RIGHT_KEY.upper()}' for RIGHT.\n\n" f"(Trial {t+1}/{len(TRIALS)} | {cfg['congruency']} | {cfg['depth']})\n\n" f"Press Trigger to Start" ) yield sightlab.startTrial(startTrialText=msg) # Start RT timer at trial start start_time = sightlab.hud.getCurrentTime() # Wait for response key = yield viztask.waitKeyDown([RESPONSE_LEFT_KEY, RESPONSE_RIGHT_KEY]) rt = sightlab.hud.getCurrentTime() - start_time resp_dir = 'L' if key == RESPONSE_LEFT_KEY else 'R' correct = (resp_dir == cfg['target_dir']) # Log to console; SightLab will also log trial timing automatically. print(f"Trial {t+1}: target={cfg['target_dir']} flankers={cfg['flanker_dir']} " f"cong={cfg['congruency']} depth={cfg['depth']} resp={resp_dir} " f"correct={correct} rt={rt:.3f}s") yield sightlab.endTrial(endTrialText="") # ------------------------------------------------------------ # 7) Schedule SightLab # ------------------------------------------------------------ viztask.schedule(sightlab.runExperiment) # required for data collection loop viztask.schedule(sightLabExperiment) # your experiment logic viz.callback(viz.getEventID('ResetPosition'), sightlab.resetViewPoint) # 'r' to reset |
![]() |
| Tags |
| grouping, objects, sightlab, vizard |
| Thread Tools | |
| Display Modes | Rate This Thread |
|
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Motion Builder + Vizard Objects | ForeverBound | Vizard | 1 | 04-01-2015 03:49 AM |
| Grouping Objects | javadi | Vizard | 3 | 09-17-2013 07:14 AM |
| Picking up Vizard Objects on mouse down with collisions | pwsnow | Vizard | 2 | 09-17-2012 02:02 AM |
| Vizard 4 Beta Testing | farshizzo | Announcements | 0 | 02-01-2011 10:46 AM |
| Vizard tech tip: Using the Python Imaging Library (PIL) | Jeff | Vizard | 0 | 03-23-2009 11:13 AM |