pouët.net

Raymarching Beginners' Thread

category: code [glöplog]
Thanks for you tips guys, it's a lot more clear now. I'm going to try it soon.
added on the 2013-09-22 20:19:44 by Tigrou Tigrou
Hi. I have a question. Hope some of you guys have time to take a look at it.

I have a simple distance function for a cone :
it calculate distance to cylinder and progressivly lower the radius along one axis.

something like :

Code: d = sqrt(x*x+y*y) - mix(ra, rb, (height+z)/(height*2)); //some height clipping...

it works great (check left picture), however for low values of "height" (right picture) it returns a too big distance.

BB Image

Is there simple ways to fix this ?
added on the 2014-02-03 22:34:25 by Tigrou Tigrou
Try this, i just coded it to see how i would do it, it´s not exactly a cone, but a double-cone, but you will find your way from there i guess.
Code: float coneY(float3 p,float r,float c) { return max(abs(p.y)-c,length(p.xz)-r+abs(p.y)/c); }


r = radius (maximum)
c = height

coneY(p, 1.0, 5.0);
should build a nice doubleCone.
or to put it in your style of code:
Code: d = max(abs(y)-height, length(float2(x,z))-radius + abs(y)/height);


float2 is vec2 if you use GLSL obviously.

p in my last posting is a float3/vec3 holding x,y,z
oops, i screwed it up a bit, with my approach your radius has to be 1.0 to form a cone.
but i guess you can figure how to fix that ;)
using "length(x,z)" instead of "sqrt(x^2+z^2)" should be a bit faster aswell. and you´re happy if your DEs are fast, believe me ;) you call them that many times, everything speeding it up is nice.
@hArdy : thanks for reply. i tried what you suggest and (as I excepted) it does not worked (same issues as initial problem).

on the picture: left is your double cone (which looks like a coffin) , with high height value, it works (left), but with low height value, it does not return correct distance. note its only when position of ray is at left top, left bottom, right top , right bottom and such not middle top/bottom.

about length() vs sqrt(), ... : i'm working with a tool where length() is not available. when converting it to shader i will use built in function and vectors as I should :)

BB Image
added on the 2014-02-04 00:19:57 by Tigrou Tigrou
hmm, thats what i get with my version:
coneY(p, 1.0, 5.0);

and when i lower the height drastically:
coneY(p, 1.0, 0.1)

So either your marcher has a bug or you had to change my algo so it produces the same as your version. i think it´s about the latter.

To make your life more easy, you should consider using Shadertoy or the good old Rendermonkey to prototype your stuff.
I can recommend Rendermonkey, i am still using it myself, you can easily put some sliders for values you´d like to tweak, set up multiple shader-pairs to work on rendertargets and so on. Easy to get into and helps a lot while tweaking/pimping your routines. :)

By prototyping directly in shaderCode you avoid a lot of problems. ;)
In soviet russia, rays march you.
added on the 2014-02-04 09:01:18 by nystep nystep
@hArdy : i have converted my script to shadertoy : http://glsl.heroku.com/e#14079.0

As you can see, there is always some error between distance returned by cone function and the "real distance" : distance returned by function is too large, and the more distant you are from center, the bigger the error.

If you uncomment line 21, there is an example with spheres, which works perfectly.
added on the 2014-02-06 19:58:41 by Tigrou Tigrou
first of all have a correct version of a cone on the Y-Axis here:
Code: float coneYcorrect(float3 p,float r,float c) { return max(abs(p.y)-c,length(p.xz)-r+r*abs(p.y)/c); }

with this you can change the radius and/or the height at any time without it getting a "coffin" ;)

Then there´s one thing in raymarching...IF you change the geometry of your DE (Distance Estimation-function) based on position, or rotate or anything like that, you cannot simply walk the full distance on your ray your DE gives you, thats why you see artifacts a lot in raymarched scenes. To avoid this you normally only walk d*0.5, or even lesser as in d*.33333333.

In your glsl-heroku (NOT shadertoy ;) ) you only sample the object a single time, the "p.y" the DE (coneY) uses is the Y-position of your mouseCursor ofcourse this way! ;) The DE-Routine doesnt know yet the distance would be different, if you would have moved on your ray, this way having changed the Y-Position.

If you really want it to show sth accurate you need to take some more samples, as in 50 or sth! Remember: the distance you get in your first sample is already too big, as you wondered...so take that distance*0.5 and walk that on your ray, then sample again.
Having a simple iteration should do the trick for what you are trying to achieve/measure there!

Here´s a glsl-heroku with fixed coneY for you:
http://glsl.heroku.com/e#14084.0
Sorry for having dropped unfinished code on you last time, was just a fast, tired approach to your problem. Now that i actually saw your problem in code it still took me some minutes to think about it, but i finally got what your problem is atleast! ;)
Hope i could help, if still questions or you didn´t get what i tried to say you, feel free to ask again! will watch this thread some closer from now!
Hey guys, Im new to the forum and almost as new to ray marching. First of all I'd like to thank everyone for all the useful info on this subject, its pretty difficult to find :P I'd also like to especially thank Iq for his distance functions and incredibly useful articles and code snippets :D.

Im attempting my first ray marcher with distance functions as a research project at Uni, the aim is to create a realistic looking cave with a reasonable frame rate. Heres a cap of progress and issue so far:

