POV-Ray : Newsgroups : povray.advanced-users : isosurface: Does the order of multiple functions matter? Server Time
14 Oct 2026 22:03:34 EDT (-0400)
  isosurface: Does the order of multiple functions matter? (Message 1 to 28 of 28)  
From: Kenneth
Subject: isosurface: Does the order of multiple functions matter?
Date: 28 Jan 2023 05:30:00
Message: <web.63d4f81d3b647a9d9b4924336e066e29@news.povray.org>
I have an isosuface made from multiple functions that is working quite nicely--
but I want to rearrange the order of the functions to see the different(?)
results. The code is complex, so I'll leave out the ugly function details and
syntax. The following is just pseudo code.

Right now, it is like this (very simplified):
isosurface{
function{A + B + C + D}
....
}

Only four, thankfully! :-)

Does the order of the functions matter when POV-ray evaluates them? Or are they
evaluated 'all at once' regardless of the order?

If the ordering does matter, what would be the most efficient way to set up
'switches' at the beginning of the scene to easily change the order of A,B,C and
D? Possibilities that occur to me would be some kind of combination of
#switch/#case, or #if blocks, or select(?), or maybe an array; but I want the
top-of-code selection process to be relatively easy-- something like
              #declare FUNCTION_ORDER= <C,A,D,B>;
.... and without having to make multiple copies of the functions for all of the
different permutations.

Any ideas?

(BTW: #if and #switch/#case do work well in the body of the isosurface, within
the main function, to at least eliminate certain parts. Probably not good code
practice, but it causes no problems AFAIK.)


Post a reply to this message

From: jr
Subject: Re: isosurface: Does the order of multiple functions matter?
Date: 28 Jan 2023 05:45:00
Message: <web.63d4fc0e9b90547bfbdc16836cde94f1@news.povray.org>
hi,

"Kenneth" <kdw### [at] gmailcom> wrote:
> ... but I want the
> top-of-code selection process to be relatively easy-- something like
>               #declare FUNCTION_ORDER= <C,A,D,B>;
> .... and without having to make multiple copies of the functions for all of the
> different permutations.
>
> Any ideas?

you could supply some integer corresponding to eg a #case via the command-line,
using the "declare=myInt=N" option switch.

re the function stuff (sticking my neck out :-)), I'd say 'A + B' will be
evaluated as per the expression (parser) syntax:
<https://wiki.povray.org/content/Reference:Numeric_Expressions#Operators>


regards, jr.


Post a reply to this message

From: Thomas de Groot
Subject: Re: isosurface: Does the order of multiple functions matter?
Date: 28 Jan 2023 07:30:08
Message: <63d51550$1@news.povray.org>
Op 28-1-2023 om 11:25 schreef Kenneth:
> I have an isosuface made from multiple functions that is working quite nicely--
> but I want to rearrange the order of the functions to see the different(?)
> results. The code is complex, so I'll leave out the ugly function details and
> syntax. The following is just pseudo code.
> 
> Right now, it is like this (very simplified):
> isosurface{
> function{A + B + C + D}
> ....
> }
> 
> Only four, thankfully! :-)
> 
> Does the order of the functions matter when POV-ray evaluates them? Or are they
> evaluated 'all at once' regardless of the order?
> 
> If the ordering does matter, what would be the most efficient way to set up
> 'switches' at the beginning of the scene to easily change the order of A,B,C and
> D? Possibilities that occur to me would be some kind of combination of
> #switch/#case, or #if blocks, or select(?), or maybe an array; but I want the
> top-of-code selection process to be relatively easy-- something like
>                #declare FUNCTION_ORDER= <C,A,D,B>;
> .... and without having to make multiple copies of the functions for all of the
> different permutations.
> 
> Any ideas?
> 

Funny you ask that, I am currently also wondering about the same. ;-)

I get the impression that it does not really matter, however, when in 
doubt, I tend to use parentheses to isolate/group some parts.

My example here (from a project - not isosurfaces - I am slowly working on):
   function(x,z) { 2*( f_bozo(5*(x-0.5), 0, 5*(z-0.5)) * 
f_granite(15*(x-0.5), 0, 15*(z-0.5)) ) * f_spherical(2.1*(x-0.5), 0, 
2.1*(z-0.5))}

uses multiplicators, which is somewhat easier to visualise for me, but I 
think I did not really got surprises when I experimented with + or -.

Fun to experiment with indeed.

> (BTW: #if and #switch/#case do work well in the body of the isosurface, within
> the main function, to at least eliminate certain parts. Probably not good code
> practice, but it causes no problems AFAIK.)
> 

As long as it does what is intended...

-- 
Thomas


Post a reply to this message

From: Kenneth
Subject: Re: isosurface: Does the order of multiple functions matter?
Date: 28 Jan 2023 09:05:00
Message: <web.63d52b309b90547b9b4924336e066e29@news.povray.org>
Thomas de Groot <tho### [at] degrootorg> wrote:

>
> Funny you ask that, I am currently also wondering about the same. ;-)
>

It must be the Vulcan 'mind-meld'!

> I get the impression that it does not really matter, however, when in
> doubt, I tend to use parentheses to isolate/group some parts.
>

For multiplication of functions, I readily agree. It's the addition of functions
that has me puzzled. Strangely, I have never given much thought to the order of
them until now.

My present code is *so* complex-- for both the isosurface and matching texture
(pigment) functions-- that I cannot easily discern how the functions interact
visually, or if the order of them really matters.

I guess I should set up a much-simplified test with maybe two functions, and
switch them around to see...perhaps using a box function as the main object,
then sin(...) and f_noise3d for A and B. Or some other simple yet clearly
'different' pair of distortions. I'm still not entirely sure of what to expect,
or if I could even understand the visual difference when switching the two. It
is an interesting experiment to try, but difficult to pre-visualize the outcome.
I suppose that if there is *any* change at all, then the order does matter.


Post a reply to this message

From: Bald Eagle
Subject: Re: isosurface: Does the order of multiple functions matter?
Date: 28 Jan 2023 09:50:00
Message: <web.63d535f49b90547b1f9dae3025979125@news.povray.org>
"Kenneth" <kdw### [at] gmailcom> wrote:

> Right now, it is like this (very simplified):
> isosurface{
> function{A + B + C + D}
> ....
> }

Since you only have addition (or subtraction), your function is both associative
and commutative with respect to the relevant terms.

If you had multiplication or division, it would (also) be distributive with
respect to the affected terms.

Once you start to do things that are "term-specific", like daisy-chaining
functions together like A(B(C(D(n)))) or having the need to enclose things in
parentheses to get the proper sign or Order of Operations, then you need to be
organized and aware of the consequences of changing things around.

you may have 5 - x + a, or 5 - x -a, which is different than 5 - (x+a) and 5 -
(x-a).

5-a/x will be different than (5-a)/x
same with 5-a*x and (5-a)*x

So, you can use an online equation solver to evaluate the equation in symbolic
terms, or to plug in values.   You can also evaluate parts of your functions in
POV-Ray and send the result to the #debug stream.

#declare A = function (N) {sqrt(N)}
#declare Result = A (27);
#debug concat (str(Result, 0, DecimalPlaces), " \n")

If you are unsure about changing things around, then you can start to separate
terms in your functions into subfunctions and then start to recombine them.

#declare A = function (X, Y, Z, N) {(3*X + pow (Y, 3))/Z*sqrt(N)}
#declare Asub1 = function (X, Y, Z, N) {(3*X + pow (Y, 3))/Z}
#declare Asub1a = function (X, Y, Z, N) {3*X+pow (Y, 3)}
#declare Asub2a = function (X, Y, Z, N) {3*X}
#declare Asub2b = function (X, Y, Z, N) {pow (Y, 3)}
#declare Asub1b = function (X, Y, Z, N) {Asub2a (X, Y, Z, N) + Asub2b (X, Y, Z,
N)}
#declare Asub1c = function (X, Y, Z, N) {Asub1b (X, Y, Z, N)/ Z}
#declare Asub2c = function (X, Y, Z, N) {sqrt(N)}
#declare Asub3 = function (Term1, Term2) {Asub1c (X, Y, Z, N) * Asub2c (X, Y, Z,
N)}

*before 1st coffee, untested code

So you can see inside the curly brackets how the functions get simpler, but due
to the nature of POV-Ray's function parser, the expressions to evaluate those
can get more complex.  It is however, good practice to understand the finer bits
of the function syntax and why things go wrong, and how they can go wrong in a
hurry.

If you do you evaluations with a macro and declaring local identifiers to be the
result of chains of operations, then you can get the answers you need in the
#debug stream, and use that as a guide to getting it right in the invisible and
complicated operations that happen in functions and isosurfaces.


Your mission, Kenneth, should you choose/decide to accept it, is to concatenate
these functions and successfully render an error-free isosurface.  As always,
should you or any of your POV-Ray collaborators be caught or killed, the Dev
Team will disavow any knowledge of your actions. This message will self-destruct
in ten POV units. Good luck, Kenneth.


Post a reply to this message

From: Kenneth
Subject: Re: isosurface: Does the order of multiple functions matter?
Date: 28 Jan 2023 10:20:00
Message: <web.63d53bc39b90547b9b4924336e066e29@news.povray.org>
"Kenneth" <kdw### [at] gmailcom> wrote:

>
> For multiplication of functions, I readily agree. It's the addition of functions
> that has me puzzled...
>
> I guess I should set up a much-simplified test with maybe two functions, and
> switch them around to see...

Well, I did the test. With *three* simple functions! To make a long story short:
The order of the functions does not matter. Perhaps I should have expected that,
although it wasn't obvious to my way of thinking :-(

So the bigger question of how to easily switch them around is... of no
importance, ha. Sorry for the wasted brain power, lads. I'm actually not
disappointed-- it at least makes my code simpler!

Thanks for the comments and suggestions though; they always get me to think more
deeply.

In case you want to try the quick test (no need for 'high-quality' 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}
}


Post a reply to this message

From: Kenneth
Subject: Re: isosurface: Does the order of multiple functions matter?
Date: 28 Jan 2023 10:40:00
Message: <web.63d540fc9b90547b9b4924336e066e29@news.povray.org>
"jr" <cre### [at] gmailcom> wrote:

>
> you could supply some integer corresponding to eg a #case via the command-line,
> using the "declare=myInt=N" option switch.

That's interesting; I didn't think of it. Thanks.
>
> re the function stuff (sticking my neck out :-)), I'd say 'A + B' will be
> evaluated as per the expression (parser) syntax:
> <https://wiki.povray.org/content/Reference:Numeric_Expressions#Operators>
>

"( )  expressions in parentheses first"

Apparently, that doesn't work in my function example:

     + (BUMPS_F(x,y,z)*.5)

...again makes no difference when switched around in the function order. If I'm
writing it correctly.

It does seem that the entire set of functions is evaluated 'all at once',
regardless.


Post a reply to this message

From: Kenneth
Subject: Re: isosurface: Does the order of multiple functions matter?
Date: 28 Jan 2023 11:20:00
Message: <web.63d54b169b90547b9b4924336e066e29@news.povray.org>
"Bald Eagle" <cre### [at] netscapenet> wrote:

>
> Since you only have addition (or subtraction), your function is both
> associative and commutative with respect to the relevant terms.

Associative? Commutative?? Egads, who came up with those terms?? I have a vague
recollection of those things from... 100 years ago... :-P  Subjunctive,
prepositional... oh, wait, those are English-language terms...
>
>
> You can also evaluate parts of your functions in
> POV-Ray and send the result to the #debug stream.
>
> #declare A = function (N) {sqrt(N)}
> #declare Result = A (27);
> #debug concat (str(Result, 0, DecimalPlaces), " \n")

Good idea; although in my case it's more of a visual result-- like the bumps
pattern affecting an isosurface. I have no clue as to how debug might be used
there.
>
> If you are unsure about changing things around, then you can start to separate
> terms in your functions into subfunctions and then start to recombine them.
> [snip]

That's really neat, and useful. I *still* struggle with understanding the finer
points of function use. Your examples (here and through the years) have been a
godsend...if I can only remember them! In my current code project, many are the
times that I came up with a workable solution only by sheer trial-and-error,
discarding one failed attempt after another. It's like trying to discern the
finer points of a 'foreign language' when I don't know or remember the subtle
underlying rules, from lack of practice.


Post a reply to this message

From: Bald Eagle
Subject: Re: isosurface: Does the order of multiple functions matter?
Date: 28 Jan 2023 11:45:00
Message: <web.63d550ac9b90547b1f9dae3025979125@news.povray.org>
"Kenneth" <kdw### [at] gmailcom> wrote:

> Good idea; although in my case it's more of a visual result-- like the bumps
> pattern affecting an isosurface. I have no clue as to how debug might be used
> there.

Well, there are a number of ways that you can do these things.
you always do #declare A = function {pigment {bumps}}
and then use that to calculate numbers for your debug stream.

Another I do a lot is make a graph along one axis (usually x).
That way I can cycle through X with a loop, calculate the result, and make a
little sphere at <X, Result, 0> to see WTH is going on.


> That's really neat, and useful. I *still* struggle with understanding the finer
> points of function use. Your examples (here and through the years) have been a
> godsend...if I can only remember them!

Well, thanks - but remember, the only reason I got "this good" is because jr had
that media project, and Bill Pokorny walked me through a lot of the practical
details of using functions, and then I just practiced, practiced, practiced.

> In my current code project, many are the
> times that I came up with a workable solution only by sheer trial-and-error,
> discarding one failed attempt after another. It's like trying to discern the
> finer points of a 'foreign language' when I don't know or remember the subtle
> underlying rules, from lack of practice.

Absolutely.   Don't think that I don't do exactly the same thing ALL THE TIME.

The key, really, is looking at any given function and asking "what do the things
inside the curly braces need to be fully evaluated"?
And often, that's a matter of going back one daisy-chained function and asking
the same thing.   And then doing that again.

Because if you have A which needs X, and B which needs Y, and C which needs Z,
and D which needs W, then if you have A(B(C(D()))), your function A needs:  A
(X, Y, Z, W) {}, and so on, as you go further down into the curly braces.

It can be mind-bending, and a real mess on the screen, but going through the
simpler functions and making the mistakes that are easier to track down because
there are fewer places for the error to be allows you to learn to "think ahead"
and keep a running tab of things that could/usually go wrong.  Notes in the code
or on paper usually help me remember what the cryptic POV-Ray error heiroglyphs
actually MEAN in a practical sense.

The other thing that helps to work this all out in your head is to not delete
code that doesn't work.   Otherwise you wind up coding the same mistakes over
and over again.

Do a #switch #case #break #end block, and copy-paste #case 1 into #case 2 and
then edit case 2.  If that fails, work on case 3.   That way you have a running
documentation of what you've tried, what the results look like, notes on why it
failed, what worked, etc.

You can then copy-paste the working code into a new scene that just works, but
retain that developmental test scene for your records.  Heck, post it here, so
that people struggling with the same issues can follow along and really see how
one goes from fail to success.  What doesn;t work is often more important to
know than what does, since there's so much more of it to go wading through.

Glad you're getting it all to work out.

- BW


Post a reply to this message

From: Alain Martel
Subject: Re: isosurface: Does the order of multiple functions matter?
Date: 28 Jan 2023 12:27:51
Message: <63d55b17$1@news.povray.org>
Le 2023-01-28 à 05:25, Kenneth a écrit :
> I have an isosuface made from multiple functions that is working quite nicely--
> but I want to rearrange the order of the functions to see the different(?)
> results. The code is complex, so I'll leave out the ugly function details and
> syntax. The following is just pseudo code.
> 
> Right now, it is like this (very simplified):
> isosurface{
> function{A + B + C + D}
> ....
> }
> 
> Only four, thankfully! :-)
> 
> Does the order of the functions matter when POV-ray evaluates them? Or are they
> evaluated 'all at once' regardless of the order?
> 
> If the ordering does matter, what would be the most efficient way to set up
> 'switches' at the beginning of the scene to easily change the order of A,B,C and
> D? Possibilities that occur to me would be some kind of combination of
> #switch/#case, or #if blocks, or select(?), or maybe an array; but I want the
> top-of-code selection process to be relatively easy-- something like
>                #declare FUNCTION_ORDER= <C,A,D,B>;
> .... and without having to make multiple copies of the functions for all of the
> different permutations.
> 
> Any ideas?
> 
> (BTW: #if and #switch/#case do work well in the body of the isosurface, within
> the main function, to at least eliminate certain parts. Probably not good code
> practice, but it causes no problems AFAIK.)
> 

The order should have no effect in this case. As long as you have all 
additions or all multiplications, shuffling the terms won't change the 
end result.
BUT, remember that A-B is different from B-A and A/B is also different 
from B/A.


Post a reply to this message

From: Cousin Ricky
Subject: Re: isosurface: Does the order of multiple functions matter?
Date: 28 Jan 2023 12:40:02
Message: <63d55df2$1@news.povray.org>
On 2023-01-28 06:25 (-4), Kenneth wrote:
> 
> isosurface{
> function{A + B + C + D}
> ....
> }
> 
> Only four, thankfully! :-)
> 
> Does the order of the functions matter when POV-ray evaluates them? Or are they
> evaluated 'all at once' regardless of the order?

