Skip to content

Instantly share code, notes, and snippets.

@velikodniy
Last active December 21, 2020 13:36
Show Gist options
  • Save velikodniy/fdfa5ca223c13e1cc6323a1f655c1415 to your computer and use it in GitHub Desktop.
Save velikodniy/fdfa5ca223c13e1cc6323a1f655c1415 to your computer and use it in GitHub Desktop.
Ray marching example
const int MAX_STEPS = 200;
const float MAX_DEPTH = 20.0;
const float EPS = 0.0001;
const float DIFF_EPS = 0.0001;
const float VERT_FOV = radians(40.0);
const vec3 K_a = vec3(0.1, 0.3, 0.0);
const vec3 K_d = vec3(0.3, 0.7, 0.5);
const vec3 K_s = vec3(1.0, 1.0, 1.0);
const float K_shine = 4.0;
const vec3 lightPos1 = vec3(2.0, -1.0, 0.0);
const vec3 lightIntensity1 = vec3(0.4, 0.4, 0.4);
const vec3 lightPos2 = vec3(-1.0, 3.0, 1.0);
const vec3 lightIntensity2 = vec3(0.2, 0.2, 0.2);
const vec3 ambientLight = vec3(0.3, 0.3, 0.3);
float sphere(vec3 center, float r, vec3 pos) {
return length(pos - center) - r;
}
float cube(vec3 center, float r, vec3 pos) {
vec3 p = pos - center;
vec3 d = abs(p) - r;
float inside = min(0.0, max(max(d.x, d.y), d.z));
float outside = length(max(d, 0.0));
return inside + outside;
}
float scene(vec3 pos) {
float a = (1.0 + cos(iTime * 2.0)) / 2.0;
float cubic_sphere = a * cube(vec3(1.0, -1.0, 3.0), 0.7, pos) +
(1.0 - a) * sphere(vec3(1.0, -1.0, 3.0), 0.7, pos);
float two_spheres = min(
sphere(vec3(0.0, 0.0, 4.0 + 0.5 * cos(iTime)), 0.8, pos),
sphere(vec3(sin(iTime), 0.2, 2.5), 0.4, pos));
return min(cubic_sphere, two_spheres);
}
vec3 estimateNormal(vec3 pos) {
const vec2 delta = vec2(DIFF_EPS, 0.0);
float dx = scene(pos + delta.xyy) - scene(pos - delta.xyy);
float dy = scene(pos + delta.yxy) - scene(pos - delta.yxy);
float dz = scene(pos + delta.yyx) - scene(pos - delta.yyx);
return normalize(vec3(dx, dy, dz));
}
vec3 castRay(vec3 origin, vec3 direction, out bool inter) {
float depth = 0.0;
for(int i = 0; i < MAX_STEPS; i++) {
vec3 pos = origin + depth * direction;
float dist = scene(pos);
if (dist < EPS) {
inter = true;
return pos;
}
depth += dist;
if (depth > MAX_DEPTH)
break;
}
inter = false;
return vec3(0.0);
}
vec3 phongColor(vec3 K_d, vec3 K_s, float shininess, vec3 pos, vec3 camera,
vec3 lightPos, vec3 lightIntensity) {
vec3 N = estimateNormal(pos);
vec3 L = normalize(lightPos - pos);
vec3 V = normalize(camera - pos);
vec3 R = normalize(reflect(-L, N));
float NL = dot(N, L);
float RL = dot(R, L);
vec3 color = vec3(0.0);
bool inter;
castRay(pos + 10.0 * EPS * L, L, inter);
if ((NL < 0.0) || inter) {
return color;
}
color += lightIntensity * K_d * NL;
if (RL < 0.0) {
return color;
}
color += lightIntensity * K_s * pow(RL, shininess);
return color;
}
vec3 phongColor(vec3 K_a, vec3 K_d, vec3 K_s, float shininess, vec3 pos, vec3 camera) {
vec3 color = K_a * ambientLight;;
color += phongColor(K_d, K_s, shininess, pos, camera, lightPos1, lightIntensity1);
color += phongColor(K_d, K_s, shininess, pos, camera, lightPos2, lightIntensity2);
return color;
}
void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
vec2 coord = fragCoord - iResolution.xy / 2.0;
coord /= max(iResolution.x, iResolution.y) / 2.0;
vec3 camera = vec3(0.5 * cos(iTime), 0.5 * sin(iTime), -1.0 / tan(VERT_FOV / 2.0));
vec3 direction = normalize(vec3(coord, 0.0) - camera);
bool inter;
vec3 pos = castRay(camera, direction, inter);
vec3 color;
if (!inter) {
color = vec3(0.0);
} else {
color = phongColor(K_a, K_d, K_s, K_shine, pos, camera);
}
fragColor = vec4(color, 1.0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment