% Clear the workspace clear; close all; sca; % Randomly seed the random number generation rng('shuffle'); % Here we call some default settings for setting up Psychtoolbox PsychDefaultSetup(2); %---------------------------------------------------------------------- % Physical set-up variables %---------------------------------------------------------------------- % Assumed viewing distance distanceCm = 60; % Height of the surface we are applying the texture to surfaceHeightCm = 10; % Our surface will oscilate with a sine wave function around the X Y ans Z % axes % Amplitude of ossilation amplitude = 50; % Frequency in each dimension (these are just a few random numbers to make % the simulation look nice) frequencyX = 0.2; frequencyY = 0.25; frequencyZ = 0.18; % Angular frequency angFreqX = 2 * pi * frequencyX; angFreqY = 2 * pi * frequencyY; angFreqZ = 2 * pi * frequencyZ; % Starting phase startPhaseX = rand * 360; startPhaseY = rand * 360; startPhaseZ = rand * 360; % Zero time time = 0; %---------------------------------------------------------------------- % Screen initialisation %---------------------------------------------------------------------- % Make sure that the computer is running the OpenGL psych toolbox AssertOpenGL; % Setup Psychtoolbox for OpenGL 3D rendering support and initialize the % mogl OpenGL for Matlab wrapper InitializeMatlabOpenGL; % Number of samples per pixel for multisampling multiSample = 4; % Find the screen to use for display screenid = max(Screen('Screens')); % Set the black and white index black = BlackIndex(screenid); % Start the PsychImaging Configuration PsychImaging('PrepareConfiguration'); PsychImaging('AddTask', 'General', 'FloatingPoint32Bit'); % Open an on screen window using PsychImaging to optimise drawing [window, winRect] = PsychImaging('OpenWindow', screenid, black,... [], 32, 2, [], multiSample); % Set to maximum priority topPriorityLevel = MaxPriority(window); Priority(topPriorityLevel); % Get the width and height of the window in pixels [screenXpix, screenYpix] = Screen('WindowSize', window); % Reported dimensions of the screen in cm [widthMm, heightMm] = Screen('DisplaySize', screenid); screenWidth = widthMm / 10; screenHeight = heightMm / 10; % Measure the vertical refresh rate of the monitor ifi = Screen('GetFlipInterval', window); % Fill the screen black Screen('FillRect', window, black); Screen('Flip', window); %---------------------------------------------------------------------- % Timing information %---------------------------------------------------------------------- % Number of frames to wait before drawing again waitframes = 1; %---------------------------------------------------------------------- % Load movie into textures %---------------------------------------------------------------------- % Load the movie moviename = [ PsychtoolboxRoot 'PsychDemos/MovieDemos/DualDiscs.mov' ]; [movie, movieduration, fps, imgw, imgh] = Screen('OpenMovie', window, moviename); % Calculate the aspect ratio of the movie movieAspectRatio = imgw / imgh; % We will play the movie back at the normal speed playbackRate = 1; % We will loop the movie to play over and over doLoop = 1; % Movie will play at full volume soundFrac = 1; % Start movie playback Screen('PlayMovie', movie, playbackRate, doLoop, soundFrac); %---------------------------------------------------------------------- % OpenGL Setup %---------------------------------------------------------------------- % Setup the OpenGL rendering context of the onscreen window for use by % OpenGL wrapper Screen('BeginOpenGL', window); % Set background color to 'black' glClearColor(0, 0, 0, 0); % Enable depth buffer glEnable(GL.DEPTH_TEST); %---------------------------------------------------------------------- % We will use perspective projection %---------------------------------------------------------------------- % Near and far clipping planes (these difine the rendering volume, anything % outside of these is not rendered) clipNear = 0.1; clipFar = 100; % Angular subtense of the screen angle = 2 * atand((screenHeight / 2) / distanceCm); % Aspect ratio of the screen aspectRatio = screenWidth / screenHeight; % Lets set up a projection matrix, the projection matrix defines how images % in our 3D simulated scene are projected to the images on our 2D monitor glMatrixMode(GL.PROJECTION); glLoadIdentity; gluPerspective(angle, aspectRatio, clipNear, clipFar); % Setup modelview matrix: This defines the position, orientation and % direction of the virtual camera that will look at our scene with glMatrixMode(GL.MODELVIEW); glLoadIdentity; % Location of the camera cam = [0 0 0]; % Set our camera to be looking directly down the -Z axis (depth) of our % coordinate system fix = [0 0 -1]; % Define "up" up = [0 1 0]; % Here we set up the attributes of our camera using the variables we have % defined in the last three lines of code gluLookAt(cam(1), cam(2), cam(3), fix(1), fix(2), fix(3), up(1), up(2), up(3)); %---------------------------------------------------------------------- % Setup the lighting for the environment %---------------------------------------------------------------------- % Enable OpenGL Lighting glEnable(GL.LIGHTING); % Force there to be no ambient light (OpenGL default is for there to be % some) glLightModelfv(GL.LIGHT_MODEL_AMBIENT, [0 0 0 1]); % Define a local light source glEnable(GL.LIGHT0); % Defuse light only glLightfv(GL.LIGHT0, GL.DIFFUSE, [1 1 1 1]); % Point the light at the origin (this is where we will place our sphere) glLightfv(GL.LIGHT0, GL.SPOT_DIRECTION, [0 0 -distanceCm]); % Allow normalisation glEnable(GL.NORMALIZE); %---------------------------------------------------------------------- % Display list for the slanted surface %---------------------------------------------------------------------- % Surface dimensions surfaceWidthCm = surfaceHeightCm * movieAspectRatio; surfaceHalfHeightCm = surfaceHeightCm / 2; surfaceHalfWidthCm = surfaceWidthCm / 2; % Surface corner coordinates surfCoords = [-surfaceHalfWidthCm surfaceHalfHeightCm 0;... surfaceHalfWidthCm surfaceHalfHeightCm 0;... surfaceHalfWidthCm -surfaceHalfHeightCm 0;... -surfaceHalfWidthCm -surfaceHalfHeightCm 0]'; % Calculate the surface normal (this insures proper lighting calculations) surfNormal = cross(surfCoords(:, 3) - surfCoords(:, 2), surfCoords(:, 2) - surfCoords(:, 1)); % End the open GL wrapper for now Screen('EndOpenGL', window); %---------------------------------------------------------------------- % Keyboard information %---------------------------------------------------------------------- % Unify the keyboard names for mac and windows computers KbName('UnifyKeyNames'); % Define the keyboard keys that are listened for escapeKey = KbName('ESCAPE'); %---------------------------------------------------------------------- % Drawing Loop %---------------------------------------------------------------------- % Get a vbl for the start time vbl = Screen('Flip', window); startTimeFix = vbl; while ~KbCheck % Orientation of the square on this frame angleX = amplitude * sin(angFreqX * time + startPhaseX); angleY = amplitude * sin(angFreqY * time + startPhaseY); angleZ = amplitude * sin(angFreqZ * time + startPhaseZ); % Get the current movie frame texid = Screen('GetMovieImage', window, movie); % Get the size of the movie frame [imw, imh] = Screen('WindowSize', texid); % Retrieve an OpenGL texture handle and texture mapping parameters: % texName contains the OpenGL texture ID, target is the texture % type, tu and tv are the texture coodinates of the (imw,imh) % position of the texture [texName, target, tu, tv] = Screen('GetOpenGLTexture', window, texid, imw, imh); % Begin open GL Screen('BeginOpenGL', window); % Clear the buffers glClear; % Push and pop are needed to avoid accumulations of transforms glPushMatrix; % Rotate and then translate the surface (these commands need to be % issued in the opposite way in which you want them applied by OpenGL) glTranslatef(0, 0, -distanceCm); glRotatef(angleX, 1, 0, 0); glRotatef(angleY, 0, 1, 0); glRotatef(angleZ, 0, 0, 1); % Enable and bind the texture glEnable(target); glBindTexture(target, texName); % Texture color will interact with the lighting glTexEnvfv(GL.TEXTURE_ENV,GL.TEXTURE_ENV_MODE, GL.MODULATE); % Filtering for our texture glTexParameterfv(GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, GL.NEAREST); glTexParameterfv(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.NEAREST); % Set the surface normal we calculated earlier glNormal3f(surfNormal(1), surfNormal(2), surfNormal(3)); % Begin drawing of a quad (square) which will be the support of our % texture, we associate the geometric coordinates of the plane with the % texture coordinates of the image glBegin(GL.QUADS); glTexCoord2f(0, 0); glVertex3f(surfCoords(1, 1), surfCoords(2, 1), surfCoords(3, 1)); glTexCoord2f(tu, 0); glVertex3f(surfCoords(1, 2), surfCoords(2, 2), surfCoords(3, 2)); glTexCoord2f(tu, tv); glVertex3f(surfCoords(1, 3), surfCoords(2, 3), surfCoords(3, 3)); glTexCoord2f(0, tv); glVertex3f(surfCoords(1, 4), surfCoords(2, 4),surfCoords(3, 4)); glEnd; % Ditch the matrix transforms glPopMatrix; % End the open GL context Screen('EndOpenGL', window); % Flip to the screen vbl = Screen('Flip', window, vbl + (waitframes - 0.5) * ifi); % Close the current texture Screen('Close', texid); % Increment time time = time + ifi; end % Close the screen sca