PP2014 Material Room Math_Functions Nodes - No atan, asin, acos ?
I've run into this problem a few times before while playing with ideas and decided it's time to ask rather than abandon again.
I wish to convert the 2D cartesian u and v variables (for a point on the UV map) to 2D spherical/cylindrical r and ϴ, which is really quite simple:
r = sqrt (u^2 + v^2)
ϴ = atan(u/v)
But not so simple without any inverse trig functions.
Any thoughts ?
I did consider a sort of binary chop estimation, something along these lines.
Assume a ϴ in the range 0 to 90deg and using ϴ = asin(u/sqrt (u^2 + v^2)) rather than ϴ = atan(u/v). Sin has a -1 to +1 range allowing a binary chop to quickly (10 or so iterations?) close in on the correct result, whereas the infinite range of tan would pose a problem.
First calculate (u/sqrt (u^2 + v^2) and then compare that to sin(45deg)
If it's bigger then compare it to sin(45+22.5), if smaller compare with sin(45-22.5).
Etc, with 11.125, 5.5625, 2.78, ... until I'm within some arbitrary tolerance.
I think that can be done with nodes ?
Hopefully somebody has a better idea.
The math room is not very good at loops unless you hard-code the number of iterations.
For what it is worth: check
for approximations if u/v is between -1.0 and 1.0
obviously the more terms you use, the slower it will become.
Thanks for those. Following your lead I did a bit of googling and with the keywords "arcsine approximation" found "A Guide To Approximations" at www.ganssle.com/approx/approx.pdf. I need to double-check that I understand the maths, but I think the atan_66 apoproximation there should do me.
There were two threads at RDNA that addressed conversion to polar coordinates - too bad they're gone.
I found the formula we used for arcsin on this page, formula 4.4.45
Unfortunately the implementation of circular bricks that first caused the discussion is lost.
I see the atan_66 you found is going to work well, too.
Damn you. I was curious as to whether these approximations from the 50's and 60's could be improved upon. After all, my desktop computer is probably a trillion times more powerful than the best university computers back then.
So - I decided to assemble a Genetic Algorithm program that could be used to optimize the numerical values in any approximation. It works beyond my wildest dreams.
At first I found some modest improvements of existing expressions. But so many of the approximations involve polynomials. The definition of polynomial is that all terms with exponents have only positive integer exponents (like 0, 1, 2, 3). I wondered if relaxing the conditions and permitting real exponents (like 1.5353 and 3.9994353) would give better solutions.
My very first run of the GA produced a 10-fold increase in one of the oft-quoted arcsin approximations, without any change in the form, just changing the coefficients and exponent values!!!!
I'm so distracted from anything else. This is fascinating.
Here are four formulae.
Y4 is the published formula 4.4.45, scaled to produce output of 0 to 1 instead of 0 to Pi/2.
Y6 is the same exact form but I let my GA solver come up with these numbers. Y4 and Y6 cost the same to calculate, but the results are vastly different.
Y1 (off screen) is the actual Arcsin x divided by Pi/2. So Y5 and Y7 are going to show the magnitude of the deviation between each approximation and the correct values.
Here is the resulting graph of Y5 (red) and Y7 (green). The Y6 approximation is WAY better.
The black line is the superposition of the two approximations, in red and green. Where they appear to overlap it is black. They are so close we can't visually tell the difference at this scale.
Here I've zoomed in on the actual graphs of the correct value (blue dash) the published approximation (red) and my improved approximation (green).
The difference is astonishing.
The x range here is .80146 to .80158, which is a difference of .00012, so the magnification is about 8333 x.
The GA is still running and it just found an even better solution. It's incredible how it works.
It has NO IDEA what it's doing, it's just evolving a population of genomes (a list of numbers) with sexual (two-parent) reproduction mixing the genetic material and occasional mutation spontaneously changing a gene or two of an offspring. The selection of parents for reproduction is biased towards genomes that are a better match to the arcsin equation. The population is only 25 individuals, which is surprising to me.
Also on each generation, the worst performing individuals are culled and replaced with completely random genomes. These "monsters" usually die immediately, but some have led to extremely sudden improvements. They mostly have an effect on rapid improvement at the beginning. Once a decent subset of the population settles near an optimum, the monsters do nothing. The slower evolutionary processes of reproduction and mutation refine the solution, getting ever closer to some unknown minimum error.
I'd got as far as:
(1) putting the atan_66 stuff into a spreadsheet to help visualize how it worked
(2) realizing that if O (opposite) and A (adjacent) are both positive, then if O<A use ϴ=atan(O/A) which gives 0° to 45°, and if O>A use ϴ=π-atan(A/O) which gives 45° to 90°.
(3) realizing that the atan approximation only needs to be valid for input values in the range 0 to +1 (results of 0° to 45°), since input values of +1 to +∞ can be converted to the +1 to 0 range by simply taking the reciprocal.
(4) knowing that if I have separate values O and A rather than just a single value O/A then the signs of O and A give the quadrant.
And I thought that I was doing well !
I think you are doing perfectly well. The result of a shader is the color of a pixel. Depending on the situation the effect of greater accuracy may well be below the visible limit.
Like I said we solved the atan2 problem for Poser almost 10 years ago and the solution was DELETED. We used it to draw circular bricks, and the accuracy of the approximation was clearly visible in that use case, since it made the mortar along the radials wobbly.
I've evaluated that atan_66s algorithm and it's EXTREMELY good. We didn't know about that one at the time.
I've been hunting my hard drive for the matmatic file containing the previous solution and I just can't find it. I'm 4 hard drives removed from then. I'd have to go dig up an archive disk to find it.
I found a piece of the original matmatic script that does tha arcsin in unit form -- but in a different file unrelated to doing atan2. I know we did all the symmetry junk to connect the two but that's the part I can't find.
def aSinU(x): x = Clamp(x) p2 = pi / 2 a0=1.5707288 / p2 a1=-0.2121144 / p2 a2=0.0742610 / p2 a3=-0.0187293 / p2 x2 = x * x x3 = x2 * x return (1 - sqrt(1 - x) * (a0 + a1*x + a2*x2+ a3*x3))
@F_Verbaas Thanks! :) The "and I thought that I was doing well" bit was simply a comparison of the speed at which I work to the speed at which bagginsbill works !
@bagginsbill I can't help picturing a secret island somewhere in your runtime where you're now breeding/genetically engineering mathematical approximations.
Here's the simplest set of nodes that I can come up with for converting an atan result in the range 0 to π/2 (0 to 90°) to a full 2π (360°) range using the signs of opposite and adjacent to determine quadrant. I think I've got the logic correct?
(The Atan2_Approximation compound node is just a placeholder for whatever approximation I end up using)
Not sure how you'd do the quadrant stuff for asin(O,H) and acos(A,H) since unlike the opposite and adjacent the hypoteneuse doesn't really have a meaningful sign.
@3dcheapskate and @bagginsbill this is an amazing use of nodes. Wouldn't it be nice though if we had a user defined math node that we could set a path to a .py / .pyc file that implemented a defined interface that we could program however we wanted, say taking in an array of values and returning a transmuted array as output. I realise it wouldn't be fast but it would allow us to create our own logic in a single node rather than having to do the "logic" using other nodes.
I think bagginsbill has been pushing (unsuccessfully) for a user-defined node for the material room since way back !
@3dcheapskate That doesn't surprise me :) I'm guessing they wouldn't do it because of the potential support calls it might generate if people used it without understanding the implications.