topical media & game development

talk show tell print

graphic-flex-image-effects-07-source-wrapToSphere.pbk / pbk



  <languageVersion : 1.0;>
  
  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;
      }
  
  }


(C) Æliens 18/6/2009

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.