Josip Å tajdohar

Saturn-like planet fragment code:


                uniform sampler2D tDiffuse;
                uniform float iTime;
                uniform vec2 iResolution;
                varying vec2 sv;

                highp float;

                //common Math region #########################################################
                #define pi acos(-1.)

                float remap01(float value, float minimum, float maximum)
                {
                    return (value - minimum)/(maximum - minimum);
                }

                vec2 remap01(vec2 value, vec2 minimum, vec2 maximum)
                {
                    return (value - minimum)/(maximum - minimum);
                }

                float atan2(in float y, in float x)
                {
                    float s = ceil(sign(abs(x) - abs(y)));
                    return mix(pi/2.0 - atan(x,y), atan(y,x), s);
                }

                float atan3(in float y, in float x)
                {
                    return pi-pi/2.*(1.+sign(x))* (1.-sign(y*y))-pi/4.*(2.+sign(x))*sign(y)-sign(x*y)*atan((abs(x)-abs(y))/(abs(x)+abs(y)));
                }

                vec2 rot2d(vec2 pos, float theta)
                {
                    float c = cos(theta);
                    float s = sin(theta);
                    mat2  m = mat2(c,-s,s,c);
                    return m * pos;
                }

                //retruns the distance of a ray to point if the ray is starting in ro
                float DistanceFromPoinToLine0(vec3 ray, vec3 ro, vec3 point)
                {
                    //https://www.qc.edu.hk/math/Advanced%20Level/Point_to_line.htm  2. method
                    float d = length(cross(point - ro, ray))/length(ray);
                    return d;
                }


                //retruns the distance of a ray to point if the ray is starting in ro
                float DistanceFromPoinToLine(vec3 ray, vec3 ro, vec3 point)
                {
                    //https://www.qc.edu.hk/math/Advanced%20Level/Point_to_line.htm  2. method
                    float d = length(cross(point - ro, ray))/length(ray);
                    return mix(200.0, d, step(0.0, dot(point - ro, ray)));
                }

                float hash00(float p)
                {
                    p = fract(p * .1031);
                    p *= p + 33.33;
                    p *= p + p;
                    return fract(p);
                }


                float hash0(vec3 p)
                {
                    float a = dot(p,vec3(127.1,311.7, 74.7));
                    return -1.0 + 2.0 * fract(sin(a)*43758.5453123);
                }

                vec3 hash( vec3 p ) // replace this by something better
                {
                    p = vec3( dot(p,vec3(127.1,311.7, 74.7)),
                                dot(p,vec3(269.5,183.3,246.1)),
                                dot(p,vec3(113.5,271.9,124.6)));

                    return -1.0 + 2.0*fract(sin(p)*43758.5453123);
                }



                float noise( in vec3 p )
                {
                    vec3 i = floor( p );
                    vec3 f = fract( p );
                    
                    vec3 u = f*f*(3.0-2.0*f);

                    return mix( mix( mix( dot( hash( i + vec3(0.0,0.0,0.0) ), f - vec3(0.0,0.0,0.0) ), 
                                            dot( hash( i + vec3(1.0,0.0,0.0) ), f - vec3(1.0,0.0,0.0) ), u.x),
                                        mix( dot( hash( i + vec3(0.0,1.0,0.0) ), f - vec3(0.0,1.0,0.0) ), 
                                            dot( hash( i + vec3(1.0,1.0,0.0) ), f - vec3(1.0,1.0,0.0) ), u.x), u.y),
                                mix( mix( dot( hash( i + vec3(0.0,0.0,1.0) ), f - vec3(0.0,0.0,1.0) ), 
                                            dot( hash( i + vec3(1.0,0.0,1.0) ), f - vec3(1.0,0.0,1.0) ), u.x),
                                        mix( dot( hash( i + vec3(0.0,1.0,1.0) ), f - vec3(0.0,1.0,1.0) ), 
                                            dot( hash( i + vec3(1.0,1.0,1.0) ), f - vec3(1.0,1.0,1.0) ), u.x), u.y), u.z );
                }



                vec3 opTwist(in vec3 p)
                {
                    float k = 0.65; // or some other amount
                    k *= sin(p.y);
                    float c = cos(k*p.y);
                    float s = sin(k*p.y);
                    mat2  m = mat2(c,-s,s,c);
                    vec3  q = vec3(m*p.xz,p.y);
                    return q;
                }


                float opSmoothUnion(float d1, float d2, float k)
                {
                    float h = clamp( 0.5 + 0.5*(d2-d1)/k, 0.0, 1.0 );
                    return mix( d2, d1, h ) - k*h*(1.0-h);
                }

                float opSmoothSubtraction(float d1, float d2, float k) 
                {
                    float h = clamp( 0.5 - 0.5*(d2+d1)/k, 0.0, 1.0 );
                    return mix( d2, -d1, h ) + k*h*(1.0-h); 
                }
                //end of common Math region ##################################################

                float sdSphere( vec3 p, float s )
                {
                    return length(p)-s;
                }

                float sdTorus( vec3 p, vec2 t )
                {
                    vec2 q = vec2(length(p.xz)-t.x,p.y); 
                    return length(q)-t.y;
                }

                float sdRoundedCylinder( vec3 p, float ra, float rb, float h )
                {
                    vec2 d = vec2( length(p.xz)-2.0*ra+rb, abs(p.y) - h );
                    return min(max(d.x,d.y),0.0) + length(max(d,0.0)) - rb;
                }

                #define PlanetCenter vec3(0.0, 0.0, 0.0)
                #define PlanetRad 2.0
                #define RingRad vec2(0.9 + PlanetRad, 0.05)

                float map( in vec3 pos, out float id)
                {
                    pos = pos - PlanetCenter;
                    
                    float planet = sdSphere( pos, PlanetRad);
                    vec2 ringRadIterative = RingRad;

                    float ringHoles = sdTorus(pos, vec2(2.5, 0.5));
                    ringHoles = min(ringHoles, sdTorus(pos, vec2(3.5, 0.09)));
                    ringHoles = min(ringHoles, sdTorus(pos, vec2(3.8, 0.07)));
                    ringHoles = min(ringHoles, sdTorus(pos, vec2(4.7, 0.04)));
                    float ring = sdRoundedCylinder(pos, 2.5, 0.004, 0.00005);
                    ring = opSmoothSubtraction(ringHoles, ring, 0.02);
                    float dist = min(planet, ring);
                    id = step(planet - ring, 0.0);
                    return min(planet, ring);
                }

                float map( in vec3 pos)
                {
                    float id;
                    return map(pos, id);
                }

                #define MAX_STEPS 200; //Dosnt work, rewrite manualy
                #define SURFACE_DIST 0.001;
                #define MAX_DIST 50.0;
                #define MIN_DIST 0.00;

                float castRay( in vec3 ro, in vec3 rd, out float id)
                {
                    vec2 res = vec2(-1.0,-1.0);

                    float tmin = MIN_DIST;
                    float tmax = MAX_DIST;
                    float surfDistMin = SURFACE_DIST;
                    
                    float t = tmin;
                    for( int i=0; i<150; i++ )
                    {
                        float h = map( ro+rd*t, id);
                        if( abs(h)tmax ) t=-1.0;
                    return t;
                }

                vec3 calcNormal( in vec3 pos)
                {
                    vec2 e = vec2(0.0005,0.0);
                    return normalize( vec3( 
                        map( pos + e.xyy) - map( pos - e.xyy),
                        map( pos + e.yxy) - map( pos - e.yxy),
                        map( pos + e.yyx) - map( pos - e.yyx) ) );
                }

                vec2 getSphericCoord(vec3 pos)
                {
                    vec3 nor = calcNormal(pos);
                    float lon = atan(nor.x,nor.z)/pi;
                    float lat = acos(nor.y)/pi;
                    vec2 r = vec2(lat, lon);
                    
                    return r;
                }

                //Texturing region $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
                float fbm(vec3 x, float H, vec3 layers)
                {    
                    float G = exp2(-H);
                    float f = 1.2;
                    float a = 0.5;
                    float t = 0.05;

                    for( int i=0; i<6; i++ )
                    {
                        t += a*noise(f*x + layers);
                        f *= 2.0;
                        a *= G;
                    }
                    return t;
                }

                float paternAtmosphere(vec3 p, float H)
                {
                    vec3 layers = vec3(0.16 * iTime, 0.0, 0.0);

                    vec3 a = vec3( 0.0,  0.0,  0.0);
                    vec3 b = vec3( 5.2,  1.3,  1.1);
                    vec3 c = vec3(-1.7,  9.2,  3.2);
                    vec3 d = vec3( 3.7,  -1.1,  0.0);
                    vec3 e = vec3( 8.2,  1.6,  -1.9);
                    vec3 f = vec3(-1.7,  6.2,  -3.2);

                    vec3 q = vec3(fbm(p + a, H, layers),
                                    fbm(p + b, H, layers),
                                    fbm(p + c, H, layers) );

                    vec3 r = vec3(fbm(p + 4.0 * q + d, H, layers),
                                    fbm(p + 4.0 * q + e, H, layers),
                                    fbm(p + 4.0 * q + f, H, layers) );

                    return fbm(p + 4.0*r, H, layers);
                }

                vec3 paternAtmosphere(vec3 p, vec3 col1, vec3 col2)
                {
                    float grad = paternAtmosphere(opTwist(p), 1.1);
                    return mix(col1, col2, grad);
                }

                // Traditional gradient noise
                float gnoise( in float p )
                {
                    float  i = floor(p);
                    float f = fract(p);
                    float u = f*f*(3.0-2.0*f);

                    float g0 = hash00(i + 0.0 * u);
                    float g1 = hash00(i + 1.0 * u);
                    return mix( g0*(f-0.0), g1*(1.0-f), u);
                }


                float fbm( in float x)
                {    
                    float n = 0.0;
                    float s = 1.0;
                    for( int i=0; i<9; i++ )
                    {
                        n += s*gnoise(x);
                        s *= 0.5;
                        x *= 2.0;
                        x += 0.131;
                    }
                    return n;
                }

                vec3 paternRing(float dist, vec3 col1, vec3 col2)
                {
                    return mix(col1, col2, fbm(8.5 * dist));
                }
                //End Texturing region $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$


                float getLight(vec3 pos, vec3 lightPos, float intensity)
                {
                    vec3 lightDir = normalize(lightPos - pos);
                    vec3 normal = calcNormal(pos);
                    float nDotL = dot(normal, lightDir);
                    float botomClamp = 0.01;
                    float diffuseLight = intensity * clamp(nDotL, botomClamp , 1.);
                    
                    float surfDistMin = SURFACE_DIST;
                    //shadows
                    //raymarch to light pos if hit its shadow
                    float id;
                    float distToHit = castRay(pos + normal * surfDistMin, lightDir, id);
                    //if distToHit less then lightPos - pos then dif *= 0.1;
                    float isShadow = step(distToHit, length(lightPos - pos)) * step(0.0, nDotL);
                    diffuseLight = mix(diffuseLight, intensity * botomClamp, isShadow);
                    return diffuseLight;
                }

                float GetFlare0(vec3 ro, vec3 rd, vec3 lightPos, float dist, float flareAmp, float fallOff)
                {
                    return mix(0.0, flareAmp/pow(DistanceFromPoinToLine0(rd, ro, lightPos), fallOff), step(length(lightPos - ro), dist));
                }


                float GetFlare(vec3 ro, vec3 rd, vec3 lightPos, float dist, float flareAmp, float fallOff)
                {
                    return mix(0.0, flareAmp/pow(DistanceFromPoinToLine(rd, ro, lightPos), fallOff), step(length(lightPos - ro), dist));
                }

                vec3 stars(vec3 ro, vec3 rd, float dist) {
                    float r = 20.0;
                    float random0 = 0.1578;
                    vec3 starsCol = vec3(0.0, 0.0, 0.0);
                    for(float i=0.; i<200.; i++ )
                    {
                        // random0 = hash00(i);
                        // float random1 = hash00(random0);
                        // float random2 = hash00(random0 * 2.342);
                        // float random3 = hash00(random0 * 3.687);

                        random0 = hash00(i);
                        float random1 = hash00(i);
                        float random2 = hash00(i * 2.342);
                        float random3 = hash00(i * 3.687);

                        float theta = 0.8 + random1 * 0.5 * pi;
                        float phi = random2 * 2.0 * pi;
                        vec3 lightPos = vec3(r * sin(theta) * cos(phi),
                                                r * sin(theta) * sin(phi),
                                                r * cos(theta));
                        vec3 lightCol = vec3(1.0) - 0.5 * vec3(random1, 0.0, random3);
                        starsCol += lightCol * GetFlare(ro, rd, lightPos, dist, 0.00001 + 0.0002 * random2, 2.5);
                    }

                    return starsCol;
                }

                //Returns the RayDirection for a pixel given the ray origin, the look at vector and a zoom factor.
                vec3 cameraRayDirection(vec2 uv, vec3 rayOrigin, vec3 lookAt, float zoom)
                {
                    vec3 forwardDir = normalize(lookAt - rayOrigin);
                    vec3 rightDir = normalize(cross(normalize(vec3(0.2, 1, 0)), forwardDir));
                    vec3 upDir = cross(forwardDir, rightDir);
                    vec3 centerOfScreen = rayOrigin + forwardDir * zoom;
                    vec3 intersectionOfScreen = centerOfScreen + uv.x * rightDir + uv.y * upDir;
                    
                    return intersectionOfScreen - rayOrigin;
                }

                vec3 orbitCamera(float radius, float baseFreq)
                {
                    float time = iTime * baseFreq;
                    vec3 pos = vec3(sin(time), 0.8 * cos(0.5 * time), cos(time));
                    //pos = vec3(pos.x, rot2d(pos.yz, -40.));
                    return radius * normalize(pos);
                }

                vec3 render(vec2 uv, float time)
                {
                    vec3 rayOrigin = orbitCamera(10.0, 0.3); //vec3(0.0, 10.0, 0.0);
                    vec3 lookAt = PlanetCenter;
                    vec3 lightPos = vec3(+20.0, 3.2, -10.0);
                    vec3 lightCol = vec3(0.7, 1.0, 1.0);
                    
                    vec3 rayDirection = cameraRayDirection(uv, rayOrigin, lookAt, 1.);
                    
                    float id = 0.0;
                    float dist = castRay(rayOrigin, rayDirection, id);
                    vec3 pos = rayOrigin + rayDirection * dist;
                    vec3 posSphereOS = pos - PlanetCenter;

                    float flare = GetFlare(rayOrigin, rayDirection, lightPos, dist, 0.09, 2.8);
                    vec3 planetCol = vec3(paternAtmosphere(posSphereOS, vec3(0.6, 0.25, 0.25), vec3(0.8, 0.65, 0.8)));
                    vec3 ringCol = paternRing(length(posSphereOS.xz), vec3(0.05, 0.05, 0.05), vec3(0.95, 0.75, 0.8));
                    vec3 albedo = planetCol * id + step(id, 0.5) * ringCol;
                    albedo = clamp(albedo, 0.0, 1.0);
                    //sphericPosCol = vec3(noise(posSphereOS));
                    //vec3 normal = calcNormal(pos);
                    float light = getLight(pos, 4.0 * lightPos, 3.2);
                    float maxDist = MAX_DIST - 1.0;
                    //dist negative for to far fields
                    vec3 background = vec3(0, 0, 0) + flare * lightCol + stars(rayOrigin, rayDirection, dist);
                    vec3 finalCol = mix(albedo * light * lightCol, background,  step(maxDist - dist, 0.));
                    return finalCol;//vec3(length(pos * 0.2));
                }

                void main()
                {
                    // Normalized pixel coordinates (from 0 to 1)
                    vec2 uv = (sv - 0.5) * iResolution.xy / iResolution.y;

                    // Time varying pixel color
                    vec3 col = render(uv, iTime);
                    //col = vec3(gnoise(length(uv)));

                    //Gama correction
                    col = pow( col, vec3(0.4545));
                    // Output to screen
                    gl_FragColor = vec4(col ,1.0);
                }