154 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Plaintext
		
	
	
		
		
			
		
	
	
			154 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Plaintext
		
	
	
| 
								 | 
							
								#version 110
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								struct sphere
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    vec3 center;
							 | 
						||
| 
								 | 
							
								    float radius;
							 | 
						||
| 
								 | 
							
								    vec4 color;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								uniform sphere spheres[4];
							 | 
						||
| 
								 | 
							
								uniform float floor_height;
							 | 
						||
| 
								 | 
							
								uniform vec4 floor_color[2];
							 | 
						||
| 
								 | 
							
								uniform vec4 background_color;
							 | 
						||
| 
								 | 
							
								uniform vec3 light_direction;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								varying vec3 ray_origin, ray_direction;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const float FAR_AWAY = 1.0e20;
							 | 
						||
| 
								 | 
							
								const vec4 reflection_color = vec4(1.0, 0.0, 1.0, 0.0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								float sphere_intersect(sphere s, vec3 ro, vec3 rd)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    vec3 dist = (ro - s.center);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    float b = dot(dist, normalize(rd));
							 | 
						||
| 
								 | 
							
								    float c = dot(dist, dist) - s.radius*s.radius;
							 | 
						||
| 
								 | 
							
								    float d = b * b - c;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return d > 0.0 ? -b - sqrt(d) : FAR_AWAY;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								float floor_intersect(float height, vec3 ro, vec3 rd)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    return (height - ro.y) / rd.y;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void
							 | 
						||
| 
								 | 
							
								cast_ray(vec3 ro, vec3 rd, out sphere intersect_sphere, out bool intersect_floor, out float intersect_distance)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    intersect_floor = false;
							 | 
						||
| 
								 | 
							
								    intersect_distance = FAR_AWAY;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for (int i = 0; i < 4; ++i) {
							 | 
						||
| 
								 | 
							
								        float d = sphere_intersect(spheres[i], ro, rd);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (d > 0.0 && d < intersect_distance) {
							 | 
						||
| 
								 | 
							
								            intersect_distance = d;
							 | 
						||
| 
								 | 
							
								            intersect_sphere = spheres[i];
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (intersect_distance >= FAR_AWAY) {
							 | 
						||
| 
								 | 
							
								        intersect_distance = floor_intersect(floor_height, ro, rd);
							 | 
						||
| 
								 | 
							
								        if (intersect_distance < 0.0)
							 | 
						||
| 
								 | 
							
								            intersect_distance = FAR_AWAY;
							 | 
						||
| 
								 | 
							
								        intersect_floor = intersect_distance < FAR_AWAY;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								vec4 render_floor(vec3 at, float distance, bool shadowed)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    vec3 at2 = 0.125 * at;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    float dropoff = exp(-0.005 * abs(distance)) * 0.8 + 0.2;
							 | 
						||
| 
								 | 
							
								    float fade = 0.5 * dropoff + 0.5;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    vec4 color = fract((floor(at2.x) + floor(at2.z)) * 0.5) == 0.0
							 | 
						||
| 
								 | 
							
								        ? mix(floor_color[1], floor_color[0], fade)
							 | 
						||
| 
								 | 
							
								        : mix(floor_color[0], floor_color[1], fade);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    float light = shadowed ? 0.2 : dropoff;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return color * light * dot(vec3(0.0, 1.0, 0.0), -light_direction);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								vec4 sphere_color(vec4 color, vec3 normal, vec3 eye_ray, bool shadowed)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    float light = shadowed
							 | 
						||
| 
								 | 
							
								        ? 0.2
							 | 
						||
| 
								 | 
							
								        : max(dot(normal, -light_direction), 0.0) * 0.8 + 0.2;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    float spec = shadowed
							 | 
						||
| 
								 | 
							
								        ? 0.0
							 | 
						||
| 
								 | 
							
								        : 0.3 * pow(max(dot(reflect(-light_direction, normal), eye_ray), 0.0), 100.0);
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								    return color * light + vec4(spec);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								bool reflection_p(vec4 color)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    vec4 difference = color - reflection_color;
							 | 
						||
| 
								 | 
							
								    return dot(difference, difference) == 0.0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								vec4 render_sphere(sphere s, vec3 at, vec3 eye_ray, bool shadowed)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    vec3 normal = normalize(at - s.center);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    vec4 color;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (reflection_p(s.color)) {
							 | 
						||
| 
								 | 
							
								        sphere reflect_sphere;
							 | 
						||
| 
								 | 
							
								        bool reflect_floor;
							 | 
						||
| 
								 | 
							
								        float reflect_distance;
							 | 
						||
| 
								 | 
							
								        vec3 reflect_direction = reflect(eye_ray, normal);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        cast_ray(at, reflect_direction, reflect_sphere, reflect_floor, reflect_distance);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        vec3 reflect_at = at + reflect_direction * reflect_distance;
							 | 
						||
| 
								 | 
							
								        if (reflect_floor)
							 | 
						||
| 
								 | 
							
								            color = render_floor(reflect_at, reflect_distance, false);
							 | 
						||
| 
								 | 
							
								        else if (reflect_distance < FAR_AWAY) {
							 | 
						||
| 
								 | 
							
								            vec3 reflect_normal = normalize(reflect_at - reflect_sphere.center);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            color = sphere_color(reflect_sphere.color, reflect_normal, reflect_direction, false);
							 | 
						||
| 
								 | 
							
								        } else {
							 | 
						||
| 
								 | 
							
								            color = background_color;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    } else
							 | 
						||
| 
								 | 
							
								        color = s.color;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return sphere_color(color, normal, eye_ray, shadowed);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void
							 | 
						||
| 
								 | 
							
								main()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    vec3 ray_direction_normalized = normalize(ray_direction);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    sphere intersect_sphere;
							 | 
						||
| 
								 | 
							
								    bool intersect_floor;
							 | 
						||
| 
								 | 
							
								    float intersect_distance;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    cast_ray(ray_origin, ray_direction_normalized, intersect_sphere, intersect_floor, intersect_distance);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    vec3 at = ray_origin + ray_direction_normalized * intersect_distance;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    sphere shadow_sphere;
							 | 
						||
| 
								 | 
							
								    bool shadow_floor;
							 | 
						||
| 
								 | 
							
								    float shadow_distance;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    cast_ray(at - 0.0001 * light_direction, -light_direction, shadow_sphere, shadow_floor, shadow_distance);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    bool shadowed = shadow_distance < FAR_AWAY;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (intersect_floor)
							 | 
						||
| 
								 | 
							
								        gl_FragColor = render_floor(at, intersect_distance, shadowed);
							 | 
						||
| 
								 | 
							
								    else if (intersect_distance < FAR_AWAY)
							 | 
						||
| 
								 | 
							
								        gl_FragColor = render_sphere(intersect_sphere, at, ray_direction_normalized, shadowed);
							 | 
						||
| 
								 | 
							
								    else
							 | 
						||
| 
								 | 
							
								        gl_FragColor = background_color;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 |