GLSL Heroku의 셰이더 모음 계속 업데이트 예정

http://glsl.heroku.com/e#19224.0

039f49f29b201d6ea672de862d798c14

#ifdef GL_ES
precision mediump float;
#endif

uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;

float rand(vec2 v){
    return fract(sin(dot(v.xy,vec2(33.9898,78.233))) * 43758.56);
}
void main( void ) {

    vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / resolution.y ;
    float c = 0.0;
    for(int i = 0; i < 30; i++){
        float f = float(i);
        p += 
        c += max(0.5 - length(vec2(rand(vec2(f, 1.0)), rand(vec2(-1.0, f))) * 2.0 - 1.0 - p), 0.0);
    }
    gl_FragColor = vec4(vec3(smoothstep(0.1, 0.6, c), smoothstep(0.4, 1.0, c), smoothstep(0.8, 1.0, c)), 1.0 );

}

http://glsl.heroku.com/e#19097.0

2014-08-23_02-01-15

#ifdef GL_ES
precision mediump float;
#endif

uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;

void main(void)
{
    vec2 uv = -1.0 + 2.0*gl_FragCoord.xy / resolution.xy;
    uv.x *=  resolution.x / resolution.y;

    // background    
    vec3 color = vec3(0.8 + 0.2*uv.y);

    // bubbles  
    for( int i=0; i<20; i++ )
    {
        // bubble seeds
        float pha =      sin(float(i)*546.13+1.0)*0.5 + 0.5;
        float siz = pow( sin(float(i)*651.74+5.0)*0.5 + 0.5, 4.0 );
        float pox =      sin(float(i)*321.55+4.1) * resolution.x / resolution.y;

        // buble size, position and color
        float rad = 0.1 + 0.5*siz;
        vec2  pos = vec2( pox, -1.0-rad + (2.0+2.0*rad)*mod(pha+0.1*time*(0.2+0.8*siz),1.0));
        float dis = length( uv - pos );
        vec3  col = mix( vec3(0.94,0.3,0.0), vec3(0.1,0.4,0.8), 0.5+0.5*sin(float(i)*1.2+1.9));

        // render
        float f = length(uv-pos)/rad;
        f = sqrt(clamp(1.0-f*f,0.0,1.0));
        color -= col.zyx *(1.0-smoothstep( rad*0.95, rad, dis )) * f;
    }

    // vigneting    
    color *= sqrt(1.5-0.5*length(uv));

    gl_FragColor = vec4(color,1.0);
}

http://glsl.heroku.com/e#19318.0

3e8d4eb6e8695484044984ff6daa58b6

#ifdef GL_ES
precision mediump float;
#endif

#define STEPS 50
#define LIGHTPASSES 8
uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;

vec2 c = vec2(0.5,0.5*resolution.y/resolution.x);
vec3 wallColor = vec3(1.,1.,1.);

/*by Olivier de Schaetzen (citiral)
haven't really seen anything like this before, so either I don't check enough shaders or I might have made something original once ;)
*/

//random function not by me, found it somewhere on the internet!
float rand(vec2 n)
{
  return 1. * 
     fract(sin(dot(n.xy, vec2(12.898, 78.33)))* 43758.5453);
}

vec3 getColor(vec2 p)
{   
    //if (p.x >= 0.1 && p.x <= 0.19 && p.y >= 0.1 && p.y <= 0.19) {
    //  return wallColor;
    //}

    vec2 pp = p;
    vec2 ppp = p;

    p.x += sin(time*10.)*0.04;
    p.y += cos(time*10.)*0.04;
    if (length(p-c) <= 0.01) {
        return wallColor;   
    }

    pp.x += cos(time*5.)*0.08;
    pp.y += sin(time*5.)*0.08;
    if (length(pp-c) <= 0.02) {
        return wallColor;   
    }

    ppp.x += sin(time*2.5)*0.15;
    ppp.y += cos(time*2.5)*0.15;
    if (length(ppp-c) <= 0.02) {
        return wallColor;   
    }

    return vec3(0.3,0.3,0.3);
}

vec3 getLighting(vec2 p, vec2 lp)
{
    vec2 sp = p;
    vec2 v = (lp-p)/float(STEPS);

    for (int i = 0 ; i < STEPS ; i++) {
        if (getColor(sp) == wallColor) {
            return length(p-lp)/vec3(1.,1.,1.) + 1./length(p-lp)*0.075*vec3(1.0,0.5*(sin(time)+0.1),0.7);
        }
        sp += v;
    }

    return vec3(1.0,1.0,1.0)+1./length(p-lp)*0.075*vec3(1.0,0.5*(sin(time)+1.),0.6);
}

vec3 blendLighting(vec2 p, vec2 lp)
{   
    vec2 r;
    vec3 c = vec3(0.,0.,0.);

    for (int i = 1 ; i <= LIGHTPASSES ; i++) {
        r = vec2(rand(sin(time*float(i))+p.xy)*0.03-0.015,rand(cos(time*float(i))+p.yx)*0.03-0.015);
        c += getLighting(p,lp+r)/float(LIGHTPASSES);
    }

    return c;
}

void main( void ) {

    vec2 p = gl_FragCoord.xy/resolution.xy;
    vec2 lp = mouse.xy;
    p.y *= resolution.y/resolution.x;
    lp.y *= resolution.y/resolution.x;  

    gl_FragColor = vec4(getColor(p)*blendLighting(p,lp),1.);
}

http://glsl.heroku.com/e#18740.0

4002d4389cee443f4e443f75cb10c4bb

#ifdef GL_ES
precision mediump float;
#endif

uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;

float noise(vec3 p) //Thx to Las^Mercury
{
    vec3 i = floor(p);
    vec4 a = dot(i, vec3(1., 57., 21.)) + vec4(0., 57., 21., 78.);
    vec3 f = cos((p-i)*acos(-1.))*(-.5)+.5;
    a = mix(sin(cos(a)*a),sin(cos(1.+a)*(1.+a)), f.x);
    a.xy = mix(a.xz, a.yw, f.y);
    return mix(a.x, a.y, f.z);
}

float sphere(vec3 p, vec4 spr)
{
    return length(spr.xyz-p) - spr.w;
}

float flame(vec3 p)
{
    float d = sphere(p*vec3(1.,.5,1.), vec4(.0,-1.,.0,1.));
    return d + (noise(p+vec3(.0,time*2.,.0)) + noise(p*3.)*.5)*.25*(p.y) ;
}

float scene(vec3 p)
{
    return min(100.-length(p) , abs(flame(p)) );
}

vec4 raymarch(vec3 org, vec3 dir)
{
    float d = 0.0, glow = 0.0, eps = 0.02;
    vec3  p = org;
    bool glowed = false;

    for(int i=0; i<64; i++)
    {
        d = scene(p) + eps;
        p += d * dir;
        if( d>eps )
        {
            if(flame(p) < .0)
                glowed=true;
            if(glowed)
                glow = float(i)/64.;
        }
    }
    return vec4(p,glow);
}

void main()
{
    vec2 v = -1.0 + 2.0 * gl_FragCoord.xy / resolution.xy;
    v.x *= resolution.x/resolution.y;

    vec3 org = vec3(0., -2., 4.);
    vec3 dir = normalize(vec3(v.x*1.6, -v.y, -1.5));

    vec4 p = raymarch(org, dir);
    float glow = p.w;

    vec4 col = mix(vec4(1.,.5,.1,1.), vec4(0.1,.5,1.,1.), p.y*.02+.4);

    gl_FragColor = mix(vec4(0.), col, pow(glow*2.,4.));
    //gl_FragColor = mix(vec4(1.), mix(vec4(1.,.5,.1,1.),vec4(0.1,.5,1.,1.),p.y*.02+.4), pow(glow*2.,4.));

}

http://glsl.heroku.com/e#9824.11

2014-08-23_11-11-20

// water turbulence effect by @joltz0r 2013-07-04, improved 2013-07-07

// let the fluidity flow in psychedelic --@joltz0r
#ifdef GL_ES
precision mediump float;
#endif

uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;
varying vec2 surfacePosition;

#define MAX_ITER 32
void main( void ) {

    vec2 p = surfacePosition*4.0;
    vec2 i = p;
    float c = 0.0;
    float inten = 1.0;

    for (int n = 0; n < MAX_ITER; n++) {
        float t = time * (1.0 - (1.0 / float(n+1)));
        i = (p + vec2(
            cos(t - i.x) + sin(t + i.y), 
            sin(t - i.y) + cos(t + i.x)
        )) - (i - (1.0 / vec2(n+1)));
        c += 1.0/length((p*i) / vec2(
            sin(i.x + t)/inten,
            cos(i.y + t)/inten
            )
        );
    }
    c /= float(MAX_ITER);

    gl_FragColor = vec4(vec3(c)*vec3(0.95, 0.97, 1.8), 1.0);
}

http://glsl.heroku.com/e#18182.0

2014-08-24_16-52-51

#ifdef GL_ES
precision mediump float;
#endif

uniform float time;
uniform vec2 resolution;

void main()
{

    vec2 uv = (gl_FragCoord.xy/resolution.xy)-.5;

    float time = time * .1 + ((.25+.05*sin(time*.1))/(length(uv.xy)+.07))* 2.2;
    float si = sin(time);
    float co = cos(time);
    mat2 ma = mat2(co, si, -si, co);

    float c = 0.0;
    float v1 = 0.0;
    float v2 = 0.0;

    for (int i = 0; i < 100; i++)
    {
        float s = float(i) * .035;
        vec3 p = s * vec3(uv, 0.0);
        p.xy *= ma;
        p += vec3(.22,.3, s-1.5-sin(time*.13)*.1);
        for (int i = 0; i < 8; i++)
        {
            p = abs(p) / dot(p,p) - 0.659;
        }
        v1 += dot(p,p)*.0015 * (1.8+sin(length(uv.xy*13.0)+.5-time*.2));
        v2 += dot(p,p)*.0015 * (1.5+sin(length(uv.xy*13.5)+2.2-time*.3));
        c = length(p.xy*.5) * .35;
    }

    float len = length(uv);
    v1 *= smoothstep(.7, .0, len);
    v2 *= smoothstep(.6, .0, len);

    float re = clamp(c, 0.0, 1.0);
    float gr = clamp((v1+c)*.25, 0.0, 1.0);
    float bl = clamp(v2, 0.0, 1.0);
    vec3 col = vec3(re, gr, bl) + smoothstep(0.15, .0, len) * .9;

    gl_FragColor=vec4(col, 1.0);
}

http://glsl.heroku.com/e#19082.0

2014-08-27_16-31-17 2

// Blank Slate - Work in progress @P_Malin

// added pan/zoom - hard work stolen from other shaders, thanks @emackey

#ifdef GL_ES
precision highp float;
#endif

uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;

// somehow these enable pan/zoom controls (using magic)
uniform vec2 surfaceSize;
varying vec2 surfacePosition;

float kPI = acos(0.0);
float kHalfPi = asin(1.0);
float kTwoPI = kPI * 2.0;
/*
float cos(float v) // workaround for AMD Radeon on OS X
{ 
    return sin(v+kHalfPi);
}
*/

//#define ENABLE_MONTE_CARLO
#define ENABLE_REFLECTIONS
#define ENABLE_FOG
#define ENABLE_SPECULAR
#define ENABLE_POINT_LIGHT
#define ENABLE_POINT_LIGHT_FLARE

#ifdef ENABLE_MONTE_CARLO
vec4 gPixelRandom;
vec3 gRandomNormal;

void CalcPixelRandom()
{
    // Nothing special here, just numbers generated by bashing keyboard
    vec4 s1 = sin(time * 3.3422 + gl_FragCoord.xxxx * vec4(324.324234, 563.324234, 657.324234, 764.324234)) * 543.3423;
    vec4 s2 = sin(time * 1.3422 + gl_FragCoord.yyyy * vec4(567.324234, 435.324234, 432.324234, 657.324234)) * 654.5423;
    gPixelRandom = fract(2142.4 + s1 + s2);
    gRandomNormal = normalize( gPixelRandom.xyz - 0.5);
}
#endif

struct C_Ray
{
    vec3 vOrigin;
    vec3 vDir;
};

struct C_HitInfo
{
    vec3 vPos;
    float fDistance;
    vec3 vObjectId;
};

struct C_Material
{
    vec3 cAlbedo;
    float fR0;
    float fSmoothness;
    vec2 vParam;
};

vec3 RotateX( const in vec3 vPos, const in float fAngle )
{
    float s = sin(fAngle);
    float c = cos(fAngle);

    vec3 vResult = vec3( vPos.x, c * vPos.y + s * vPos.z, -s * vPos.y + c * vPos.z);

    return vResult;
}

vec3 RotateY( const in vec3 vPos, const in float fAngle )
{
    float s = sin(fAngle);
    float c = cos(fAngle);

    vec3 vResult = vec3( c * vPos.x + s * vPos.z, vPos.y, -s * vPos.x + c * vPos.z);

    return vResult;
}

vec3 RotateZ( const in vec3 vPos, const in float fAngle )
{
    float s = sin(fAngle);
    float c = cos(fAngle);

    vec3 vResult = vec3( c * vPos.x + s * vPos.y, -s * vPos.x + c * vPos.y, vPos.z);

    return vResult;
}

vec4 DistCombineUnion( const in vec4 v1, const in vec4 v2 )
{
    //if(v1.x < v2.x) return v1; else return v2;
    return mix(v1, v2, step(v2.x, v1.x));
}

vec4 DistCombineIntersect( const in vec4 v1, const in vec4 v2 )
{
    return mix(v2, v1, step(v2.x,v1.x));
}

vec4 DistCombineSubtract( const in vec4 v1, const in vec4 v2 )
{
    return DistCombineIntersect(v1, vec4(-v2.x, v2.yzw));
}

vec3 DomainRepeatXZGetTile( const in vec3 vPos, const in vec2 vRepeat, out vec2 vTile )
{
    vec3 vResult = vPos;
    vec2 vTilePos = (vPos.xz / vRepeat) + 0.5;
    vTile = floor(vTilePos + 1000.0);
    vResult.xz = (fract(vTilePos) - 0.5) * vRepeat;
    return vResult;
}

vec3 DomainRepeatXZ( const in vec3 vPos, const in vec2 vRepeat )
{
    vec3 vResult = vPos;
    vec2 vTilePos = (vPos.xz / vRepeat) + 0.5;
    vResult.xz = (fract(vTilePos) - 0.5) * vRepeat;
    return vResult;
}

vec3 DomainRepeatY( const in vec3 vPos, const in float fSize )
{
    vec3 vResult = vPos;
    vResult.y = (fract(vPos.y / fSize + 0.5) - 0.5) * fSize;
    return vResult;
}

