function [noiseid, noiserect] = CreateProceduralNoise(windowPtr, width, height, noiseType, backgroundColorOffset, varargin) % [noiseid, noiserect] = CreateProceduralNoise(windowPtr, width, height [, noiseType='ClassicPerlin'][, backgroundColorOffset =(0,0,0,0)][, param1][, param2, ...]) % % Creates a procedural texture that allows to draw random noise stimulus patches % in a very fast and efficient manner on modern graphics hardware. % % This works on GPU's with support for the OpenGL shading language and % vertex- and fragment shaders. See ProceduralNoiseDemo for examples on how to use this function. % % % Parameters and their meaning: % % 'windowPtr' A handle to the onscreen window. % % % 'width' x 'height' The maximum 2D size (in pixels) of the noise patch. % % % 'noiseType' Name of the noise function to use, defaults to 'ClassicPerlin'. % The following types of noise are currently supported: % % - 'Perlin': Generates Perlin noise, which is approximately gaussian % distributed. % % - 'ClassicPerlin': Like Perlin, but with the classic implementation. % % % 'backgroundColorOffset' Optional, defaults to [0 0 0 0]. A RGBA offset % color to add to the final RGBA colors of the drawn gabor, prior to % drawing it. % % % 'param1' ... 'paramN' - Parameters specific to the noise function. % % % The function returns a procedural texture handle 'noiseid' that you can % pass to the Screen('DrawTexture(s)', windowPtr, noiseid, ...) functions % like any other texture handle. The 'noiserect' is a rectangle which % describes the size of the noise texture support. % % A typical invocation to draw a single noise patch may look like this: % % Screen('DrawTexture', windowPtr, noiseid, [], dstRect, [], [], [], % modulateColor, [], [], [contrast, seed, 0, 0]); % % Draws the patch 'noiseid' into window 'windowPtr', at position 'dstRect', % or in the center if 'dstRect' is set to []. Make sure 'dstRect' has the % size of 'noiserect' to avoid spatial distortions! You could do, e.g., % dstRect = OffsetRect(noiserect, xc, yc) to place the patch centered at % screen position (xc,yc). % % % 'modulateColor' is the base color of the noise patch - it defaults to % white, ie. the noise has only luminance, but no color. If you'd set it to % [255 0 0] you'd get a reddish noise. % % % 'contrast' is the amplitude of your patch in intensity units - A factor % that is multiplied to the random number before converting the % value into a color value. 'contrast' may be a bit of a misleading term % here... % % 'seed' Defines the random seed for drawing of a pseudo-random patch. % % Make sure to use the Screen('DrawTextures', ...); function properly, % instead of the Screen('DrawTexture', ...); function, if you want to draw % many different patches simultaneously - this is much faster! % % History: % 18.03.2011 Written. Derived from CreateProceduralGabor. (MK) % 26.02.2012 Updated to use classic perlin noise by default. (MK) debuglevel = 1; % Global GL struct: Will be initialized in the LoadGLSLProgramFromFiles % below: global GL; if nargin < 3 || isempty(windowPtr) || isempty(width) || isempty(height) error('You must provide "windowPtr", "width" and "height"!'); end if nargin < 4 || isempty(noiseType) noiseType = 'ClassicPerlin'; end if nargin < 5 || isempty(backgroundColorOffset) backgroundColorOffset = [0 0 0 0]; else if length(backgroundColorOffset) < 4 error('The "backgroundColorOffset" must be a 4 component RGBA vector [red green blue alpha]!'); end end % Switch to windowPtr OpenGL context: Screen('GetWindowInfo', windowPtr); % Make sure we have support for shaders, abort otherwise: AssertGLSL; noiseShader = []; if strcmpi(noiseType, 'Perlin') % Load standard 2D Perlin noise shader: noiseShader = LoadGLSLProgramFromFiles({'PerlinNoiseLib.frag.txt', 'BasicPerlinNoiseShader.vert.txt', 'BasicPerlinNoiseShader.frag.txt'}, debuglevel); end if strcmpi(noiseType, 'ClassicPerlin') % Load standard 2D Perlin noise shader: noiseShader = LoadGLSLProgramFromFiles({'ClassicPerlinNoiseLib.frag.txt', 'BasicPerlinNoiseShader.vert.txt', 'BasicPerlinNoiseShader.frag.txt'}, debuglevel); end if isempty(noiseShader) error('Unknown/Unsupported noiseType specified or shader load error!'); end % Setup shader: glUseProgram(noiseShader); % Set color offset: glUniform4f(glGetUniformLocation(noiseShader, 'Offset'), backgroundColorOffset(1),backgroundColorOffset(2),backgroundColorOffset(3),backgroundColorOffset(4)); % Setup done: glUseProgram(0); % Create a purely virtual procedural texture 'gaborid' of size width x height virtual pixels. % Attach the noiseShader to it to define its appearance: noiseid = Screen('SetOpenGLTexture', windowPtr, [], 0, GL.TEXTURE_RECTANGLE_EXT, width, height, 1, noiseShader); % Query and return its bounding rectangle: noiserect = Screen('Rect', noiseid); % Ready! return;