<soapbox>
It is dangerous programming practice to rely on order of evaluation,
unless the language definition explicitly specifies it.  POV-Ray has no
such specification.
</soapbox>

In your context, it does not appear that the order makes any difference,
because functions in POV-Ray cannot have side effects.  Of course,
liberal use of parentheses will guarantee *precedence* of evaluation,
but this has limited effect on the *order* of evaluation.

> (BTW: #if and #switch/#case do work well in the body of the isosurface, within
> the main function, to at least eliminate certain parts. Probably not good code
> practice, but it causes no problems AFAIK.)

Directives (#if, #switch, etc.) in functions are parsed only once, when
the function is defined.  Directives in functions that are coded in-line
in an isosurface will be observed each time the object is parsed, but
directives in any pre-defined functions used in the isosurface will not
be re-parsed.


Post a reply to this message

From: Bald Eagle
Subject: Re: isosurface: Does the order of multiple functions matter?
Date: 28 Jan 2023 13:25:00
Message: <web.63d567619b90547b1f9dae3025979125@news.povray.org>
Cousin Ricky <ric### [at] yahoocom> wrote:
> On 2023-01-28 06:25 (-4), Kenneth wrote:

> > (BTW: #if and #switch/#case do work well in the body of the isosurface, within
> > the main function, to at least eliminate certain parts. Probably not good code
> > practice, but it causes no problems AFAIK.)
>
> Directives (#if, #switch, etc.) in functions are parsed only once, when
> the function is defined.  Directives in functions that are coded in-line
> in an isosurface will be observed each time the object is parsed, but
> directives in any pre-defined functions used in the isosurface will not
> be re-parsed.

Say what now?

I missed this in the first skim-through.

I'll be trying this out at some point - but I'd like to see a working code
example! (Considering that I had no idea this was possible)


Post a reply to this message

From: Kenneth
Subject: Re: isosurface: Does the order of multiple functions matter?
Date: 28 Jan 2023 22:20:00
Message: <web.63d5e5729b90547b9b4924336e066e29@news.povray.org>
"Bald Eagle" <cre### [at] netscapenet> wrote:
>
> The other thing that helps to work this all out in your head is to not delete
> code that doesn't work.   Otherwise you wind up coding the same mistakes over
> and over again.

Absolutely! My current real scene code is full of commented-out sections that
failed, along with notes as to why (well, at least at my current level of
understanding, ha.) Unfortunately, much of my 'knowledge' is currently spread
through hundreds of my previous files, so I have to think hard as to *where* I
might have put a particularly useful note.

Your own method of adding accumulated tidbits of knowledge into a spreadsheet--
like a 'library' of known facts-- is the envy of the modern world. ;-)  Alas, I
have not gotten around to implementing that major 'tuit.
>
> Do a #switch #case #break #end block, and copy-paste #case 1 into #case 2 and
> then edit case 2.  If that fails, work on case 3.   That way you have
> a running documentation of what you've tried, what the results look like,
> notes on why it failed, what worked, etc... What doesn't work is often more
> important to know than what does.

Exactly, Northern Cousin Walker. Excellent advice.

> If you have A which needs X, and B which needs Y, and C which needs Z,
> and D which needs W, then if you have A(B(C(D()))), your function A needs:  A
> (X, Y, Z, W) {}, and so on, as you go further down into the curly braces.

This is the concept that I have the most trouble understanding...although I'm
making slow progress.

My apologies for going a bit off-topic here, but I was recently going through
someone else's old code that uses this idea brilliantly-- it's very complex,
with nested functions-- and I *think* I came across a particular section that I
don't fully understand.

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 as-is 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* pre-declared 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 trial-and-error way...but with always-fatal 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 POV-ray's
function use.


Post a reply to this message

From: Kenneth
Subject: Re: isosurface: Does the order of multiple functions matter?
Date: 28 Jan 2023 23:00:00
Message: <web.63d5ee319b90547b9b4924336e066e29@news.povray.org>
"Kenneth" <kdw### [at] gmailcom> wrote:
> "Bald Eagle" <cre### [at] netscapenet> wrote:
>
> > If you have A which needs X, and B which needs Y, and C which needs Z,
> > and D which needs W, then if you have A(B(C(D()))), your
> > function A needs:  A(X, Y, Z, W) {}, and so on, as you go further down
> > into the curly braces.
>
> My apologies for going a bit off-topic here, but I was recently going through
> someone else's old code that uses this idea brilliantly-- it's very complex,
> with nested functions-- and I *think* I came across a particular section
> that I don't fully understand.
>

To be specific, it's in William Pokorny's "ObjectAslso" file from Sept. 19 2009,
if you would like to take a look (no pressure, of course.) In his file called
"ObjectAslso.inc", there is a function argument called 'S'.  I have a hard time
following the code because of its complexity, but I can't see where one (or
more) of the instances of that argument are assigned a value of any kind. I
could be wrong *of course*; maybe I'm just not seeing the forest for the trees--
or vice-versa!