vec3 DomainRotateSymmetry( const in vec3 vPos, const in float fSteps )
{
    float angle = atan( vPos.x, vPos.z );

    float fScale = fSteps / (kTwoPI);
    float steppedAngle = (floor(angle * fScale + 0.5)) / fScale;

    float s = sin(-steppedAngle);
    float c = cos(-steppedAngle);

    vec3 vResult = vec3( c * vPos.x + s * vPos.z,
                 vPos.y,
                -s * vPos.x + c * vPos.z);

    return vResult;
}

float GetDistanceXYTorus( const in vec3 p, const in float r1, const in float r2 )
{
    vec2 q = vec2(length(p.xy)-r1,p.z);
    return length(q)-r2;
}
float GetDistanceYZTorus( const in vec3 p, const in float r1, const in float r2 )
{
    vec2 q = vec2(length(p.yz)-r1,p.x);
    return length(q)-r2;
}
float GetDistanceCylinderY(const in vec3 vPos, const in float r)
{
    return length(vPos.xz) - r;
}
float GetDistanceBox( const in vec3 vPos, const in vec3 vSize )
{
    vec3 vDist = (abs(vPos) - vSize);
    return max(vDist.x, max(vDist.y, vDist.z));
}

float GetDistanceRoundedBox( const in vec3 vPos, const in vec3 vSize, float fRadius )
{
    vec3 vClosest = max(min(vPos, vSize), -vSize);
    return length(vClosest - vPos) - fRadius;
}

// result is x=scene distance y=material or object id; zw are material specific parameters (maybe uv co-ordinates)
vec4 GetDistanceScene( const in vec3 vPos )
{          
    vec4 vResult = vec4(10000.0, -1.0, 0.0, 0.0);

    vec3 vSphereDomain = DomainRepeatXZ(vPos, vec2(5.0, 5.0));

    vec4 vDistSphere = vec4( length(vSphereDomain) - 1.0, 2.0, vSphereDomain.xy);

    vResult = DistCombineUnion(vResult, vDistSphere);

    vec4 vDistFloor = vec4(vPos.y + 1.0, 1.0, vPos.xz);
    vResult = DistCombineUnion(vResult, vDistFloor);

    return vResult;
}

C_Material GetObjectMaterial( const in vec3 vObjId, const in vec3 vPos )
{
    C_Material mat;

    if(vObjId.x < 1.5)
    {
        // floor
        mat.fR0 = 0.1;
        mat.fSmoothness = 0.01;
        mat.cAlbedo = vec3(0, 0, 0);
    }
    else
    if(vObjId.x < 2.5)
    {
        // sphere
        mat.fR0 = 0.05;
        mat.fSmoothness = 0.9;
        mat.cAlbedo = vec3(1, 1, 1);
    }

    return mat;
}
vec3 GetSkyGradient( const in vec3 vDir )
{
    float fBlend = vDir.y * 0.5 + 0.5;
    return mix(vec3(0.0, 0.0, 0.0), vec3(0.4, 0.9, 1.0), fBlend);
}
vec3 GetLightPos()
{
    vec3 vLightPos = vec3(0.0, 1.0, 3.0);
    #ifdef ENABLE_MONTE_CARLO        
    vLightPos += gRandomNormal * 0.2;
    #endif
    return vLightPos;
}
vec3 GetLightCol()
{
    return vec3(14.0, 14.0, 10.0) * 10.0;
}

vec3 GetAmbientLight(const in vec3 vNormal)
{
    return GetSkyGradient(vNormal);
}

#define kFogDensity 0.1
void ApplyAtmosphere(inout vec3 col, const in C_Ray ray, const in C_HitInfo intersection)
{
    #ifdef ENABLE_FOG
    // fog
    float fFogAmount = exp(intersection.fDistance * -kFogDensity);
    vec3 cFog = GetSkyGradient(ray.vDir);
    col = mix(cFog, col, fFogAmount);
    #endif

    // glare from light (a bit hacky - use length of closest approach from ray to light)
    #ifdef ENABLE_POINT_LIGHT_FLARE
    vec3 vToLight = GetLightPos() - ray.vOrigin;
    float fDot = dot(vToLight, ray.vDir);
    fDot = clamp(fDot, 0.0, intersection.fDistance);

    vec3 vClosestPoint = ray.vOrigin + ray.vDir * fDot;
    float fDist = length(vClosestPoint - GetLightPos());
    col += GetLightCol() * 0.01/ (fDist * fDist);
    #endif     
}
vec3 GetSceneNormal( const in vec3 vPos )
{
    // tetrahedron normal
    float fDelta = 0.025;

    vec3 vOffset1 = vec3( fDelta, -fDelta, -fDelta);
    vec3 vOffset2 = vec3(-fDelta, -fDelta,  fDelta);
    vec3 vOffset3 = vec3(-fDelta,  fDelta, -fDelta);
    vec3 vOffset4 = vec3( fDelta,  fDelta,  fDelta);

    float f1 = GetDistanceScene( vPos + vOffset1 ).x;
    float f2 = GetDistanceScene( vPos + vOffset2 ).x;
    float f3 = GetDistanceScene( vPos + vOffset3 ).x;
    float f4 = GetDistanceScene( vPos + vOffset4 ).x;

    vec3 vNormal = vOffset1 * f1 + vOffset2 * f2 + vOffset3 * f3 + vOffset4 * f4;

    return normalize( vNormal );
}

#define kRaymarchEpsilon 0.01
#define kRaymarchMatIter 256
#define kRaymarchStartDistance 0.1
// This is an excellent resource on ray marching -> http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
void Raymarch( const in C_Ray ray, out C_HitInfo result, const float fMaxDist, const int maxIter )
{         
    result.fDistance = kRaymarchStartDistance;
    result.vObjectId.x = 0.0;

    for(int i=0;i<=kRaymarchMatIter;i++)               
    {
        result.vPos = ray.vOrigin + ray.vDir * result.fDistance;
        vec4 vSceneDist = GetDistanceScene( result.vPos );
        result.vObjectId = vSceneDist.yzw;

        // abs allows backward stepping - should only be necessary for non uniform distance functions
        if((abs(vSceneDist.x) <= kRaymarchEpsilon) || (result.fDistance >= fMaxDist) || (i > maxIter))
        {
            break;
        }                         

        result.fDistance = result.fDistance + vSceneDist.x;     
    }

    if(result.fDistance >= fMaxDist)
    {
        result.vPos = ray.vOrigin + ray.vDir * result.fDistance;
        result.vObjectId.x = 0.0;
        result.fDistance = 1000.0;
    }
}

float GetShadow( const in vec3 vPos, const in vec3 vLightDir, const in float fLightDistance )
{
    C_Ray shadowRay;
    shadowRay.vDir = vLightDir;
    shadowRay.vOrigin = vPos;

    C_HitInfo shadowIntersect;
    Raymarch(shadowRay, shadowIntersect, fLightDistance, 32);

    return step(0.0, shadowIntersect.fDistance) * step(fLightDistance, shadowIntersect.fDistance );          
}

// http://en.wikipedia.org/wiki/Schlick's_approximation
float Schlick( const in vec3 vNormal, const in vec3 vView, const in float fR0, const in float fSmoothFactor)
{
    float fDot = dot(vNormal, -vView);
    fDot = min(max((1.0 - fDot), 0.0), 1.0);
    float fDot2 = fDot * fDot;
    float fDot5 = fDot2 * fDot2 * fDot;
    return fR0 + (1.0 - fR0) * fDot5 * fSmoothFactor;
}

float GetDiffuseIntensity(const in vec3 vLightDir, const in vec3 vNormal)
{
    return max(0.0, dot(vLightDir, vNormal));
}

float GetBlinnPhongIntensity(const in C_Ray ray, const in C_Material mat, const in vec3 vLightDir, const in vec3 vNormal)
{           
    vec3 vHalf = normalize(vLightDir - ray.vDir);
    float fNdotH = max(0.0, dot(vHalf, vNormal));

    float fSpecPower = exp2(4.0 + 6.0 * mat.fSmoothness);
    float fSpecIntensity = (fSpecPower + 2.0) * 0.125;

    return pow(fNdotH, fSpecPower) * fSpecIntensity;
}

// use distance field to evaluate ambient occlusion
float GetAmbientOcclusion(const in C_Ray ray, const in C_HitInfo intersection, const in vec3 vNormal)
{
    vec3 vPos = intersection.vPos;

    float fAmbientOcclusion = 1.0;

    float fDist = 0.0;
    for(int i=0; i<=5; i++)
    {
        fDist += 0.1;

        vec4 vSceneDist = GetDistanceScene(vPos + vNormal * fDist);

        fAmbientOcclusion *= 1.0 - max(0.0, (fDist - vSceneDist.x) * 0.2 / fDist );                                   
    }

    return fAmbientOcclusion;
}

vec3 GetObjectLighting(const in C_Ray ray, const in C_HitInfo intersection, const in C_Material material, const in vec3 vNormal, const in vec3 cReflection)
{
    vec3 cScene ;

    vec3 vSpecularReflection = vec3(0.0);
    vec3 vDiffuseReflection = vec3(0.0);

    float fAmbientOcclusion = GetAmbientOcclusion(ray, intersection, vNormal);
    vec3 vAmbientLight = GetAmbientLight(vNormal) * fAmbientOcclusion;

    vDiffuseReflection += vAmbientLight;

    vSpecularReflection += cReflection * fAmbientOcclusion;

    #ifdef ENABLE_POINT_LIGHT
    vec3 vLightPos = GetLightPos();
    vec3 vToLight = vLightPos - intersection.vPos;
    vec3 vLightDir = normalize(vToLight);
    float fLightDistance = length(vToLight);

    float fAttenuation = 1.0 / (fLightDistance * fLightDistance);

    float fShadowBias = 0.1;             
    float fShadowFactor = GetShadow( intersection.vPos + vLightDir * fShadowBias, vLightDir, fLightDistance - fShadowBias );
    vec3 vIncidentLight = GetLightCol() * fShadowFactor * fAttenuation;

    vDiffuseReflection += GetDiffuseIntensity( vLightDir, vNormal ) * vIncidentLight;                                                                                 
    vSpecularReflection += GetBlinnPhongIntensity( ray, material, vLightDir, vNormal ) * vIncidentLight;
    #endif ENABLE_POINT_LIGHT

    vDiffuseReflection *= material.cAlbedo;              

    #ifdef ENABLE_SPECULAR
    float fFresnel = Schlick(vNormal, ray.vDir, material.fR0, material.fSmoothness * 0.9 + 0.1);
    cScene = mix(vDiffuseReflection , vSpecularReflection, fFresnel);
    #else
    cScene = vDiffuseReflection;
    #endif

    return cScene;
}

vec3 GetSceneColourSimple( const in C_Ray ray )
{
    C_HitInfo intersection;
    Raymarch(ray, intersection, 16.0, 32);

    vec3 cScene;

    if(intersection.vObjectId.x < 0.5)
    {
        cScene = GetSkyGradient(ray.vDir);
    }
    else
    {
        C_Material material = GetObjectMaterial(intersection.vObjectId, intersection.vPos);
        vec3 vNormal = GetSceneNormal(intersection.vPos);

        // use sky gradient instead of reflection
        vec3 cReflection = GetSkyGradient(reflect(ray.vDir, vNormal));

        // apply lighting
        cScene = GetObjectLighting(ray, intersection, material, vNormal, cReflection );
    }

    ApplyAtmosphere(cScene, ray, intersection);

    return cScene;
}

vec3 GetSceneColour( const in C_Ray ray )
{                                                           
    C_HitInfo intersection;
    Raymarch(ray, intersection, 30.0, 256);

    vec3 cScene;

    if(intersection.vObjectId.x < 0.5)
    {
        cScene = GetSkyGradient(ray.vDir);
    }
    else
    {
        C_Material material = GetObjectMaterial(intersection.vObjectId, intersection.vPos);
        vec3 vNormal = GetSceneNormal(intersection.vPos);

        #ifdef ENABLE_MONTE_CARLO
        vNormal = normalize(vNormal + gRandomNormal / (5.0 + material.fSmoothness * 200.0));
        #endif

        vec3 cReflection;
        #ifdef ENABLE_REFLECTIONS    
        {
            // get colour from reflected ray
            float fSepration = 0.05;
            C_Ray reflectRay;
            reflectRay.vDir = reflect(ray.vDir, vNormal);
            reflectRay.vOrigin = intersection.vPos + reflectRay.vDir * fSepration;

            cReflection = GetSceneColourSimple(reflectRay);                                                                         
        }
        #else
        cReflection = GetSkyGradient(reflect(ray.vDir, vNormal));                               
        #endif
        // apply lighting
        cScene = GetObjectLighting(ray, intersection, material, vNormal, cReflection );
    }

    ApplyAtmosphere(cScene, ray, intersection);

    return cScene;
}

void GetCameraRay( const in vec3 vPos, const in vec3 vForwards, const in vec3 vWorldUp, out C_Ray ray)
{
    vec2 vPixelCoord = gl_FragCoord.xy;
    #ifdef ENABLE_MONTE_CARLO
    vPixelCoord += gPixelRandom.zw;
    #endif
    vec2 vUV = ( vPixelCoord / resolution.xy );
    vec2 vViewCoord = vUV * 2.0 - 1.0;

    vViewCoord *= 0.75;

    float fRatio = resolution.x / resolution.y;

    vViewCoord.y /= fRatio;                           

    ray.vOrigin = vPos;

    vec3 vRight = normalize(cross(vForwards, vWorldUp));
    vec3 vUp = cross(vRight, vForwards);

    ray.vDir = normalize( vRight * vViewCoord.x + vUp * vViewCoord.y + vForwards);        
}

void GetCameraRayLookat( const in vec3 vPos, const in vec3 vInterest, out C_Ray ray)
{
    vec3 vForwards = normalize(vInterest - vPos);
    vec3 vUp = vec3(0.0, 1.0, 0.0);

    GetCameraRay(vPos, vForwards, vUp, ray);
}

vec3 OrbitPoint( const in float fHeading, const in float fElevation )
{
    return vec3(sin(fHeading) * cos(fElevation), sin(fElevation), cos(fHeading) * cos(fElevation));
}

vec3 Gamma( const in vec3 cCol )
{
    return cCol * cCol;
}

vec3 InvGamma( const in vec3 cCol )
{
    return sqrt(cCol);
}

vec3 Tonemap( const in vec3 cCol )
{
    // simple Reinhard tonemapping operator     
    vec3 vResult = cCol / (1.0 + cCol);

    return Gamma(vResult);
}

vec3 InvTonemap( const in vec3 cCol )
{
    vec3 vResult = cCol;
    vResult = clamp(vResult, 0.01, 0.99);
    vResult = InvGamma(vResult);
    return - (vResult / (vResult - 1.0));
}

