pouët.net

Go to bottom

Raymarching Beginners' Thread

category: code [glöplog]
Yep that one is from iq. It's works pretty well.

In case you need the euclidean distance one could do something like this:
Code: float box(vec3 p, vec3 s) { vec3 d = abs(p) - s; float m = max(d.x,max(d.y, d.z)); return mix(m, length(max(d, 0.0)),step(0.,m)); }

added on the 2011-03-27 11:14:44 by las las
thank you, las

there was a mistake in the name of first experiment, not Inverted Malevich 1.0/f(x), but Negative Malevich -1.0*f(x)

my second raymarch experiment
Cornell Box with Ambient Occlusion (AO algorithm by iq)

Code: #ifdef GL_ES precision highp float; #endif uniform float time; uniform vec2 resolution; uniform vec4 mouse; float planeX(in vec3 p, in float x) { return distance(p,vec3(x,p.y,p.z)); } float planeY(in vec3 p, in float y) { return distance(p,vec3(p.x,y,p.z)); } float planeZ(in vec3 p, in float z) { return distance(p,vec3(p.x,p.y,z)); } float f(vec3 p) { float sdf; // Cornell Box (left - red, right - green, other - grey) float sdf1 = planeX(p,-1.0); // left wall red float sdf2 = planeX(p,1.0); // right wall green float sdf3 = planeY(p,-1.0); // floor grey float sdf4 = planeY(p,1.0); // ceil grey float sdf5 = planeZ(p,1.0); // back wall grey sdf = min(sdf1,min(sdf2,min(sdf3,min(sdf4,sdf5)))); return sdf; } vec3 calcNormal( in vec3 pos ) { vec3 e = vec3(0.0002, 0.0, 0.0); vec3 n; n.x = f(pos + e.xyy) - f(pos - e.xyy); n.y = f(pos + e.yxy) - f(pos - e.yxy); n.z = f(pos + e.yyx) - f(pos - e.yyx); return normalize(n); } void main(void) { vec2 p = -1.0 + 2.0 * gl_FragCoord.xy / resolution.xy; vec3 color = vec3(0.0,0.0,0.0); // perspective fov 45? vec3 Ro = vec3(0.0,0.0,-1.0); // ray origin vec3 Rd = vec3(p.x,p.y,1.0); // ray direction Rd = normalize(Rd); float t = 0.0; const int maxsteps = 75; for(int steps = 0; steps < maxsteps; steps++) { vec3 pos = Ro+t*Rd; float d = f(pos); const float eps = 0.001; if(d < eps) { if(d == planeX(pos,-1.0)) // color = vec3(0.63,0.06,0.04); color = vec3(0.64,0.15,0.1); else if(d == planeX(pos,1.0)) // color = vec3(0.15,0.48,0.09); color = vec3(0.15,0.5,0.15); else color = vec3(0.76,0.75,0.5); //color = pos; vec3 n = calcNormal( pos ); // ambient occlusion float ao; float totao = 0.0; float sca = 1.0; for( int aoi=0; aoi<5; aoi++ ) { float hr = 0.01 + 0.02*float(aoi*aoi); vec3 aopos = n * hr + pos; float dd = f( aopos ); ao = -(dd-hr); totao += ao*sca; sca *= 0.75; } ao = 1.0 - clamp( totao, 0.0, 1.0 ); color = color * ao; break; } t = t + d; } gl_FragColor = vec4(color,1.0); }


BB Image
added on the 2011-03-29 20:52:25 by SLeo SLeo
you can change the AO calculation slightly and get some color bleeding:

Code: #ifdef GL_ES precision highp float; #endif uniform float time; uniform vec2 resolution; uniform vec4 mouse; float planeX(in vec3 p, in float x) { return distance(p,vec3(x,p.y,p.z)); } float planeY(in vec3 p, in float y) { return distance(p,vec3(p.x,y,p.z)); } float planeZ(in vec3 p, in float z) { return distance(p,vec3(p.x,p.y,z)); } float sphere( in vec3 p, in vec3 c, in float r ) { return distance( p, c ) -r; } float f(vec3 p, out int id) { float sdf; // Cornell Box (left - red, right - green, other - grey) float sdf1 = planeX(p,-1.0); // left wall red float sdf2 = planeX(p,1.0); // right wall green float sdf3 = planeY(p,-1.0); // floor grey float sdf4 = planeY(p,1.0); // ceil grey float sdf5 = planeZ(p,1.0); // back wall grey float sdf6 = sphere(p,vec3(0.4,-0.8,0.1), 0.2 ); float sdf7 = sphere(p,vec3(0.0,-0.8,0.5), 0.2 ); sdf=sdf1; id=0; if( sdf2<sdf ) { sdf=sdf2; id=1; } if( sdf3<sdf ) { sdf=sdf3; id=2; } if( sdf4<sdf ) { sdf=sdf4; id=3; } if( sdf5<sdf ) { sdf=sdf5; id=4; } if( sdf6<sdf ) { sdf=sdf6; id=5; } if( sdf7<sdf ) { sdf=sdf7; id=6; } return sdf; } vec3 calcNormal( in vec3 pos ) { vec3 e = vec3(0.0002, 0.0, 0.0); vec3 n; int id; n.x = f(pos + e.xyy,id) - f(pos - e.xyy,id); n.y = f(pos + e.yxy,id) - f(pos - e.yxy,id); n.z = f(pos + e.yyx,id) - f(pos - e.yyx,id); return normalize(n); } vec3 getColor( int id ) { vec3 color; if(id==0) color = vec3(0.64,0.15,0.1); else if(id==1) color = vec3(0.15,0.5,0.15); else if(id==5) color = vec3(0.15,0.15,0.5); else if(id==6) color = vec3(0.5,0.15,0.5); else color = vec3(0.76,0.75,0.5); return color; } void main(void) { vec2 p = -1.0 + 2.0 * gl_FragCoord.xy / resolution.xy; vec3 color = vec3(0.0,0.0,0.0); // perspective fov 45? vec3 Ro = vec3(0.0,0.0,-1.0); // ray origin vec3 Rd = vec3(p.x,p.y,1.0); // ray direction Rd = normalize(Rd); float t = 0.0; const int maxsteps = 75; for(int steps = 0; steps < maxsteps; steps++) { vec3 pos = Ro+t*Rd; int id; float d = f(pos,id); const float eps = 0.001; if(d < eps) { color = getColor( id ); vec3 n = calcNormal( pos ); // ambient occlusion vec4 totao = vec4(0.0); float sca = 1.0; for( int aoi=0; aoi<5; aoi++ ) { float hr = 0.01 + 0.02*float(aoi*aoi); vec3 aopos = n * hr + pos; int tid; float dd = f( aopos, tid ); float ao = clamp( -(dd-hr), 0.0, 1.0); totao += ao*sca*vec4(getColor(tid),1.0); sca *= 0.75; } totao.w = 1.0 - clamp( 1.5*totao.w, 0.0, 1.0 ); color = 1.2*color*(0.6+0.4*dot(n,vec3(0.577)))*totao.w; color += 2.4*vec3(1.0)*pow(0.5+0.5*dot(n,Rd),2.0)*totao.w; color += 2.0*(0.5+0.5*color)*totao.xyz*totao.w; break; } t = t + d; } gl_FragColor = vec4(color,1.0); }


BB Image

But at this point it would be beneficial to generate the AO points really in an hemisphere, not just in a line, i guess.
added on the 2011-03-29 23:35:14 by iq iq
Nice work iq + SLeo!

One question though, anyone got any ideas for antialising? Its pretty much the only thing that hasn't been talked about yet.
added on the 2011-03-30 05:49:26 by Mewler Mewler
yes hemispherical AO is that it supposed to be by definition of AO, I will try to implement it later, there are some similarities to casting rays in random direction i.e. vec3 noise(int n) and calculation average!?

Adding point light halfed FPS and also this my perspective Rd is sux
BB Image

BB Image

Antialiasing has Scatter Not Gather problem, so I think it is possible using multistep post-processing using world space positions texture? Doing this in fragment shader of two triangles will be not realtime?
added on the 2011-03-30 06:49:11 by SLeo SLeo
For anti aliasing, you can use "cone tracing" described in this paper.
Else you can implement MLAA in a post process pass!
added on the 2011-03-30 09:28:26 by Anat Anat
sleo: nice shadows.