https://news.povray.org/povray.binaries.scene-files/thread/%3Cweb.4aae23151285f23f15ee2c550%40news.povray.org%3E/


Post a reply to this message

From: Kenneth
Subject: Re: isosurface: Does the order of multiple functions matter?
Date: 28 Jan 2023 23:50:00
Message: <web.63d5fa0c9b90547b9b4924336e066e29@news.povray.org>
Cousin Ricky <ric### [at] yahoocom> wrote:
>
> <soapbox>
> It is dangerous programming practice to rely on order of evaluation,
> unless the language definition explicitly specifies it.  POV-Ray has no
> such specification.
> </soapbox>
>
> In your context, it does not appear that the order makes any difference,
> because functions in POV-Ray cannot have side effects.  Of course,
> liberal use of parentheses will guarantee *precedence* of evaluation,
> but this has limited effect on the *order* of evaluation.
>

I can't say that I really understand those distinctions, conceptually. In any
case, my attempts so far at sprinkling parentheses "here, there, and eveywhere"
in my simplistic example code has had no effect; the order of the isosurface's
inner functions still shows no visible difference when changed around.


Post a reply to this message

From: Kenneth
Subject: Re: isosurface: Does the order of multiple functions matter?
Date: 29 Jan 2023 01:30:00
Message: <web.63d6115f9b90547b9b4924336e066e29@news.povray.org>
"Bald Eagle" <cre### [at] netscapenet> wrote:
>
> The other thing that helps to work this all out in your head is to not delete
> code that doesn't work.   Otherwise you wind up coding the same mistakes over
> and over again.
>
>..That way you have a running documentation of what you've tried, ..., why it
> failed, what worked, etc. Heck, post it here, so
> that people struggling with the same issues can follow along and really
> see how one goes from fail to success...

Well, since you mentioned it... :-)

[more off-topic stuff, sorry!]
In my current real scene, I'm using the 'object pattern' to make an isosurface
shape, necessarily using functions. Here is a somewhat simplified version of a
problem I had:

#declare OBJ_PATTERN_FUNC = function{pigment{object{MY_OBJECT rgb 0 rgb 1}}}
#declare PIG_DISTORTION_FUNC = function{pigment{bumps scale .2}}
#declare MAG = 1.5; // the magnitude of the bumps distortion to be added

This is how I originally wrote my main function:

isosurface{function{
1 - (OBJ_PATTERN_FUNC(
x + MAG*PIG_DISTORTION_FUNC (x,y,z).x - .5*MAG,
y + MAG*PIG_DISTORTION_FUNC (x,y,z).y - .5*MAG,
z + MAG*PIG_DISTORTION_FUNC (x,y,z).z - .5*MAG
     ).gray)
     } ... }

This worked-- but the resulting bumps distortion had a spatial 'skew' aligned
along <1,1,1>, which *finally* became understandable because I was using full
(x,y,z) in all 3 inner functions. (I had to do that to solve other problems that
I ran into, up to this point.) But substituting 0.0 for the appropriate
'un-needed' x,y,z arguments resulted in *very* strange isosurface effects.

So I came up with this solution, which nicely fixed the skew--by subtracting the
'offending' arguments from 1.0. But I have NO idea why it works. I finally
arrived at it through pure chance and desperation:

isosurface{function{
1 - (OBJ_PATTERN_FUNC(
x + MAG*PIG_DISTORTION_FUNC (x,1-y,1-z).x - .5*MAG,
y + MAG*PIG_DISTORTION_FUNC (1-x,y,1-z).y - .5*MAG,
z + MAG*PIG_DISTORTION_FUNC (1-x,1-y,z).z - .5*MAG
     ).gray)
     } ...}

