#version 430 layout(local_size_x = 1, local_size_y = 1) in; #include #include #include uniform float seconds = 0; uniform vec3 camera_position = vec3(0, 1, 0); uniform mat3 camera_transformation; uniform vec3 key_light_position; layout(rgba8) uniform writeonly image2D output_image; const vec3 door1_light_position = vec3(0.8, 4, 0.4); const vec3 sunlight_color = vec3(1, 0.99, 0.99); #define PI 3.14159265358979323 struct Obj { int objid; float dist; vec3 material; bool lighting; float shine; }; Obj null_object = Obj(-1, -1.0, vec3(0.01), false, 0.0); // 0.35, 0.6, 0.9 Obj create_obj(in int objid, in float dist) { return Obj(objid, dist, vec3(1), true, 0.0); } Obj scene(in vec3 p) { vec3 doorpos = p - vec3(-0.5, 1.4, 5); vec3 doorsize = vec3(1., 2., 0.1); float doorbody = sdf_box(doorpos, doorsize, 0.04); doorbody = ssubtract(doorbody, sdf_box(doorpos - vec3(0, 1.1, -0.2), vec3(0.65, 0.5, 0.1), 0), 0.1); doorbody = ssubtract(doorbody, sdf_box(doorpos - vec3(0, -0.75, -0.2), vec3(0.65, 0.85, 0.1), 0), 0.1); Obj doorhandle = create_obj(2, sdf_circle(doorpos - vec3(0.75, 0.34, -0.3), 0.1)); doorhandle.material = vec3(0.4, 0.4, 0.4); doorhandle.shine = 22.0; Obj door = create_obj(2, doorbody); door.material = vec3(0.68, 0.17, 0.20); door.shine = 2.0; float doorframe = ssubtract( sdf_box(doorpos - vec3(0, 0.5, 0), vec3(2., 2.6, 0.1), 0), sdf_box(doorpos, doorsize + vec3(0.01, 0.01, 0.04), 0), 0.0); vec3 wallpos = doorpos; wallpos.xz *= mat2x2(cos(PI / 2.), -sin(PI / 2.), sin(PI / 2.), cos(PI / 2.)); float wallsides = min( sdf_box(wallpos - vec3(0, 0.5, -2), vec3(2., 2.6, 0.08), 0), sdf_box(wallpos - vec3(0, 0.5, 2), vec3(2., 2.6, 0.08), 0)); float roof = sdf_box(doorpos - vec3(0, 3.3, -2), vec3(2., 0.08, 2.6), 0); Obj walls = create_obj(2, min(min(doorframe, wallsides), roof)); walls.material = vec3(0.15, 0.28, 0.42); Obj debugdot = create_obj(-1, sdf_circle(p - door1_light_position, 0.1)); debugdot.lighting = false; debugdot.material = vec3(0, 1, 0); Obj floor = create_obj(0, sdf_plane(p - vec3(0, -0.6, 0), vec3(0, 1, 0), 0.0)); floor.material = vec3(0.4); float dist = floor.dist; dist = min(door.dist, dist); dist = min(doorhandle.dist, dist); dist = min(walls.dist, dist); dist = min(debugdot.dist, dist); if (dist == door.dist) return door; if (dist == doorhandle.dist) return doorhandle; if (dist == floor.dist) return floor; if (dist == walls.dist) return walls; if (dist == debugdot.dist) return debugdot; return null_object; } #define RM_SHADOW_MAX_ITERATIONS 100 #define RM_MAX_ITERATIONS 300 #define RM_MAX_DISTANCE 80 Obj ray_march_scene(in vec3 ray_origin, in vec3 ray_direction) { float dist = 0; for (int i = 0; i < RM_MAX_ITERATIONS && dist < RM_MAX_DISTANCE; i++) { vec3 p = ray_origin + ray_direction * dist; Obj o = scene(p); dist += o.dist; if (o.dist <= 0.01) { o.dist = dist; return o; } } return null_object; } vec3 surface_normal_scene(in vec3 p) { vec2 e = vec2(0.01, 0); return normalize(vec3( scene(p + e.xyy).dist - scene(p - e.xyy).dist, scene(p + e.yxy).dist - scene(p - e.yxy).dist, scene(p + e.yyx).dist - scene(p - e.yyx).dist)); } float shadow_scene(in vec3 ray_origin, in vec3 ray_direction, in float light_intensity) { float dist = 0.015; float res = 1.; float prev_gap = 1e10; for (int i = 0; i < RM_SHADOW_MAX_ITERATIONS && dist < RM_MAX_DISTANCE; i++) { vec3 p = ray_origin + dist * ray_direction; Obj obj = scene(p); float gap = obj.dist; if (!obj.lighting) continue; float y = gap * gap / (10000.0 * prev_gap); float d = sqrt(abs(gap * gap - y * y)); res = min(res, light_intensity * d / max(0, dist - y)); prev_gap = gap; dist += gap; if (res < 0.0001) break; } res = clamp(res * 1.1, 0.18, 1.0); return res * res * (3.0 - 2.0 * res); } void main() { vec2 resolution = vec2(imageSize(output_image).xy); float aspect_ratio = resolution.y / resolution.x; vec2 uv = (gl_GlobalInvocationID.xy - resolution / 2) * vec2(1.0, aspect_ratio) / resolution; vec3 origin = vec3(0); vec3 uv_direction = normalize((vec3(uv.x, uv.y, 1) - origin) * camera_transformation + origin); Obj obj = ray_march_scene(camera_position, uv_direction); vec3 p = camera_position + uv_direction * obj.dist; vec3 normal = surface_normal_scene(p); vec3 color = srgb(obj.material); if (obj.lighting) { float ambient = 0.03; vec3 keyl_dir = normalize(key_light_position - p); float key_contrast = 1.; key_contrast *= clamp(dot(normal, keyl_dir), 0, 1); key_contrast *= shadow_scene(p, keyl_dir, 8.); key_contrast = clamp(key_contrast, 0, 1); vec3 door1_ldir = normalize(door1_light_position - p); float door1_contrast = 1.; door1_contrast *= clamp(dot(normal, door1_ldir), 0, 1); door1_contrast *= shadow_scene(p, door1_ldir, 128.); door1_contrast = clamp(door1_contrast, 0, 1); float contrast = max(key_contrast, door1_contrast); color *= clamp(ambient + contrast * (1.0 - ambient), 0, 1); vec3 hal_door1 = normalize(door1_ldir - uv_direction); float spec_door1 = pow(clamp(dot(normal, hal_door1), 0.0, 1.0), 16.0) * contrast * (0.04 + 0.96 * pow(clamp(1.0 + dot(hal_door1, uv_direction), 0.0, 1.0), 5.0)); color += obj.shine * spec_door1 * vec3(1.00, 0.70, 0.5); } color = clamp(color, 0, 1); imageStore(output_image, ivec2(gl_GlobalInvocationID.xy), vec4(color, 1)); }