KlassischeKeplerKriege/game/renderer_ray_tracer/raycaster.fs
2016-09-28 11:50:35 +02:00

234 lines
4.7 KiB
GLSL

R"raw_string(
#version 120
struct intersection
{
bool intersected;
vec3 point;
vec3 normal;
vec3 color;
float reflection;
int idx;
//todo different types
};
varying vec2 outvertex;
//settings
uniform float aspectratio;
uniform float time;
uniform int supersamples;
uniform int reflections;
uniform bool shadows;
uniform vec3 backgroundcolor;
//light
uniform vec3 l_position;
uniform float l_radius;
//spheres
//todo ubo?
uniform int s_length;
uniform vec3 s_positions[100];
uniform float s_radii[100];
uniform vec4 s_colors[100];
uniform float s_reflections[100];
const float PI = 3.14159265359;
//din = german industrial normal
float light_diffuse(vec3 pos, vec3 din)
{
vec3 l_dir = normalize(l_position - pos);
return max(dot(l_dir, din), 0.0f);
}
//adapted from https://wiki.delphigl.com/index.php/shader_ConeVolumeShadow
float light_shadow(vec3 pos)
{
float s = 1.0f;
for(int l = 0; l < s_length; l++)
{
vec3 s_pos = s_positions[l];
float s_rad = s_radii[l];
// project fragment (pos) on the cone axis => F_
vec3 nvLO = s_pos - l_position;
float dLO = length(nvLO);
nvLO /= dLO;
vec3 vLF = pos - l_position;
float dLF_ = dot(vLF, nvLO);
if (dLF_ < dLO) {
// fragment before occluder => no shadow
continue;
}
vec3 F_ = l_position + dLF_ * nvLO;
float rF = distance(F_, pos);
// compute outer and inner radius at F_
float rF_outer = (s_rad + l_radius) * (dLF_ / dLO) - l_radius;
if (rF >= rF_outer) {
// outside the outer cone => no shadow
continue;
}
float rF_inner = (s_rad - l_radius) * (dLF_ / dLO) + l_radius;
if (rF_inner >= rF) {
// inside the inner cone => full shadow
return 0.0;
}
else if (rF_inner >= 0.0 || rF >= -rF_inner) {
// soft shadow, linear interpolation
s *= (rF - rF_inner) / (rF_outer - rF_inner);
}
else {
// light from both sides of the occluder
s *= (-2.0*rF_inner) / (rF_outer - rF_inner);
}
}
return s;
}
intersection intersect_sphere(vec3 r_pos, vec3 r_dir, vec3 s_pos, float s_rad, inout float minimum)
{
intersection result = intersection(false,vec3(0.0f, 0.0f, 0.0f),
vec3(0.0f, 0.0f, 0.0f),
vec3(0.0f, 0.0f, 0.0f), 0.0f, -1);
vec3 v = r_pos - s_pos;
float a = dot(r_pos, r_pos);
float b = dot(v, r_dir);
float c = dot(v, v) - (s_rad * s_rad);
float d = b * b - c;
if(d >= 0)
{
float w1 = -b - sqrt(d);
float w2 = -b + sqrt(d);
if(w1 > 0.0f || w2 > 0.0f)
{
float w = min(w1, w2);
float o = max(w1, w2);
if(w1 <= 0.0f)
w = w2;
else
if(w2 <= 0.0f)
w = w1;
if(w < minimum)
{
minimum = w;
}
else
{
return intersection(false,vec3(0.0f, 0.0f, 0.0f),
vec3(0.0f, 0.0f, 0.0f),
vec3(0.0f, 0.0f, 0.0f), 0.0f, -1);
}
vec3 p = r_pos + (w * r_dir);
result.intersected = true;
result.point = p;
result.normal = normalize((p - s_pos) / s_rad);
return result;
}
}
return result;
}
intersection intersect(vec3 r_pos, vec3 r_dir, int idx)
{
intersection result = intersection(false,vec3(0.0f, 0.0f, 0.0f),
vec3(0.0f, 0.0f, 0.0f),
vec3(0.0f, 0.0f, 0.0f), 0.0f, -1);
float minimum = 1000.0f;
for(int l = 0; l < s_length; l++)
{
if(idx == l)
continue;
float maximum;
intersection r = intersect_sphere(r_pos, r_dir, s_positions[l], s_radii[l], minimum);
if(r.intersected)
{
r.color = s_colors[l].rgb;
r.idx = l;
r.reflection = s_reflections[l];
result = r;
}
//todo other geometric objects
//todo handle min with other geometric objects
}
return result;
}
vec3 cast_ray(vec3 r_pos, vec3 r_pixel)
{
vec3 r_dir = normalize(r_pixel - r_pos);
vec3 color = backgroundcolor;
intersection i = intersection(false,vec3(0.0f, 0.0f, 0.0f),
vec3(0.0f, 0.0f, 0.0f),
vec3(0.0f, 0.0f, 0.0f), 0.0f, -1);
vec3 p = r_pos;
vec3 d = r_dir;
int idx = -1;
for(int bounce = 0; bounce < reflections; bounce++)
{
intersection i = intersect(p,d, idx);
if(i.intersected)
{
float l_factor = light_diffuse(i.point, i.normal);
if(shadows && l_factor > 0.004f)
{
l_factor *= light_shadow(i.point);
}
if(bounce == 0)
{
color = i.color * l_factor;
}
else
{
color = mix(color, color * i.color * l_factor, i.reflection);
}
//d = 2*(dot(p, i.normal))*i.normal - p;
d = reflect(-p, i.normal);
p = i.point;
idx = i.idx;
}
else
break;
}
return color;
}
void main()
{
vec2 rp = outvertex;
rp.x = rp.x * aspectratio;
vec4 outcolor = vec4(cast_ray(vec3(0.0f, 0.0f, 1.0f), vec3(rp, 0.0f)), 0.0f);
for(int supersample = 1; supersample < supersamples; supersample++)
{
outcolor = mix(outcolor, vec4(cast_ray(vec3(sin(supersample * PI/supersamples)/200, cos(supersample * PI/supersamples)/200, 1.0f), vec3(rp, 0.0f)), 0.0f), 0.5f);
}
gl_FragColor = outcolor;
}
)raw_string"