Maybe this is a special-case solution because of the object pattern scheme? I
don't know.


Post a reply to this message

From: Thomas de Groot
Subject: Re: isosurface: Does the order of multiple functions matter?
Date: 29 Jan 2023 02:21:20
Message: <63d61e70$1@news.povray.org>
Op 28/01/2023 om 19:20 schreef Bald Eagle:
> Cousin Ricky <ric### [at] yahoocom> wrote:
>> On 2023-01-28 06:25 (-4), Kenneth wrote:
> 
>>> (BTW: #if and #switch/#case do work well in the body of the isosurface, within
>>> the main function, to at least eliminate certain parts. Probably not good code
>>> practice, but it causes no problems AFAIK.)
>>
>> Directives (#if, #switch, etc.) in functions are parsed only once, when
>> the function is defined.  Directives in functions that are coded in-line
>> in an isosurface will be observed each time the object is parsed, but
>> directives in any pre-defined functions used in the isosurface will not
>> be re-parsed.
> 
> Say what now?
> 
> I missed this in the first skim-through.
> 
> I'll be trying this out at some point - but I'd like to see a working code
> example! (Considering that I had no idea this was possible)
> 

Hmmmmm.... this makes sense, somehow, but I guess this behaviour could 
produce unexpected results, with no clue of /where/ the diverging 
behaviour would come from (if unaware of this behaviour).

-- 
Thomas


Post a reply to this message

From: Tor Olav Kristensen
Subject: Re: isosurface: Does the order of multiple functions matter?
Date: 29 Jan 2023 08:20:00
Message: <web.63d671f79b90547b383c879289db30a9@news.povray.org>
"Kenneth" <kdw### [at] gmailcom> wrote:
>...
> [more off-topic stuff, sorry!]
> In my current real scene, I'm using the 'object pattern' to make an isosurface
> shape, necessarily using functions. Here is a somewhat simplified version of a
> problem I had:
>...
> #declare OBJ_PATTERN_FUNC = function{pigment{object{MY_OBJECT rgb 0 rgb 1}}}
> #declare PIG_DISTORTION_FUNC = function{pigment{bumps scale .2}}
> #declare MAG = 1.5; // the magnitude of the bumps distortion to be added
>
> This is how I originally wrote my main function:
>
> isosurface{function{
> 1 - (OBJ_PATTERN_FUNC(
> x + MAG*PIG_DISTORTION_FUNC (x,y,z).x - .5*MAG,
> y + MAG*PIG_DISTORTION_FUNC (x,y,z).y - .5*MAG,
> z + MAG*PIG_DISTORTION_FUNC (x,y,z).z - .5*MAG
>      ).gray)
>      } ... }
>
> This worked-- but the resulting bumps distortion had a spatial 'skew' aligned
> along <1,1,1>, which *finally* became understandable because I was using full
> (x,y,z) in all 3 inner functions. (I had to do that to solve other problems that
> I ran into, up to this point.) But substituting 0.0 for the appropriate
> 'un-needed' x,y,z arguments resulted in *very* strange isosurface effects.
>
> So I came up with this solution, which nicely fixed the skew--by subtracting the
> 'offending' arguments from 1.0. But I have NO idea why it works. I finally
> arrived at it through pure chance and desperation:
>
> isosurface{function{
> 1 - (OBJ_PATTERN_FUNC(
> x + MAG*PIG_DISTORTION_FUNC (x,1-y,1-z).x - .5*MAG,
> y + MAG*PIG_DISTORTION_FUNC (1-x,y,1-z).y - .5*MAG,
> z + MAG*PIG_DISTORTION_FUNC (1-x,1-y,z).z - .5*MAG
>      ).gray)
>      } ...}
>
> Maybe this is a special-case solution because of the object pattern scheme? I
> don't know.

I recommend that you use pattern functions here instead of pigment
functions. That is because the pigments you use here always has the
same values for the red, green and blue components (extracted with
...red .green .blue or .x .y .z) The gray component will then also
have the same value as the red, green and blue components.

You can then write your declared functions like this:

#declare OBJECT_FUNC =
    function {
        pattern {
            object { MY_OBJECT }
        }
    }
;
#declare DISTORTION_FUNC =
    function {
        pattern {
            bumps
            scale <0.2, 0.2, 0.2>
        }
    }
;

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. When you set some of the
arguments to the PIG_DISTORTION_FUNC function to zero, you where
either "sampling" this function in a plane, along a line or at a point.

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)
    )
}

