





 
 




 
 


"Kenneth" <kdw### [at] gmailcom> wrote:
> Using your example: When A(X,Y,Z,W){} is the major function, I would imagine
> that *all* of these variables (arguments?) in the body of the function would, at
> some point in the code, have to be replaced with some actual value or other
> pre#declared variable. In almost all of the instances of X,Y,Z and W, that is
> so. But in one section, there appears to be just W used asis and not with any
> substitution. (Sorry if I'm not describing this understandably.) AFAICT, there
> is nowhere in the entire scene code that has *something* predeclared for W. So
> in this case, what does that 'naked' W represent? The code *works* of course
> and I've tried substituting actual float values for that one mysterious instance
> of W, in my usual fumbling trialanderror way...but with alwaysfatal results.
>
> If indeed that one W is 'naked' so to speak, and I haven't made a stupid error
> in detecting a substitution for it, then how does it work successfully? If I
> could figure *that* out, it would certainly expand my understanding of POVray's
> function use.
"at some point in the code, have to be replaced with some actual value or other
pre#declared variable"
Well, yes and no.
Absolutely NOT, first of all, because if _somewhere else_ in the code, PRIOR to
defining the function, you declare one of those identifiers to be a value, then
POVRay will give you an error.
#declare N = 3;
#declare Q = function (N) {N}
Parse Error: Expected 'parameter identifier', float function 'float identifier'
found instead
Whereas
#declare N = 3;
#declare Q = function (Placeholder) {N*3}
#declare Res = Q (0);
#debug concat ("Res = ", str (Res, 0, 3), "\n")
Works just fine.
The Placeholder argument is there just because declaring a function like
#declare Q = function {N*3}
automatically defines it to be dependent on (x, y, z), and I don't know how to
work around that ATM.
So, now we get to the most practical issue, IMO  using function in things like
pigments and isosurfaces.
Let's say that I want to make an onion pattern. That would simply be the
distance from the origin.
#declare Onion = function {sqrt (x*x + y*y + z*z)}
And that would likely work fine.
But now let's say that you wanted to evaluate that function and send a result to
the #debug stream.
You can't just plug in x, y, or z, because outside of the function those are
vectors, and functions operate on scalar inputs.
But what you CAN do is rewrite your function like this:
#declare Onion = function (X, Y, Z) {sqrt (X*X + Y*Y + Z*Z)}
and it will work in EITHER/BOTH case(s). Because then X will take on the
immediate scalar value of x when POVRay is going through rendering each pixel,
and passing that x value into the function for each pixel evaluation.
AND you can also write a loop where you can pass in your own values for X so
that you can evaluate and graph the function.
It's easy to lose track, get confused, and just start coding on autopilot in the
wrong paradigm, namespace, macro/function syntax.
I make these mistakes, and Heck, even Cousin Ricky makes these mistakes:
https://news.povray.org/povray.newusers/thread/%3C5ef11205%40news.povray.org%3E/
"Yes", because those function arguments get 'replaced' (I'd say assigned) at the
instant that you make the function call from somewhere else. Look atsomewhere
that you're invoking the function, and you are assigning some concrete value to
be passed into it.
In some ways, it functions exactly like you understand macros to work.
So let's say you wrote a macro like:
#macro PerformTaskRegarding (Kenneth)
ExplainCodeTo (Kenneth)
#end
Then you can invoke the macro code using:
PerformTaskRegarding (TdG) or PerformTaskRegarding (jr) or PerformTaskRegarding
(Bill) or EVEN PerformTaskRegarding (Kenneth)
The "Kenneth" written in the #macro definition is a phantom Kenneth that gets
created when the macro is invoked, assigned whatever value you put in
parentheses when you call the macro from later in code, and then gets undefined
when the macro exits.
So in your head, you can imagine that you're doing something like
PerformTaskRegarding (#local Kenneth = Bill)
And then I become your Evil Twin for the duration of the macro operations, or
viceversa however you like to see it ;) .
With a macro, you can even masquerade as yourself, because the "Kenneth" in the
main code and the "Kenneth" in the macro block are in two different namespaces.
One acts as a proxy for the other.
Now for functions, this is similar, but more limited, as I explained above,
regarding a function parameter being declared as a float identifier prior to
declaring the function. That's either a bug, or the function parser "has a
bug", or it's working exactly as it was designed to, depending on who you ask.
Now, every time you invoke a function, the things in parentheses take on new,
temporary values, until you hit that closing } and the function is fully
evaluated.
You can still use named float identifiers in your function.
The sort of "dumb" way to do it is the way I described above, but the more
useful way is when you want to use a function with a float identifier, and for
whatever reason you want to use that in the function's terms rather than passing
it in as an argument. Then you can write a macro that makes your function using
that float identifier. But why this is useful is because you #undef the
function before you #declare it, so that for every macro call, you get a fresh
function with whatever value that "static" float identifier holds, and then you
can use it in a loop.
This is the kind of thing TOK taught me to do with control points for Bezier
splines and surfaces. The control points are "static" for any given spline or
patch, but if I wanted to animate it, then I'd be changing the control points,
and I'd want an automatic way to rewrite my function(s).
And finally (I think), nested functions.
Let's say that you have three functions.
#declare Function1 = function (A) {A*2}
#declare Function2 = function (B) {B/2}
#declare Function3 = function (A, B, C) {pow (Function1 (A) + Function2 (B), C)}
Function1 and Function2 are easy to understand  you just plug some value or
float identifier into the function call and whatever value A takes on gets
processed according to what's inside the {} curly brackets.
Function3 is a nested function. It uses values returned by those functions to
calculate its own result. And so even though Function3 only uses C in its own
calculation, it needs to pass on both A and B to its nested functions so that
they have their required parameter identifiers to do THEIR calculations with.
Now, you can _passin_ float identifiers, numerical scalar values, rendertime
scalar values like x, y, and z, but the key is that those values get assigned to
the parameter names in the _parentheses of the function_. When that function
then evaluates what's in the curly braces, it needs to know which of the
parameters is being used where, and most importantly, what gets passed _through_
to the nested functions.
I hope that is clear enough and helps.
 Walker, New Hampshire Ranger
Post a reply to this message


 
 




 
 


"Bald Eagle" <cre### [at] netscapenet> wrote:
> And then I become your Evil Twin for the duration of the macro operations, or
> viceversa however you like to see it ;) .
OK. I admit it. I'm your Evil Twin. But oh so happy to be so. :D
Post a reply to this message
Attachments:
Download 'photo_20230128_173904.jpg' (41 KB)
Preview of image 'photo_20230128_173904.jpg'


 
 




 
 


