YOUR ACCOUNT

Login or Register to post new topics or replies
David Roberson
Artist
Posts: 404
Filters: 36
I recently looked at and updated the Rotatable Sphere Snippet by ThreeDee. Unfortunately, I could think of no way to correct the distortions that are part of it, and started wondering how I'd make an undistorted version I could use in a filter designed to showcase a planet. The obvious thing to do is to try and create a Map Script that will produce a gradient sphere like the example (below) that could be used to map a surface using the Lookup component. Sadly, I have no idea how to do it.

If you think you can help I'd be very grateful, just a link to a good example would be appreciated. I am looking at the Raytracing Snippet by Egret as a starting point, so even help with mapping a gradient onto one of his spheres would be great.

Thanks for your attention.

  Details E-Mail
David Roberson
Artist
Posts: 404
Filters: 36
I was able to get pretty far working with a Refraction based mapping to a rotatable sphere. Unfortunately, it's only fooling the eye; there's still unwanted distortion and not-quite full range of motion. A proper sphere mapping will take a bit of pseudo 3d scripting. Lua can do it, but most of the methods I've come across require external libraries. For what amounts to a sphere primitive, I don't think I would need to go that far.

Anyway, here's the ffxml for my rotatable sphere snippet:

Rotatable Sphere Snippet V3.ffxml
  Details E-Mail
David Roberson
Artist
Posts: 404
Filters: 36
I've been tinkering with the Raytracing Snippet by Egret, trying to map a gradient onto one of his spheres. I got as far as isolating a sphere in a bigger space with an associated uv surface, but it only seems to respond to the alpha channel. The RGB channels do not respond to the raytrace, so I get either a clear, refractive surface or a black one (reflections still work, too). I'll post what I've got here, in case someone can point out where I'm going wrong. l think this is on hold until then...

Raytracing Lab.ffxml
  Details E-Mail
David Roberson
Artist
Posts: 404
Filters: 36
I succeeded in accomplishing half of the gradients needed to create a Rotatable Sphere Script -- a gradient from the north to south pole (is that the y-axis?). To complete my script I need some help with the math to produce the x-axis, basically an angle gradient from the far east to the far west. There's an example of this above. I have tried finding an example of cartesian to polar mapping for lua, but have had no luck. I'm hoping that is the solution I'm looking for.


Code
-- 3d sphere
   -- produces rgb gradient mapped to a 3d sphere, but not correctly.
   -- how would one map x:red and y:green gradients instead?
   -- this is basically missing an angle gradient in the y-axis...
function prepare()
   -- tilt & rotation precalc
      -- it would be nice to know how this works!
   toRad = 180/math.pi

   radius = get_slider_input(RADIUS)

   angle = get_angle_input(ROTATION)/toRad
   cosa = math.cos(angle)
   sina = math.sin(angle)

   tilt = get_angle_input(TILT)/toRad
   cosa2 = math.cos(tilt)
   sina2 = math.sin(tilt)
end;


function get_sample(x, y)
   local r, g, b, a = get_sample_map(x, y, SOURCE)
   -- color gradient example
   --    local r = x
   --    local g = y
   --    local b = (x + y) / 2
   --    local a = 1
   -- image generation
   local px = (x*2.0) - 1.0
   local py = (y*2.0) - 1.0
   px = px/radius
   py = py/radius
   local len = math.sqrt((px*px)+(py*py))
   if len > 1.0 then return 0,0,0,0 end

   local z = -math.sqrt(1.0 - ((px*px)+(py*py)))

   local tz = (cosa2 * z) - (sina2 * py)
   local ty = (sina2 * z) + (cosa2 * py)
   z = tz
   py = ty

   local tx = (cosa * px) - (sina * z)
   local tz = (sina * px) + (cosa * z)
   px = tx
   z = tz

   return px/2+.5,px/2+.5,px/2+.5,a -- r, g, b, a
end;


Here are a couple examples from other scripting languages...

Code
   --  cartesian to polar (reference)
   --   example 1
   --    r = math.sqrt((cart.x * cart.x + cart.y * cart.y + cart.z * cart.z));
   --    long = math.acos(cart.x / math.sqrt(cart.x * cart.x + cart.y * cart.y)) * (cart.y < 0 ? -1 : 1);
   --    lat = math.acos(cart.z / radius) * (cart.z < 0 ? -1 : 1);
   --   example 2
   --   r = sqrt(x * x + y * y + z * z)
   --    long = acos(x / sqrt(x * x + y * y)) * (y < 0 ? -1 : 1)
   --    lat = acos(z / r)
  Details E-Mail
David Roberson
Artist
Posts: 404
Filters: 36
Since I've just been banging my head against a wall on this, here's an upd ate on my progress. This may clarify what kind of help I'm looking for, in case what I've already posted is unclear.

0


I am working on a Spherical Map Script that generates a linear gradient along the y-axis and an angular gradient around the y-axis in the green and red channels, respectively. I have been unable to find any documentation suited to this online, but have experimented using examples in Javascript and C#. The linear gradient has worked out fine, but the angular gradient (one describing a 360 degree arc around the y-axis) continues to elude me.

My working script is as follows.

Code
-- 3d sphere
   -- produces rgb gradient mapped to a 3d sphere, but not correctly.
   -- this is basically missing an angle gradient around the y-axis...
function prepare()
   -- tilt & rotation precalc
   toRad = 180/math.pi
   -- toCir = 360/math.pi -- may or may not work for circumference...

   radius = get_slider_input(RADIUS)

   angle = get_angle_input(ROTATION)/toRad
   cosa = math.cos(angle)
   sina = math.sin(angle)

   tilt = get_angle_input(TILT)/toRad
   cosa2 = math.cos(tilt)
   sina2 = math.sin(tilt)
end;


function get_sample(x, y)
   local r, g, b, a = get_sample_map(x, y, SOURCE)
   -- color gradient example
      -- local r = x
      -- local g = y
      -- local b = (x + y) / 2
      -- local a = 1
   -- spherical mapping formulae (polar to cartesian, apparently)
      -- local x = x * math.pi -- * aspect
      -- local y = y * math.pi
      -- conversion from r, lat, long to x, y, z
      -- local nx = math.cos(x) * math.sin(y)
      -- local ny = math.sin(x) * math.sin(y)
      -- local nz = math.cos(y)
   -- cartesian to polar (reference)
      -- radius : distance from focus to surface
      -- latitude : -90 to 90 degrees (math.pi/2), along y-axis (phi)
      -- longitude : -180 to 180 degrees (math.pi) around y-axis (theta)
   --   example 1
      -- r = math.sqrt(((x * x) + (y * y) + (z * z)))
      -- long = math.acos(x / math.sqrt((x * x) + (y * y))) * (y < 0 ? -1 : 1)
      -- lat = math.acos(z / radius) * (z < 0 ? -1 : 1)
   --   example 2
      -- r = math.sqrt((x * x) + (y * y) + (z * z))
      -- long = math.acos(x / math.sqrt((x * x) + (y * y))) * (y < 0 ? -1 : 1)
      -- lat = math.acos(z / r)
  
   -- image generation
   -- shift origin to center and se t radius limits
   local px = (x*2.0) - 1.0
   local py = (y*2.0) - 1.0
   px = px/radius
   py = py/radius
   local len = math.sqrt((px*px)+(py*py))
   if len > 1.0 then return 0,0,0,0 end

   local z = -math.sqrt(1.0 - ((px*px)+(py*py)))

   -- cartesian to polar
      -- r = math.sqrt((x * x) + (y * y) + (z * z))
      -- lat = math.acos(z / r)
      -- long = math.acos(x / math.sqrt((x * x) + (y * y))) * (y < 0) ? -1 : 1)
         -- equation cannot accept boolean comparison
         -- boolean syntax may not be valid in lua
      -- test long = math.acos(x / math.sqrt((x * x) + (y * y)))

   -- apply rotation and tilt
   local ty = (sina2 * z) + (cosa2 * py) -- gradient along y-axis is correct
   py = ty
   local tz = (cosa2 * z) - (sina2 * py) -- not used before overridden
   z = tz -- not used before overridden

   local tz = (sina * px) + (cosa * z)
   px = tx
   local tx = (cosa * px) - (sina * z) -- gradient needs to go around y-axis
   z = tz

   -- return r, g, b, a
   -- return px,py,z,a
   return px/2+.5,py/2+.5,long,a
   -- return px/2+.5,px/2+.5,px/2+.5,a
   -- return long,long,long,a
