POV-Ray : Newsgroups : povray.advanced-users : Functions in SDL - - - Kenneth : Functions in SDL - - - Kenneth Server Time
4 Oct 2024 04:50:23 EDT (-0400)
  Functions in SDL - - - Kenneth  
From: Bald Eagle
Date: 23 Feb 2021 21:30:01
Message: <web.6035b9cdb554d2ab1f9dae300@news.povray.org>
The Other Walker wrote:

> What do you want to do with the function once you've got it, that you need to
> have it in function form?

That's a good question. My main answer would be, just to see if could be done.
And to try and better-understand the real power of function use in SDL.

So, just to put this here - I looked for the source code for implementing
arrays, and couldn't find where it is (yet).
I would think it might be easy to store the image_map data in a 2D array, that
maybe has an identifier name that is Array_filename_ext
At least that way the array could be created using the compiled source code
(fast).

Now, using eval_pigment to get that data into an array is going to be a pretty
roundabout way to get the color data, so I think what you can do is this:
You don't need any objects in the scene, no trace, no eval_pigment.

#declare Fn_Image = function {pigment{image_map}}

And here is where functions get a little bit wonky.
The above function takes a full-color pigment pattern as an input.
In order to spit out a scalar value, which is the only allowable way to execute
a function, you need to evaluate only a single color channel at a time.

#declare Image_red = function {Fn_Image (x, y, z).red}
#declare Image_grn = function {Fn_Image (x, y, z).green}
#declare Image_blu = function {Fn_Image (x, y, z).blue}

Now, as you can imagine, whether we're interested in r, g, & b, or x, y, and z -
this can start propagating intermediate functions very rapidly.

One day we might have proper vector functions - but this is just the way it is
right now.


Functions kinda seem magical and complicated at first, but they are easily
learned.


I'd start off by just trying to graph your usual high school functions.
lines, sine waves, parabolas, cubics, etc.

So let's say we do a line.

#declare Line = function (Number) {Number}

Then when we want to evaluate that function, we do:

#for (X, 0, 10)
     #local Y = function {Line (X)};
#end

What are the things to notice here:
1. we define "line" as a function, that takes "Number" as its argument (input),
and its output is what is in parentheses - which right now is just "Number" -
the same as the input.

2. in our loop, we define Y as a function of X.  What function of X?  "Line"
So in goes X, Out pops the value of X, which gets assigned to Y, and we get a
45-degree angle line.

Plot some spheres and cylinders or something.


It gets more interesting when you shove the function into a pigment pattern,
because you're using the function as an interface between the coordinates in all
of POV-space and some color value.

So, let's take a pattern like onion.
#declare Onion = function {mod(sqrt(x*x+y*y+z*z), 1.0)}

#declare Rectangle = union {
 triangle {<-10, 0, -5>, <-10, 0, 5>, <10, 0, -5>}
 triangle {<10, 0, -5>, <-10, 0, 5>, <10, 0, 5> }
}

object {Rectangle pigment {Onion}}

If you're going to want to use infinite patterns, you're going to have to get
nice and cozy with the modulo operator.  It basically just gives the fractional
component of a division, ensuring that your function output is always between 0
and 1.

mod(A,B) Value of A modulo B. Returns the remainder after the integer division
of A/B. Formula is mod=((A/B)-int(A/B))*B.
http://www.povray.org/documentation/view/3.6.1/228/


So what is sqrt(x*x+y*y+z*z)?  It's the 3D distance from the origin to any point
in POV-Space.  All the spheres of every radius, all nested together.  So as you
go from 0 to 1, your values go from 0 to 1, and then when you go over 1 up to 2,
the fractional components are still 0 to 1. And on and on forever.  Onion.

In an isosurface, you're only going to be looking at the surface where the
function equals the threshold value.  So, every integer step, where the
fractional part is 0.
0/1 = 0;
1/1 = 1 remainder 0
2/1 = 2 remainder 0
etc.

isosurface {
     function {Onion (x, y, z)}
     open
     threshold 0
     max_gradient 1.5
     accuracy     0.001
     contained_by {box {<-4, -4, 0>, <4, 4, 4>}}
     pigment {rgb 0.5}
}

The thing to notice here is that the input for the function is the x, y, and z
of POV-space, not the x, y, and z unit vector quantities.  The function virtual
machine interprets these identifiers differently than in the rest of SDL.

This is important when you're playing with functions in loops, because if you
define your function with x, y, and z, you can't use those as loop variables.
If you use X, Y and Z, then those are placeholders, like with a macro.
When you pass x, y, and z into the function with a pigment or isosurface, it
works, and when you pass a loop X, Y, or Z into the function, it works that way
too.

Basically you're just using x, y, and z to calculate a single number - think of
it as a grayscale value in any of the patterns.

Once you get the hang of it, you can add a color map, and then you can use 3
different functions for r, g, and b values (and filter and transmit) and average
them together to get a full color pigment pattern.


Post a reply to this message

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.