Skip to content

Instantly share code, notes, and snippets.

@ishikawash
Created January 27, 2013 13:46
Show Gist options
  • Save ishikawash/4648390 to your computer and use it in GitHub Desktop.
Save ishikawash/4648390 to your computer and use it in GitHub Desktop.
Distance function with texture mapping.
#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_position;
uniform float shiness;
uniform sampler2D tex;
const float PI = 3.14159265;
const float HALF_PI = 0.5*PI;
const float TWO_PI = 2.0*PI;
const float INV_PI = 1.0/PI;
const float INV_TWO_PI = 1.0/TWO_PI;
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 sdCylinder( vec3 p, vec3 c )
{
return length(p.xz-c.xy)-c.z;
}
float opU( float d1, float d2 )
{
return min(d1,d2);
}
float opS( float d1, float d2 )
{
return max(-d1,d2);
}
float opI( float d1, float d2 )
{
return max(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)
{
/*
float d1 = sdSphere(position, 1.0);
float d2 = sdTorus(position, vec2(2.0, 1.2));
return opU(d1, d2);
*/
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));
}
// 'p' must be normalized
vec2 compute_texcoord(vec3 p)
{
float phi = atan(p.y, p.x);
float theta = acos(p.z);
float s = phi*INV_TWO_PI;
float t = theta*INV_PI;
return vec2(s, t);
}
vec4 shade(vec3 E, vec3 N, vec3 L, vec2 st)
{
float kd = clamp(dot(N, L), 0.0, 1.0);
vec3 H = normalize(E + L);
float ks = pow(clamp(dot(N, H), 0.0, 1.0), shiness);
vec4 texel = texture2D(tex, 3.0*st);
vec3 color = kd*texel.xyz + ks*vec3(0.8);
return vec4(color, 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(1.0, 0.0, 0.0), HALF_PI) * rotate_matrix(vec3(0.0, 1.0, 0.0), time) * scale_matrix(1.0, 1.0, 1.0) * translate_matrix(0.0, 0.0, 1.0);
vec3 P = vec3(0.0);
vec3 E = vec3(0.0);
vec3 L = vec3(0.0);
vec3 N = vec3(0.0);
vec2 st = vec2(0.0);
float t = 0.0;
bool hit = false;
for (int i = 0; i < ITERATION_MAX; i++) {
P = ( M * vec4(ray_origin + t*ray_direction, 1.0) ).xyz;
float d = compute_distance(P);
if (d < EPSILON) {
N = estimate_normal( P );
L = normalize((M * light_position).xyz - P);
E = normalize( P );
st = compute_texcoord(E);
hit = true;
break;
}
t += d;
}
if (hit) {
gl_FragColor = shade(E, N, L, st);
} 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