end;
  Details E-Mail
David Roberson
Artist
Posts: 404
Filters: 36
After several days of poking around I have only found one working example in which the x and y gradients can only be generated along their respective axes. I just can't puzzle out a method of generating a gradient around an axis using polar-to-cartesian and cartesian-to-polar coordinate conversions. Does that seem right? I may just be failing to do the cartesian-to-polar correctly, most likely due to the boolean operation inside the examples I found for other coding languages. I still have to say that the apparent logic of those equations makes it seem like longitude variable contains a circumferential gradient. You just can't pull it out using polar-to-cartesian equations. If I could, then a sampling of source images would be possible in a map script. Maybe that requires some form of computational uv mapping?

Any kind of feedback would be welcome here...
  Details E-Mail
David Roberson
Artist
Posts: 404
Filters: 36
Well, I finally got a grip on how this map script works and the solution was so much simpler that what I'd been trying to do. Here's my solution:

Code
-- 3d vector sphere
   -- produces rgb vector gradient mapped to a 3d sphere
function prepare()
   -- tilt & rotation precalc
   toRad = 180/math.pi

   radius = get_slider_input(RADIUS)

   angle = get_angle_input(ROTATION)/toRad
   cosa = math.cos(angle)
   sina = math.sin(angle)

   tilt = get_angle_input(TILT)/toRad
   cosa2 = math.cos(tilt)
   sina2 = math.sin(tilt)
end;


function get_sample(x, y)
   -- image generation

   -- sphere generation and manipulation
   -- origin to center
   local px = (x*2.0) - 1.0
   local py = (y*2.0) - 1.0
   -- set sphere radius (max -- screen height)
   px = px/radius
   py = py/radius
   local len = math.sqrt((px*px)+(py*py))
   -- check radius and clip
   if len > 1.0 then return 0,0,0,0 end

   local z = -math.sqrt(1.0 - ((px*px)+(py*py)))

   local tz = (cosa2 * z) - (sina2 * py)
   local ty = (sina2 * z) + (cosa2 * py)
   z = tz
   py = ty

   local tx = (cosa * px) - (sina * z)
   local tz = (sina * px) + (cosa * z)
   px = tx
   z = tz
   if z <= 0 then px = (0 - (1 - px)) end

   return px/2+.5,py/2+.5,0,1
   -- return px,py,0,1
end;


Edit: I may have spoken to soon.... On first glance the circumferential gradient looked right, but as soon as I tried to test it in a Lookup I discovered a problem. I'm inverting the values wrong, dealing with the -1 to 1 range. It's probably a simple fix but my brain is too tired to sort it out right now.
  Details E-Mail
David Roberson
Artist
Posts: 404
Filters: 36
Well, the long and the short of it is that the process I've been working with is in the wrong coordinate system. The gradient sphere I have is based on the polar-to-cartesian coordinate system. That gives me x, y, z gradients in the three axes. What I want is gradients for theta and phi, or longitude and latitude. I'm actually getting values for theta and phi from my control sliders, which rotate the generated sphere. I'll try to see if I can sample those values, and if they (somehow) produce the correct gradients, but a little help would be appreciated, since I don't have any examples to work with like that.
  Details E-Mail
