kernel WrapToSphere < namespace: "27Bobs"; vendor: "Todd Yard"; version: 1; description: "Wraps image around sphere."; > { parameter float radius < minValue: float(5.0); maxValue: float(512.0); defaultValue: float(144.0); description: "The radius of the sphere."; >; parameter float textureWidth < minValue: float(5.0); maxValue: float(1024.0); defaultValue: float(360.0); description: "The width of the texture to wrap."; >; parameter float textureHeight < minValue: float(5.0); maxValue: float(1024.0); defaultValue: float(288.0); description: "The height of the texture to wrap."; >; const float PI = 3.14159265; input image4 source; output pixel4 result; void evaluatePixel() { float2 coord = outCoord(); float2 center = float2(radius, radius); pixel4 px; // all pixels outside the radius made transparent if (distance(coord, center) > radius) { px = sample(source, coord); px.a = 0.0; } else { // equations taken from (and explained at): // http://blogs.msdn.com/coding4fun/archive/2006/10/31/912562.aspx // http://www.cs.unc.edu/~rademach/xroads-RT/RTarticle.html float2 relativePos = coord - center; float theta = acos(length(relativePos)/radius); float z = (sin(theta)*radius); float3 p = float3(relativePos.x, relativePos.y, -z); // north pole vector float3 n = float3(0, 1, 0); // equator vector float3 e = float3(0, 0, 1); // normalize() should work, but is buggy in PixelBender; // the following two lines do the same thing // p = normalize(p); float pLength = length(p); p = float3(p.x/pLength, p.y/pLength, p.z/pLength); float phi = acos(-dot(n, p)); float u; float v = phi/PI; if (z == radius) { u = 0.5; } else { u = (acos(max(min(dot(p, e)/sin(phi), 1.0), -1.0)))/(2.0*PI); if (dot(cross(n, e), p) > 0.0) { u = 1.0-u; } } u *= float(textureWidth); v *= float(textureHeight); if (u > float(textureWidth)) { px = pixel4(1.0, 0.0, 0.0, 1.0); } else if (u < 0.0) { px = pixel4(0.0, 1.0, 0.0, 1.0); } else if (v > float(textureHeight)) { px = pixel4(0.0, 0.0, 1.0, 1.0); } else if (v < 0.0) { px = pixel4(1.0, 0.0, 1.0, 1.0); } else { px = sample(source, float2(u, v)); px.a = 1.0; } } result = px; } }