(GLSL) Menger Sponge, Raymarching Code Samples Updated

(GLSL) Menger sponge, raymarching



I updated the code samples of the Raymarching article that were a little bit incompatible with recent versions of GLSL Hacker, especially the latest v0.6.3.11 DEV version. Now all raymarching code samples are fully operational.

I took the opportunity to add a new raymarching code sample based on iq’s article about Menger sponge.

The GLSL Hacker demo (menger_sponge.xml) is available in the host_api/GLSL_raymarching/ folder of the code sample pack (DEV version). The use of the latest DEV version of GLSL Hacker to play with demos is highly recommended!

(GLSL) Menger sponge, raymarching
Menger sponge demo under OS X 10.9 with a GeForce GT 650M

(GLSL) Menger sponge, raymarching
Menger sponge demo under Windows with A Radeon R7 (A10-7850K APU)

I don’t know what GLSL instructions are problematic with NVIDIA hardware under Windows, but the tuning of the Menger sponge with a GeForce GTX 660 was just awful. I had tons of NVIDIA OpenGL driver lost connection message boxes with countless reboots (drivers: R334.67)!

NVIDIA OpenGL driver lost connection message box

So I switched to my recent AMD A10-7850K based setup to finish and test the menger sponge demo. With the Radeon R7, there was absolutely no issue!

Here is the complete GLSL fragment shader that does the job:

#version 120
uniform vec3 cam_pos;
uniform float time;
uniform vec2 resolution;
uniform vec2 mouse;

float PI=3.14159265;

vec2 obj_union(in vec2 obj0, in vec2 obj1)
{
  if (obj0.x < obj1.x)
  	return obj0;
  else
  	return obj1;
}

//Floor
vec2 obj_floor(in vec3 p)
{
  return vec2(p.y+10.0,0);
}

//Floor Color (checkerboard)
vec3 floor_color(in vec3 p)
{
   if (fract(p.x*0.2)>0.2)
  {
     if (fract(p.z*0.2)>0.2)
       return vec3(0,0.1,0.2);
     else
       return vec3(1,1,1);
  }
  else
  {
    if (fract(p.z*.2)>.2)
      return vec3(1,1,1);
    else
      return vec3(0.3,0,0);
   }
}

// Primitive color
vec3 prim_c(in vec3 p)
{
  return vec3(0.6,0.6,0.8);
}

///////////////////////////////
// Menger sponge routines
///////////////////////////////

float maxcomp(vec3 p)
{
  float m1 = max(p.x, p.y);
  return max(m1, p.z);
}

vec2 obj_box_s(vec3 p, vec3 b)
{
  vec3  di = abs(p) - b;
  float mc = maxcomp(di);
  float d = min(mc,length(max(di,0.0)));
  return vec2(d,1);
}

vec2 obj_box(vec3 p)
{
  vec3 b=vec3(4.0, 4.0, 4.0);
  return obj_box_s(p, b);
}

vec2 obj_cross(in vec3 p)
{
  float inf = 100;
  vec2 da = obj_box_s(p.xyz,vec3(inf,2.0,2.0));
  vec2 db = obj_box_s(p.yzx,vec3(2.0,inf,2.0));
  vec2 dc = obj_box_s(p.zxy,vec3(2.0,2.0,inf));
  return vec2(min(da.x,min(db.x,dc.x)), 1);
}

vec2 obj_menger_simple(in vec3 p)
{
  vec2 d1 = obj_box(p);
  vec2 d2 = obj_cross(p/3.0);
  float d = max(d1.x, -d2.x);
  return vec2(d,1.0);  
}

vec2 obj_menger(in vec3 p)
{
  vec2 d2 = obj_box(p);
  float s = 1.0;
  for (int m=0; m<3; m++)
  {
    vec3 a = mod(p*s, 2.0)-1.0;
    s *= 3.0;
    vec3 r = 1.0 - 4.0*abs(a);
    vec2 c = obj_cross(r)/s;
    d2.x = max(d2.x,c.x);
  } 
  return d2;  
}

//Objects union
vec2 distance_to_obj(in vec3 p)
{
  return obj_union(obj_floor(p), obj_menger(p));
}

//Scene End

void main(void)
{
  vec2 q = gl_TexCoord[0].xy;
  vec2 vPos = -1.0 + 2.0 * q;

  //Camera animation
  vec3 vuv=vec3(0,1,0);//Change camere up vector here
  vec3 vrp=vec3(0,0,0); //Change camere view here
  float mx=mouse.x*PI*2.0;
  float my=mouse.y*PI/2.01;
  //vec3 prp=vec3(cos(my)*cos(mx),sin(my),cos(my)*sin(mx))*6.0; //Trackball style camera pos
  vec3 prp = cam_pos;
  

  //Camera setup
  vec3 vpn=normalize(vrp-prp);
  vec3 u=normalize(cross(vuv,vpn));
  vec3 v=cross(vpn,u);
  vec3 vcv=(prp+vpn);
  float aspect = (resolution.x/resolution.y);
  vec3 scrCoord=vcv+vPos.x*u*aspect+vPos.y*v;
  //vec3 scrCoord=vcv+vPos.x*u*0.8+vPos.y*v*0.8;
  vec3 scp=normalize(scrCoord-prp);

  //Raymarching
  const vec3 e=vec3(0.02,0,0);
  const float maxd=100.0; //Max depth
  vec2 d=vec2(0.02, 0.0);
  vec3 d2=vec3(0.02, 0.0, 0.0);
  vec3 c,p,n;

  float f=1.0;
  for(int i=0;i<256;i++)
  {
    if ((abs(d.x) < .001) || (f > maxd)) 
      break;
    
    f+=d.x;
    p=prp+scp*f;
    d = distance_to_obj(p);
  }
  
  if (f < maxd)
  {
    if (d.y==0) // y is used to manage materials.
      c=floor_color(p);
    else
      c=prim_c(p);
    
    n=normalize(
      vec3(d.x-distance_to_obj(p-e.xyy).x,
           d.x-distance_to_obj(p-e.yxy).x,
           d.x-distance_to_obj(p-e.yyx).x));
    float b=dot(n,normalize(prp-p));
    gl_FragColor=vec4((b*c+pow(b,60.0))*(1.0-f*.01),1.0);
  }
  else 
  {
    gl_FragColor=vec4(0,0,0,1); //background color
  }
}




I also added in the code sample pack two variations or the Menger sponge fractal: the Menger Journey and the Menger Tower:

(GLSL) Menger Journey demo
Menger Journey

(GLSL) Menger Tower demo
Menger Tower

One thought on “(GLSL) Menger Sponge, Raymarching Code Samples Updated”

  1. John Smith

    Interesting demos.
    Menger sponge demo works good on my GeGorce 660 and 331.93 driver.

Comments are closed.