Raymarching Toolbox Thread

category: code [glöplog]

This works like a charm, and I ended up with a nice tunnel of spheres.
Is it possible to make an object that is repeated using the modulus repeat with an offset?

My intuition is no, but maybe I am missing something.

Like for instance, a square being repeated, but it's height being modulated by a sine wave for each iteration.

Am I missing something silly?
You just get a constant value for each "cell" the sphere is in, and use that for the sphere height. You can get that constant value easily, e.g. if you're modulating the repeat with a value of 1, it's just "value = floor(pos)". You can hash that or use a sin or whatever.
added on the 2018-06-14 11:11:49 by psonice psonice
This will yield you many graphical bugs, also known as artefacts.
Because you will get a closest distance (to the grid of cells) of f.e. 0.7 and so you step 0.7 on your ray, 0.5 of those into the next cell...where a long cube resides, which was only 0.2 away, but because we got the info of 0.7 away in the last cell we just went 0.5 into its body.
The only workaround is to not walk the full distance, i.e.:
"rayPosition += rayDirection * ( distance * 0.25);".
You may want to only walk fractions of distances for just the objects you are using such techniques for (or which yield artefacts in other words), so you should not globally add the fraction of a distance, but do it in the return of your map()-function already instead, i.e.:
"return min(X, 0.25 * artefactObjectDistance);", where X=other distances.
or like this:
"return min(X, 0.25 * Cube(p, float3(1,1 + 0.5 * sin(floor(pos.x) * 0.1 + time),1));", where X=other distances.
The "0.25" was just a random number...you want to finetune it, until you don´t get any artefacts anymore and of course being as high as possible (while not above 1), because this means many more calculations per pixel of course, the lower this number gets.
I think for a field of different y-sized cubes the 0.25 could even work, but i think it needs to go even lower! :(
I saw this mistake way too often by now! (so imma maybe repeat what has been said before in this thread, i won´t reread it now completely just to see, if! ;) )

Many people realized writing something like
Code:float PI = 3.14159265359;

1. takes some time to type
2. needs one to remember all the digits
3. can be done more precise...

...by just using sth like
Code:#define PI acos(-1.0);

But here´s where you all seem to stop thinking!
A #define just substitutes every portion of your code saying "PI" with given code...
...which makes your code recalculate the whole thing each time you use it!
Imagine a loop of 256 iterations, 256 times calcing acos(-1.0) ...ridiculous! :P

So, what you really want to do is to just calculate it once and keep it for later usage, as in a Global-Variable!
That easy:
Code:static const float PI = acos(1.0);

Now your code is a lot faster...and bigger in size, but it´s worth it!
Also a define needs a newline, so would look like
Code:#define PI acos(1.0)/n

which is compared to
Code:static const float PI=acos(1.0);

just 8 bytes extra...which again crinklered(crunched) a lot less anyway! ;)

Stop being Fools, please! ;) Having splendid GPUs does not mean to waste processing-power for no reason! Not in the Demoscene! :P

This is DirectX of course! If one wants to add the OpenGL-Version, go on! I have no clue how to make a global variable in OGL, last time i used it was like 10 years ago!
Shouldn't every compiler worth its salt fold the "acos(-1.0)" call into a constant anyway?
added on the 2019-11-28 15:20:17 by KeyJ KeyJ
You're missing the sign in your global version, so your PI will always be 0 :P
Code:float PI; [...your code...] void main() { PI=acos(-1.); [...your code...] }

