# pouët.net

Go to bottom

## Raymarch Simple Question

category: code [glöplog]
Each step I can either

(1) Add abs(dist) (or half dist, or some other fraction of it) to the current recorded distance.

Or

(2) I can take dist<0 to mean I have overshot the surface, and commence a bisection to find dist==0.

Then the problem with (1) is that you can overshoot surfaces, resulting in patches, especially when the surfaces are thin. This is what I tried to overcome with (2).

But the problem with (2) is that when the ray should not actually hit the object at all, so that you'd fall through to rendering the background (sky or something), it gets stuck around ray.z=object_center.z and you end up with this interesting, but undesirable, blur effect.

Is there a (3)... a (4)... ? How do I overcome this?

(1) Patches in the object due to overshooting:

(2) Getting stuck with ray.z is around the center of the object (backside of the object is missing!)

added on the 2014-10-10 01:46:25 by dila
You are assuming that the distance function is returning the distance but how you implemented it its actually not...

The distance function can't change more than one unit of it's sampled at two points which are one unit away.

In other words if the distance function returns 2.0, you move the ray forward by 2.0 units and then if your distance function returns -0.4 then something went wrong.

This happens when you stretch the space.
If distance function is x*2.0 - 4.0 it's obvious that the distance function. For space stretching to work you need to normalize the derivative to 1.

For the above example you need to divide by two.
(x*2.0 - 4.0) / 2.0 is the proper distance function. You can also rewrite it as x - 2.0

Another not so obvious example:
x+sin(y)*4.0

To properly fix it you need to implement distance from sine function, or use the lazy mode and divide by 4.
x*.25 + sin(y) becomes a better aproximation of the distance function if x is small otherwise x - 1.0 is a better aproximation if x is big.

Try to implement a generic stretchable cube. That should make you understand this concept.

This is your shader with the distance function divided by 10 and iterations increased to 200
added on the 2014-10-10 07:54:21 by mu6k
FWIW, your first picture looks a lot more interesting than most raymarchers that work well.
added on the 2014-10-10 09:32:26 by Preacher
You have a bug in the cartesian to polar coordinate transform (the second atan). Also, for the marcher, maybe you can try this:

Code:```vec2 dist(vec3 pos) { vec3 center = vec3(0.0, 0.0, 3.0); float d = 0.0; float g = 0.0; for (int i = 0; i < 1; ++i) { vec3 delta = pos - center; float theta = iGlobalTime * 0.1 + atan(delta.x, delta.z); float phi = iGlobalTime * 0.1 + acos(delta.y/length(delta)); g = 0.5 + 0.5 * sin(theta*10.0) * sin(phi*10.0); g = pow(g, 4.0); float rad = 0.5 + 0.5* g; d = length(delta) - rad; } return vec2(d, g); } void main(void) { vec2 uv = (gl_FragCoord.xy + 0.5) / iResolution.xy * 2.0 - 1.0; uv.y *= iResolution.y / iResolution.x; vec3 ray = normalize(vec3(uv, 1.0)); float t = 0.0; float g = 0.0; float hit = 0.0; for (int i = 0; i <256; ++i) { vec3 pos = ray * t; vec2 d = dist(pos); if (d.x < 0.001) { hit = 1.0; g = d.y; break; } g = d.y; t += d.x*0.1; } vec3 col = vec3(0.0); if( hit>0.5 ) { float diff = 1.0 - 1.0 / (1.0 + g * 10.0); float fog = 1.0 / (1.0 + t * 0.1); col = diff * vec3(fog, fog, fog); } gl_FragColor = vec4(col,1.0); }```

added on the 2014-10-10 09:46:19 by iq
Wow thanks guys it's working much better now!

added on the 2014-10-10 09:58:44 by dila
looks nice :)
added on the 2014-10-10 10:05:13 by visy
I actually like the way the first "buggy" screenshot looks like.
added on the 2014-10-10 11:18:10 by kbi
What Preacher and kbi said :)
Sure the broken image it looks interesting, but don't mislead him.

The problem with bug-art is that most of the times you don't understand it (as clearly proven by the questions he made). And if you don't understand it you cannot control it. And I'm not going to ask if it is legitimate art if you don't direct it.

I think it's better he controls the image to be what he wants (especially if he's a beginner), and only afterwards can he "break" the rules and introduce bugs to make it artsy... Sticking to the bug at this stage because it looks cool won't led him too far.