"Tor Olav Kristensen" <tor### [at] TOBEREMOVEDgmailcom> wrote:
> When you set some of the
> arguments to the PIG_DISTORTION_FUNC function to zero, you were
> either "sampling" this function in a plane, along a line or at a point.
Yes, the odd isosurface result looked kind of like 'cubes' joined together
restricted to (or made up of) many x,y,z planes. The effect is actually hard to
describe.
>
> With pattern functions you can rewrite your isosurface function like
> this:
>
> function {
> 1 
> OBJECT_FUNC(
> x + MAG*(DISTORTION_FUNC( x, 1  y, 1  z)  0.5),
> y + MAG*(DISTORTION_FUNC(1  x, y, 1  z)  0.5),
> z + MAG*(DISTORTION_FUNC(1  x, 1  y, z)  0.5)
> )
> }
Originally, I did use 0.5 for the 'bias' (but unfortunately without the
additional parentheses you've added.) As the MAG multiplier value increasedto
bring in more of the bumps distortion I began to notice that the entire
distorted isosurface was shifting its position in space(!), along the vector
direction of <1,1,1>. I didn't know if that was a result of something
specific to my current code; I had never noticed such movement before in a
normal isosurface. My 'informed guess' of using the *changing* .5*MAG for the
bias eliminated that movement.
Now I see that the extra parentheses would have made 0.5 work as planned.
Thanks for pointing this out! It simply didn't occur to me... and would have
saved me a lot of coding grief.
Post a reply to this message


 
 




 
 


hi,
"Bald Eagle" <cre### [at] netscapenet> wrote:
> "Kenneth" <kdw### [at] gmailcom> wrote:
> ...
> > in detecting a substitution for it, then how does it work successfully?
>
> "at some point in the code, have to be replaced with some actual value or other
> pre#declared variable"
> ...
> Then you can invoke the macro code using:
>
> PerformTaskRegarding (TdG) or PerformTaskRegarding (jr) or PerformTaskRegarding
> (Bill) or EVEN PerformTaskRegarding (Kenneth)
so. we're all just .. "scalar values"?! (wondering, I do have a sense of
direction, will that make me a vector? </grin>)
regards, jr.
Post a reply to this message


 
 




 
 


