/***************************************************************************** * * Copyright (C) 2008 Adobe Systems Incorporated * All Rights Reserved. * * NOTICE: All information contained herein is, and remains the property of * Adobe Systems Incorporated and its suppliers, if any. The intellectual and * technical concepts contained herein are proprietary to Adobe Systems * Incorporated and its suppliers and may be covered by U.S. and Foreign * Patents, patents in process, and are protected by trade secret or copyright * law. Dissemination of this information or reproduction of this material is * strictly forbidden unless prior written permission is obtained from Adobe * Systems Incorporated. * *****************************************************************************/ // twirl: A simple example to demonstrate the use of the hydra sampling // function to yield an interesting effect. The filter performs // some math based on the parameter values to change the sampling // location. kernel twirl < namespace : "AIF"; vendor : "Adobe Systems"; version : 2; description : "twist an image around"; > { // define PI for the degrees to radians calculation const float PI = 3.14159265; // An input parameter to specify the radius of the twirl effect. // For this parameter, we're using metadata to indicate the minimum, // maximum, and default values, so that the tools can set the values // in the correctly in the UI for the filter. // NOTE: This parameter indicates how many pixel values out from the // center location we would like to twirl. The radius is in the pixel // coordinate space to ensure that we always rotate in a circle. For // more information regarding the coordinate spaces, please consult the // pixel bender spec. parameter float radius < minValue:float(0.1); maxValue:float(2048.0); defaultValue:float(10.0); >; // An input parameter to specify the center of the twirl effect. // As above, we're using metadata to indicate the minimum, // maximum, and default values, so that the tools can set the values // in the correctly in the UI for the filter. parameter float2 center < minValue:float2(0.0, 0.0); maxValue:float2(2048.0, 2048.0); defaultValue:float2(256.0, 256.0); >; // An input parameter to specify the angle that we would like to twirl. // For this parameter, we're using metadata to indicate the minimum, // maximum, and default values, so that the tools can set the values // in the correctly in the UI for the filter. parameter float twirlAngle < minValue:float(0.0); maxValue:float(360.0); defaultValue:float(90.0); >; // An input parameter that indicates how we want to vary the twirling // within the radius. We've added support to modulate by one of two // functions, a gaussian or a sinc function. Since Flash does not support // bool parameters, we instead are using this as an int with two possible // values. Setting this parameter to be 1 will // cause the gaussian function to be used, unchecking it will cause // the sinc function to be used. parameter int gaussOrSinc < minValue:int(0); maxValue:int(1); defaultValue:int(0); >; input image4 oImage; output float4 outputColor; // Region functions are not available in Flash targets, so we only define // the functions if we are executing on a different backend. #if !AIF_FLASH_TARGET // needed(): Indicates what area of the input is needed to fulfill the // requested output region. In this case, we consider a // radius = 1.0 area of the input for each output pixel, so we // need to outset the area by one. region needed(region outputRegion, imageRef inputRef) { // if we have a gaussian function, negligible rotation occurs at 3 * radius // for a sinc function, we want a radius where the value is < 0.03. That // happens at a factor of 33.3 times the radius. float2 fallOffPoint = pixelSize(oImage); fallOffPoint *= radius; if(gaussOrSinc == 0) fallOffPoint *= 3.0; else fallOffPoint *= 33.3; region rotatedRegion = region(float4(center.x - fallOffPoint.x, center.y - fallOffPoint.y, center.x + fallOffPoint.x, center.y + fallOffPoint.y)); return union(outputRegion, rotatedRegion); } // changed(): Indicates what area of the output is affected by the // specified input. In this case, we will blur out the image // by exactly one pixel, so the output is the input outset by // one. region changed(region inputRegion, imageRef inputRef) { // if we have a gaussian function, negligible rotation occurs at 3 * radius // for a sinc function, we want a radius where the value is < 0.03. That // happens at a factor of 33.3 times the radius. float2 fallOffPoint = pixelSize(oImage); fallOffPoint *= radius; if(gaussOrSinc == 0) fallOffPoint *= 3.0; else fallOffPoint *= 33.3; region rotatedRegion = region(float4(center.x - fallOffPoint.x, center.y - fallOffPoint.y, center.x + fallOffPoint.x, center.y + fallOffPoint.y)); return union(inputRegion, rotatedRegion); } #endif // evaluatePixel(): The function of the filter that actually does the // processing of the image. This function is called once // for each pixel of the output image. void evaluatePixel() { // convert the angle to radians float twirlAngleRadians = radians(twirlAngle); // adjust the radius value from pixel coordinates to world coordinates // to do this, we multiply by the pixel size. float adjustedRadius = length(radius * pixelSize(oImage)); // calculate where we are relative to the center of the twirl float2 relativePos = outCoord() - center; // calculate the absolute distance from the center normalized // by the twirl radius. float distFromCenter = length( relativePos ); distFromCenter /= adjustedRadius; // modulate the angle based on either a gaussian or a sync. float adjustedRadians; // precalculate either the gaussian or the sinc weight float sincWeight = sin( distFromCenter ) * twirlAngleRadians / ( distFromCenter ); float gaussWeight = exp( -1.0 * distFromCenter * distFromCenter ) * twirlAngleRadians; // protect the algorithm from a 1 / 0 error adjustedRadians = (distFromCenter == 0.0) ? twirlAngleRadians : sincWeight; // switch between a gaussian falloff or a sinc fallof adjustedRadians = (gaussOrSinc == 1) ? adjustedRadians : gaussWeight; // rotate the pixel sample location. float cosAngle = cos( adjustedRadians ); float sinAngle = sin( adjustedRadians ); float2x2 rotationMat = float2x2( cosAngle, sinAngle, -sinAngle, cosAngle ); relativePos = rotationMat * relativePos; // sample and set as the output color. since relativePos // is related to the center location, we need to add it back in. // We use linear sampling to smooth out some of the pixelation. outputColor = sampleLinear( oImage, relativePos + center ); } }