I love how with these things, the first pic looks really crappy (like your first box, and my first one which was just a grey sphere) but it's awesome because of what it represents. Then in a short time it goes from something crappy looking to something really cool :)
added on the 2011-03-30 10:55:25 by psonice psonice
psonice: hope you dont mean the shadows in the last image?
added on the 2011-03-30 12:56:31 by the_Ye-Ti the_Ye-Ti
psionice: uhmm.. the last picture is (more or less) the original cornell box, ie the "target"
added on the 2011-03-30 12:58:11 by Psycho Psycho
haha, missed that :D Oops!
added on the 2011-03-30 13:11:18 by psonice psonice
Nice cornell box you got there. Can you share the code? :)
I would like to try some further colorbleeding - "hemisphere" stuff.
added on the 2011-03-30 14:58:37 by las las
(and yes I am even too lazy to do my own cornell box) ;)
added on the 2011-03-30 14:59:13 by las las
las, most of the code is there above :)

I had a quick go at the cornell box during lunch. Got it looking kind of ok, but the lighting sucks compared to the one above. My soft shadows don't look anywhere near as good.

I tried colour bleeding too, but it ended up looking like broken reflections. So in the end I turned on reflections properly and played with a cornell mirror box ;)
added on the 2011-03-30 15:07:19 by psonice psonice
it is not my Cornell Box, it is original Cornell Box, I also would like to see shadertoyish code for it :)
added on the 2011-03-30 16:11:52 by SLeo SLeo
sleo: you pretty much have the code, no? Just replace the balls with boxes. And add some crazy lighting :)

