234 lines
4.7 KiB
GLSL
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"
|