pouët.net

Go to bottom

Time to solve a hard math problem

category: general [glöplog]
So, spherical harmonics are fun! They're more fun with a parallax shader on them. I made that. Yay me!
BB Image
BB Image
But, for the last 17 years, Paul Bourke has had the question of a closed-form solution for a bounding box to his Eval function. Is there one? Is there a way to normalize this spherical harmonic shape generation to fit in a unit cube?
http://local.wasp.uwa.edu.au/~pbourke/surfaces_curves/sphericalh/
It'd make it easier to include these shapes in a demo, and especially in a viz. I honestly don't think there is one.
Here's the C code. The m array is a bunch of positive numbers. The geometry doesn't have any discontinuities at non int values, but it still looks nifty.
Code: XYZ Eval(double theta,double phi, int *m) { double r = 0; XYZ p; r += pow(sin(m[0]*phi),(double)m[1]); r += pow(cos(m[2]*phi),(double)m[3]); r += pow(sin(m[4]*theta),(double)m[5]); r += pow(cos(m[6]*theta),(double)m[7]); p.x = r * sin(phi) * cos(theta); p.y = r * cos(phi); p.z = r * sin(phi) * sin(theta); return(p); }


Now, if I were generating the shape in CPU and sending the geometry to the card, it'd be easy. I'd just keep track of the largest value and scale. Except I'm generating this in shader code, so each vertex only knows about itself. Any ideas?
added on the 2007-09-24 07:04:54 by GbND GbND
Quote:
The geometry doesn't have any discontinuities at non int values

Oops, meant to say 'Although the geometry has a discontinuity at non int values...'
added on the 2007-09-24 07:12:17 by GbND GbND
r= min(abs(sec(theta)), abs(csc(theta)), abs(sec(phi))) is more interesting.
and i guess
r = min(abs(sec(theta)) * abs(csc(phi)), abs(csc(theta)) * abs(csc(phi)), abs(sec(phi)))
is a cube. haven't tried it though.
Uhmm.. aren't those blobs fairly boring, though?
added on the 2007-09-24 10:34:44 by doomdoom doomdoom
doom: thats easily repaired with some hypnoglow.
added on the 2007-09-24 10:45:13 by psenough psenough
They're boring if they're static. I'm changing all 8 params each frame just sending floats to global shader memory, so it's all a matter of feeding those parameters with enough chutzpah.
added on the 2007-09-24 10:50:32 by GbND GbND
Oh, and about fitting the blobs in the unit cube, replace your last line with:

return(p/4);

Voila! \o/ You are teh welcome.
added on the 2007-09-24 10:59:42 by doomdoom doomdoom
No, sorry, they're also boring when they move. It's just been done way too much. And doing it with a shader doesn't make it look any less cheap. Why not do something with implicit surfaces? Or iterative geometry, or modelled mesh based geometry, or cleverly animated cubes, or, you know, tits.
added on the 2007-09-24 11:11:27 by doomdoom doomdoom
I kind of agree with doom.. plasmaballs are just dull, no matter how they move.
added on the 2007-09-24 11:14:18 by Preacher Preacher
can we leave the effect boredometer discussion for another thread and focus on the math problem? :D
added on the 2007-09-24 11:27:59 by psenough psenough
I'm somewhat nonplussed by the fact that Preacher of all people got into that math vs boredom quagmire. You're supposed to be the math-o-meter guy, damn you.
added on the 2007-09-24 11:31:35 by Shifter Shifter
That's what they all think. I never understood why.

As for the original question, I can't think of any obvious way. Constrainting the parameters would do the trick, but that would effect the shape.
added on the 2007-09-24 11:41:53 by Preacher Preacher
why don't you just do a coarse version of the mesh on the cpu just to get an estimate on the bounding box?
added on the 2007-09-24 12:01:33 by Hyde Hyde
Just use some numerical methods and solve the damn equation :D
And yeah, discontinuities are some evil bitches.
added on the 2007-09-24 12:15:40 by xernobyl xernobyl
The discontinuity is on the boundary of the interval (0 < th < 2Pi, 0 < phi < Pi), so you can differentiate, and the resulting equations aren't unsolvable (at the very least you can find arbitrarily precise approximate solutions). You can also trivially do the same along the rectangular boundary, so all it takes is a huge amount of work and you'll have a routine that's probably a little bit dodgy, only works in some cases (positive powers only etc.), and at the end of the day it's probably way slower than just generating a highly detailed mesh with the GPU.

