/* * Petri Leskinen, Espoo, Finland, December 2008 * demo for metablobs with pixel bender and flash player 10 * * leskinen.petri[at]luukku.com pixelero.wordpress.com */ kernel MetaBlobs < namespace : "MetaBlobs"; vendor : "Petri Leskinen"; version : 1; description : "MetaBalls for pixel bender"; > { parameter float4 materialcolor < minValue:float4(0.0); maxValue:float4(1.0); defaultValue:float4(0.75,0.5,0.4,1); description: "materialcolor"; >; parameter float3 blob1 < minValue:float3(-200.0, -200.0,0.0); maxValue:float3(2048.0, 2048.0,200.0); defaultValue:float3(115.0,270.0,84); description: "Blob 1, x,y -coordinates and radius"; >; parameter float3 blob2 < minValue:float3(-200.0, -200.0,0); maxValue:float3(548.0, 548.0,200); defaultValue:float3(363,85,95); description: "Blob 2, x,y -coordinates and radius"; >; parameter float3 blob3 < minValue:float3(-200.0, -200.0,0); maxValue:float3(548.0, 548.0,200); defaultValue:float3(250.0,115.0,86); description: "Blob 3"; >; parameter float3 blob4 < minValue:float3(-200.0, -200.0,0); maxValue:float3(548.0, 548.0,200); defaultValue:float3(210.0,325.0,80); description: "Blob 4"; >; parameter float3 blob5 < minValue:float3(-200.0, -200.0,0); maxValue:float3(548.0, 548.0,200); defaultValue:float3(291.0,241.0,95); description: "Blob 5"; >; parameter float3 blob6 < minValue:float3(-200.0, -200.0,0); maxValue:float3(548.0, 548.0,200); defaultValue:float3(250.0,105.0,86); description: "Blob 6"; >; parameter float3 blob7 < minValue:float3(-200.0, -200.0,0); maxValue:float3(548.0, 548.0,200); defaultValue:float3(10.0,35.0,40); description: "Blob 7"; >; parameter float3 blob8 < minValue:float3(-200.0, -200.0,0); maxValue:float3(548.0, 548.0,200); defaultValue:float3(91.0,141.0,55); description: "Blob 8"; >; parameter float3 lightsrc < minValue:float3(-1000.0); maxValue:float3(1000.0); defaultValue:float3(100, 200, 110); description: "xyz-location of the light source"; >; parameter float4 lightcolor < minValue:float4(0.0); maxValue:float4(1.0); defaultValue:float4(1,1,0.7,1); description: "color of the light"; >; parameter float4 shadowcolor < minValue:float4(0.0); maxValue:float4(1.0); defaultValue:float4(0.2,0.1,0.1,0.75); description: "color in the shadows"; >; parameter float shininess < minValue:float(1.0); maxValue:float(20.01); defaultValue:float(15.0); description: "shininess"; // value used as an exponent, for correct result use an integer value ! >; parameter float shadow < minValue:float(0.0); maxValue:float(1.0); defaultValue:float(0.25); description: "depth of shadow areas"; >; parameter float flatness < minValue:float(0.0); maxValue:float(2.0); defaultValue:float(1.00); description: "controls the depth of the blobs' appearance"; >; output pixel4 dst; // // comment the next line before exporting to flash player: region generated() { return region(float4(0.0, 0.0, 300.0, 200.0)); } void evaluatePixel() { float3 p, p2, p3, p4, p5, p6, p7, p8, lightbeam; float w1, w2, w3, w4, w5, w6, w7, w8, r2, z2, refl; // To do blobs with pb, I came up with a slightly different kind of algorithm, // For each blob we count the distance (r2) and the height on a z-level (z2) // Each blob is given a 'weight' depending on these two values // The output is generated by counting a weighted average of all the blobs, // the result of that, point p with x,y and z-coordinates is rendered as we were dealing with a sphere p.xy = outCoord()-blob1.xy; r2= p.x*p.x +p.y*p.y; z2 = blob1.z*blob1.z; p.z = z2-r2; w1 = z2/r2; p2.xy = outCoord()-blob2.xy; r2= p2.x*p2.x +p2.y*p2.y; z2 = blob2.z*blob2.z; p2.z = z2-r2; w2 = z2/r2; p3.xy = outCoord()-blob3.xy; r2= p3.x*p3.x +p3.y*p3.y; z2 = blob3.z*blob3.z; p3.z = z2-r2; w3 = z2/r2; p4.xy = outCoord()-blob4.xy; r2= p4.x*p4.x +p4.y*p4.y; z2 = blob4.z*blob4.z; p4.z = z2-r2; w4 = z2/r2; p5.xy = outCoord()-blob5.xy; r2= p5.x*p5.x +p5.y*p5.y; z2 = blob5.z*blob5.z; p5.z = z2-r2; w5 = z2/r2; p6.xy = outCoord()-blob6.xy; r2= p6.x*p6.x +p6.y*p6.y; z2 = blob6.z*blob6.z; p6.z = z2-r2; w6 = z2/r2; p7.xy = outCoord()-blob7.xy; r2= p7.x*p7.x +p7.y*p7.y; z2 = blob7.z*blob7.z; p7.z = z2-r2; w7 = z2/r2; p8.xy = outCoord()-blob8.xy; r2= p8.x*p8.x +p8.y*p8.y; z2 = blob8.z*blob8.z; p8.z = z2-r2; w8 = z2/r2; // weighted average of all the blobs: p= (w1*p + w2*p2+ w3*p3+ w4*p4 +w5*p5+ w6*p6+ w7*p7 +w8*p8) / (w1+w2+w3+w4+w5+w6+w7+w8); // check if we're inside the metablob: if (p.z>0.0) { // lightbeam, vector from lightsource to current output coordinate: lightbeam.x= outCoord().x; lightbeam.y= outCoord().y; lightbeam.z= p.z= flatness*sqrt(p.z); lightbeam= lightsrc-lightbeam; // there's still something wrong with 'normalize()' in flash player: lightbeam /= length(lightbeam); // diffuse shading by the dotproduct of the normal vector and light direction refl = shadow+(1.0-shadow)*dot(p /=length(p),lightbeam); // something like blinn-phong algorithm for specular reflection // 'lightbeam' becomes the unit vector of average of light and view directions, here constant z=1.0; // amount is the dot product of this average and surface normal raised to a power determinating the shininess lightbeam.z += 1.0; lightbeam /= length(lightbeam); // combine these two refl += pow( dot(p,lightbeam),shininess); if (refl<1.0) { // on the shadow side, output's interpolated between shadowcolor and material color // dst =mix(shadowcolor, color,refl) ; dst = (1.0-refl)*shadowcolor + refl*materialcolor; } else { // on the light side, output's interpolated between material color and light color dst =mix(materialcolor,lightcolor, refl-1.0); } } else { // empty area, no blobs here dst = pixel4(0,0,0,0); } } }