void main( void )
{
    #ifdef ENABLE_MONTE_CARLO             
    CalcPixelRandom();
    #endif

    C_Ray ray;

    const float fCamreaInitialHeading = 2.5;
    const float fCamreaInitialElevation = 0.4;
    const float fCamreaInitialDist = 7.0;
    const float fCameraHeight = 0.9;
    const float fOrbitSpeed = 1.0;

    // This magic stolen from other 3d pan/zoom examples
    float fZoom = surfaceSize.y * 0.5 + 0.4;

    vec2 vCenterPosition = (0.5 - ( gl_FragCoord.xy / resolution )) * surfaceSize + surfacePosition;
    float fHeading = vCenterPosition.x * fOrbitSpeed + fCamreaInitialHeading;
    float fElevation = (vCenterPosition.y * fOrbitSpeed + fCamreaInitialElevation);

    vec3 vCameraPos = OrbitPoint(fHeading, fElevation) * fCamreaInitialDist * fZoom;

    vCameraPos += vec3(mouse.x*5., mouse.y*5., 0.0);

    vCameraPos += vec3(0.0, -fCameraHeight, 0.0);
    #ifdef ENABLE_MONTE_CARLO             
    float fDepthOfField = 0.025;
    vCameraPos += gRandomNormal * fDepthOfField;
    #endif

    GetCameraRayLookat( vCameraPos, vec3(0.0, 0.0, 0.0), ray);
    //GetCameraRayLookat(vec3(0.0, 0.0, -5.0), vec3(0.0, 0.0, 0.0), ray);

    vec3 cScene = GetSceneColour( ray );   

    float fExposure = 2.5;
    cScene = cScene * fExposure;

    #ifdef ENABLE_MONTE_CARLO                              
    vec3 cPrev = texture2D(backbuffer, gl_FragCoord.xy / resolution).xyz;
    // add noise to pixel value (helps values converge)
    cPrev += (gPixelRandom.xyz - 0.5) * (1.0 / 255.0);
    cPrev = InvTonemap(cPrev);
    // converge speed
    float fBlend = 0.1;
    vec3 cFinal = mix(cPrev, cScene, fBlend);
    #else
    vec3 cFinal = cScene;
    #endif

    cFinal = Tonemap(cFinal);

    float fAlpha = 1.0;

    gl_FragColor = vec4( cFinal, fAlpha );
}

http://glsl.heroku.com/e#19075.0

2014-08-27_16-31-33 2

// Blank Slate - Work in progress @P_Malin

// added pan/zoom - hard work stolen from other shaders, thanks @emackey

#ifdef GL_ES
precision highp float;
#endif

uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;

// somehow these enable pan/zoom controls (using magic)
uniform vec2 surfaceSize;
varying vec2 surfacePosition;

float kPI = acos(0.0);
float kHalfPi = asin(1.0);
float kTwoPI = kPI * 2.0;
/*
float cos(float v) // workaround for AMD Radeon on OS X
{ 
    return sin(v+kHalfPi);
}
*/

//#define ENABLE_MONTE_CARLO
#define ENABLE_REFLECTIONS
#define ENABLE_FOG
#define ENABLE_SPECULAR
#define ENABLE_POINT_LIGHT
#define ENABLE_POINT_LIGHT_FLARE

#ifdef ENABLE_MONTE_CARLO
vec4 gPixelRandom;
vec3 gRandomNormal;

void CalcPixelRandom()
{
    // Nothing special here, just numbers generated by bashing keyboard
    vec4 s1 = sin(time * 3.3422 + gl_FragCoord.xxxx * vec4(324.324234, 563.324234, 657.324234, 764.324234)) * 543.3423;
    vec4 s2 = sin(time * 1.3422 + gl_FragCoord.yyyy * vec4(567.324234, 435.324234, 432.324234, 657.324234)) * 654.5423;
    gPixelRandom = fract(2142.4 + s1 + s2);
    gRandomNormal = normalize( gPixelRandom.xyz - 0.5);
}
#endif

struct C_Ray
{
    vec3 vOrigin;
    vec3 vDir;
};

struct C_HitInfo
{
    vec3 vPos;
    float fDistance;
    vec3 vObjectId;
};

struct C_Material
{
    vec3 cAlbedo;
    float fR0;
    float fSmoothness;
    vec2 vParam;
};

vec3 RotateX( const in vec3 vPos, const in float fAngle )
{
    float s = sin(fAngle);
    float c = cos(fAngle);

    vec3 vResult = vec3( vPos.x, c * vPos.y + s * vPos.z, -s * vPos.y + c * vPos.z);

    return vResult;
}

vec3 RotateY( const in vec3 vPos, const in float fAngle )
{
    float s = sin(fAngle);
    float c = cos(fAngle);

    vec3 vResult = vec3( c * vPos.x + s * vPos.z, vPos.y, -s * vPos.x + c * vPos.z);

    return vResult;
}

vec3 RotateZ( const in vec3 vPos, const in float fAngle )
{
    float s = sin(fAngle);
    float c = cos(fAngle);

    vec3 vResult = vec3( c * vPos.x + s * vPos.y, -s * vPos.x + c * vPos.y, vPos.z);

    return vResult;
}

vec4 DistCombineUnion( const in vec4 v1, const in vec4 v2 )
{
    //if(v1.x < v2.x) return v1; else return v2;
    return mix(v1, v2, step(v2.x, v1.x));
}

vec4 DistCombineIntersect( const in vec4 v1, const in vec4 v2 )
{
    return mix(v2, v1, step(v2.x,v1.x));
}

vec4 DistCombineSubtract( const in vec4 v1, const in vec4 v2 )
{
    return DistCombineIntersect(v1, vec4(-v2.x, v2.yzw));
}

vec3 DomainRepeatXZGetTile( const in vec3 vPos, const in vec2 vRepeat, out vec2 vTile )
{
    vec3 vResult = vPos;
    vec2 vTilePos = (vPos.xz / vRepeat) + 0.5;
    vTile = floor(vTilePos + 1000.0);
    vResult.xz = (fract(vTilePos) - 0.5) * vRepeat;
    return vResult;
}

vec3 DomainRepeatXZ( const in vec3 vPos, const in vec2 vRepeat )
{
    vec3 vResult = vPos;
    vec2 vTilePos = (vPos.xz / vRepeat) + 0.5;
    vResult.xz = (fract(vTilePos) - 0.5) * vRepeat;
    return vResult;
}

vec3 DomainRepeatY( const in vec3 vPos, const in float fSize )
{
    vec3 vResult = vPos;
    vResult.y = (fract(vPos.y / fSize + 0.5) - 0.5) * fSize;
    return vResult;
}

vec3 DomainRotateSymmetry( const in vec3 vPos, const in float fSteps )
{
    float angle = atan( vPos.x, vPos.z );

    float fScale = fSteps / (kTwoPI);
    float steppedAngle = (floor(angle * fScale + 0.5)) / fScale;

    float s = sin(-steppedAngle);
    float c = cos(-steppedAngle);

    vec3 vResult = vec3( c * vPos.x + s * vPos.z,
                 vPos.y,
                -s * vPos.x + c * vPos.z);

    return vResult;
}

float GetDistanceXYTorus( const in vec3 p, const in float r1, const in float r2 )
{
    vec2 q = vec2(length(p.xy)-r1,p.z);
    return length(q)-r2;
}
float GetDistanceYZTorus( const in vec3 p, const in float r1, const in float r2 )
{
    vec2 q = vec2(length(p.yz)-r1,p.x);
    return length(q)-r2;
}
float GetDistanceCylinderY(const in vec3 vPos, const in float r)
{
    return length(vPos.xz) - r;
}
float GetDistanceBox( const in vec3 vPos, const in vec3 vSize )
{
    vec3 vDist = (abs(vPos) - vSize);
    return max(vDist.x, max(vDist.y, vDist.z));
}

float GetDistanceRoundedBox( const in vec3 vPos, const in vec3 vSize, float fRadius )
{
    vec3 vClosest = max(min(vPos, vSize), -vSize);
    return length(vClosest - vPos) - fRadius;
}

// result is x=scene distance y=material or object id; zw are material specific parameters (maybe uv co-ordinates)
vec4 GetDistanceScene( const in vec3 vPos )
{          
    vec4 vResult = vec4(10000.0, -1.0, 0.0, 0.0);

    vec3 vSphereDomain = DomainRepeatXZ(vPos, vec2(5.0, 5.0));

    vec4 vDistSphere = vec4( length(vSphereDomain) - 1.0, 2.0, vSphereDomain.xy);

    vResult = DistCombineUnion(vResult, vDistSphere);

    vec4 vDistFloor = vec4(vPos.y + 1.0, 1.0, vPos.xz);
    vResult = DistCombineUnion(vResult, vDistFloor);

    return vResult;
}

C_Material GetObjectMaterial( const in vec3 vObjId, const in vec3 vPos )
{
    C_Material mat;

    if(vObjId.x < 1.5)
    {
        // floor
        mat.fR0 = 0.02;
        mat.fSmoothness = 0.0;
        mat.cAlbedo = vec3(0.7, 0.8, 0.3);
    }
    else
    if(vObjId.x < 2.5)
    {
        // sphere
        mat.fR0 = 0.05;
        mat.fSmoothness = 0.9;
        mat.cAlbedo = vec3(0.05, 0.35, 0.75);
    }

    return mat;
}
vec3 GetSkyGradient( const in vec3 vDir )
{
    float fBlend = vDir.y * 0.5 + 0.5;
    return mix(vec3(0.0, 0.0, 0.0), vec3(0.4, 0.9, 1.0), fBlend);
}
vec3 GetLightPos()
{
    vec3 vLightPos = vec3(0.0, 1.0, 3.0);
    #ifdef ENABLE_MONTE_CARLO        
    vLightPos += gRandomNormal * 0.2;
    #endif
    return vLightPos;
}
vec3 GetLightCol()
{
    return vec3(32.0, 6.0, 1.0) * 10.0;
}

vec3 GetAmbientLight(const in vec3 vNormal)
{
    return GetSkyGradient(vNormal);
}

#define kFogDensity 0.0025
void ApplyAtmosphere(inout vec3 col, const in C_Ray ray, const in C_HitInfo intersection)
{
    #ifdef ENABLE_FOG
    // fog
    float fFogAmount = exp(intersection.fDistance * -kFogDensity);
    vec3 cFog = GetSkyGradient(ray.vDir);
    col = mix(cFog, col, fFogAmount);
    #endif

    // glare from light (a bit hacky - use length of closest approach from ray to light)
    #ifdef ENABLE_POINT_LIGHT_FLARE
    vec3 vToLight = GetLightPos() - ray.vOrigin;
    float fDot = dot(vToLight, ray.vDir);
    fDot = clamp(fDot, 0.0, intersection.fDistance);

    vec3 vClosestPoint = ray.vOrigin + ray.vDir * fDot;
    float fDist = length(vClosestPoint - GetLightPos());
    col += GetLightCol() * 0.01/ (fDist * fDist);
    #endif     
}
vec3 GetSceneNormal( const in vec3 vPos )
{
    // tetrahedron normal
    float fDelta = 0.025;

    vec3 vOffset1 = vec3( fDelta, -fDelta, -fDelta);
    vec3 vOffset2 = vec3(-fDelta, -fDelta,  fDelta);
    vec3 vOffset3 = vec3(-fDelta,  fDelta, -fDelta);
    vec3 vOffset4 = vec3( fDelta,  fDelta,  fDelta);

    float f1 = GetDistanceScene( vPos + vOffset1 ).x;
    float f2 = GetDistanceScene( vPos + vOffset2 ).x;
    float f3 = GetDistanceScene( vPos + vOffset3 ).x;
    float f4 = GetDistanceScene( vPos + vOffset4 ).x;

    vec3 vNormal = vOffset1 * f1 + vOffset2 * f2 + vOffset3 * f3 + vOffset4 * f4;

    return normalize( vNormal );
}

#define kRaymarchEpsilon 0.01
#define kRaymarchMatIter 256
#define kRaymarchStartDistance 0.1
// This is an excellent resource on ray marching -> http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
void Raymarch( const in C_Ray ray, out C_HitInfo result, const float fMaxDist, const int maxIter )
{         
    result.fDistance = kRaymarchStartDistance;
    result.vObjectId.x = 0.0;

    for(int i=0;i<=kRaymarchMatIter;i++)               
    {
        result.vPos = ray.vOrigin + ray.vDir * result.fDistance;
        vec4 vSceneDist = GetDistanceScene( result.vPos );
        result.vObjectId = vSceneDist.yzw;

        // abs allows backward stepping - should only be necessary for non uniform distance functions
        if((abs(vSceneDist.x) <= kRaymarchEpsilon) || (result.fDistance >= fMaxDist) || (i > maxIter))
        {
            break;
        }                         

        result.fDistance = result.fDistance + vSceneDist.x;     
    }

    if(result.fDistance >= fMaxDist)
    {
        result.vPos = ray.vOrigin + ray.vDir * result.fDistance;
        result.vObjectId.x = 0.0;
        result.fDistance = 1000.0;
    }
}

float GetShadow( const in vec3 vPos, const in vec3 vLightDir, const in float fLightDistance )
{
    C_Ray shadowRay;
    shadowRay.vDir = vLightDir;
    shadowRay.vOrigin = vPos;

    C_HitInfo shadowIntersect;
    Raymarch(shadowRay, shadowIntersect, fLightDistance, 32);

    return step(0.0, shadowIntersect.fDistance) * step(fLightDistance, shadowIntersect.fDistance );          
}

// http://en.wikipedia.org/wiki/Schlick's_approximation
float Schlick( const in vec3 vNormal, const in vec3 vView, const in float fR0, const in float fSmoothFactor)
{
    float fDot = dot(vNormal, -vView);
    fDot = min(max((1.0 - fDot), 0.0), 1.0);
    float fDot2 = fDot * fDot;
    float fDot5 = fDot2 * fDot2 * fDot;
    return fR0 + (1.0 - fR0) * fDot5 * fSmoothFactor;
}

float GetDiffuseIntensity(const in vec3 vLightDir, const in vec3 vNormal)
{
    return max(0.0, dot(vLightDir, vNormal));
}

float GetBlinnPhongIntensity(const in C_Ray ray, const in C_Material mat, const in vec3 vLightDir, const in vec3 vNormal)
{           
    vec3 vHalf = normalize(vLightDir - ray.vDir);
    float fNdotH = max(0.0, dot(vHalf, vNormal));

    float fSpecPower = exp2(4.0 + 6.0 * mat.fSmoothness);
    float fSpecIntensity = (fSpecPower + 2.0) * 0.125;

    return pow(fNdotH, fSpecPower) * fSpecIntensity;
}