It is a worthwhile optimization in regards to performance, that said I rarely if ever use PI in my intros and a good shader compiler should be able to constant fold this so in theory performance should be the same no matter how often you use it and (compressed-) size-wise it'd be best to just write "acos(-1)" everywhere you'd want to use PI because everything else just introduces more entropy.
added on the 2019-11-28 15:36:52 by LJ LJ
@KeyJ haha yeah .... *goes into a corner and cries*
added on the 2019-11-28 15:38:27 by LJ LJ
I mean, decent CPU compilers do it: https://godbolt.org/z/CNuGRG (GCC even in -O0, Clang from -O1 on, only MSVC is too dumb)
GPU HW compilers do it too: http://shader-playground.timjones.io/936d80024f8c6f8f2378601972370db1
In case of HLSL, the frontend compiler already does it: http://shader-playground.timjones.io/aeb6ca29ae25a6480db6a047d89e3a6a
added on the 2019-11-28 15:42:10 by KeyJ KeyJ
Use 3 instead of pi. Packs best. B)
added on the 2019-11-28 22:35:31 by Virgill Virgill
haha, missing the sign! :D
Code:static const float PI = acos(-1.0);

it all depends on your shader-optimization-settings i guess. setting it to lowest opt yielded me smaller executeables in the past, so i went with it and the global version is a lot faster for me.
FWIW, d3dcompiler_47.dll already performs acos(-1) constant folding if optimization is disabled completely.
added on the 2019-11-29 09:13:05 by KeyJ KeyJ
Use 3 instead of pi

...according to C=64 coders... XD
added on the 2019-11-29 10:57:08 by d0DgE d0DgE
a way to draw incomplete circles
added on the 2019-11-29 12:17:49 by rutra80 rutra80
KeyJ: hardy prefers way more ancient HLSL compilers. ;)

The only workaround is to not walk the full distance, i.e.:

Not really true.

There are some options to do this correctly, without any overstepping:
- design the distance function which is returned from a "cell" such that it wont overshoot into any object of neighboring cells.
- or do something like this
added on the 2019-11-29 23:01:14 by las las
That was meant as the only workaround to not fuck with lipschitz! ;)
Of course there are ways to do it correctly...just not without a lot of extra-code you don´t want in a small intro...i´m maybe too stuck in 4K, as this is a general Raymarching-Thread, which i keep forgetting! ;)
Those workarounds just trick Lipschitz, without actually fucking him, btw! :P If sth ain´t predictable at all positions, you cannot call it sphere-tracing anymore...it would be sth like a hybrid of everything known maybe, but not sphereTracing! Even since we started using it, we fucked with it, and it wasn´t always the sphere´s distance we travelled! A Cube-Twister is not Lipschitz-conform already!
You could simply admit that you were wrong. But I'm happy to help.

For the twist(er) see the original Hart paper from 1996 - Appendix E / Figure 14 / Equation 44.

It's totally okay to "not know" something. But IMHO it's not okay to behave as if you have a clue while you don't. You'll just end up confusing everyone.
added on the 2019-12-06 09:57:06 by las las
If sth ain´t predictable at all positions, you cannot call it sphere-tracing anymore

Albeit I'm missing the formal definition of "spheretracing", having a discontinuous SDF doesn't change anything about the actual core logic, if you were to go by that defintion understepping alone makes it "sth like a hybrid" ?

btw. my allusion in regards to shader compilers might not constant folding acos(-1) was based on glsl live compilers on mobile devices being almost passthrough compilers when I looked at them a few years back. Then again these were hardly target platforms for intros... that said this is the "General Raymarching-Thread" :P
added on the 2019-12-06 19:40:44 by LJ LJ
having a low localLipschitzConstant is great for performance (and continuity), but not essential.

laving a large localLipschitzConstant up to 8x can still be fine.
this is then more often called signedDistanceBound , and not as much a SignedDistanceFunction.

ideally, any distanceFunction takes and returns a localLipschitzsConstant, and the raymarching stepwidth scales by its (inverse) co compensate.

this can be done via AutomaticDifferentiation of the [Ad] core of:
this sure increases compile times.

but ideally, you learn to not care much for lipschitzConstants, and instead just understep close to the camera, and may not care how much you ooverstep far away from the camera.
then you can distort space, like any RelativityEngine:
and you may automatically adjust your epsilon precision and stepLength, to approach a mostly constant fps, at che cost of more dynamic precision.
added on the 2020-12-06 08:10:17 by ollj ollj