Last active
December 21, 2020 13:36
-
-
Save velikodniy/fdfa5ca223c13e1cc6323a1f655c1415 to your computer and use it in GitHub Desktop.
Ray marching example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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