// use distance field to evaluate ambient occlusion
float GetAmbientOcclusion(const in C_Ray ray, const in C_HitInfo intersection, const in vec3 vNormal)
{
    vec3 vPos = intersection.vPos;

    float fAmbientOcclusion = 1.0;

    float fDist = 0.0;
    for(int i=0; i<=5; i++)
    {
        fDist += 0.1;

        vec4 vSceneDist = GetDistanceScene(vPos + vNormal * fDist);

        fAmbientOcclusion *= 1.0 - max(0.0, (fDist - vSceneDist.x) * 0.2 / fDist );                                   
    }

    return fAmbientOcclusion;
}

vec3 GetObjectLighting(const in C_Ray ray, const in C_HitInfo intersection, const in C_Material material, const in vec3 vNormal, const in vec3 cReflection)
{
    vec3 cScene ;

    vec3 vSpecularReflection = vec3(0.0);
    vec3 vDiffuseReflection = vec3(0.0);

    float fAmbientOcclusion = GetAmbientOcclusion(ray, intersection, vNormal);
    vec3 vAmbientLight = GetAmbientLight(vNormal) * fAmbientOcclusion;

    vDiffuseReflection += vAmbientLight;

    vSpecularReflection += cReflection * fAmbientOcclusion;

    #ifdef ENABLE_POINT_LIGHT
    vec3 vLightPos = GetLightPos();
    vec3 vToLight = vLightPos - intersection.vPos;
    vec3 vLightDir = normalize(vToLight);
    float fLightDistance = length(vToLight);

    float fAttenuation = 1.0 / (fLightDistance * fLightDistance);

    float fShadowBias = 0.1;             
    float fShadowFactor = GetShadow( intersection.vPos + vLightDir * fShadowBias, vLightDir, fLightDistance - fShadowBias );
    vec3 vIncidentLight = GetLightCol() * fShadowFactor * fAttenuation;

    vDiffuseReflection += GetDiffuseIntensity( vLightDir, vNormal ) * vIncidentLight;                                                                                 
    vSpecularReflection += GetBlinnPhongIntensity( ray, material, vLightDir, vNormal ) * vIncidentLight;
    #endif ENABLE_POINT_LIGHT

    vDiffuseReflection *= material.cAlbedo;              

    #ifdef ENABLE_SPECULAR
    float fFresnel = Schlick(vNormal, ray.vDir, material.fR0, material.fSmoothness * 0.9 + 0.1);
    cScene = mix(vDiffuseReflection , vSpecularReflection, fFresnel);
    #else
    cScene = vDiffuseReflection;
    #endif

    return cScene;
}

vec3 GetSceneColourSimple( const in C_Ray ray )
{
    C_HitInfo intersection;
    Raymarch(ray, intersection, 16.0, 32);

    vec3 cScene;

    if(intersection.vObjectId.x < 0.5)
    {
        cScene = GetSkyGradient(ray.vDir);
    }
    else
    {
        C_Material material = GetObjectMaterial(intersection.vObjectId, intersection.vPos);
        vec3 vNormal = GetSceneNormal(intersection.vPos);

        // use sky gradient instead of reflection
        vec3 cReflection = GetSkyGradient(reflect(ray.vDir, vNormal));

        // apply lighting
        cScene = GetObjectLighting(ray, intersection, material, vNormal, cReflection );
    }

    ApplyAtmosphere(cScene, ray, intersection);

    return cScene;
}

vec3 GetSceneColour( const in C_Ray ray )
{                                                           
    C_HitInfo intersection;
    Raymarch(ray, intersection, 30.0, 256);

    vec3 cScene;

    if(intersection.vObjectId.x < 0.5)
    {
        cScene = GetSkyGradient(ray.vDir);
    }
    else
    {
        C_Material material = GetObjectMaterial(intersection.vObjectId, intersection.vPos);
        vec3 vNormal = GetSceneNormal(intersection.vPos);

        #ifdef ENABLE_MONTE_CARLO
        vNormal = normalize(vNormal + gRandomNormal / (5.0 + material.fSmoothness * 200.0));
        #endif

        vec3 cReflection;
        #ifdef ENABLE_REFLECTIONS    
        {
            // get colour from reflected ray
            float fSepration = 0.05;
            C_Ray reflectRay;
            reflectRay.vDir = reflect(ray.vDir, vNormal);
            reflectRay.vOrigin = intersection.vPos + reflectRay.vDir * fSepration;

            cReflection = GetSceneColourSimple(reflectRay);                                                                         
        }
        #else
        cReflection = GetSkyGradient(reflect(ray.vDir, vNormal));                               
        #endif
        // apply lighting
        cScene = GetObjectLighting(ray, intersection, material, vNormal, cReflection );
    }

    ApplyAtmosphere(cScene, ray, intersection);

    return cScene;
}

void GetCameraRay( const in vec3 vPos, const in vec3 vForwards, const in vec3 vWorldUp, out C_Ray ray)
{
    vec2 vPixelCoord = gl_FragCoord.xy;
    #ifdef ENABLE_MONTE_CARLO
    vPixelCoord += gPixelRandom.zw;
    #endif
    vec2 vUV = ( vPixelCoord / resolution.xy );
    vec2 vViewCoord = vUV * 2.0 - 1.0;

    vViewCoord *= 0.75;

    float fRatio = resolution.x / resolution.y;

    vViewCoord.y /= fRatio;                           

    ray.vOrigin = vPos;

    vec3 vRight = normalize(cross(vForwards, vWorldUp));
    vec3 vUp = cross(vRight, vForwards);

    ray.vDir = normalize( vRight * vViewCoord.x + vUp * vViewCoord.y + vForwards);        
}

void GetCameraRayLookat( const in vec3 vPos, const in vec3 vInterest, out C_Ray ray)
{
    vec3 vForwards = normalize(vInterest - vPos);
    vec3 vUp = vec3(0.0, 1.0, 0.0);

    GetCameraRay(vPos, vForwards, vUp, ray);
}

vec3 OrbitPoint( const in float fHeading, const in float fElevation )
{
    return vec3(sin(fHeading) * cos(fElevation), sin(fElevation), cos(fHeading) * cos(fElevation));
}

vec3 Gamma( const in vec3 cCol )
{
    return cCol * cCol;
}

vec3 InvGamma( const in vec3 cCol )
{
    return sqrt(cCol);
}

vec3 Tonemap( const in vec3 cCol )
{
    // simple Reinhard tonemapping operator     
    vec3 vResult = cCol / (1.0 + cCol);

    return Gamma(vResult);
}

vec3 InvTonemap( const in vec3 cCol )
{
    vec3 vResult = cCol;
    vResult = clamp(vResult, 0.01, 0.99);
    vResult = InvGamma(vResult);
    return - (vResult / (vResult - 1.0));
}