I'm sure it's possible to render at that quality with raymarching, just maybe not quite in realtime ;) We should be able to get a decent compromise though.
added on the 2011-03-30 16:30:49 by psonice psonice
psonice: given that you're dealing with a bunch of boxes there are you seriously going to raymarch? ray/box test anyone? :)
added on the 2011-03-30 16:55:03 by smash smash
raytrace the boxes, raymarch the shadows? (That's how I've been doing it anyway.. or combination trace/march for scenes with stuff I can't trace).

One thing I've not managed to figure out though: is it possible to raytrace a cube with domain repetition?
added on the 2011-03-30 17:05:59 by psonice psonice
@XT95^FRq Thanks! I'd seen that site but didn't know they had released the code. Looks my Antialising problem is solved. For now :D
added on the 2011-03-31 02:58:29 by Mewler Mewler
Ok, I just ported the MLAA shader from http://www.iryoku.com/mlaa/ to GLSL and have run into some problems with the weight calculation code. The rest of the shaders are really straightforward but I have no idea what this is doing. All it does is return a black screen when I run it. Its also asking for some areamap texture, which I gave it, but I have no idea what it does. Still a black screen :/
added on the 2011-03-31 07:25:56 by Mewler Mewler
Heres the code in question.

/**
* Ok, we have the distance and both crossing edges, can you please return
* the float2 blending weights?
*/

float2 Area(float2 distance, float e1, float e2) {
// * By dividing by areaSize - 1.0 below we are implicitely offsetting to
// always fall inside of a pixel
// * Rounding prevents bilinear access precision problems
float areaSize = MAX_DISTANCE * 5;
float2 pixcoord = MAX_DISTANCE * round(4.0 * float2(e1, e2)) + distance;
float2 texcoord = pixcoord / (areaSize - 1.0);
return areaTex.SampleLevel(PointSampler, texcoord, 0).rg;
}

/**
* Search functions for the 2nd pass.
*/

float SearchXLeft(float2 texcoord) {
texcoord -= float2(1.5, 0.0) * PIXEL_SIZE;
float e = 0.0;
// We offset by 0.5 to sample between edgels, thus fetching two in a row
for (int i = 0; i < maxSearchSteps; i++) {
e = edgesTex.SampleLevel(LinearSampler, texcoord, 0).g;
// We compare with 0.9 to prevent bilinear access precision problems
[flatten] if (e < 0.9) break;
texcoord -= float2(2.0, 0.0) * PIXEL_SIZE;
}
// When we exit the loop without founding the end, we want to return
// -2 * maxSearchSteps
return max(-2.0 * i - 2.0 * e, -2.0 * maxSearchSteps);
}

float SearchXRight(float2 texcoord) {
texcoord += float2(1.5, 0.0) * PIXEL_SIZE;
float e = 0.0;
for (int i = 0; i < maxSearchSteps; i++) {
e = edgesTex.SampleLevel(LinearSampler, texcoord, 0).g;
[flatten] if (e < 0.9) break;
texcoord += float2(2.0, 0.0) * PIXEL_SIZE;
}
return min(2.0 * i + 2.0 * e, 2.0 * maxSearchSteps);
}

float SearchYUp(float2 texcoord) {
texcoord -= float2(0.0, 1.5) * PIXEL_SIZE;
float e = 0.0;
for (int i = 0; i < maxSearchSteps; i++) {
e = edgesTex.SampleLevel(LinearSampler, texcoord, 0).r;
[flatten] if (e < 0.9) break;
texcoord -= float2(0.0, 2.0) * PIXEL_SIZE;
}
return max(-2.0 * i - 2.0 * e, -2.0 * maxSearchSteps);
}

float SearchYDown(float2 texcoord) {
texcoord += float2(0.0, 1.5) * PIXEL_SIZE;
float e = 0.0;
for (int i = 0; i < maxSearchSteps; i++) {
e = edgesTex.SampleLevel(LinearSampler, texcoord, 0).r;
[flatten] if (e < 0.9) break;
texcoord += float2(0.0, 2.0) * PIXEL_SIZE;
}
return min(2.0 * i + 2.0 * e, 2.0 * maxSearchSteps);
}


/**
* S E C O N D P A S S
*/

float4 BlendingWeightCalculationPS(float4 position : SV_POSITION,
float2 texcoord : TEXCOORD0) : SV_TARGET {
float4 weights = 0.0;

float2 e = edgesTex.SampleLevel(PointSampler, texcoord, 0).rg;

[branch]
if (e.g) { // Edge at north

// Search distances to the left and to the right:
float2 d = float2(SearchXLeft(texcoord), SearchXRight(texcoord));

// Now fetch the crossing edges. Instead of sampling between edgels, we
// sample at -0.25, to be able to discern what value has each edgel:
float4 coords = mad(float4(d.x, -0.25, d.y + 1.0, -0.25),
PIXEL_SIZE.xyxy, texcoord.xyxy);
float e1 = edgesTex.SampleLevel(LinearSampler, coords.xy, 0).r;
float e2 = edgesTex.SampleLevel(LinearSampler, coords.zw, 0).r;

// Ok, we know how this pattern looks like, now it is time for getting
// the actual area:
weights.rg = Area(abs(d), e1, e2);
}

[branch]
if (e.r) { // Edge at west

// Search distances to the top and to the bottom:
float2 d = float2(SearchYUp(texcoord), SearchYDown(texcoord));

// Now fetch the crossing edges (yet again):
float4 coords = mad(float4(-0.25, d.x, -0.25, d.y + 1.0),
PIXEL_SIZE.xyxy, texcoord.xyxy);
float e1 = edgesTex.SampleLevel(LinearSampler, coords.xy, 0).g;
float e2 = edgesTex.SampleLevel(LinearSampler, coords.zw, 0).g;

// Get the area for this direction:
weights.ba = Area(abs(d), e1, e2);
}

return saturate(weights);
}
added on the 2011-03-31 07:27:32 by Mewler Mewler
Mewler: no idea on the shader as a whole, not tried it, but does the shader compile?

You have a bunch of ints used in floats there (as in float x = 0; instead of float x = 0.;) which will surely break it on ATI as it's against the spec. Nvidia will likely let it go and run it. (Which is why you should code on ATI if you're doing openGL :)
added on the 2011-03-31 11:50:28 by psonice psonice
no, it's hlsl and ints are okay to use there, for both nvidia and ati
glsl sucks!=D
added on the 2011-03-31 12:08:47 by unc unc
Hmm... but he said he ported it to glsl. And then posted hlsl code, which I totally failed to notice. Somebody needs more sleep, but I don't know who. Maybe all of us need more sleep :)
added on the 2011-03-31 12:13:57 by psonice psonice
Mewler: I also tried this implementation of MLAA and it works perfect. But I was using dx9 version.
If you just copied shader code (so its ok) problem must be somewhere else.
added on the 2011-03-31 17:55:51 by dys129 dys129
we can use "sphere tracing's" parallel surfaces problem as cool effect :)

Code:color = vec3(float(steps)/float(maxsteps)); gl_FragColor = vec4(color,1.0); return;


BB Image
added on the 2011-03-31 19:35:03 by SLeo SLeo

login

Go to top