I implemented an ImplicitObject last night.
The formula of the implicit "equation" is expected to generate fine surface detail on the object.
However, so far my test renders are very smooth, with some detail showing, but more as lines on a flat surface rather than "ravines" and "mountains".
Now the most likely explanation is that my code/maths is wrong, but I wondered if the RTImplicitObject logic was even intended to be capable of rendering fine (and deep) surface detail?
Is there any assumption that the surface is effectively smoothed?
I can't see in the RTImplicitObject logic quite how the ray marching works, and so I can't see any place where the code resolves the precise location of the surface intersections.
On that point: I can't even see how the "tolerance" parameter works.
Changing it in the render settings certainly changes the level of detail shown in the "lines" rendered on my object's surface, but apparently not the depth of the detail.
Q: I assume that the tolerance parameter controls the march step in some way? - either the max step, the initial step, or the minimum step?
In my logic, I don't see any particular way I can use the "tolerance" parameter passed into getFieldValue(), as I can't return a modified intersection point as a result of "hunting" for a more precise intersection point in my code.
Any comments from those with more experience would be greatly appreciated :o)
Cheers!
Nik
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I have been playing with Implicit objects today too. I have been having a go at 3d Mandebrout (fractuals) with some very limited success. In this case its because a fractual does not have a well defined normal -espeially if its estimated with finite differences.
My attempts at adding a surface with moving averages etc failed in different ways. However none failed via lack of detail. I would guess the bug lies in your getField…..
> I have been having a go at 3d Mandebrout (fractuals)
*snap!* Me too!
ObNox posted some referencs to the MandelBulb (3D Mandelbrot) set in FriendlySkies, and I thought I'd have a go. Certainly AOI should be able to do it.
Your renders are far more reassuring than mine!
I certainly noticed that the normals are not good, but the bigger problem is that while the general patterns are sort of there, the surface is not 3D.
I've tried to implement the maths based on the (incomplete) formulae on a couple of sites, coupled with definitions of the 2D Mandelbrot set.
So far… not so good.
Thanks, I'll keep trying.
Cheers!
Nik
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Would you be prepared to share you code so far?
I would be interested in:
- comparing your getFieldValue() to mine
- packaging it as a plugin, as I have mine
- implementing spedups, as per trig-free speedups I've seen on the web
- experiments on furter imroving the normal calculation
- supporting texturing and colouring based on the escape value
Cheers!
Nik
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
> Q: I assume that the tolerance
> parameter controls the march step in
> some way? - either the max step, the
> initial step, or the minimum step?
Correct. This is done in RTImplicitObject. The tolerance is the size of each step.
> I don't see any particular way I can
> use the "tolerance" parameter passed
> into getFieldValue(), as I can't
> return a modified intersection point
> as a result of "hunting" for a more
> precise intersection point in my code.
You aren't supposed to hunt. What you are supposed to do is return the average value over a region of the specified size. That's how you avoid aliasing.
> So, what exactly is the meaning
> associated with points where the field
> value is equal to the cutoff value?
Those points are exactly on the surface.
> I have been having a go at 3d
> Mandebrout (fractuals) with some very
> limited success.
That's fantastic! I saw an article about it the other day, and thought it would be interesting to try implementing in AoI. I don't know how other people define the surface normal for it, but clearly they're doing something reasonable, since they manage to get nicely shaded surfaces.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
It seems some fine-tuning of my iteration get me started, and then the definition of the "gradient" has a large effect too.
Just what exactly is the gradient supposed to represent?
I inferred it was an indication of the total difference between the smallest and largest x, y, and z values within the area indicated by tolerance?
However, it seems to be having a large effect on the apparent normal that is being rendered?
I've written a "better" version of getFieldGradient(), but it is still miles from what I need, in visual terms…
In terms of the normal, what is supposed to happen?
Does RTImplicitObject calculate normals from surrounding surface points, or …?
Cheers!
Nik
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Q: What is the field value actually meat to represent?
I have been returning the iteration excape value, which indicates the degree of membership to the set. Basically, if this value is larger than the cutoff value, then the point is on or within the object.
Should I be returning something else instead??
If so what?
- The distance of the point from the object origin?
- other??
Cheers!
Nik
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I use a "repeated" doubling of the angles to avoid using any trig functions. So this is a "hypercomplex" implementation, and i think my spherical coords are a little different. What i return is a sampling of that. The best "surface" look is with a average of 27 samples per "grid" point. I then use trilinear interpolation. Its pretty slow, but then i didn't add proper gradient estimation, ie i left it doing the finite difference thing.
The gradient is the gradient of the field at that point. This is a vector. It is the grad operator (upside down triangle) in every sense in vector calculus. This will give the correct normal at the surface point.
Finally I am happy to give you all the code. But its a mess. The cache of the field values and the like is not finished and as i said i don't do field gradients properly. When i have a surface its painfully slow.
With "passthrough" -ie i directly sample the iteration function without any area parameters, cranking up the samples per pixel do almost as well as my surface code and is faster. This uses no caching.
So this was hitting the abandoned pile… esp since no one else would be interested in the plugin either.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
If you would either send me your code, or post it somewhere I could download it from, that would be awesome, thank you!
My evaluation function is doing pretty much the same as yours, (except I implemeted with the trig functions to begin with), so I'm really interested to see where the other differences are in the code.
(That being said, I'll compare mine to yours and see what differences there are in results.)
I did find that implementing my own gradient function improved the lighting of the render, but it also seemed to destroy some of the tiny amount of detail I was generating.
> The best "surface" look is with a average of 27 samples per "grid" point.
Is that 27 the result of performing a 9-times sample 3 times (as per your trisample)?
Is the 9-times iteration the iteration within the Mandelbud evaluation?
Ie, iterationLimit = 9?
I will try my improving sampler with a gradient function that calculates the normal, and see if that improves things.
However, I would also much prefer to combine parts of your code with parts of mine and produce a plugin that can be used by anyone else as well.
Judging by the posts in FriendlySkies and in this thread, I can see folks would enjoy messing with it :o)
Cheers!
Nik
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Note that this is just a pure dump of the code as is. Its hacky. Its broken. Its everything you probably don't want. However i won't get to look at it for a while since i will be germany next week.
In particular i don't save all the parameters with the serilization stuff, so the cutoff keeps getting set to zero. Cutoff should be set to iterations-1. or close to it.
Next if you put samples up much it will kill performance. we talking 2 hours on a dual core for a 400x300 pixel image and only 4samples AA.
There is a lot of dead code that was simply the wrong direction. Namly the gradient interpolation is rubbish. I would dump it, i get better results with the default.
Finally the cache is quite odd. Its a cuckoo hashing table that once it hits its storage limit, it deletes half the entries "approximately" and preferentially the oldest in access order. But its not done well yet…
Feel free to ask questions…
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I'm sure I will get a number of really useful answers from your code.
I'll let you know if I incorporated your code into my plugin, or bits of my code into yours! :o)
Thanks again, and I'm hoping I can publish something others can play with in a few days, or by the end of the week (this weekend is looking rather busy :o)
Thanks again!
Cheers!
Nik
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
>>I hereby put in the public domain<<
Thanks - I already play without success - all I got was an cube with many different properties settings. Now after re-reading your post and try again, I can see that the cutoff is maybe the parameter one shouldn´t forget!
Just 5 min. away from my first picture (on my old athlon - so it´s not that bad). Well done - lets burn some energy as long as it´s cheap…
Greetings
Harald
PS: Have fun in Germany
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thanks **a lot** for sharing your plugin and, especially, the source code! I'm pretty sure this will shed some light on the interesting parts. I need more spare time, though…
Greetings,<br>
TroY
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Okay. My main problem is to get a good distance estimator. What I mean with that is a function which, for a given point in space, estimates the distance to the fractal's "surface". Something like the <a href="http://www.devmaster.net/forums/showthread.php?t=4448">unbounding volumes we have for quaternion fractals</a> (there's a nice illustration). As far as I know, this is crucial in order to avoid dumb and slow raymarching with small step sizes.
Actually, my point in posting this on this forum is: How to realize such an estimator in AoI? Is that even possible without implementing an own raytracer class? I know, Nik already asked this, but: An ImplicitObject doesn't have any *direct* control over raymarching, does it? Say, "next step size will be 0.000123". At least, I can't see such a thing in RTImplicitObject.
BTW, I'm calculating my normal vector based on the last value for "r" (and doing the "finite difference thing" :)). In Bobs code above, that would be the "r2" used in "if (r2 > 4)". Doing it with the iteration count didn't work very well… Especially, it didn't work at all when doing bisection (in order to get very close to the "surface"), but that may be related to my raytracer - or me being stupid. :)
Greetings,<br>
TroY
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
great images. You got a hard surface look which is exactly what i was after.
You can infact get at least some control over what you want with the max gradient value. Peter added this at my request and can speed up the fluid raytracing by a large amount. It is the maxamium gradient that the function is expected to give anywhere in the field. A low value means the ray marching can use steps bigger than min Tol. Otherwise is marches with fixed steps.
However none of this would affect the final render. Only how long it takes. How did you get such a nice surface, as in a nice surface normal. (I get nice surface, but a "random" normal, that gives me more of a ray sampled Oren–Nayar Reflectance Model).
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
If you want fine control over how your object gets raytraced, you can do that by creating your own subclass of RTObject. The standard subclass used for implicit objects is RTImplicitObject, so you could probably start with that and then either subclass or modify it. Then you create a subclass of RTObjectFactory and register it as a plugin.
Peter
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thats a funny question Delt0r!
It´s your plugin! Fast and pretty accurate for my taste.
So to be honest I don´t know how "I" dealt with the normals,
because AoI has done it.
Sometimes I get the feeling I shouldn´t write in the dev section - especially when I only understand a fraction of what you´re talking about.
:(
HTH anyway
Harald
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi All,
I implemented an ImplicitObject last night.
The formula of the implicit "equation" is expected to generate fine surface detail on the object.
However, so far my test renders are very smooth, with some detail showing, but more as lines on a flat surface rather than "ravines" and "mountains".
Now the most likely explanation is that my code/maths is wrong, but I wondered if the RTImplicitObject logic was even intended to be capable of rendering fine (and deep) surface detail?
Is there any assumption that the surface is effectively smoothed?
I can't see in the RTImplicitObject logic quite how the ray marching works, and so I can't see any place where the code resolves the precise location of the surface intersections.
On that point: I can't even see how the "tolerance" parameter works.
Changing it in the render settings certainly changes the level of detail shown in the "lines" rendered on my object's surface, but apparently not the depth of the detail.
Q: I assume that the tolerance parameter controls the march step in some way? - either the max step, the initial step, or the minimum step?
In my logic, I don't see any particular way I can use the "tolerance" parameter passed into getFieldValue(), as I can't return a modified intersection point as a result of "hunting" for a more precise intersection point in my code.
Any comments from those with more experience would be greatly appreciated :o)
Cheers!
Nik
In fact, another question:
The documentation for ImplicitObject.getCutoff says:
> Get the cutoff value which defines the surface of the object. Points for which
> the field value is greater than the cutoff are inside the object.
So, what exactly is the meaning associated with points where the field value is *equal* to the cutoff value?
- the point is *outside* the object?
- the point is on the surface of the object?
Cheers!
Nik
I have been playing with Implicit objects today too. I have been having a go at 3d Mandebrout (fractuals) with some very limited success. In this case its because a fractual does not have a well defined normal -espeially if its estimated with finite differences.
My attempts at adding a surface with moving averages etc failed in different ways. However none failed via lack of detail. I would guess the bug lies in your getField…..
warning links are to cluttered websites.
Here it is without a surface:
http://tinypic.com/r/1zv9wna/6
and with a surface:
http://tinypic.com/r/5bbgcz/6
> I have been having a go at 3d Mandebrout (fractuals)
*snap!* Me too!
ObNox posted some referencs to the MandelBulb (3D Mandelbrot) set in FriendlySkies, and I thought I'd have a go. Certainly AOI should be able to do it.
Your renders are far more reassuring than mine!
I certainly noticed that the normals are not good, but the bigger problem is that while the general patterns are sort of there, the surface is not 3D.
I've tried to implement the maths based on the (incomplete) formulae on a couple of sites, coupled with definitions of the 2D Mandelbrot set.
So far… not so good.
Thanks, I'll keep trying.
Cheers!
Nik
Hi Deltor,
Would you be prepared to share you code so far?
I would be interested in:
- comparing your getFieldValue() to mine
- packaging it as a plugin, as I have mine
- implementing spedups, as per trig-free speedups I've seen on the web
- experiments on furter imroving the normal calculation
- supporting texturing and colouring based on the escape value
Cheers!
Nik
> Q: I assume that the tolerance
> parameter controls the march step in
> some way? - either the max step, the
> initial step, or the minimum step?
Correct. This is done in RTImplicitObject. The tolerance is the size of each step.
> I don't see any particular way I can
> use the "tolerance" parameter passed
> into getFieldValue(), as I can't
> return a modified intersection point
> as a result of "hunting" for a more
> precise intersection point in my code.
You aren't supposed to hunt. What you are supposed to do is return the average value over a region of the specified size. That's how you avoid aliasing.
> So, what exactly is the meaning
> associated with points where the field
> value is equal to the cutoff value?
Those points are exactly on the surface.
> I have been having a go at 3d
> Mandebrout (fractuals) with some very
> limited success.
That's fantastic! I saw an article about it the other day, and thought it would be interesting to try implementing in AoI. I don't know how other people define the surface normal for it, but clearly they're doing something reasonable, since they manage to get nicely shaded surfaces.
Ok,
It seems some fine-tuning of my iteration get me started, and then the definition of the "gradient" has a large effect too.
Just what exactly is the gradient supposed to represent?
I inferred it was an indication of the total difference between the smallest and largest x, y, and z values within the area indicated by tolerance?
However, it seems to be having a large effect on the apparent normal that is being rendered?
I've written a "better" version of getFieldGradient(), but it is still miles from what I need, in visual terms…
In terms of the normal, what is supposed to happen?
Does RTImplicitObject calculate normals from surrounding surface points, or …?
Cheers!
Nik
Woops!
I also mean to ask:
Q: What is the field value actually meat to represent?
I have been returning the iteration excape value, which indicates the degree of membership to the set. Basically, if this value is larger than the cutoff value, then the point is on or within the object.
Should I be returning something else instead??
If so what?
- The distance of the point from the object origin?
- other??
Cheers!
Nik
I was writing it as a plugin.
The "field value" is calulated in mine as follows:
private double fieldValue(double x, double y, double z) {
// if(true){
// return 1-x*x-y*y-z*z;
// }
double px =x;
double py =y;
double pz =z;
for (int count =0; count < iterationLimit; count++) {
double x2 =x * x;
double y2 =y * y;
double z2 =z * z;
double r2 =x2 + y2 + z2;
if (r2 > 4) {
// System.out.println("CycleOut:"+count);
return count - 1;
}
double r =Math.sqrt(r2) + EPS;
double rxy =Math.sqrt(x2 + y2) + EPS;
double sinPhi =z / r;
double sinTheta =y / rxy;
double cosTheta =x / rxy;
double cosPhi =rxy / r;
// now apply the double angle formular 3 times
for (int i =0; i < cascadeLevel; i++) {
double sin2Phi =2 * sinPhi * cosPhi;
double cos2Phi =cosPhi * cosPhi - sinPhi * sinPhi;
double sin2Theta =2 * sinTheta * cosTheta;
double cos2Theta =cosTheta * cosTheta - sinTheta * sinTheta;
sinPhi =sin2Phi;
sinTheta =sin2Theta;
cosPhi =cos2Phi;
cosTheta =cos2Theta;
}
r =Math.pow(r, 1 << cascadeLevel);
x =r * cosPhi * cosTheta + px;
y =r * cosPhi * sinTheta + py;
z =r * sinPhi + pz;
}
// System.out.println("NotOut:"+iterationLimit);
return iterationLimit;
}
I use a "repeated" doubling of the angles to avoid using any trig functions. So this is a "hypercomplex" implementation, and i think my spherical coords are a little different. What i return is a sampling of that. The best "surface" look is with a average of 27 samples per "grid" point. I then use trilinear interpolation. Its pretty slow, but then i didn't add proper gradient estimation, ie i left it doing the finite difference thing.
The gradient is the gradient of the field at that point. This is a vector. It is the grad operator (upside down triangle) in every sense in vector calculus. This will give the correct normal at the surface point.
Finally I am happy to give you all the code. But its a mess. The cache of the field values and the like is not finished and as i said i don't do field gradients properly. When i have a surface its painfully slow.
With "passthrough" -ie i directly sample the iteration function without any area parameters, cranking up the samples per pixel do almost as well as my surface code and is faster. This uses no caching.
So this was hitting the abandoned pile… esp since no one else would be interested in the plugin either.
mmm. If i use the size value… well i get too much AA about 30-40 pixels worth. Do i need to transform it with the local scaling matrix or something.
Hi Deltor.
If you would either send me your code, or post it somewhere I could download it from, that would be awesome, thank you!
My evaluation function is doing pretty much the same as yours, (except I implemeted with the trig functions to begin with), so I'm really interested to see where the other differences are in the code.
(That being said, I'll compare mine to yours and see what differences there are in results.)
I did find that implementing my own gradient function improved the lighting of the render, but it also seemed to destroy some of the tiny amount of detail I was generating.
> The best "surface" look is with a average of 27 samples per "grid" point.
Is that 27 the result of performing a 9-times sample 3 times (as per your trisample)?
Is the 9-times iteration the iteration within the Mandelbud evaluation?
Ie, iterationLimit = 9?
I will try my improving sampler with a gradient function that calculates the normal, and see if that improves things.
However, I would also much prefer to combine parts of your code with parts of mine and produce a plugin that can be used by anyone else as well.
Judging by the posts in FriendlySkies and in this thread, I can see folks would enjoy messing with it :o)
Cheers!
Nik
The jar that will work as a plugin with src included is here
http://www.cibiv.univie.ac.at/~greg/3dMandy.jar
Note that this is just a pure dump of the code as is. Its hacky. Its broken. Its everything you probably don't want. However i won't get to look at it for a while since i will be germany next week.
In particular i don't save all the parameters with the serilization stuff, so the cutoff keeps getting set to zero. Cutoff should be set to iterations-1. or close to it.
Next if you put samples up much it will kill performance. we talking 2 hours on a dual core for a 400x300 pixel image and only 4samples AA.
There is a lot of dead code that was simply the wrong direction. Namly the gradient interpolation is rubbish. I would dump it, i get better results with the default.
Finally the cache is quite odd. Its a cuckoo hashing table that once it hits its storage limit, it deletes half the entries "approximately" and preferentially the oldest in access order. But its not done well yet…
Feel free to ask questions…
Oh and that dogs breakfast of source code in the previous post, I hereby put in the public domain etc.
Thanks Bob - that's awesome!
I'm sure I will get a number of really useful answers from your code.
I'll let you know if I incorporated your code into my plugin, or bits of my code into yours! :o)
Thanks again, and I'm hoping I can publish something others can play with in a few days, or by the end of the week (this weekend is looking rather busy :o)
Thanks again!
Cheers!
Nik
>>I hereby put in the public domain<<
Thanks - I already play without success - all I got was an cube with many different properties settings. Now after re-reading your post and try again, I can see that the cutoff is maybe the parameter one shouldn´t forget!
Just 5 min. away from my first picture (on my old athlon - so it´s not that bad). Well done - lets burn some energy as long as it´s cheap…
Greetings
Harald
PS: Have fun in Germany
> all I got was an cube
Yes, but that cube rendered *really* quickly! :o)
Cheers!
Nik
Once more, Bob, this is great. :)
I've been into fractals for <a href="http://n-to-infty.deviantart.com/gallery/#Fractals">some time</a> but I haven't heard of that mandelbulb until ObNox posted it.
Thanks **a lot** for sharing your plugin and, especially, the source code! I'm pretty sure this will shed some light on the interesting parts. I need more spare time, though…
Greetings,<br>
TroY
Hey guys,
I've been playing with those bulbs a bit.
To get started, I added a new object type to my own raytracer, so I have full control over raymarching and everything else. Some of the results can be seen <a href="http://www.uninformativ.de/?section=pics&picoffset=0&showGal=mGal/fractals/mandelbulb">over here</a>.
Okay. My main problem is to get a good distance estimator. What I mean with that is a function which, for a given point in space, estimates the distance to the fractal's "surface". Something like the <a href="http://www.devmaster.net/forums/showthread.php?t=4448">unbounding volumes we have for quaternion fractals</a> (there's a nice illustration). As far as I know, this is crucial in order to avoid dumb and slow raymarching with small step sizes.
<a href="http://www.fractalforums.com/3d-fractal-generation/true-3d-mandlebrot-type-fractal/msg8073/#msg8073">The clever guys at fractalforums.com</a> claim to have found such an estimator (obviously, they did - given the fact that their gallery is awesome). Well, I haven't really understood that yet. :/
Actually, my point in posting this on this forum is: How to realize such an estimator in AoI? Is that even possible without implementing an own raytracer class? I know, Nik already asked this, but: An ImplicitObject doesn't have any *direct* control over raymarching, does it? Say, "next step size will be 0.000123". At least, I can't see such a thing in RTImplicitObject.
BTW, I'm calculating my normal vector based on the last value for "r" (and doing the "finite difference thing" :)). In Bobs code above, that would be the "r2" used in "if (r2 > 4)". Doing it with the iteration count didn't work very well… Especially, it didn't work at all when doing bisection (in order to get very close to the "surface"), but that may be related to my raytracer - or me being stupid. :)
Greetings,<br>
TroY
great images. You got a hard surface look which is exactly what i was after.
You can infact get at least some control over what you want with the max gradient value. Peter added this at my request and can speed up the fluid raytracing by a large amount. It is the maxamium gradient that the function is expected to give anywhere in the field. A low value means the ray marching can use steps bigger than min Tol. Otherwise is marches with fixed steps.
However none of this would affect the final render. Only how long it takes. How did you get such a nice surface, as in a nice surface normal. (I get nice surface, but a "random" normal, that gives me more of a ray sampled Oren–Nayar Reflectance Model).
If you want fine control over how your object gets raytraced, you can do that by creating your own subclass of RTObject. The standard subclass used for implicit objects is RTImplicitObject, so you could probably start with that and then either subclass or modify it. Then you create a subclass of RTObjectFactory and register it as a plugin.
Peter
http://s12.directupload.net/file/d/1987/8mc3xzqo_jpg.htm
6 and a half hour for this cuty on a Quadcore 9550…
Worth the time.
Wow. Impressive. What code did you use for that? How do you deal with normals?
Thats a funny question Delt0r!
It´s your plugin! Fast and pretty accurate for my taste.
So to be honest I don´t know how "I" dealt with the normals,
because AoI has done it.
Sometimes I get the feeling I shouldn´t write in the dev section - especially when I only understand a fraction of what you´re talking about.
:(
HTH anyway
Harald
How did you get it to work? What setting did you use. I hope you wrote them down, cus it won't have saved a lot of them.
Here you are Delt0r:
http://s12.directupload.net/file/d/1987/2o3eqdxi_jpg.htm