But sure, that noisy image is more interesting than the perfect octopus, it's more fun for your brain to try to interpret. Plus of course, noise/broken stuff is always "cool". And easier.
added on the 2014-10-10 20:29:55 by iq
btw, if you're using a signed distance field, if you overshoot the distance is negative. Drop that abs() and the next step will be backwards to the surface, not further inside the object :)
added on the 2014-10-10 20:30:19 by psonice
Thanks psonice, but it seems that with long extrusions this doesn't behave so well.

What iq suggests is to actually terminate the trace if the distance becomes negative, since this indicates surface penetration.

Code:``` for (int i = 0; i < 64; ++i) { vec3 pos = ray * t; vec2 d = dist(pos); if (d.x<0.1) { g = d.y; hit = 1.0; break; } g = d.y; t += d.x * 0.1; } ```

After the trace I tried a second refinement step by bisection to try to find dist=0 exactly, but this did not fix any of the artifacts.

I'm now wondering how to render long thin tubes with this technique to give better tentacles. Perhaps I'd get better results from stretching a cylinder and make it go to a point at one end? Thinking of something like the legs in slisesix.
added on the 2014-10-10 22:00:41 by dila
I like iq's screenshot the most.
added on the 2014-10-10 22:10:30 by rudi
dila, better (and faster) than a capped dylinder, you can use the distance to a segment:

Code:```float sdSegment( vec3 p, vec3 a, vec3 b, float r ) { vec3 pa = p - a; vec3 ba = b - a; float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1. ); return length( pa - ba*h ) - r; }```

where p is your point in space, a and b are the end points of the segment/capsule, and r is it's thickness. You can see that being used here and here
added on the 2014-10-11 00:07:17 by iq
Something like this:

Code:```float sdSegment( vec3 p, vec3 a, vec3 b, float r ) { vec3 pa = p - a; vec3 ba = b - a; float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1. ); return length( pa - ba*h ) - r; } vec2 dist(vec3 pos) { vec3 center = vec3(0.0, 0.0, 4.0); vec3 delta = pos - center; float rad = length(delta); float the = atan(delta.x,delta.z)+3.1416 + 0.1*iGlobalTime; float phi = acos(delta.y/rad) + 0.1*iGlobalTime; the = mod( the/6.2831, 0.04 ) - 0.02; phi = mod( phi/6.2831, 0.04 ) - 0.02; float d = sdSegment( vec3(the,phi,rad), vec3(0.0), vec3(0.0,0.0,1.5), 0.01 ); return vec2(d, rad / 1.5); } void main( void ) { vec2 uv = (-iResolution.xy+2.0*gl_FragCoord.xy)/iResolution.y; vec3 ray = normalize( vec3(uv, 2.0) ); float t = 0.0; float g = 0.0; float hit = 0.0; for (int i = 0; i < 256; ++i) { vec3 pos = ray * t; vec2 d = dist(pos); if (d.x<0.001) { g = d.y; hit = 1.0; break; } g = d.y; t += d.x; } float diff = g; float fog = 1.0 / (1.0 + t * 0.1); vec3 col = hit * diff * vec3(fog, fog, fog); gl_FragColor = vec4(col,1.0); }```

added on the 2014-10-11 00:35:54 by iq
Thanks iq, that works perfectly:

added on the 2014-10-11 01:28:54 by dila
Awesome.

I couldn't resist playing with the idea myself. The mod() trick to create many arms out of one single actual tube is not working very well on the poles of the sphere (you can see lots of noise there). Well. At least it's cheap.

added on the 2014-10-11 11:24:50 by iq
"The problem with bug-art is that most of the times you don't understand it (as clearly proven by the questions he made). And if you don't understand it you cannot control it. And I'm not going to ask if it is legitimate art if you don't direct it."

Sometimes the fact that you cannot control it is a lot more interesting than the fact that you can. Chance and chaos can yield many interesting results.
added on the 2014-10-11 13:25:58 by visy
My attempt at the same thing:

added on the 2014-10-12 01:00:56 by dila

I can't help but notice it looks really bad next to iq's creation. But it's midnight and i need to sleep :)
added on the 2014-10-12 01:06:50 by dila

added on the 2014-10-12 09:57:45 by dila
i hope this will be part of your next demo/intro :)
Hmm not sure about that :D

If only there were more bytes in 256b!
added on the 2014-10-12 12:04:23 by dila
Has anyone seen this kind of artifact before when implementing soft shadows?

I've been stuck here for a few hours. Can't figure out what I'm doing wrong:

added on the 2014-10-12 16:22:36 by dila
there are more bytes in 512b :D
Looks like regular floating point errors that can easily be fixed by adding a small bias when sampling the shadow map (or the whatever you're getting your pixel-light distance from)
added on the 2014-10-12 16:41:26 by MsK`