"Tor Olav Kristensen" <tor### [at] TOBEREMOVEDgmailcom> wrote:
> "Kenneth" <kdw### [at] gmailcom> wrote:
> >
> > In my current real scene...here is a somewhat simplified version of a
> > problem I had:
> >...
> > #declare OBJ_PATTERN_FUNC = function{pigment{object{MY_OBJECT rgb 0 rgb 1}}}
>
> I recommend that you use pattern functions here instead of pigment
> functions...
>
> You can then write your declared functions like this:
>
> #declare OBJECT_FUNC =
> function {
> pattern {
> object { MY_OBJECT }
> }
> }
You are correct...as I have just discovered(!) not because I didn't try using
'pattern' there (which I did) but because it outright failed for me. The syntax
was not accepted. HOWEVER, this is because I actually did not write my real
scene's object pattern/function code like the oneline example I gave, but
instead splitup the code into two parts, for no real reason:
#declare OBJ_PATTERN = pigment{object{MY_OBJECT rgb 0 rgb 1}}
#declare OBJ_PATTERN_FUNC = function{pigment{OBJ_PATTERN}}
When OBJ_PATTERN is written this wayinitially without a function wrapper
POVray does not accept 'pattern' as a valid parameter, only 'pigment' and
'density'. So, I thought that this was the only way to write it. If I had
thought to combine the two operations into one, 'pattern' would have been
accepted! This is one of several undocumented syntaxrule quirks of the 'object
pattern'; there are others too, as I keep discovering. The docs say that it is a
colorlist pattern, so I guess it has special rules and limitations like similar
patterns.
Post a reply to this message


 
 




 
 


