pouët.net

Raymarching Beginners' Thread

category: code [glöplog]
You are not the first to figure that out ;)
Watch for instance cdak.
added on the 2011-03-31 19:54:16 by las las
added on the 2011-03-31 22:08:04 by iq iq
I think there's a TON of quite stuff to use that actually..
added on the 2011-04-01 02:50:49 by ferris ferris

@SLeo I use this for my glow, completely kills banding.

Code:// Marching Loop... m+=d; a+=smoothstep(.0,.00555555/m,d); // Bla bla bla glow=smoothstep(0,1.6180339887,a*0.00555555); glow*=glow*1.6180339887;


You don't need to use 1.6180- but it looks good for HDR, plus I love messing with the golden ration. Try twisting things with it :D

@psonice I ported it perfectly over to opengl, it compiles fine, just doesn't render anything. Here's my ported code for that part. A few hacks, but I just want to get it to render the weights. All the other passes I've ported without problems. I think its something to do with the area calculation texture, but I don't have a clue what it does so I can't work it out.

Code:uniform sampler2D Tex0; uniform sampler2D Tex1; float SearchXLeft(vec2 texcoord) { texcoord -= vec2(1.5, 0.0) * vec2(1.0 / 1920.0, 1.0 / 1080.0); float e = 0.0; int i; // We offset by 0.5 to sample between edgels, thus fetching two in a row for (i = 0; i < 8; i++) { e = texture2D(Tex0, texcoord).g; // We compare with 0.9 to prevent bilinear access precision problems //if (e < 0.9) {return max(-2.0 * i - 2.0 * e, -2.0 * 8);}; texcoord -= vec2(2.0, 0.0) * vec2(1.0 / 1920.0, 1.0 / 1080.0); } // 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 * 8); } float SearchXRight(vec2 texcoord) { texcoord += vec2(1.5, 0.0) * vec2(1.0 / 1920.0, 1.0 / 1080.0); float e = 0.0; int i; for (i = 0; i < 8; i++) { e = texture2D(Tex0, texcoord).g; //if (e < 0.9) {min(2.0 * i + 2.0 * e, 2.0 * 8);}; texcoord += vec2(2.0, 0.0) * vec2(1.0 / 1920.0, 1.0 / 1080.0); } return min(2.0 * i + 2.0 * e, 2.0 * 8); } float SearchYUp(vec2 texcoord) { texcoord -= vec2(0.0, 1.5) * vec2(1.0 / 1920.0, 1.0 / 1080.0); float e = 0.0; int i; for (i = 0; i < 8; i++) { e = texture2D(Tex0, texcoord).r; // if (e < 0.9) {max(-2.0 * i - 2.0 * e, -2.0 * 8);}; texcoord -= vec2(0.0, 2.0) * vec2(1.0 / 1920.0, 1.0 / 1080.0); } return max(-2.0 * i - 2.0 * e, -2.0 * 8); } float SearchYDown(vec2 texcoord) { texcoord += vec2(0.0, 1.5) * vec2(1.0 / 1920.0, 1.0 / 1080.0); float e = 0.0; int i; for (i = 0; i < 8; i++) { e = texture2D(Tex0, texcoord).r; //if (e < 0.9) {min(2.0 * i + 2.0 * e, 2.0 * 8);}; texcoord += vec2(0.0, 2.0) * vec2(1.0 / 1920.0, 1.0 / 1080.0); } return min(2.0 * i + 2.0 * e, 2.0 * 8); } vec4 mad(vec4 a, vec4 b, vec4 c) { return a*b+c; } vec2 Area(vec2 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 = 32 * 5; vec2 r = 4.0 * vec2(e1, e2); //r.x = sign(r.x) * floor(abs(r.x) + 0.5); //r.y = sign(r.y) * floor(abs(r.y) + 0.5); vec2 pixcoord = 32 * r + distance; vec2 texcoord = pixcoord / (areaSize - 1.0); return texture2D(Tex1, texcoord).rg; } void main(void) { vec4 weights = vec4(0.0); vec2 e = texture2D(Tex0, gl_TexCoord[0].xy).rg; if (e.g>0.0f) { // Edge at north // Search distances to the left and to the right: vec2 d = vec2(SearchXLeft(gl_TexCoord[0].xy), SearchXRight(gl_TexCoord[0].xy)); // 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: vec4 coords = mad(vec4(d.x, -0.25, d.y + 1.0, -0.25), vec2(1.0 / 1920.0, 1.0 / 1080.0).xyxy, gl_TexCoord[0].xyxy); float e1 = texture2D(Tex0, coords.xy, 0).r; float e2 = texture2D(Tex0, 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); } if (e.r>0.0f) { // Edge at west // Search distances to the top and to the bottom: vec2 d = vec2(SearchYUp(gl_TexCoord[0].xy), SearchYDown(gl_TexCoord[0].xy)); // Now fetch the crossing edges (yet again): vec4 coords = mad(vec4(-0.25, d.x, -0.25, d.y + 1.0), vec2(1.0 / 1920.0, 1.0 / 1080.0).xyxy, gl_TexCoord[0].xyxy); float e1 = texture2D(Tex0, coords.xy, 0).g; float e2 = texture2D(Tex0, coords.zw, 0).g; // Get the area for this direction: weights.ba = Area(abs(d), e1, e2); } gl_FragColor = clamp(weights, 0.0, 1.0); }
added on the 2011-04-01 03:15:03 by Mewler Mewler
Worked for me, after I fixed the 'nvidia bugs' ;) (There was still a bunch of int * float operations, and floats declared without the decimal). I've increased the brightness a lot to make it more visible (maybe if your screen isn't quite right, it's working ok but it's too dark to see?)