http://postimg.org/image/sffihxnq1/

Up until I implemented a bit of noise, the lighting was great, that leads me to suspect the normal calculations. Heres the code thus far:

http://pastebin.com/8fdS9B1t

It has an expiry date on it as if the code is found online I could be penalised for plagiarism. I was hoping one of you guys could give me some pointers/ advice on how to fix my normals and any tips on optimisation or anything at all would definitely be appreciated :).

I can also link the full VS solution if its needed, just pm me and ill send you a onedrive link :) Just no posting it online :P
chimpslave: the way you use noise is wrong. Instead of multiplying p with it everywhere, you should only add it in distance_to_object, and only at the end, like this:

return .5 * ( perlin(p)+object_union(s4, ConeRep(p + vec3(0.0, 42.0, 0.0), vec3(7.0, 68.0, 9.5))) );

The .5 is a safety factor, because you're no longer using a pure distance function. You might need to tweak it, depending on how fast your perlin noise can fluctuate. Here's an old post of me in this thread explaining this: https://www.pouet.net/topic.php?which=7920&page=57#c401939

Here's a useful page for beginning raymarch-coders:
http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
Look at the "displacement" example.
added on the 2014-03-17 19:15:28 by Seven Seven
Thanks for the quick response Seven, Im reading through the articles now :)

I tried the fix you suggested before I reached this point, I tested again to be sure but same result. It stops rendering everything but the repeated cones and returns the background colour, it also causes the normals to break on the cones :/

Before noise is implemented at all it looks like this:
http://postimg.org/image/4cjayclpt/

Any other suggestions?
i think your problem is this line:
Code: vec3 q = mod(p,c) - 0.5 * c;

tey adding some offset to p first, as everything negatively moduloed looks wrong:
Code: vec3 q = mod(p+1000.0,c) - 0.5 * c;
Once again, thanks for the quick response, its very much appreciated.

hArDy:
vec3 q = mod(p+1020.0,c) - 0.5 * c;

Adding to 'p' in this line of code only changes the height. I had to use the domain repitition on an intersect of Iq's cone and box due to an issue with the cones rendering infinitely in one direction. At +1020 its in the same place as it is without it and there doesnt seem to be any change at all.

Thanks for the suggestion all the same.
What Seven said makes a lot of sense in my mind! ;)
But here another try to remote-fix, this time i found this line
Code: t += dist;

two times in your code. Try changing it to
Code: t += dist * 0.25;

instead. That´s the same suggestion Seven made, but here´s another thing:
Once you found an intersection, you get the normal, break out of your for-loop, then start to calculate AO etc. BUT: you didnt walk the last calculated distance on your ray! So you should add an extra line of "t+=dist;" right before "pos = ro + rd * t;".

Let me tell you, the way you use the perlin seems to be wrong from my remote-standpoint of view. You should use it only in your distance_to_object-function, as Seven said already! Else this doesnt make sense (atleast to me) and also is quite costy for the extra-calculations several times in your code.

I mean: Take your normal()-function...you use the perlin, then call the distance_to_object() (3 times), where you use the perlin again, so you used the perlin twice! makes no sense, does it?!

My suggestion is to get a simple sphere working with perlin first! Your distance_to_object() should look like this maybe:
Code: float distance_to_object(vec3 p) /* distance function */ { return sphere(p,1.+perlin(p*20.0)); }

And the perlin should NOT get called anywhere else except in this line!
Should yield a nice perlin-noised-sphere looking like an asteroid! (the 20.0 is the amount of noise you want to apply ofcourse. And dont forget about the "t += dist * 0.25;"-part from above! )
Once you got this working as expected to be, you can try again on your scene.
"two times in your code" --> forget about the "two times", i just woke up, my head is still not working properly!
If you get some broken geometry, consider allowing for more steps by increasing the number in "rmSteps"...as you only walk quarter-distances and thus will need a lot of more steps on your ray. Walking this way is needed btw, as the perlin changes the object based on the rayPosition (p) for every step you take...making overstepping of geometry pretty easy, yielding artefacts.
Seven: I see exactly what you mean with Iq's displacement, it should simply be a case of adding noise to the distance function. So the problem is either with the noise function or something else...
I just tried what i implied above, with exactly your code, so same perlin()...works as expected here! ;) nice asteroid!
See this:
BB Image
The only change i had to make is the addition instead of your multiplication...also added a factor (the 10.0) for the noise.
the distance function is the only place i use the perlin! Dont use it in your normal-calcs or anywhere else again.
hArDy: Sorry, the page hadn't refreshed by the time I last posted so I didn't notice your posts! Thank you so much for the explaination, I knew I wasnt far off. I hadn't even considered that it wasn't walking the last part of the ray so thanks again for clearing that up for me.

As for the noise everywhere, I hadn't originally intended for that to work. It was a last ditch attempt to get something that didnt quite work :P But as stated, the explaination really helped. Thanks guys!

I'll spend the next few hours turning that asteroid into a cave hopefully! Ill be sure to share the results when I'm done :)

Any other suggestions or advice will be greatly appreciated! I think I've learnt more in the past 2 days from here than I have in the last 4 weeks!
Its looking a lot better, but its pretty damn slow.

Can anyone recommend any optimisations?

login