David Roberson
Artist
Posts: 404
Filters: 36
I found a potential solution that would employ rotational offsets on three versions of the x-axis gradient fed as r, g, b components of an rgb2hsl function to produce a spherical angle gradient. Unfortunately, an odd problem popped up with the rotational offsets. They are not constant during rotation, which creates a messed up gradient. Am I doing them wrong here?

Code
-- 3d sphere
   -- produces rgb gradient mapped to a 3d sphere.
   -- an angle gradient can be derived using an extract hue component for x lookup
   -- a get alpha component provides for y lookup
function prepare()
   -- tilt & rotation precalc
   toRad = 180/math.pi

   radius = get_slider_input(RADIUS)

   angle = get_angle_input(ROTATION)
   angle = angle/toRad
   angle1 = (angle + 120)/toRad
   angle2 = (angle + 240)/toRad
      -- offsets are correct at 0 but are not constant during rotation

   cosa0 = math.cos(angle)
   sina0 = math.sin(angle)

   cosa1 = math.cos(angle1)
   sina1 = math.sin(angle1)

   cosa2 = math.cos(angle2)
   sina2 = math.sin(angle2)

   tilt = get_angle_input(TILT)/toRad
   cosa3 = math.cos(tilt)
   sina3 = math.sin(tilt)
end;


function get_sample(x, y)
   --   input image; requires uvw mapping...
   local r, g, b, a = get_sample_map(x, y, SOURCE)
   a = 1

   -- image generation
   local px = (x*2.0) - 1.0
   local py = (y*2.0) - 1.0
   px = px/radius
   px1 = px/radius
   px2 = px/radius
   py = py/radius
   local len = math.sqrt((px*px)+(py*py))
   if len > 1.0 then return 0,0,0,0 end

   local z = -math.sqrt(1.0 - ((px*px)+(py*py)))
   local z1 = z
   local z2 = z

   local tz = (cosa3 * z) - (sina3 * py)
   local ty = (sina3 * z) + (cosa3 * py)
   py = ty
   z = tz

   local tx = (cosa0 * px) - (sina0 * z)
   local tz = (sina0 * px) + (cosa0 * z)
   px = tx
   z = tz
   
   local tx1 = (cosa1 * px1) - (sina1 * z)
   local tz1 = (sina1 * px1) + (cosa1 * z)
   px1 = tx1
   z1 = tz1

   local tx2 = (cosa2 * px2) - (sina2 * z)
   local tz2 = (sina2 * px2) + (cosa2 * z)
   px2 = tx2
   z2 = tz2

   -- to do
      -- internal hue extraction (hsb):
      -- internal lookup on source image
      -- add screen relative z-axis rotation (spin)

   return px/2+.5,px1/2+.5,px2/2+.5,py/2+.5
   -- return px/2+.5,px/2+.5,px/2+.5,0
   -- return px1/2+.5,px1/2+.5,px1/2+.5,0
   -- return px2/2+.5,px2/2+.5,px2/2+.5,0
   -- return r, g, b, a
end;
  Details E-Mail
David Roberson
Artist
Posts: 404
Filters: 36
I managed to solve the problem of scripting a rotatable sphere with the proper remapping gradients sometime last month, but am still tweaking and experimenting with the next logical steps. I never bothered to update this thread with my progress, and now there are too many different script versions; I can't decide which one to share. However, there's a good chance a few of them will find their way into filters. I have a number of planetary filters in the works, so you can expect to see some there. I'll probably submit one as a 3d rotatable sphere snippet (or even effect filter, since I can now map the input to a sphere, assuming it's prepared for spherical mapping). If I do, I'll come back and post the code that goes with it, for anyone who might just want to look at the script but doesn't need a working copy.

TTFN
  Details E-Mail

Join Our Community!

Filter Forge has a thriving, vibrant, knowledgeable user community. Feel free to join us and have fun!

33,711 Registered Users
+18 new in 30 days!

153,533 Posts
+38 new in 30 days!

15,348 Topics
+73 new in year!

Create an Account

Online Users Last minute:

18 unregistered users.