Josip Å tajdohar

2d global ilumination with refractions fragment code:


                uniform sampler2D tDiffuse;
                uniform float iTime;
                uniform vec2 iResolution;
                varying vec2 sv;
                
                #define pi acos(-1.)
                #define aTime 0.2 * iTime 
                #define SAMPLES 128
                #define TRACE_LIM 32
                #define REFLECTION_DEAPTH 4
                
                #define MAX_DIST 1.5e1
                #define MIN_DIST 1e-3
                #define BIAS 1e-2
                #define EPSILON 1e-3
                
                //Based on https://www.shadertoy.com/view/lldcDf, https://github.com/miloyip/light2d, https://dev.to/khalilsaboor/fibonacci-recursion-vs-iteration--474l
                float random (in vec2 st) {
                    return fract(sin(dot(st.xy, vec2(12.9898,78.233)))*43758.5453123);
                }
                
                mat2 r2(float a) {
                    float c = cos(a), s = sin(a);
                    return mat2(c,s,-s,c);
                }
                
                float sphereSDF(vec2 p, float size) {
                    return length(p) - size;
                }
                
                float boxSDF(vec2 p, vec2 size) {
                    vec2 r = abs(p) - size;
                    return min(max(r.x, r.y),0.) + length(max(r,vec2(0,0)));
                }
                
                float lenseSDF(vec2 p, vec2 size)
                {
                    float box = boxSDF(p, size);
                    float sphere = sphereSDF(p - vec2(0.0, 1.0) * size.x, size.x);
                    return max(-sphere, box);
                }
                
                float lenseSDF2(vec2 p, vec2 sizeAndFocus)
                {
                    float sphere1 = sphereSDF(p - vec2(sizeAndFocus.y, 0.0), sizeAndFocus.x);
                    float sphere2 = sphereSDF(p + vec2(0.0, sizeAndFocus.y), sizeAndFocus.x);
                    return max(sphere1, sphere2);
                }
                
                //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                //! Reflect Global Ilumination
                struct PBRstruct
                {
                    float dist;
                    vec3 color;
                    float emissive;
                    float reflectivity;
                    float eta;
                };
                
                PBRstruct unionOp(PBRstruct a, PBRstruct b)
                {
                    if(a.dist < b.dist) return a;
                    return b;
                }
                
                PBRstruct intersectOp(PBRstruct a, PBRstruct b)
                {
                    if(a.dist > b.dist) return a;
                    return b;
                }
                
                PBRstruct subtractOp(PBRstruct a, PBRstruct b)
                {
                    PBRstruct c = a;
                    if(a.dist > -b.dist) c.dist = a.dist;
                    else c.dist = -b.dist;
                    return c;
                }
                
                PBRstruct reflectScene(vec2 pos)
                {
                    PBRstruct ball1 = PBRstruct(sphereSDF(pos - vec2(1,3), 1.), vec3(1,.1,.1), 0.8, 0.0, 1.0);
                    PBRstruct ball2 = PBRstruct(sphereSDF(pos - vec2(-1,1), 0.5), vec3(0.02, 0.82,.02), 0.65, 0.0, 1.0);
                
                    PBRstruct lens = PBRstruct(lenseSDF(pos - vec2(0,-1), 5.0 * vec2(0.5, 0.25)),  vec3(.2,.3, 0.3), 0.1, 0.5, 1.3);
                    PBRstruct lens2 = PBRstruct(lenseSDF2(pos - vec2(-5.5, 3.5), vec2(2.0, 1.9)) ,vec3(.2,.3, 0.3), 0.1, 0.20, 1.6);
                    //return unionOp(ball2, lens);
                    return unionOp(unionOp(unionOp(ball1, ball2), lens2), lens);
                }
                
                void gradient(vec2 pos, inout vec2 norm)
                {
                    vec2 deltaX = vec2(EPSILON, 0.0);
                    vec2 deltaY = vec2(0.0, EPSILON);
                    norm.x = (reflectScene(pos + deltaX).dist - reflectScene(pos - deltaX).dist)/ 2.0 * EPSILON;
                    norm.y = (reflectScene(pos + deltaY).dist - reflectScene(pos - deltaY).dist)/ 2.0 * EPSILON;
                    norm = normalize(norm);
                }
                
                void reflect(vec2 dir, vec2 norm, inout vec2 ref)
                {
                    float DdotN = dot(dir, norm) * 2.0;
                    ref = dir - DdotN * norm; 
                    ref = normalize(ref);
                }
                
                int refract(vec2 dir, vec2 norm, float eta, inout vec2 ref)
                {
                    float DdotN = dot(dir, norm);
                    float k = 1.0 - eta * eta * (1.0 - DdotN * DdotN);
                    if(k < 0.0) return 0; //Total internal reflection
                
                    float a = eta * DdotN + sqrt(k);
                    ref = eta * dir - a * norm;
                    ref = normalize(ref);
                    return 1;
                }
                
                void traceRef(inout vec2 pos, inout vec2 dir, inout vec3 c, inout float reflectivity)
                {
                    float d = 0.0;
                    for (int i = 0; i < TRACE_LIM; i++) 
                    {
                        PBRstruct pbrObject = reflectScene(pos);
                        if (abs(pbrObject.dist) < MIN_DIST)
                        {
                            c += pbrObject.color * pbrObject.emissive * reflectivity;
                            reflectivity *= pbrObject.reflectivity;
                            vec2 normal = vec2(0.0);
                            vec2 refl = vec2(0.0);
                
                            float signOfDist = sign(pbrObject.dist);
                
                
                            if(pbrObject.reflectivity > 0.0)
                            {
                                gradient(pos, normal);
                                normal *= signOfDist;
                                reflect(dir, normal, refl);
                            }
                
                            pos += BIAS * normal;
                            dir = refl;
                
                            return;
                        } 
                        if (d > MAX_DIST) break;
                        d += pbrObject.dist;
                        pos += dir * pbrObject.dist;
                    }
                }
                
                void traceRefRef(inout vec2 pos, inout vec2 dir, inout vec3 c, inout float reflectivity, inout float eta)
                {
                    float d = 0.0;
                    for (int i = 0; i < TRACE_LIM; i++) 
                    {
                        PBRstruct pbrObject = reflectScene(pos);
                        if (abs(pbrObject.dist) < MIN_DIST)
                        {
                            c += pbrObject.color * pbrObject.emissive * reflectivity;
                
                            reflectivity *= pbrObject.reflectivity;
                            eta = pbrObject.eta;
                
                
                            vec2 normal = vec2(0.0);
                            vec2 refl = vec2(0.0);
                
                            gradient(pos, normal);
                
                            float signOfDist = sign(pbrObject.dist);
                            normal *= signOfDist;
                
                            eta = pow(pbrObject.eta, -signOfDist);
                
                            int isExternal = refract(dir, normal, eta, refl);
                            vec2 refractionDir = refl;
                
                            if(isExternal == 0)
                            {
                                reflectivity = 1.0;
                                eta = 0.0;
                            }
                
                            if(pbrObject.reflectivity > 0.0)
                            {
                                reflect(dir, normal, refl);
                            }
                
                            float isReflection = 1.0;
                
                            if(eta > 0.0)
                            {
                                isReflection = sign(random(iTime + pos + dir) - 0.5);
                            }
                
                            //isReflection = -1.0;
                
                            pos = pos + isReflection * BIAS * normal;
                            dir = mix(refractionDir, refl, isReflection);
                            reflectivity = mix(1.0 - reflectivity, reflectivity, isReflection);
                
                            return;
                        } 
                        if (d > MAX_DIST) break;
                        d += pbrObject.dist;
                        pos += dir * pbrObject.dist;
                    }
                }
                
                void multiTraceRef(vec2 pos, vec2 dir, out vec3 col)
                {
                    float reflectivity = 1.0;
                    float eta = 1.0;
                    for (int i = 0; i < REFLECTION_DEAPTH; i++)
                    {
                        reflectivity *= pow(2.0, float(i - 1));
                        traceRefRef(pos, dir, col, reflectivity, eta);
                        if(reflectivity <= 0.0 && eta <= 0.0) break;
                    }
                }
                
                void multiTrace(vec2 pos, vec2 dir, out vec3 col)
                {
                    float reflectivity = 1.0;
                    for (int i = 0; i < REFLECTION_DEAPTH; i++)
                    {
                        traceRef(pos, dir, col, reflectivity);
                        if(reflectivity <= 0.0 ) break;
                    }
                }
                
                //! Reflect Global Ilumination
                //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                
                vec3 sample(vec2 uv)
                {
                    vec3 col = vec3(0,0,0);
                    for (int i = 0; i < SAMPLES; i++) {
                        float t = (float(i) + random(uv+float(i)+iTime)) / float(SAMPLES) * 2. * pi;
                        vec3 c = vec3(0.0);
                        multiTraceRef(uv, vec2(cos(t), sin(t)), c);
                        col += c;
                    }
                    col /= float(SAMPLES);
                    return col;
                }
                
                void main()
                {
                    // Normalized pixel coordinates (from 0 to 1)
                    vec2 uv = (sv - 0.5) * iResolution.xy / iResolution.y;
                    uv *= 10.;
                    vec3 col = sample(uv);
                    gl_FragColor = vec4(col, 1.0);
                }