--
Tor Olav
http://subcube.com
https://github.com/t-o-k


Post a reply to this message

From: Bald Eagle
Subject: Re: isosurface: Does the order of multiple functions matter?
Date: 29 Jan 2023 10:00:00
Message: <web.63d6896c9b90547b1f9dae3025979125@news.povray.org>
"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 as-is 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* pre-declared 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 trial-and-error way...but with always-fatal 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 POV-ray'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
POV-Ray 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 POV-Ray 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
vice-versa 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 re-write 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 _pass-in_ float identifiers, numerical scalar values, render-time
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

From: Bald Eagle
Subject: Re: isosurface: Does the order of multiple functions matter?
Date: 29 Jan 2023 11:20:00
Message: <web.63d69bff9b90547b1f9dae3025979125@news.povray.org>
"Bald Eagle" <cre### [at] netscapenet> wrote:

> And then I become your Evil Twin for the duration of the macro operations, or
> vice-versa 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_2023-01-28_17-39-04.jpg' (41 KB)

Preview of image 'photo_2023-01-28_17-39-04.jpg'
photo_2023-01-28_17-39-04.jpg


 

From: Kenneth
Subject: Re: isosurface: Does the order of multiple functions matter?
Date: 29 Jan 2023 11:55:00
Message: <web.63d6a43e9b90547b9b4924336e066e29@news.povray.org>
"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 increased--to
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

From: jr
Subject: Re: isosurface: Does the order of multiple functions matter?
Date: 29 Jan 2023 12:50:00
Message: <web.63d6b09c9b90547bfbdc16836cde94f1@news.povray.org>
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

From: Kenneth
Subject: Re: isosurface: Does the order of multiple functions matter?
Date: 29 Jan 2023 13:00:00
Message: <web.63d6b2b79b90547b9b4924336e066e29@news.povray.org>
"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 one-line example I gave, but
instead split-up 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 way--initially without a function wrapper--
POV-ray 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 syntax-rule quirks of the 'object
pattern'; there are others too, as I keep discovering. The docs say that it is a
color-list pattern, so I guess it has special rules and limitations like similar
patterns.


Post a reply to this message

From: Kenneth
Subject: Re: isosurface: Does the order of multiple functions matter?
Date: 29 Jan 2023 20:50:00
Message: <web.63d721309b90547b9b4924336e066e29@news.povray.org>
"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
brilliant exposé of the dark and secret underworld of functions, ha.) To say
that I appreciate all of the info and your time in writing it is an
understatement-- it is so in-depth, 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.

It's a lot to chew on! I should print out your exposé, frame it, and put it on
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!) trial-and-error 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 (?? Uh-oh, 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

From: Kenneth
Subject: Re: isosurface: Does the order of multiple functions matter?
Date: 29 Jan 2023 21:20:00
Message: <web.63d729139b90547b9b4924336e066e29@news.povray.org>
"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 dark-to-light
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

From: Kenneth
Subject: Re: isosurface: Does the order of multiple functions matter?
Date: 30 Jan 2023 02:20:00
Message: <web.63d76f8e9b90547b9b4924336e066e29@news.povray.org>
"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 thank-you.


Post a reply to this message

From: Bald Eagle
Subject: Re: isosurface: Does the order of multiple functions matter?
Date: 30 Jan 2023 07:10:00
Message: <web.63d7b2fe9b90547b1f9dae3025979125@news.povray.org>
With regard to your problems with :

isosurface{function{
1 - (OBJ_PATTERN_FUNC(
x + MAG*PIG_DISTORTION_FUNC (x,1-y,1-z).x - .5*MAG,
y + MAG*PIG_DISTORTION_FUNC (1-x,y,1-z).y - .5*MAG,
z + MAG*PIG_DISTORTION_FUNC (1-x,1-y,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

From: Kenneth
Subject: Re: isosurface: Does the order of multiple functions matter?
Date: 30 Jan 2023 21:50:00
Message: <web.63d880da9b90547b9b4924336e066e29@news.povray.org>
"Kenneth" <kdw### [at] gmailcom> wrote:
>
> In case you want to try the quick test (no need for 'high-quality' 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

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