Raymarching Toolbox Thread
category: code [glöplog]
Quote:
can anybody check???
I used the epsilon glass stuff on it - which depends on having more or less proper negative values inside - it worked surprisingly well. But from the tests - it's not a correct euclidean SDF - more like some upper bound for the SDF. I should take a sheet of paper and "think" about it... Maybe later :)
Quote:
But from the tests - it's not a correct euclidean SDF
Just in case anyone cares - my (ugly) testing procedure for that is:
Take the function you want to examine and plug it in the code... something like this...
Code:
float f(vec3 p) {
return udHexPrism(p, vec2(1,1));
}
[...]
Now I just change the "level set".
Code:
float f(vec3 p) {
return udHexPrism(p, vec2(1,1)) - 0.1;
}
[...]
If the object "blows up" with round edges (in case we had something convex with sharp edges before) - I suspect it's likely to be an correct euclidean [S]DF. If it does not... well then it's maybe still a good upper bound.
i was thinking in the train that the way i computed the distance to the hexagon was by taking the distance to the two side lines (that make the quarter hexagon after the abs), and those distances behave nicely in both sides of the lines/planes, and so does the max function. so, since the formula should work in the inside too properly, i have promoted the DF to SDF in the website.
Bascially that's a clever mix of space folding and half space intersection.
I'm pretty sure it's not an euclidian SDF but an upper bound to the euclidian SDF - well it doesn't matter that much - but having an real euclidian SDF allows some other tricks.
Interactive Modeling of Implicit Surfaces using a Direct Visualization Approach
with Signed Distance Functions has already been posted here before - interesting in our context are figure 1 and section 3.3 and also the notes on min/max CSG operatiors are something that is usually ignored (section 3.4.3).
I'm pretty sure it's not an euclidian SDF but an upper bound to the euclidian SDF - well it doesn't matter that much - but having an real euclidian SDF allows some other tricks.
Interactive Modeling of Implicit Surfaces using a Direct Visualization Approach
with Signed Distance Functions has already been posted here before - interesting in our context are figure 1 and section 3.3 and also the notes on min/max CSG operatiors are something that is usually ignored (section 3.4.3).
yeah, in general the min/max ops don't return the smaller distance possible.
on other topic, i wonder why they use the Chebyshev distance intead of the euclidean distance for the box, euclidean doesn't involve branchinig: d(p) = length(max(abs(p)-b,0))
on other topic, i wonder why they use the Chebyshev distance intead of the euclidean distance for the box, euclidean doesn't involve branchinig: d(p) = length(max(abs(p)-b,0))
Here a comparison of different methods for computing the a box "SDF":
DEBUG BOXES
Is only unsigned - and I consider unsigned basically useless for my purposes - you can't do fake sss, you can't trace easily through it and it also screws up your normal computations (central differences with 0 distance -> meh).
You definitly want to use either d4 ("chebyshev") or d5 (euclidean) which basically combines d3 and d4 based on the sign.
DEBUG BOXES
Code:
d(p) = length(max(abs(p)-b,0)) // d3 in the heroku thing.
Is only unsigned - and I consider unsigned basically useless for my purposes - you can't do fake sss, you can't trace easily through it and it also screws up your normal computations (central differences with 0 distance -> meh).
You definitly want to use either d4 ("chebyshev") or d5 (euclidean) which basically combines d3 and d4 based on the sign.
Really guys, this is just a bit too academic for my brain... too bad that I don't have such an affinity to maths, although I'd wish otherwise...
xTr1m: Most helpful post ever.
iq - you might want to add this to your nice collection:
in your notation that would be "sdTriPrism" - should be "inner"-style.
iq - you might want to add this to your nice collection:
Code:
float ftri(vec3 p, vec2 h) {
vec3 q = abs(p);
return max(q.z - h.y, max(dot(vec2(q.x, p.y), vec2(0.866025, 0.5)), -p.y) - h.x*0.5);
}
in your notation that would be "sdTriPrism" - should be "inner"-style.
another alternative:
Still, i think i prefer the original sdBox i think
Code:
float sdBox1( vec3 p, vec3 b )
{
vec3 d = abs(p) - b;
vec3 a = max(d,0.0);
vec3 b = min(d,0.0);
return length(a) + max(b.x,max(b.y, b.z));
}
Still, i think i prefer the original sdBox i think
Well - I guess for most cases it doesn't really matter. But if you really want to have an euclidean SDF for a box - sdBox1 is one good way to go. For the most purposes the "chebyshev" versions will do the job.
Actually I just noticed that your sdBox (not sdBox1) - uses length - but the result gets somewhat discarded.
At least in the test thingy on glsl.heroku.com this one does a pretty good job (iirc that's also what they do in the paper):
See here
Enough with boxes now...
Actually I just noticed that your sdBox (not sdBox1) - uses length - but the result gets somewhat discarded.
At least in the test thingy on glsl.heroku.com this one does a pretty good job (iirc that's also what they do in the paper):
Code:
float sdBox2( vec3 p, vec3 b )
{
vec3 di = abs(p) - b;
return max(max(di.x, di.y), di.z);
}
See here
Enough with boxes now...
allows other tricks is exactly why i never posted here before ;)
-> i used them all already, but the prod got never finished! (well, that happens if you´ve got a job!)
sorry for not posting mathematical correct procedures here ;) (but who the heck needs/uses sphereMarching for anything else than 4ks? ;) ) i posted why i did so before ;) le backread!
-> i used them all already, but the prod got never finished! (well, that happens if you´ve got a job!)
sorry for not posting mathematical correct procedures here ;) (but who the heck needs/uses sphereMarching for anything else than 4ks? ;) ) i posted why i did so before ;) le backread!
hArDy: great post... could you please stop spamming in more or less helpful threads?
lol, i'm not sure i follow the conversation anymore. why would you choose the non length() correct euclidean one? is it to avoid the sqrt()?
Did you look at one of the glsl.heroku links I posted? The sdBox version in your collection is _not_ euclidian.
Let me repeat:
Go here and compare d4 to d7. If you want correct euclidean you have to use d5/d6. Maybe we should have this conversation in a more realtime way - could help to avoid misunderstandings + we are flooding this thread with minor details.
Let me repeat:
Quote:
Actually I just noticed that your sdBox (not sdBox1) - uses length - but the result gets somewhat discarded.
Go here and compare d4 to d7. If you want correct euclidean you have to use d5/d6. Maybe we should have this conversation in a more realtime way - could help to avoid misunderstandings + we are flooding this thread with minor details.
Related, the new version of Fragmentarium has some cool animation stuff built in now. Would be great for demos! http://blog.hvidtfeldts.net/index.php/2012/08/fragmentarium-version-0-9-12-prague-released/
ahhh, it's supposed to be euclidean of course, but it's buggy indeed! i'l lreplace it by d6 or d5. The question still remains, why why would you want a non-euclidean distance if you have the euclidean?
yeah, indeed, too much hexagons and boxes ^_^ . somebody do more pretty images, please!
yeah, indeed, too much hexagons and boxes ^_^ . somebody do more pretty images, please!
Quote:
The question still remains, why why would you want a non-euclidean distance if you have the euclidean?
Well - if you can have it "for free" I would always go for proper euclidean - if you can't have it for free... The evaluation of the non euclidean sdBox version should be faster - even if "length" shouldn't be that expensive it is more expensive than sub/abs/max/max/max.
Thus a single evaluation is cheaper, but you will step a shorter distance in some cases (i.e. if you evaluate in the voronoi feature region of a vertex/edge you get a smaller distance than euclidean - voronoi feature regions of faces return the correct distance)
therefore the count of marching steps will increase - now it depends where the break even point is - that's up to experimentation.
CSG ops with min/max will break your "euclideaness" anyways...
But most important: it's smaller and that is what counts if you target n<=4k bytes.
I am having fun re-reading these threads these days and just stumbled upon some code for the dingdong-surface posted by Knighty:
Knowing the algebraic formula is as easy as
x^2+y^2=(1-z)z^2
i wondered a bit about knightys code and brought it down to this:
But now i wonder about the squaring...wasn´t there that neat trick of using length() in order to avoid the sqrt() and the dot()s? I tried but the "1.-p.z"-part is completely confusing me right now. Do i need to sqrt() it in order to use length() on the rest of the equation or sth alike? Or is that trick simply not applicable here?
Sorry, but my math is really rusty by now! :/
Anyway, i think using length() gives unsigned distances only, so i leave the dingdong here, as small as it got, maybe someone will make good use of it this way...i won´t, as it was just a small exercise to me, trying to regain math-skills! ;)
If you want to use it, remember to move your camera a bit on the y-axis...else you will be inside the object most likely.
Code:
dingdong(x,y,z){
r2=x*x+y*y;
r=r2-z^2*(1-z);
dr=sqrt(4*r2+((3*z-2)*z)^2);//modulus of the gradient
abs((r-param1)/(dr+param2))*0.75;//learned from IQ.
//param1 is to change the level set.
//param2 in order to remove singularity. Not always necessary.
//0.75 is for scaling the DE
}
Knowing the algebraic formula is as easy as
x^2+y^2=(1-z)z^2
i wondered a bit about knightys code and brought it down to this:
Code:
float dingdong(float3 p)
{
// float r=(1.-p.z)*dot(p.z,p.z)-dot(p.xy,p.xy);
float r=(1.-p.z)*p.z*p.z-dot(p.xy,p.xy);
return sqrt(r*r)*.25;
}
But now i wonder about the squaring...wasn´t there that neat trick of using length() in order to avoid the sqrt() and the dot()s? I tried but the "1.-p.z"-part is completely confusing me right now. Do i need to sqrt() it in order to use length() on the rest of the equation or sth alike? Or is that trick simply not applicable here?
Sorry, but my math is really rusty by now! :/
Anyway, i think using length() gives unsigned distances only, so i leave the dingdong here, as small as it got, maybe someone will make good use of it this way...i won´t, as it was just a small exercise to me, trying to regain math-skills! ;)
If you want to use it, remember to move your camera a bit on the y-axis...else you will be inside the object most likely.
it's pretty late here and admittedly i've had some beer, but... is that last line seriously sqrt(r squared)?
If so there's possibly a small optimisation there.
If so there's possibly a small optimisation there.
You are absolutely right, haha! Man was i confused at that point of time, trying to get the length()-version working! Here´s a working, even smaller version:
Code:
float dingdong(float3 p)
{
return -((1.-p.z)*p.z*p.z-dot(p.xy,p.xy));
}
I'm quite new to raymarching and I'm stuck with a glitch trying to repeat primitives over a range. What I'm doing is a simple combination of clamp/mod to get the primitive repeated over one axis, but depending on the camera orientation, I get what seems to be tracing errors.
I've uploaded an example to shadertoy, based on an iq's example, and here's how it look on Chrome to me (it also fails on my native OpenGL implementation):
Most of that shader code is iq's, with my attempt to repeat primitives being like this:
The problems dissapear if I change 'c' to 1, but obviously then I get more primitives than I want :S
Any pointers from someone with more experience with raymarching?
I've uploaded an example to shadertoy, based on an iq's example, and here's how it look on Chrome to me (it also fails on my native OpenGL implementation):
Most of that shader code is iq's, with my attempt to repeat primitives being like this:
Code:
const float c = 2.;
vec3 posB = pos;
posB.z = mod( clamp(posB.z, -2., 6.), c );
vec2 res = opU( vec2( sdPlane(pos), 1.0 ),
vec2( sdBox( posB-vec3(-0.5,0.25,0.5), vec3(0.25) ), 3.0 ) );
The problems dissapear if I change 'c' to 1, but obviously then I get more primitives than I want :S
Any pointers from someone with more experience with raymarching?
Try:
You have to be a bit careful when using modulo style repeats, rule of thumb: You better place your object into the middle of a "cell".
Quote:
vec2 res = opU( vec2( sdPlane(pos), 1.0 ),
vec2( sdBox( posB-vec3(-0.5,0.25,1.0), vec3(0.25) ), 3.0 ) );
You have to be a bit careful when using modulo style repeats, rule of thumb: You better place your object into the middle of a "cell".
Oh, of course, I was hitting the boundaries! Thanks for the heads up :)
So, we finally wrapped it up and made a website about it:
http://mercury.sexy/hg_sdf/
This page hosts the hg_sdf library for building signed distance functions. This lib is the one that we used ourselves to make 64k intros like the timeless and on, straight from our version control system. Much of what we learned from those productions ended up in here.
Please download and actually read the comments in the source code: most of the info is there. The website additionally provides screenshots for some of the operators - you should be able to figure out the rest. We might add more examples for real-world usage, but for the moment we're happy about finally publishing this lump of code that we had been sitting on for far too long.
Now go make some intros :D
Quote:
Please check our internet use policy.
You tried to visit:
http://mercury.sexy/hg_sdf/
Not allowed to browse Pornography category
argh, I have to wait until I'm at home :D