BB Image

Code:uniform sampler2D Tex0; uniform sampler2D Tex1; float SearchXLeft(vec2 texcoord) { texcoord -= vec2(1.5, 0.0) * vec2(1.0 / 1920.0, 1.0 / 1080.0); float e = 0.0; float i; // We offset by 0.5 to sample between edgels, thus fetching two in a row for (i = 0.; i < 8.; i++) { e = texture2D(Tex0, texcoord).g; // We compare with 0.9 to prevent bilinear access precision problems //if (e < 0.9) {return max(-2.0 * i - 2.0 * e, -2.0 * 8);}; texcoord -= vec2(2.0, 0.0) * vec2(1.0 / 1920.0, 1.0 / 1080.0); } // 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 * 8.); } float SearchXRight(vec2 texcoord) { texcoord += vec2(1.5, 0.0) * vec2(1.0 / 1920.0, 1.0 / 1080.0); float e = 0.0; float i; for (i = 0.; i < 8.; i++) { e = texture2D(Tex0, texcoord).g; //if (e < 0.9) {min(2.0 * i + 2.0 * e, 2.0 * 8);}; texcoord += vec2(2.0, 0.0) * vec2(1.0 / 1920.0, 1.0 / 1080.0); } return min(2.0 * i + 2.0 * e, 2.0 * 8.); } float SearchYUp(vec2 texcoord) { texcoord -= vec2(0.0, 1.5) * vec2(1.0 / 1920.0, 1.0 / 1080.0); float e = 0.0; float i; for (i = 0.; i < 8.; i++) { e = texture2D(Tex0, texcoord).r; // if (e < 0.9) {max(-2.0 * i - 2.0 * e, -2.0 * 8);}; texcoord -= vec2(0.0, 2.0) * vec2(1.0 / 1920.0, 1.0 / 1080.0); } return max(-2.0 * i - 2.0 * e, -2.0 * 8.); } float SearchYDown(vec2 texcoord) { texcoord += vec2(0.0, 1.5) * vec2(1.0 / 1920.0, 1.0 / 1080.0); float e = 0.0; float i; for (i = 0.; i < 8.; i++) { e = texture2D(Tex0, texcoord).r; //if (e < 0.9) {min(2.0 * i + 2.0 * e, 2.0 * 8);}; texcoord += vec2(0.0, 2.0) * vec2(1.0 / 1920.0, 1.0 / 1080.0); } return min(2.0 * i + 2.0 * e, 2.0 * 8.); } vec4 mad(vec4 a, vec4 b, vec4 c) { return a*b+c; } vec2 Area(vec2 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 = 32. * 5.; vec2 r = 4.0 * vec2(e1, e2); //r.x = sign(r.x) * floor(abs(r.x) + 0.5); //r.y = sign(r.y) * floor(abs(r.y) + 0.5); vec2 pixcoord = 32. * r + distance; vec2 texcoord = pixcoord / (areaSize - 1.0); return texture2D(Tex1, texcoord).rg; } void main(void) { vec4 weights = vec4(0.0); vec2 e = texture2D(Tex0, gl_TexCoord[0].xy).rg; if (e.g>0.0) { // Edge at north // Search distances to the left and to the right: vec2 d = vec2(SearchXLeft(gl_TexCoord[0].xy), SearchXRight(gl_TexCoord[0].xy)); // 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: vec4 coords = mad(vec4(d.x, -0.25, d.y + 1.0, -0.25), vec2(1.0 / 1920.0, 1.0 / 1080.0).xyxy, gl_TexCoord[0].xyxy); float e1 = texture2D(Tex0, coords.xy, 0.).r; float e2 = texture2D(Tex0, 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); } if (e.r>0.0) { // Edge at west // Search distances to the top and to the bottom: vec2 d = vec2(SearchYUp(gl_TexCoord[0].xy), SearchYDown(gl_TexCoord[0].xy)); // Now fetch the crossing edges (yet again): vec4 coords = mad(vec4(-0.25, d.x, -0.25, d.y + 1.0), vec2(1.0 / 1920.0, 1.0 / 1080.0).xyxy, gl_TexCoord[0].xyxy); float e1 = texture2D(Tex0, coords.xy, 0.).g; float e2 = texture2D(Tex0, coords.zw, 0.).g; // Get the area for this direction: weights.ba = Area(abs(d), e1, e2); } gl_FragColor = clamp(weights*4., 0.0, 1.0); }
added on the 2011-04-01 13:43:55 by psonice psonice
looks... beautiful... should i wear some sort of fancy yellow-blue stereo glasses?
added on the 2011-04-01 19:15:01 by iq iq
No, weighted glasses ;) (it's generating weightings for the AA filter).
added on the 2011-04-01 19:21:53 by psonice psonice
Thanks allot psonice! But it still doesn't work... Still completely black no matter how much I increase the weights by. How are you loading the areatexture(Tex1)? I might be doing it the wrong way of something.
added on the 2011-04-02 06:00:51 by Mewler Mewler
mewler: I had no idea what the textures should be, so I just stuck the colour texture into one and depth into the other. It seemed to generate a weight map, but maybe that's what's wrong?
added on the 2011-04-03 03:54:22 by psonice psonice
in code you are using, tex0 is texture with detected edges (they provide some shader code how to do it) and tex1 (areatexture) is some precalculated texture to get proper weights for blending. If you've downloaded their source code you can find this texture in Media folder - AreaMap9.dds. And you should sample it with clamping and without filtering.
added on the 2011-04-04 00:14:06 by dys129 dys129
@dys129 Thanks, but it still doesn't work. I've ported and tweaked the edge detection shaders to give the EXACT same output as the example program. I've loaded the areatex9 file (Converted to png, is that a problem?), turned of filtering and clamping, and the weight shader is still giving me bogus output. :(

Heres the areatex9 load code, am I doing it right?
Code:int b=8; unsigned char *data = stbi_load(fname, &sx, &sy, &b, 4); glGenTextures(1, &this->tex[texnum]); glBindTexture(GL_TEXTURE_2D, this->tex[texnum]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sx, sy, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*) data); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glBindTexture(GL_TEXTURE_2D, 0);


