Skip to content

Instantly share code, notes, and snippets.

@ishikawash
Created January 23, 2013 16:05
Show Gist options
  • Save ishikawash/4608718 to your computer and use it in GitHub Desktop.
Save ishikawash/4608718 to your computer and use it in GitHub Desktop.
Distance function : example program
#version 120
// === vertex shader
//
// When you use OpenGL Shader Builder to execute shader programs,
// * select plane as geometry
// * set resolution to 640x480
// * set scale_factor to 2.5
uniform vec2 resolution;
const float scale_factor = 2.5;
void main()
{
float aspect = resolution.y/resolution.x;
vec2 v = vec2(scale_factor*gl_Vertex.x, aspect*scale_factor*gl_Vertex.y);
gl_Position = gl_ModelViewProjectionMatrix * vec4(v.x, v.y, 0.0, 1.0);
}
#version 120
// === fragment shader
//
// reference
// * http://www.iquilezles.org/www/articles/raymarchingdf/raymarchingdf.htm
// * http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
uniform float time;
uniform vec2 resolution;
uniform vec4 light_direction;
const float EPSILON = 1.0e-4;
const int ITERATION_MAX = 48;
float sdSphere( vec3 p, float s )
{
return length(p)-s;
}
float udRoundBox( vec3 p, vec3 b, float r )
{
return length(max(abs(p)-b,0.0))-r;
}
float sdTorus( vec3 p, vec2 t )
{
vec2 q = vec2(length(p.xz)-t.x,p.y);
return length(q)-t.y;
}
float opU( float d1, float d2 )
{
return min(d1,d2);
}
mat4 translate_matrix(float x, float y, float z)
{
mat4 m = mat4(1.0);
m[3][0] = x;
m[3][1] = y;
m[3][2] = z;
return m;
}
mat4 scale_matrix(float x, float y, float z)
{
mat4 m = mat4(1.0);
m[0][0] = x;
m[1][1] = y;
m[2][2] = z;
return m;
}
mat4 rotate_matrix(vec3 n, float theta)
{
float c = cos(theta);
float s = sin(theta);
mat4 m = mat4(1.0);
m[0][0] = n.x*n.x*(1.0 - c) + c;
m[1][0] = n.x*n.y*(1.0 - c) + n.z*s;
m[2][0] = n.z*n.x*(1.0 - c) - n.y*s;
m[0][1] = n.x*n.y*(1.0 - c) - n.z*s;
m[1][1] = n.y*n.y*(1.0 - c) + c;
m[2][1] = n.y*n.z*(1.0 - c) + n.x*s;
m[0][2] = n.z*n.x*(1.0 - c) + n.y*s;
m[1][2] = n.y*n.z*(1.0 - c) - n.x*s;
m[2][2] = n.z*n.z*(1.0 - c) + c;
return m;
}
float compute_distance(vec3 position)
{
// return sdTorus(position, vec2(1.0, 0.5));
float d1 = sdSphere(position, 2.0);
float d2 = udRoundBox(position, vec3(1.4), 0.1);
return opU(d1, d2);
}
vec3 estimate_normal(vec3 p)
{
float dx = compute_distance(vec3(p.x + EPSILON, p.y, p.z)) - compute_distance(vec3(p.x - EPSILON, p.y, p.z));
float dy = compute_distance(vec3(p.x, p.y + EPSILON, p.z)) - compute_distance(vec3(p.x, p.y - EPSILON, p.z));
float dz = compute_distance(vec3(p.x, p.y, p.z + EPSILON)) - compute_distance(vec3(p.x, p.y, p.z - EPSILON));
return normalize(vec3(dx, dy, dz));
}
vec4 shade(vec3 N, vec3 L)
{
float kd = clamp(dot(N, L), 0.0, 1.0);
return vec4(kd, kd, kd, 1.0);
}
void main()
{
float aspect = resolution.y/resolution.x;
vec2 uv = 2.0*gl_FragCoord.xy/resolution - 1.0;
uv.y = aspect*uv.y;
vec3 ray_origin = vec3(0.0, 0.0, 5.0);
vec3 ray_direction = normalize(vec3(uv - ray_origin.xy, -1.0));
mat4 M = rotate_matrix(vec3(0.0, 1.0, 0.0), 0.7) * rotate_matrix(vec3(1.0, 0.0, 0.0), time) * scale_matrix(1.0, 1.0, 1.0) * translate_matrix(0.0, 0.0, 1.0);
vec3 L = normalize(-1.0 * ( M * light_direction ).xyz);
vec3 N = vec3(0.0);
float t = 0.0;
bool hit = false;
for (int i = 0; i < ITERATION_MAX; i++) {
vec3 p = ( M * vec4(ray_origin + t*ray_direction, 1.0) ).xyz;
float d = compute_distance(p);
if (d < EPSILON) {
N = estimate_normal(p);
hit = true;
break;
}
t += d;
}
if (hit) {
gl_FragColor = shade(N, L);
} else {
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment