Title: Calculating normals Post by: ZsquaredplusC on November 20, 2009, 03:30:22 AM Was there any progress on a formula to determine a normal once a point in 3D space is found?
ie you churn through the iterations and get an XYZ point in space. how do you guys calculate a normal for the point for lighting the point? Options I can see are; 1. Use the north, west and current pixel and use that as a polygon for normal calculations. Because the north and west points have been calculated if you are going top to bottom and left to right while generating the image. 2. Send out another set of rays for each point very slightly askew from the calculated point to use them to get a normal (but this means you need another 3 rays per pixel). Any ideas/advice? Title: Re: Calculating normals Post by: David Makin on November 20, 2009, 03:58:08 AM Was there any progress on a formula to determine a normal once a point in 3D space is found? ie you churn through the iterations and get an XYZ point in space. how do you guys calculate a normal for the point for lighting the point? Options I can see are; 1. Use the north, west and current pixel and use that as a polygon for normal calculations. Because the north and west points have been calculated if you are going top to bottom and left to right while generating the image. 2. Send out another set of rays for each point very slightly askew from the calculated point to use them to get a normal (but this means you need another 3 rays per pixel). Any ideas/advice? If our found point is vp+alpha*vcentre has distance estimate decentre from inside where vp is the viewpoint, alpha is the distance stepped and vcentre is the direction vector then I get the 4 adjacent distance estimates at vp+alpha*vleft, vp+alpha*vright, vp+alpha*vtop, vp+alpha*vbottom which gives me 5 points at vp+(alpha+decentre)*vcentre, vp+(alpha+deleft)*vleft etc. and then use the 4 triangles from the 5 points to compute the normals by summing the 4 unnormalised normals and normalising the result. Note that I do do some limited extra ray stepping (backwards) if the adjacent points are found to be truly "inside" in order to get a valid DE value obviously adjusting the calculations accordingly. I do all 4 adjacent points to allow restriction of the extra ray-stepping which means that occaissionally one or more adjacent point values are invalid. The 4 adjacent rays I use by default are at 1/2 pixel offsets. If not using UF, or if using a global buffer in UF then it would perhaps be slightly more optimum to use whole pixel offsets for the adjacent rays. This method is vastly superior to using the actual surface found method :) Title: Re: Calculating normals Post by: David Makin on November 20, 2009, 04:27:03 AM As to getting the normal analytically, I think iq is working on it:
http://www.fractalforums.com/3d-fractal-generation/true-3d-mandlebrot-type-fractal/msg8595/#msg8595 (http://www.fractalforums.com/3d-fractal-generation/true-3d-mandlebrot-type-fractal/msg8595/#msg8595) Though given that he mentions the Jacobian I'm guessing that it may be a little complicated and possibly less optimum than other methods :) Title: Re: Calculating normals Post by: fractalrebel on November 20, 2009, 05:00:36 AM My first step is to calculate the array that forms the fractal surface. The normals are then calculated from the x, y and z vectors to the immediately neighboring points.
Title: Re: Calculating normals Post by: ZsquaredplusC on November 20, 2009, 05:27:07 AM Thanks guys.
If iq can get a formula running that will be interesting. Even if it turns out somewhat complex it may be less processor intensive that shooting an extra 4 rays per pixel. I will have a go at no extra rays and using the immediate neighbours then and see if it loses anything in detail. Title: Re: Calculating normals Post by: lycium on November 20, 2009, 06:33:00 AM using extra rays is basically incorrect (and outrageously inefficient besides); the gradient of the potential function is the (un-normalised) normal, or at least the finite difference approximation to it.
Title: Re: Calculating normals Post by: JosLeys on November 20, 2009, 07:21:24 PM Quote using extra rays is basically incorrect (and outrageously inefficient besides); the gradient of the potential function is the (un-normalised) normal, or at least the finite difference approximation to it. I've been trying to do this without success. How do you derive the x,y,z components of the gradient to form a normal vector?Title: Re: Calculating normals Post by: lycium on November 21, 2009, 04:50:37 AM i use a finite difference approach as mentioned, and it's the worst-behaved bit of numerical code i've ever written :-\
to approximate the normal at a point p, you get the potential at p, then three potentials at a "small" (herein lies the problem) offset along each dimension. then your grad vector is <px - p0, py - p0, pz - p0> where pxyz are the potentials at the offset locations. this is a first order finite difference approximation, pick up any numerical methods book to find better appoximations (bearing in mind that they assume the existence of higher derivatives, i.e. greater smoothness). Title: Re: Calculating normals Post by: ZsquaredplusC on November 21, 2009, 05:17:14 AM Can you share a snippet of code. ie going from the 3d point calculated on the surface up to the point the normals found?
Why does the "small amount" cause issues? I would assume that like when shooting more rays to get a normal, you step half the distance to the next pixel? I have gotten the basic rendering working, but the excess of 5 rays per pixel is killing rendering time. Title: Re: Calculating normals Post by: lycium on November 21, 2009, 05:29:26 AM if your potential function is p(x,y,z),
p0 = p(x,y,z) px = p(x + d, y, z) py = p(x, y + d, z) pz = p(x, y, z + d) then your normal vector is normalise(px - p0, py - p0, pz - p0) the trouble with the delta d is that you want it to be as small as possible, but if you make it too small then you destroy all the floating point precision in the estimate. see for example http://en.wikipedia.org/wiki/Numerical_differentiation#Practical_considerations this is exacerbated by the fact that our function p isn't some nice x^2 + 2x or whatever, it's this nasty fractal function :-\ Title: Re: Calculating normals Post by: lycium on November 21, 2009, 05:38:10 AM whoops, just fixed a copy-paste error in my post above.
Title: Re: Calculating normals Post by: ZsquaredplusC on November 21, 2009, 06:15:01 AM OK, but what is the potential function? How do we get from the XYZ point in space to the potential?
These posts have stirred a lot of interest so hopefully there will be someone reading with the smarts to work out how to automatically find the optimal d value? Title: Re: Calculating normals Post by: reesej2 on November 21, 2009, 07:10:40 AM I've been diverting around the problem of calculating normals by just assuming that each "pixel" is a separate, very small sphere. Unfortunately, while this does make a somewhat 3D effect, it's not nearly the quality of the images I've seen. I'd be interested to see an efficient way of calculating the normal vector. Alternatively, any ideas on how to improve the sphere strategy would be welcome...
Title: Re: Calculating normals Post by: JosLeys on November 21, 2009, 11:40:15 AM OK Lycium, I think I know what you mean. See the sketch below for the 2D analogy. Is my assumption correct ?
So in 3D you need the analytical distance estimate in three extra points. I will try this.. What I have been doing is shooting 4 extra rays. If the point on the surface is VP+t.V (VP=viewpoint, V=vector), I take VP+(t-epsilon).Vi (Vi =vector with slight offset, epsilon=something small). So I go back just a small distance on the ray so that finding the intersection points for the vectors Vi goes very fast. (but I have to calculate the normalised vectors Vi of course) Title: Re: Calculating normals Post by: lycium on November 21, 2009, 12:01:04 PM um, it is with some embarrassment that i must admit, i have no idea what's going on in that picture ???
think of it this way: your potential function is zero when you're on the surface. the grad vector tells you in which direction the function is growing most rapidly; this is exactly what the normal vector is: it points "away" from the surface (i.e. the direction in which the function most quickly goes from zero to a positive number). Title: Re: Calculating normals Post by: David Makin on November 21, 2009, 12:20:28 PM Can you share a snippet of code. ie going from the 3d point calculated on the surface up to the point the normals found? Why does the "small amount" cause issues? I would assume that like when shooting more rays to get a normal, you step half the distance to the next pixel? I have gotten the basic rendering working, but the excess of 5 rays per pixel is killing rendering time. If you're using the method I suggested (which is basically the same as lyciums actually except that it's his method *combined* with the surface method) then the overhead for getting the points on adjacent rays should be negligible - if not then you're ray-tracing on the adjacent rays when you shouldn't be. Title: Re: Calculating normals Post by: lycium on November 21, 2009, 12:33:18 PM *ahem* it's not the same method at all, consider the behaviour of the "multiple rays" approach on the object silhouette and at visibility boundaries...
Title: Re: Calculating normals Post by: David Makin on November 21, 2009, 12:53:40 PM *ahem* it's not the same method at all, consider the behaviour of the "multiple rays" approach on the object silhouette and at visibility boundaries... Huh ? Remember I'm *not* ray tracing the adjacent rays, just using them to get my offset positions (using the position on the adjacent rays that's the same distance as the centre point from the viewpoint) - this is basically what you're doing except using different offsets. Also I should add that since my previous post where I said "I do do limited tracing if the adjacent point is 'inside'" I have stopped doing that because I realised that generally the calculated DE value is OK to use even if we reached max iterations (as long as we aren't *too* far 'inside') - this point was brought home by the recent renders of the "Mandeliers" (I tried rendering them and found I couldn't because as soon as max. iter was hit my algorithm said "solid found"). BTW - is it just me or are the Mandeliers just a figment of the distance estimator's imagination, as I recall for Mandelbrots of negative power everywhere should be "inside" ? Title: Re: Calculating normals Post by: David Makin on November 21, 2009, 12:55:53 PM Can you share a snippet of code. ie going from the 3d point calculated on the surface up to the point the normals found? Why does the "small amount" cause issues? I would assume that like when shooting more rays to get a normal, you step half the distance to the next pixel? I have gotten the basic rendering working, but the excess of 5 rays per pixel is killing rendering time. If you're using the method I suggested (which is basically the same as lyciums actually except that it's his method *combined* with the surface method) then the overhead for getting the points on adjacent rays should be negligible - if not then you're ray-tracing on the adjacent rays when you shouldn't be. I did some timings with and without lighting and got 1:54 and 1:49 with and 1:54 and 1:48 without. (for "with" I mean without shadow-tracing). Title: Re: Calculating normals Post by: JosLeys on November 21, 2009, 01:37:04 PM Sorry if it was not clear :
The blue triangle represents the surface. P is a point on the ray. The potential function is the distance to the surface.(which is zero on the surface) So we take two other points, a distance d away in the x and y directions, and mesure the distance there. The differences in distances give the surface normal components.. Title: Re: Calculating normals Post by: subblue on November 21, 2009, 06:25:09 PM I've been following the Mandelbulb discussion for a few weeks and have a GPU implementation working using Adobe Pixel Bender, but haven't yet managed to generate clean normals. I've been attempting to create a Jacobian matrix that Iq mentioned (http://www.fractalforums.com/3d-fractal-generation/true-3d-mandlebrot-type-fractal/msg8595/#msg8595) (further discussion in GPU gems (http://http.developer.nvidia.com/GPUGems/gpugems_ch42.html)), but without any success yet.
Below are the differentials defined by Mathematica and the code used to calculate it. I thought I'd share it in case anyone else can shed some light. (http://www.subblue.com/assets/misc/jacobian.png) (http://www.subblue.com/assets/misc/jacobian.png) So in principle using the code below the normal should be created with n = normalize(Jacobian(z) * z), where z is the intersection point: Code: float3x3 Jacobian(float3 z) I'd be interested to see Iq's approach to this ;) Title: Re: Calculating normals Post by: David Makin on November 21, 2009, 06:43:02 PM Maybe I'm missing something here ?
*But* isn't it true that you need the Jacobian for the actual equaton for the point found ? In which case in order to get the correct Jacobian you have to iterate it in a similar way to getting the derivative ? i.e. You can't simply use the Jacobian for the Mandelbulb z^b+c, you have to use the Jacobian for the equation of the nth iteration of the formula. At least that's what I thought and is the reason I abandoned using the analytical method for getting the normal. Title: Re: Calculating normals Post by: cKleinhuis on November 21, 2009, 06:58:08 PM just a note, you can use LaTeX inside posts !
like: Title: Re: Calculating normals Post by: fractalrebel on November 21, 2009, 07:02:44 PM Sorry if it was not clear : The blue triangle represents the surface. P is a point on the ray. The potential function is the distance to the surface.(which is zero on the surface) So we take two other points, a distance d away in the x and y directions, and mesure the distance there. The differences in distances give the surface normal components.. Hi Jos, Thats essentially the method I use, except I chose 4 neighboring points and determine the normals in pairs, and finally averge the normals to get a better approximation to the "true" normal. This adds very little overhead. Most of the calc time is for determining the fractal surface. Title: Re: Calculating normals Post by: fractalrebel on November 21, 2009, 07:04:58 PM just a note, you can use LaTeX inside posts ! like: <Quoted Image Removed> Thanks! That will be vary useful. Title: Re: Calculating normals Post by: Buddhi on November 21, 2009, 09:40:03 PM With DE I think it's quite simple to calculate normal vector because we can calculate some central differences or gradient of potential function. But what we can do when calculating of DE is impossible, for example for some strange non-linear fractal formulas? Now I know only one method. It is not so fast but gives very accurate and smooth normals (fractal details are also sharp). It is something like central difference but average for some area.
Code: for (double xx = -1.0; xx <= 1.0; xx += 0.2) Maybe someone knows any other universal algorithm. I tried to found something in Internet but without result. Title: Re: Calculating normals Post by: David Makin on November 21, 2009, 10:04:58 PM @lycium:
Here's the difference in the DE angles found using essentially the same method I'm using in 3D and the analytical method on the good old complex 2D Mandy, just compare the 2 layers, granted it's not perfect but it is pretty close: Code: Fractal2 {Just to add that you'll notice there are significant differences if you zoom in but if you put another layer of the Mandy on top using my class "Field estimator" outside colouring in distance estimator "distance" mode and use a solid black "outside" with opacities set such that the black area only appears closer than a certain distance away from inside and then leave that layer on and turn the middle layer on and off to see the two different DE angle colourings you should see that the method I use matches the actual outline of the DE at the threshold set by the transparency in the top layer whereas the analytical angle is showing the angle based on true inside - obviously in 3D the former is a better option i.e. the DE angles and hence the normals should match the shape of the actual rendered solid not the shape of the true "inside". Title: Re: Calculating normals Post by: David Makin on November 21, 2009, 10:34:36 PM With DE I think it's quite simple to calculate normal vector because we can calculate some central differences or gradient of potential function. But what we can do when calculating of DE is impossible, for example for some strange non-linear fractal formulas? Now I know only one method. It is not so fast but gives very accurate and smooth normals (fractal details are also sharp). It is something like central difference but average for some area. Maybe someone knows any other universal algorithm. I tried to found something in Internet but without result. My delta DE distance estimation method can be used in such cases (provided you can get an accurate smooth iteration value) essentially the same way as using the analytical DE *except* you obviously can't use the analytical calculation for the normal you can only use either the solid surface found or the central difference method. Note that my current formula for UF uses exactly the same method to get the normals for both analytical DE and delta DE i.e. get the DE values at the points at the same distance from the viewpoint as the central point on adjacent rays giving 5 points including the central point, assume all 5 DE values are perfect *and* along the relevant rays and calculate the normal using the assumed surface points. Title: Re: Calculating normals Post by: David Makin on November 22, 2009, 12:13:08 AM With DE I think it's quite simple to calculate normal vector because we can calculate some central differences or gradient of potential function. But what we can do when calculating of DE is impossible, for example for some strange non-linear fractal formulas? Now I know only one method. It is not so fast but gives very accurate and smooth normals (fractal details are also sharp). It is something like central difference but average for some area. Maybe someone knows any other universal algorithm. I tried to found something in Internet but without result. My delta DE distance estimation method can be used in such cases (provided you can get an accurate smooth iteration value) essentially the same way as using the analytical DE *except* you obviously can't use the analytical calculation for the normal you can only use either the solid surface found or the central difference method. Note that my current formula for UF uses exactly the same method to get the normals for both analytical DE and delta DE i.e. get the DE values at the points at the same distance from the viewpoint as the central point on adjacent rays giving 5 points including the central point, assume all 5 DE values are perfect *and* along the relevant rays and calculate the normal using the assumed surface points. Just to add that to get an accurate smooth iteration value for more esoteric formulas e.g. involving transcendentals or conditionals then see here: http://www.fractalforums.com/3d-fractal-generation/re-true-3d-mandelbrot-type-fractal/msg8714/#msg8714 (http://www.fractalforums.com/3d-fractal-generation/re-true-3d-mandelbrot-type-fractal/msg8714/#msg8714) In even worse cases then you can use exponential smoothing (with appropriate scaling adjustments) in the delta DE method as an alternative to iteration smoothing, the only real drawback? with that is that it is generally a noticeably different outline to either solid on iteration or solid on DE based on potential/iteration. Title: Re: Calculating normals Post by: gaston3d on November 23, 2009, 10:18:45 PM Hi, all methods based on gradient requires smooth potential function which is very hard or impossible to get when formula function is true/false only. I use method like this (2D equivalent, see picture): 1. raytrace R(t) by small "dt" values (~1e-3) until hit the object (blue line), then fine tune hitpoint using bisection method until |R(t1)-R(t2)|<epsilon (~1e-9) 2. create small "cube" around hitpoint getting four points ABCD (8 points in 3D case); parameter N~100 gives size of the cube around ~2*1e-7 3. search points P1, P2 on the surface - bisection between proper point pairs (one "in" one "out"); in 3D case, it may sounds weird, there can be 12 points (not belonging to the same surface...) 4. having set of points on the surface calculate normal as average of partial normals (perpendicular to green lines, or triangles in 3D case) "cloud" set of points on the surface can be used in another methods: 1. approxiamte points by ordinary plane using least squares method; having plane equation, normal vector is trivial (hard...) http://www.infogoaround.org/JBook/LSQ_Plane.html (http://www.infogoaround.org/JBook/LSQ_Plane.html) 2. make local analytical parametric surface R(u,v) and calculate partial derivatives (dR/du, dR/dv) that leads to exact normal vector (very hard I think...) http://en.wikipedia.org/wiki/Parametric_surface#Notation (http://en.wikipedia.org/wiki/Parametric_surface#Notation) I've used method described by David in Reply #1 some time ago and results were fine (x & y +/- 0.25 of a pixel). It's not necessary to raytrace 4 rays from camera location, you can use ray distance "t" from central point and trace surrounding 4 rays forward or backward. One disatwantage is when central point is on the edge of the object, then one of additional points can miss the fractal and you raytrace till hit the bounding sphere or other far part of the object. Title: Re: Calculating normals Post by: David Makin on November 24, 2009, 12:39:13 AM One disatwantage is when central point is on the edge of the object, then one of additional points can miss the fractal and you raytrace till hit the bounding sphere or other far part of the object. I now just assume the DE values from the 4 adjacent points are correct and don't do any extra ray-tracing at all, this doesn't seem to cause any issues. Title: Re: Calculating normals Post by: Snakehand on December 11, 2009, 11:28:11 AM I have implemented my own GPU renderer from scratch, and use a "quaternion fitting" to find normals. Here is an image rendered with flat ambient + diffuse and specular from a single point light source. (http://traxme.net/fractal/MBdetail3.png) The fitting picks a random (fixed) incidental vector to the point, and searches for a rotation around this axis that brings a small perpendicular displacement flush with the boundary. The process is then repeat using the vector that has been found to be flush with the surface, and the dot product of the two flush vector gives the normal. |