Also, if I'm loading the areamap9 file, then shouldn't the maxdistance be 8?
added on the 2011-04-04 10:16:56 by Mewler Mewler
you should be using (i guess, im using dx):

Code: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);


and areamap9 is in A8L8 format, so in png you propably have L value in rgb, and A in alpha. So you should sample it like this:

texture2D(Tex1, texcoord).ra;

difference between areamap9,17,33 is just resolution (higher = better and slower).
added on the 2011-04-04 20:53:15 by dys129 dys129
dys129: That should probably be GL_CLAMP_TO_EDGE, not GL_CLAMP.
added on the 2011-04-04 21:01:22 by kusma kusma
uniform sampler2D Tex0;
uniform sampler2D Tex1;

So, here you have 2 textures. Can you show with which portion of your code you assign each of these to your texture images? If you don't initialize your uniforms they will be initialized to 0 by default, so Tex1 should have the same content as Tex0.

Well, i mean, i use something like this in my engine to bind a texture image to a uniform sampler from a fragment shader:

Code: void shaderTextureSet::setTextures( shader *s ) { glUseProgram( s->programID ); for (int i=0; i<int(textures.size()); i++) { glActiveTexture( GL_TEXTURE0+textures[i].textureUnit ); glBindTexture( textures[i].tex->target, textures[i].tex->textureId ); int location = glGetUniformLocation( s->programID, textures[i].name ); if (location >= 0) { glUniform1i( location, textures[i].textureUnit ); } } }

added on the 2011-04-05 10:45:07 by nystep nystep
Can anybody explain me how I can convert an implicit surface formula to a form usable for raymarching?
Let's say I wanna raymarch the Ding-Dong surface:
[code]x^2+y^2=(1-z)z^2[code]
added on the 2011-05-02 14:31:57 by raer raer
to and /code... well.
added on the 2011-05-02 14:32:25 by raer raer
Hello, thank you guys for awesome threads. Well that's my first experience in raymarching http://vimeo.com/23018524
added on the 2011-05-02 19:31:47 by a13X_B a13X_B
Clickable(I hope so) link http://vimeo.com/23018524
added on the 2011-05-02 19:33:00 by a13X_B a13X_B
nice, but it needs more contrast and a ground with shadow :)
added on the 2011-05-02 19:39:48 by las las
a13X_B: better than most! :)
added on the 2011-05-02 19:40:44 by decipher decipher
Yep, that's a cool start. Definitely needs more contrast though, maybe just crank up the AO?
added on the 2011-05-02 20:47:41 by psonice psonice
@RareWtFailWhale: replace = with < or > ?
added on the 2011-05-02 23:01:00 by Inopia Inopia
I thought so too. 0 schould be where the surface is. I tried it, but it didn't work somehow...
added on the 2011-05-03 11:45:45 by raer raer
That is that the function should return something else than 0 for points inside/outside the object...
added on the 2011-05-03 11:46:49 by raer raer
Hi,
Maybe:
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 }
evaldraw syntax :)
added on the 2011-05-03 16:05:34 by knighty knighty

login