void main( void )
{
    #ifdef ENABLE_MONTE_CARLO             
    CalcPixelRandom();
    #endif

    C_Ray ray;

    const float fCamreaInitialHeading = 2.5;
    const float fCamreaInitialElevation = 0.4;
    const float fCamreaInitialDist = 7.0;
    const float fCameraHeight = 0.9;
    const float fOrbitSpeed = 1.0;

    // This magic stolen from other 3d pan/zoom examples
    float fZoom = surfaceSize.y * 0.5 + 0.4;

    vec2 vCenterPosition = (0.5 - ( gl_FragCoord.xy / resolution )) * surfaceSize + surfacePosition;
    float fHeading = vCenterPosition.x * fOrbitSpeed + fCamreaInitialHeading;
    float fElevation = (vCenterPosition.y * fOrbitSpeed + fCamreaInitialElevation);

    vec3 vCameraPos = OrbitPoint(fHeading, fElevation) * fCamreaInitialDist * fZoom;

    vCameraPos += vec3(mouse.x*5., mouse.y*5., 0.0);

    vCameraPos += vec3(0.0, -fCameraHeight, 0.0);
    #ifdef ENABLE_MONTE_CARLO             
    float fDepthOfField = 0.025;
    vCameraPos += gRandomNormal * fDepthOfField;
    #endif

    GetCameraRayLookat( vCameraPos, vec3(0.0, 0.0, 0.0), ray);
    //GetCameraRayLookat(vec3(0.0, 0.0, -5.0), vec3(0.0, 0.0, 0.0), ray);

    vec3 cScene = GetSceneColour( ray );   

    float fExposure = 2.5;
    cScene = cScene * fExposure;

    #ifdef ENABLE_MONTE_CARLO                              
    vec3 cPrev = texture2D(backbuffer, gl_FragCoord.xy / resolution).xyz;
    // add noise to pixel value (helps values converge)
    cPrev += (gPixelRandom.xyz - 0.5) * (1.0 / 255.0);
    cPrev = InvTonemap(cPrev);
    // converge speed
    float fBlend = 0.1;
    vec3 cFinal = mix(cPrev, cScene, fBlend);
    #else
    vec3 cFinal = cScene;
    #endif

    cFinal = Tonemap(cFinal);

    float fAlpha = 1.0;

    gl_FragColor = vec4( cFinal, fAlpha );
}

< http://glsl.heroku.com/e#19432.1 >

2014-08-27_16-44-29

//shader from https://www.shadertoy.com/view/XsfXWH
//I just copied

#ifdef GL_ES
precision mediump float;
#endif

uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;

// ray marching
const int max_iterations = 128;
const float stop_threshold = 0.01;
const float grad_step = 0.05;
const float clip_far = 1000.0;

// math
const float PI = 3.14159265359;
const float DEG_TO_RAD = PI / 180.0;

mat3 roty( float angle ) {
    float c = cos( angle );
    float s = sin( angle );

    return mat3(
        c  , 0.0, -s  ,
        0.0, 1.0, 0.0,
        s  , 0.0, c  
    );
}

mat3 rotzx( vec2 angle ) {
    vec2 c = cos( angle );
    vec2 s = sin( angle );

    return
    mat3(
        c.y, s.y, 0.0,
        -s.y, c.y, 0.0,
        0.0, 0.0, 1.0
    ) *
    mat3(
        1.0, 0.0, 0.0,
        0.0, c.x, s.x ,
        0.0, -s.x, c.x
    );
}

// distance function
float dist_sphere( vec3 pos, float r ) {
    return length( pos ) - r;
}

float dist_box( vec3 pos, vec3 size ) {
    return length( max( abs( pos ) - size, 0.0 ) );
}

float dist_cone( vec3 p, float r, float h )
{
    vec2 c = normalize( vec2( h, r ) );
    float q = length(p.xy);
    return max( dot(c,vec2(q,p.z)), -(p.z + h) );
}

float dist_capsule( vec3 p, vec3 a, vec3 b, float r )
{
    vec3 pa = p - a, ba = b - a;
    float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );
    return length( pa - ba*h ) - r;
}

vec2 princess( vec3 p ) {
    p = vec3( p.x,abs(p.y),p.z );

    // hat
    float d0 = dist_cone( roty( radians( 70.0  ) ) * ( p - vec3( -3.4, 0.0, 2.04 ) ), 0.97, 3.3 );
    // skirt
    float d1 = dist_cone( roty( radians( -10.0 ) ) * ( p - vec3( 0.03, 0.0, -0.1 ) ), 1.6, 2.6 );
    // head
    float d2 = dist_sphere( p + vec3( 0.0, 0.0, -0.8 ), 1.0 );
    // neck
    float d3 = dist_capsule( p, vec3( 0.0, 0.0, -0.5 ), vec3( 0.0, 0.0, 1.0 ), 0.18 );
    // legs
    float d4 = dist_capsule( p + vec3( 0.0, -0.4, 0.0 ), vec3( 0.0, 0.0, -4.6 ), vec3( 0.0, 0.0, -2.0 ), 0.15 );
    // feet
    float d5 = dist_cone( roty( -90.0 * DEG_TO_RAD ) * ( p + vec3( -0.53, -0.4, 4.58 ) ), 0.16, 0.5 );

    float g0 = min( min( d0, d1 ), min( d4, d5 ) );

    float d = g0;
    float id = 1.0;

    if ( d > d3 ) { d = d3; id = 0.0; }
    if ( d > d2 ) { d = d2; id = step( 0.2, p.x ); }

    return vec2( d, id );
}

// distance
vec2 dist_field( vec3 p ) {
    return princess( p + vec3( 0.0, 0.0, -0.85 ) );
}

// gradient
vec3 gradient( vec3 pos ) {
    const vec3 dx = vec3( grad_step, 0.0, 0.0 );
    const vec3 dy = vec3( 0.0, grad_step, 0.0 );
    const vec3 dz = vec3( 0.0, 0.0, grad_step );
    return normalize (
        vec3(
            dist_field( pos + dx ).x - dist_field( pos - dx ).x,
            dist_field( pos + dy ).x - dist_field( pos - dy ).x,
            dist_field( pos + dz ).x - dist_field( pos - dz ).x         
        )
    );
}

// ray marching
vec2 ray_marching( vec3 origin, vec3 dir, float start, float end ) {
    float depth = start;
    for ( int i = 0; i < max_iterations; i++ ) {
        vec2 hit = dist_field( origin + dir * depth );
        if ( hit.x < stop_threshold ) {
            return hit;
        }
        depth += hit.x;
        if ( depth >= end) {
            break;
        }
    }
    return vec2( end, -1.0 );
}

// othogonal ray direction
vec3 ray_dir( float fov, vec2 size, vec2 pos ) {
    vec2 xy = pos - size * 0.5;

    float cot_half_fov = tan( ( 90.0 - fov * 0.5 ) * DEG_TO_RAD );  
    float z = size.y * 0.5 * cot_half_fov;

    return normalize( vec3( xy, -z ) );
}

vec3 EvalPixel( vec2 pix ) {
    // default ray dir
    vec3 dir = ray_dir( 45.0, resolution.xy, pix );

    // default ray origin
    vec3 eye = vec3( 0.0, 0.0, 13.0 );

    // rotate camera
    mat3 rot = rotzx( vec2( 70.0 * DEG_TO_RAD, 0.7 * time ) );
    dir = rot * dir;
    eye = rot * eye;

    // ray marching
    vec2 hit = ray_marching( eye, dir, 0.0, clip_far );
    if ( hit.x >= clip_far ) {
        return mix( vec3( 0.0, 0.3, 0.4 ), vec3( 0.17, 0.7, 0.7 ), gl_FragCoord.y / resolution.y );
    }

    // shading
    return vec3( hit.y );
}

void main(void)
{
    vec3 color = vec3( 0.0 );

#if 1
    color += EvalPixel( gl_FragCoord.xy                    );
    color += EvalPixel( gl_FragCoord.xy + vec2( 0.5, 0.0 ) );
    color += EvalPixel( gl_FragCoord.xy + vec2( 0.0, 0.5 ) );
    color += EvalPixel( gl_FragCoord.xy + vec2( 0.5, 0.5 ) );

    color *= 0.25;
#else
    color = EvalPixel( gl_FragCoord.xy );
#endif 

    gl_FragColor = vec4( color, 1.0 );
}