PixelBenderのサンプルをちょこっとずつやってみる。
日曜プログラミングってことでPixelBenderのサンプルをちょこっとずつやってみてます。
ファイル元はこちら。
Pixel Bender Toolkit:Gallery
置き換えマップ(DisplacementMap )
オリジナルページ
Flexでの同様のフィルター
置き換えマップフィルタ
出力画像
入力画像その1(マップ画像
入力画像その2(マップ適応先画像
ソースコードにちょびっとコメントを追加してます。
そしてなんか日本語が挿入でいない。
// // DisplacementMapFilter.pbk // // Copyright (c) 2008 Ryan Taylor | http://www.boostworthy.com // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without // restriction, including without limitation the rights to use, // copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // // // + + + + + + + + + // // <languageVersion : 1.0;> kernel DisplacementMapFilter < namespace : "Boostworthy::Filters"; vendor : "Ryan Taylor"; version : 1; description : "Standard filter for displacing source pixels based on map color values."; > { //setting parameter parameter int2 component < minValue : int2(0, 0); maxValue : int2(3, 3); defaultValue : int2(1, 2); >; parameter float2 offset < minValue : float2(-256.0, -256.0); maxValue : float2(256.0, 256.0); defaultValue : float2(0.0, 0.0); >; parameter float scale < minValue : -1.0; maxValue : 1.0; defaultValue : 1.0; >; //input output image input image4 source; input image4 map; output pixel4 result; //main function void evaluatePixel() { //get now point x , y; float2 coord = outCoord(); //get pixels from now point pixel4 mapPixel = sampleLinear(map, coord); // Note: The following statements are used for the sake of // Flash compatibility. mapPixel[component[0]], for instance, // is not allowed because the index must be a constant. float componentX; if(component[0] == 0) componentX = mapPixel[0]; else if(component[0] == 1) componentX = mapPixel[1]; else if(component[0] == 2) componentX = mapPixel[2]; else if(component[0] == 3) componentX = mapPixel[3]; float componentY; if(component[1] == 0) componentY = mapPixel[0]; else if(component[1] == 1) componentY = mapPixel[1]; else if(component[1] == 2) componentY = mapPixel[2]; else if(component[1] == 3) componentY = mapPixel[3]; //set new points x, y float x = coord.x + (componentX - 0.5) * offset[0] * scale; float y = coord.y + (componentY - 0.5) * offset[1] * scale; //output image from new point result = sampleLinear(source, float2(x, y)); } }
色相・彩度・明度を変更するフィルター
画像の色相・彩度・明度を変更するフィルター。
HLS て Hue , Lightness , Saturation の略なんだね。
ソース元
HLSについて
HSVの計算方法
// ***************************************************************************************** // HSLFilter.pbk // // Copyright (c) 2008 Ryan Taylor | http://www.boostworthy.com // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without // restriction, including without limitation the rights to use, // copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // ***************************************************************************************** // // + + + + + + + + + // // ***************************************************************************************** <languageVersion : 1.0;> kernel HSLFilter < namespace : "Boostworthy::Filters"; vendor : "Ryan Taylor"; version : 1; description : "Basic filter for adjusting the hue, saturation, and lightness of an image."; > { //setting parameter parameter float hue < minValue : -180.0; maxValue : 180.0; defaultValue : 0.0; >; parameter float saturation < minValue : -100.0; maxValue : 100.0; defaultValue : 0.0; >; parameter float lightness < minValue : -100.0; maxValue : 100.0; defaultValue : 0.0; >; //input output image input image4 source; output pixel4 result; //main function void evaluatePixel() { // Convert sampled pixel from RGB space to HSL space. pixel4 samp; float sampMin; float sampMax; float sampDiff; float sampSum; float sampH; float sampS; float sampL; samp = sampleNearest(source, outCoord()); sampMin = min(samp.r, samp.g); sampMin = min(sampMin, samp.b); sampMax = max(samp.r, samp.g); sampMax = max(sampMax, samp.b); sampDiff = sampMax - sampMin; sampSum = sampMax + sampMin; sampL = sampSum * 0.5; if(sampMin == sampMax) sampH = 0.0; else if(sampMax == samp.r) sampH = mod(60.0 * ((samp.g - samp.b) / sampDiff), 360.0); else if(sampMax == samp.g) sampH = 60.0 * ((samp.b - samp.r) / sampDiff) + 120.0; else if(sampMax == samp.b) sampH = 60.0 * ((samp.r - samp.g) / sampDiff) + 240.0; else sampH = 0.0; if(sampMin == sampMax) sampS = 0.0; else if(sampL > 0.5) sampS = sampDiff / (2.0 - sampSum); else sampS = sampDiff / sampSum; // Transform the sampled HSL values by the amounts specified // by the hue, saturation, and lightness parameters. float outH; float outS; float outL; outH = sampH - hue; outS = sampS * (saturation / 100.0 + 1.0); outL = sampL - (1.0 - (lightness / 100.0 + 1.0)); // Convert the transformed HSL values back to RGB space. float q; float p; float h; if(outL < 0.5) q = outL * (1.0 + outS); else q = outL + outS - outL * outS; p = 2.0 * outL - q; h = outH / 360.0; float oneOverThree = 1.0 / 3.0; float twoOverThree = 2.0 / 3.0; float oneOverSix = 1.0 / 6.0; float3 t = float3(h + oneOverThree, h, h - oneOverThree); if(t.r < 0.0) t.r += 1.0; else if(t.r > 1.0) t.r -= 1.0; if(t.g < 0.0) t.g += 1.0; else if(t.g > 1.0) t.g -= 1.0; if(t.b < 0.0) t.b += 1.0; else if(t.b > 1.0) t.b -= 1.0; pixel4 c = pixel4(0.0, 0.0, 0.0, samp.a); if(t.r < oneOverSix) c.r = p + (q - p) * 6.0 * t.r; else if(t.r >= oneOverSix && t.r < 0.5) c.r = q; else if(t.r >= 0.5 && t.r < twoOverThree) c.r = p + (q - p) * 6.0 * (twoOverThree - t.r); else c.r = p; if(t.g < oneOverSix) c.g = p + (q - p) * 6.0 * t.g; else if(t.g >= oneOverSix && t.g < 0.5) c.g = q; else if(t.g >= 0.5 && t.g < twoOverThree) c.g = p + (q - p) * 6.0 * (twoOverThree - t.g); else c.g = p; if(t.b < oneOverSix) c.b = p + (q - p) * 6.0 * t.b; else if(t.b >= oneOverSix && t.b < 0.5) c.b = q; else if(t.b >= 0.5 && t.b < twoOverThree) c.b = p + (q - p) * 6.0 * (twoOverThree - t.b); else c.b = p; // Apply the final ARGB color to the pixel. result = c; } }
画像をグレースケールにして足し算
2枚の画像で片方をグレースケールにして合成。
合成用画像
画像の足し算は簡単で
dst = src1 * src2 でOK
#掛け算になるところがミソ。
src1 + 0.1 とすると明るくなり
src1 - 0.1 とすると暗くなる。
AlphaMatteComposite
// ***************************************************************************************** // AlphaMatteComposite.pbk // // Copyright (c) 2008 Ryan Taylor | http://www.boostworthy.com // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without // restriction, including without limitation the rights to use, // copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // ***************************************************************************************** // // + + + + + + + + + // // ***************************************************************************************** <languageVersion : 1.0;> kernel AlphaMatteComposite < namespace : "Boostworthy::Filters"; vendor : "Ryan Taylor"; version : 1; description : "Given a source image and grayscale matte which represents alpha, a composite of the two will result in a masked source image."; > { input image4 source; input image4 alphaMatte; output pixel4 result; void evaluatePixel() { // Note: The 'alphaMatte' input is of type image4 rather // than image1 for maximum compatibilty with Flash. float2 coord = outCoord(); pixel4 sampSource = sampleNearest(source, coord); pixel4 sampAlphaMatte = sampleNearest(alphaMatte, coord); pixel1 alphaMatte = (sampAlphaMatte.r + sampAlphaMatte.g + sampAlphaMatte.b) / 3.0; result = sampSource * alphaMatte; } }
バンプマップ
Bump Mapping
テクスチャで疑似的に凹凸を見せる方法。
テクスチャ画像
内積関数 dot を使って影を作成。
dot って関数は dot ( a , b )で a と b の内積を計算します。
内積についてはこちらがとても参考になります。
GLSLでの例
計算部分
float3 normal = float3( sampleNearest(src, outCoord()).rgb ) ; float dp = dot(normal, light);
ソースコード一覧
<languageVersion: 1.0;> kernel map < namespace : "AIF"; vendor : "Valentin valyard Simonov"; version : 2; description : "A simple bump mapping shader"; > { input image4 src; input image4 map; output float4 dst; parameter float3 light < minValue:float3(0, 0, 0); maxValue:float3(255, 255, 255); defaultValue:float3(0, 0, 40); >; void evaluatePixel() { float3 light = light.xyz - float3(outCoord().x, outCoord().y, 0); light = normalize(light); float3 normal = 2.0*(sampleNearest(map, outCoord()).rgb - 0.5); float dp = dot(normal, light); if (dp < 0.0) dp = 0.0; if (dp > 1.0) dp = 1.0; dst = float4(0, 0, 0, 1); dst.rgb = sampleNearest(src, outCoord()).rgb * dp; } }
チューブ型フィルター
float2 p = outCoord() - param_center; float dist = length(p);
画像のミックス
mix( pixel4 , param_bgColor , a );
pixel4 (たいてい src 画像 )に param_bgColor を a の割合で足す。
リファレンスには
Returns x * ( 1.0 - a ) + y * a.
linear interpolation between x and y
#xとyの直線的な挿入
って書かれてます。
/***************************************************************************** * * Petri Leskinen, Espoo, Finland, Jan 2008, May 2008 * Tube-View ' effect * leskinen.petri [at] luukku.com * *****************************************************************************/ <languageVersion: 1.0;> kernel TubeView < namespace : "Tube View"; vendor : "your vendor"; version : 1; description : "Tube view"; > { parameter float radius < minValue :float(0.1); maxValue :float(300.0); defaultValue:float(50.0); >; parameter float turbulence < minValue :float(-3.14); maxValue :float(3.14); defaultValue:float(1.0); description :"Turbulence"; >; parameter float fade1 < minValue :float(-1.0); maxValue :float(1.0); defaultValue:float(0.2); description :"Fading on the edge of the tube"; >; parameter float fade2 < minValue :float(0.0); maxValue :float(2.0); defaultValue:float(0.4); description :"Fading by distance"; >; parameter float2 center < minValue :float2(-200.0, -200.0); maxValue :float2(2048.0, 2048.0); defaultValue:float2(64.0, 128.0); description :"Center point"; >; parameter float4 bgColor < minValue :float4(0.0, 0.0, 0.0, 0.0); maxValue :float4(1.0, 1.0,1.0,1.0); defaultValue:float4(0.0, 0.0, 0.0, 1.0); description :"Background color"; >; //input output image input image4 src; output float4 pxl; //main function void evaluatePixel() { // point relative to center float2 p = outCoord() - center; // relative distance from center, rel<0.0 if inside the circle float rel = length(p) /radius; float tmp = rel*rel; rel -= 1.0; // if outside, modify point location, new coordinates inside circle p /= (rel < 0.0) ? 1.0 : tmp ; // 'turbulence'-rotation float rotAngle = turbulence *( rel < 0.0 ? 0.0 : rel ) ; p = float2( p.x*cos(rotAngle)-p.y*sin(rotAngle), p.x*sin(rotAngle)+p.y*cos(rotAngle) ); // sample pixel from new location pxl= sample(src, center+p); // mix with bgColor according to distance float mx = fade1+ rel*fade2; pxl= mix(pxl, bgColor, rel < 0.0 ? 0.0 : mx ); } }
クリスタル化
// Jan 2008, Espoo, Finland // updated April 2008 // leskinen 'dot' petri [at] luukku (dot) com // - please send me a note if you use the code for anything cool ! // <languageVersion: 1.0;> kernel Crystallize < namespace : "by Petri Leskinen"; vendor : ""; version : 1; description : "Crystallize -filter"; > { parameter float size < minValue : float(1); maxValue : float(300); defaultValue: float(20); description : "size"; >; // rot1: rotation matrix, 18 degrees // rot1r: reverse rotation, -18 degrees // base1: rotation base point (somewhere far enough from origin) const float2x2 rot1 = float2x2(0.951,0.309,-0.309,0.951); const float2x2 rot1r = float2x2(0.951,-0.309,0.309,0.951); const float2 base1 = float2(2400,-100); // rot2: rotation matrix, 30 degrees // rot2r: reverse rotation, -30 degrees // base2: base point const float2x2 rot2 = float2x2(0.866,0.5,-0.5,0.866); // 30 degress const float2x2 rot2r = float2x2(0.866,-0.5,0.5,0.866); const float2 base2 = float2(-100,2400); input image4 src; output pixel4 dst; void evaluatePixel() { // Crystallize, pseudo Voronoi-diagram using three nearby points, // calculated from 'randomly' placed and rotated rectangular grids // 1st grid and point float div=size; float2 newP= base1 + rot1r*div*( floor( rot1*(outCoord()-base1)/div ) +0.5); // 2nd grid div= 21.0/20.0*size; // factor 21, I picked some number that has no common denominators with the default size 20 float2 p= base2 + rot2r*div*( floor( rot2*(outCoord()-base2)/div ) +0.5); // comparing distance to the 1st sample point newP = length(p-outCoord()) < length(newP-outCoord()) ? p : newP; // 3rd grid div= 19.0/20.0*size; p= div*( floor( outCoord()/div ) +0.5); // comparing distance newP = length(p-outCoord()) < length(newP-outCoord()) ? p : newP; // the new color is picked from the nearist point dst = sampleNearest(src,newP); } }