"Bald Eagle" <cre### [at] netscapenet> wrote:
> "Kenneth" <kdw### [at] gmailcom> wrote:
> >
> > "at some point in the code, have to be replaced with some actual
> > value or other pre#declared variable"
>
> Well, yes and no.
> [snip]
> I hope that is clear enough and helps.
>
Wow. That is a really brilliant presentation. (Or maybe I should say that it's a
that I appreciate all of the info and your time in writing it is an
understatement it is so indepth, especially about 'placeholders' in
functions, which has always been mysterious to me and a real stumbling block.
It's no wonder that I was flummoxed by W. Pokorny's masterful code that I
referenced earlier it probably makes use of *all* of the various function
rules and different 'namespace' conventions that you mentioned.
the wall in front of my computer to stare at for hours at a time so that I can
absorb it all. Through osmosis! At some point, I am going to have to carve out
the time to concentrate on *just* function use and experiments, and compare my
older (and current!) trialanderror scene successes to the actual methodology
and your very helpful notes (from both here and in the past).
Thanks, as always. You would be a good teacher of this stuff.

An actual function named after ME?! (**blushes**) I am thrilled and humbled. I
shall invoke it many times in the future as a mark of distinction. I shall name
my first child "function{Kenneth,2}" to carry on the tradition (?? Uhoh, maybe
that was bad function syntax?? I'm still learning...)

"Bald Eagle Smashes Window at Virginia Tax Office"
Good work, ha! But you forgot to say HELLO as you passed through!
Post a reply to this message


 
 




 
 


"Tor Olav Kristensen" <tor### [at] TOBEREMOVEDgmailcom> wrote:
>
> I suspect that the reason that the "skew" disappears when using your
> "desperation" code is that there you are "sampling" the
> PIG_DISTORTION_FUNC at different locations in 3D space for each of
> the red, green and blue components (.x .y .z), This causes the 3
> components to have different values.
That is a very interesting and subtle point, and I think I grasp the idea. I can
sort of visualize this effect 'writ large' if I had used, say, the bozo pattern
for my 'distortion' function it has very distinct primary colors, and thus
three distinctly different grayscale values when made into a function. But in my
case I used the bumps pigment, which is grayscale to begin with...so all the
color channels are the same, as you mentioned and should(?) all be 'sampled'
in the same 3D space location.
[conjecture]
Or maybe your point is that even grayscale 'bumps' has darktolight
variations... and it is *those* variations that are sampled in different 3D
space?
Hmm, much food for thought. Thanks for the intriguing explanation.
(BTW: Using the bumps pigment, I scaled it *very* small to be almost like noise,
and its 'skew' still showed up and was even more obvious...until I fixed it of
course.)
Post a reply to this message


 
 




 
 


"Kenneth" <kdw### [at] gmailcom> wrote:
> "Bald Eagle" <cre### [at] netscapenet> wrote:
> > "Kenneth" <kdw### [at] gmailcom> wrote:
> > >
> > > "at some point in the code, have to be replaced with some actual
> > > value or other pre#declared variable"
> >
> > Well, yes and no.
> > [snip]
> > I hope that is clear enough and helps.
> >
>
> Wow. That is a really brilliant presentation. (Or maybe I should say that it's a
>
> that I appreciate all of the info and your time in writing it is an
> understatement
Hmm. My post got screwed up and truncated :( I've never had that happen
before.
Anyway, a big thankyou.
Post a reply to this message


 
 




 
 


With regard to your problems with :
isosurface{function{
1  (OBJ_PATTERN_FUNC(
x + MAG*PIG_DISTORTION_FUNC (x,1y,1z).x  .5*MAG,
y + MAG*PIG_DISTORTION_FUNC (1x,y,1z).y  .5*MAG,
z + MAG*PIG_DISTORTION_FUNC (1x,1y,z).z  .5*MAG
).gray)
} ...}
I don't think that the problem lies with any particular grayscale, color, or
pattern values, but with the way in which you are incorporating them into your
function call.
It's a bit hard to describe without diagrams or animations, but I think that you
ought to think about the coordinates of what you're passing into your function
as a mathematical form of translate <x, y, z>.
The ONLY thing you're doing when you change the values in the "slots" for x, y,
and z in your function calls is telling the function what value  what 3D point
in space (for a 3D pigment or pattern function)  to get its calculated value
from.
If you take a look at Mike Williams' Isosurface Tutorial, you'll see how he goes
about systematically manipulating small parts of any given function to achieve
specific results. These are all based on very simple algebraic concepts that
you can readily find with a few clicks on the web.
When you take something like a parabola, y = x*x, or declare Parabola = function
(X) {pow (X, 2)}, then you have a specific, hard coded relationship between the
value of X and what the result of the calculation is.
The visual an often counterintuitive result of many mathematical manipulations
of that basic equation is that it moves in the opposite direction of what you
initially might expect.
If I subtract from the "X" that I _pass into_ the function call, then I'm moving
the function result to the left, because I'm decreasing X itself. If I
subtract that same value from the X _inside the function_, then I shift it to
the right, because I'm taking the input value that's needed to achieve the
original result, and by subtracting from it, "increasing the value needed" to
get the same result  so I shift it to the right.
Now, I'm tired, and it's early, and I've only had half a coffee, so this may be
wrong or backwards  but the point is, all of the elements of what goes on are
right there for you to be aware of and experiment with.
find out what you have to do with any given function (I'd start with #declare
Test = function (X) {X} to get a straight line) to get it move exactly as much
as you think it should in any given direction.
Try a circle next (my onion example) and do the same, but now add scaling.
Always ask what is going in, how does that now get evaluated in the function's
equation, and what is required to achieve any target result value.
To get back to your original problem, I think that you are trying to modify your
x, y, and z input values, but you're comingling your terms by making your
distortion function for each term depend on the other 2 terms, rather than that
vector component alone. Your function that modifies x ought to have (x, 0, 0)
going into it, y should have (0, y, 0), and z should have (0, 0, z).
But without graphing the result and SEEING what the results of each function
evaluation are, I'm just speculating. But I'm suspecting that you're adding
some sort of bias using all 3 vector components, which is consistent with an
overall shift/skew in the +/ <1, 1, 1> direction of any given magnitude.
Friedrich Lohmueller's site is down, but I'll bet you can use Wayback
(archive.org) to look at his geometric transformations section using matrix
transforms. When you change around the values in the top 3 rows of the matrix,
you're multiplying what contribution that x, y, and z have on "where that axis
points" when you use functions in that redefined geometric space. When you put
values into the bottom row, you add to those vectors, and do a translation.
So if I use <1, 1, 0> in my definition for "the y axis", then I achieve a skew
effect  because everything that used to be pointed straight up now points in
the direction of: <1, 1, 0>. Which is at a 45 degree angle to the right.
Therefore if I use <1, 1, 1> * SomeScalingFactor, then I'd get a skew that's
forward and to the right by SomeScalingFactor.
Anyway, that's my early morning take, you breakfast food for thought, and you
math homework for the week. :D
 The AntiTax Man
Post a reply to this message


 
 




 
 


"Kenneth" <kdw### [at] gmailcom> wrote:
>
> In case you want to try the quick test (no need for 'highquality' settings
> here):
> 
> #declare BUMPS_F =
> function{pattern{bumps scale .2}}
>
> #declare GRANITE_F =
> function{pattern{granite scale 3}}
>
> #declare SIN_F = function(x){sin(7*pi*x)}
>
> isosurface{
> function { sqrt(pow(x,2)+pow(y,2)+pow(z,2)).7 // sphere
>
> // switch these around...
> + BUMPS_F(x,y,z)*.5
>
>  GRANITE_F(x,y,z)*.5
>
>  SIN_F(x)*.2
>
> }
>
> threshold 0
> accuracy .01
> max_gradient 8
>
> contained_by{box{1.1,1.1}}
> pigment{ rgb 1}
> }
Just to be complete:
Here is an instance where the order of functions does matter, *when* using
additional parentheses. This is to be expected of course. As Alain pointed out
earlier (paraphrasing),
+(A  B) is different from (B + A)
+ (BUMPS_F(x,y,z)*.5
 GRANITE_F(x,y,z)*.5)
 SIN_F(x)*.2
vs.
 (GRANITE_F(x,y,z)*.5)
+ (BUMPS_F(x,y,z)*.5)
 SIN_F(x)*.2
Post a reply to this message


 
 




 