Real question is, why would you even want to normalize the blobs?
added on the 2007-09-24 12:37:05 by doomdoom doomdoom
And why the unit cube? The unit sphere would make more sense, and it'd simplify the problem a lot.
added on the 2007-09-24 12:46:55 by doomdoom doomdoom
Quote:
And why the unit cube? The unit sphere would make more sense, and it'd simplify the problem a lot.

guess his engine is optimized for boxes and not both spheres and boxes..
added on the 2007-09-24 15:04:57 by psenough psenough
But the unit sphere itself fits perfectly inside the unit cube. So by normalizing r you make sure that (x,y,z) fit within the unit cube, while resizing the blob in a way that "makes sense" and/or "looks natural", given that it's inherently a sphere, not a box. A blob that could've reached the corners of the unit cube will still occupy most of it if you normalize r. What sort of optimization wouldn't work then?
added on the 2007-09-24 15:28:49 by doomdoom doomdoom
hmm.. right.
added on the 2007-09-24 15:44:40 by psenough psenough
first, doom is right, fitting it inside the unit sphere should be far easier because the expression is in polar coordinates anyway and you just need to normalize r.

second, the phi/theta terms are completely independent of each other, so you can treat them separately and combine the results (yummy, 2 1D problems instead of 1 2D problem). in this particular case, you just need minima/maxima of the terms of r depending on theta/phi. so say you have theta_min, theta_max, phi_min, phi_max. then the overall minimum radius is reached at (theta_min,phi_min) and the overall maximum radius is reached at (theta_max,phi_max). since r could possibly get negative, you need both; you're interested in the maximum absolute value of r, and that could be maximal at either of those two points.

third, you can now compute the extremal points for the terms depending on theta/phi. you could do it analytically, but for high values of the even m's there'll probably be a shitload of critical points in the search interval, which kinda sucks if you want to do it numerically. btw, discontinuities my ass, the function you are trying to maximize is well-defined on R^2 and continuous everywhere as long as you keep the odd m's >=0 - of course the surface generated by that function isn't necessarily continuous when you stitch it together, but that doesn't mean squat because you only really care about maxima of r depending on (theta,phi), and r is perfectly well-behaved on [0,2pi]x[0,pi].

anyway, analytically solving it isn't the best option (see above), but you know how you're going to tesselate your mesh, and you can solve for theta_min/_max and phi_min/_max independently, so you basically just need to execute two loops: (pseudocode)

Code: float r_phi_max = -4.0f, r_phi_min = 4.0f; for(int i = 0; i < res_v; i++) { float phi = i * PI / res_v; float r = pow(sin(m[0]*phi),(double)m[1]); r += pow(cos(m[2]*phi),(double)m[3]); r_phi_max = max(r_phi_max,r); r_phi_min = min(r_phi_min,r); } float r_theta_max = -4.0f, r_theta_min = 4.0f; for(int i = 0; i < res_u; i++) { float theta = i * 2 * PI / res_u; float r = pow(sin(m[4]*theta),(double)m[5]); r += pow(cos(m[6]*theta),(double)m[7]); r_theta_max = max(r_theta_max,r); r_theta_min = min(r_theta_min,r); } float r_max = max(r_theta_max + r_phi_max, -r_theta_min-r_phi_min); // normalizing factor is 1/r_max


which is res_u+res_v runs through these loops. should be reasonable for practical values of res_u/res_v and has the advantage that it's actually the exact value you need for the mesh you're getting.

hope that helps.
added on the 2007-09-24 16:35:45 by ryg ryg
I still like those spherical coordinate 3d shit no matter how many times I have seen them before. No sucks for me!
added on the 2007-09-24 17:20:08 by Optimus Optimus
threads like this make me realise how much i'm not a democoder.
added on the 2007-09-24 17:29:06 by skrebbel skrebbel
skrebbel: its ok, you dont need to be a democoder. we all know musicians code better demos anyways. like that bloke from j'ecoute.
added on the 2007-09-24 19:02:03 by psenough psenough
Oh, my previous statement was wrong.

And so is ryg's, although he is right about the theta and phi terms being independent (and that you can solve for each independently of the other).

But the function is not well-defined on R^2. x^y evaluates to an imaginary number when x is negative and y is fractional. And the range of sin and cos is [-1..1]. I dunno what pow() does in that case though.
added on the 2007-09-24 20:40:17 by doomdoom doomdoom

login

Go to top