gl_FragColor은 화면 전체의 색상 값을 가지고 있는 색상 표라고 볼 수 있다.
img

우리가 배우는 GLSL은 그래픽 카드에 직접 말하는 언어라고 볼 수 있는데, 그래픽 카드가 하는 일은 바로 우리가 보는 화면에 색을 칠하는 것이다. 그 화면이 애니메이션이 됬든, 그림판이 됬든, 동영상이든, 사진이든 모두 다 빨강, 파랑, 녹색 세가지 색을 이용해서 보여주는 것임을 이미 알고 있을 것이다. 위의 이미지는 그걸 아주 간단히 보여주는건데, 0은 검은색, 1은 흰색을 의미하는 것이다. 1로 칠해져 있기 때문에 모두 흰색이다. 그럼 다음은 어떨까.

name
이렇게 보일 것이다. 한 칸 하나하나를 픽셀이라고 볼 수 있는 것이다.
흑백은 심심하니 여러가지 색을 써보고 싶다. 그럼 어떤 규칙을 가져야 할까. 모든 색은 RGB의 합성으로 나타낼 수 있으니 픽셀 하나당 세가지 값을 가지도록 해보자.

n1

이렇게 표현될 것이다. 우리가 모든 디스플레이에서 보는 모든 것은 이런 과정을 거친다고 볼 수 있다. 글씨나 그림 영상 모두 마찬가지인 것이다. 자 그럼 다시 glsl로 돌아오자. 이 코드들은 무엇인가. 바로 어느 위치에 어떤 색을 칠하라 라는 내용들을 말해준다.

n2

화면을 이렇게 그리고 싶다면 어떻게 해야 할까? 그림판에서는 쉽다. 마우스로 화면의 반을 선택하고 검은색으로 칠하면 된다. glsl에서는 이런게 통하지 않는다. 프로그래밍을 통해 이야기를 해야 하는 것이다.

화면의 가운데부터 왼쪽 끝까지는 색 1로, 오른쪽 끝까지 색을 0으로 칠해라

라는 명령을 전달해야 저런 모양이 되는 것이다. 이 내용을 glsl에서 표현하면 다음과 같다.

    vec2 position = ( gl_FragCoord.xy / resolution.xy );
    float color = 1.0;
    if(position.x > 0.5) color = 0.0;
    gl_FragColor = vec4( color, color, color, 1 );

n3

이해가 가는가? 맨 마지막 줄 부터 보자.

gl_FragColor이 이해가 안갈 수 있는데, 이를 어떤 틀이라고 생각해보자. 계란판이라고 생각하면 쉽다.

gl_fragcolor

gl_FragColor = vec4( color, color, color, 1 );`
//계란판 = 무슨계란

이때 계란에는 4가지 성분으로 색상값이 들어간다. vec4는 4가지 요소를 묶어주는 방법이라고 할 수 있는데 각각 R, G, B, Alpha값이 들어간다.
color라는 변수에 어디에 어떤 색이 들어가는지를 결정해 주어야 하는데, 이를 바로 그 위해서 전달하게 된다. 현재 RGB에 같은 color가 들어가는 것을 알 수 있다.

    vec2 position = ( gl_FragCoord.xy / resolution.xy );
    float color = 1.0;
    if(position.x > 0.5) color = 0.0;
    gl_FragColor = vec4( color, color, color, 1 );

2번째 줄에서 color

Tags : #shader

이번 목표로 설정!
(이미 열흘전에 정한거지만..)
http://glsl.herokuapp.com/e#13456.1
img

#ifdef GL_ES
precision mediump float;
#endif

#define STEPS 80
#define LIGHTPASSES 2
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.9898, 78.233)))* 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;
    }

    p.x += sin(time)*0.1;
    p.y += cos(time)*0.1;
    if (length(p-c) <= 0.05) {
        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)+1.),0.6);
        }
        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.);
}
Tags : #shader

굉장하다!
img

http://glslsandbox.com/e#20806

#ifdef GL_ES
precision mediump float;
#endif

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

vec3 iMouse=vec3(time*50.0);
vec2 iResolution=resolution;
float iGlobalTime=time;



// "Wet stone" by Alexander Alekseev aka TDM - 2014
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
// Mahmud Yuldashev modification mahmud9935@gmail.com

#define SMOOTH

const int NUM_STEPS = 32;
const int AO_SAMPLES = 3;
const vec2 AO_PARAM = vec2(1.2, 3.8);
const vec2 CORNER_PARAM = vec2(0.25, 40.0);
const float INV_AO_SAMPLES = 1.0 / float(AO_SAMPLES);
const float TRESHOLD    = 0.1;
const float EPSILON     = 1e-4;
const float LIGHT_INTENSITY = 0.25;
const vec3 RED      = vec3(1.0,0.7,0.7) * LIGHT_INTENSITY;
const vec3 ORANGE   = vec3(1.0,0.67,0.43) * LIGHT_INTENSITY;
const vec3 BLUE     = vec3(0.54,0.77,1.0) * LIGHT_INTENSITY;
const vec3 WHITE    = vec3(1.2,1.07,0.98) * LIGHT_INTENSITY;

const float DISPLACEMENT = 0.1;

// math
mat3 fromEuler(vec3 ang) {
    vec2 a1 = vec2(sin(ang.x),cos(ang.x));
    vec2 a2 = vec2(sin(ang.y),cos(ang.y));
    vec2 a3 = vec2(sin(ang.z),cos(ang.z));
    mat3 m;
    m[0] = vec3(a1.y*a3.y+a1.x*a2.x*a3.x,a1.y*a2.x*a3.x+a3.y*a1.x,-a2.y*a3.x);
    m[1] = vec3(-a2.y*a1.x,a1.y*a2.y,a2.x);
    m[2] = vec3(a3.y*a1.x*a2.x+a1.y*a3.x,a1.x*a3.x-a1.y*a3.y*a2.x,a2.y*a3.y);
    return m;
}
float hash11(float p) {
    return fract(sin(p * 727.1)*43758.5453123);
}
float hash12(vec2 p) {
    float h = dot(p,vec2(127.1,311.7)); 
    return fract(sin(h)*43758.5453123);
}
vec3 hash31(float p) {
    vec3 h = vec3(1275.231,4461.7,7182.423) * p;    
    return fract(sin(h)*43758.543123);
}

// 3d noise
float noise_3(in vec3 p) {
    //p += 123.0;
    vec3 i = floor(p);
    vec3 f = fract(p);  
    vec3 u = f*f*(3.0-2.0*f);

    vec2 ii = i.xy + i.z * vec2(5.0);
    float a = hash12( ii + vec2(0.0,0.0) );
    float b = hash12( ii + vec2(1.0,0.0) );    
    float c = hash12( ii + vec2(0.0,1.0) );
    float d = hash12( ii + vec2(1.0,1.0) ); 
    float v1 = mix(mix(a,b,u.x), mix(c,d,u.x), u.y);

    ii += vec2(5.0);
    a = hash12( ii + vec2(0.0,0.0) );
    b = hash12( ii + vec2(1.0,0.0) );    
    c = hash12( ii + vec2(0.0,1.0) );
    d = hash12( ii + vec2(1.0,1.0) );
    float v2 = mix(mix(a,b,u.x), mix(c,d,u.x), u.y);

    return max(mix(v1,v2,u.z),0.0);
}

// fBm
float fbm3(vec3 p, float a, float f) {
    return noise_3(p);
}

float fbm3_high(vec3 p, float a, float f) {
    float ret = 0.0;    
    float amp = 1.0;
    float frq = 1.0;
    for(int i = 0; i < 4; i++) {
        float n = pow(noise_3(p * frq),2.0);
        ret += n * amp;
        frq *= f;
        amp *= a * (pow(n,0.2));
    }
    return ret;
}

// lighting
float diffuse(vec3 n,vec3 l,float p) { return pow(max(dot(n,l),0.0),p); }
float specular(vec3 n,vec3 l,vec3 e,float s) {    
    float nrm = (s + 8.0) / (3.1415 * 8.0);
    return pow(max(dot(reflect(e,n),l),0.0),s) * nrm;
}

// distance functions
float plane(vec3 gp, vec4 p) {
    return dot(p.xyz,gp+p.xyz*p.w);
}
float sphere(vec3 p,float r) {
    return length(p)-r;
}
float capsule(vec3 p,float r,float h) {
    p.y -= clamp(p.y,-h,h);
    return length(p)-r;
}
float cylinder(vec3 p,float r,float h) {
    return max(abs(p.y/h),capsule(p,r,h));
}
float box(vec3 p,vec3 s) {
    p = abs(p)-s;
    return max(max(p.x,p.y),p.z);
}
float rbox(vec3 p,vec3 s) {
    p = abs(p)-s;
    return length(p-min(p,0.0));
}
float quad(vec3 p,vec2 s) {
    p = abs(p) - vec3(s.x,0.0,s.y);
    return max(max(p.x,p.y),p.z);
}

// boolean operations
float boolUnion(float a,float b) { return min(a,b); }
float boolIntersect(float a,float b) { return max(a,b); }
float boolSub(float a,float b) { return max(a,-b); }

// smooth operations. thanks to iq
float boolSmoothIntersect(float a, float b, float k ) {
    float h = clamp(0.5+0.5*(b-a)/k, 0.0, 1.0);
    return mix(a,b,h) + k*h*(1.0-h);
}
float boolSmoothSub(float a, float b, float k ) {
    return boolSmoothIntersect(a,-b,k);
}   

// world
float rock(vec3 p) {    
    float d = sphere(p,1.0);    
    for(int i = 0; i < 9; i++) {
        float ii = float(i);
        float r = 2.5 + hash11(ii);
        vec3 v = normalize(hash31(ii) * 2.0 - 1.0);
        #ifdef SMOOTH
        d = boolSmoothSub(d,sphere(p+v*r,r * 0.8), 0.03);
        #else
        d = boolSub(d,sphere(p+v*r,r * 0.8));
        #endif        
    }
    return d;
}

float map(vec3 p) {
    float d = rock(p) + fbm3(p*4.0,0.4,2.96) * DISPLACEMENT;
    d = boolUnion(d,plane(p,vec4(0.0,1.0,0.0,1.0)));
    return d;
}

float map_detailed(vec3 p) {
    float d = rock(p) + fbm3_high(p*4.0,0.4,2.96) * DISPLACEMENT;
    d = boolUnion(d,plane(p,vec4(0.0,1.0,0.0,1.0)));
    return d;
}

// tracing
vec3 getNormal(vec3 p, float dens) {
    vec3 n;
    n.x = map_detailed(vec3(p.x+EPSILON,p.y,p.z));
    n.y = map_detailed(vec3(p.x,p.y+EPSILON,p.z));
    n.z = map_detailed(vec3(p.x,p.y,p.z+EPSILON));
    return normalize(n-map_detailed(p));
}
vec2 getOcclusion(vec3 p, vec3 n) {
    vec2 r = vec2(0.0);
    for(int i = 0; i < AO_SAMPLES; i++) {
        float f = float(i)*INV_AO_SAMPLES;
        float hao = 0.01+f*AO_PARAM.x;
        float hc = 0.01+f*CORNER_PARAM.x;
        float dao = map(p + n * hao) - TRESHOLD;
        float dc = map(p - n * hc) - TRESHOLD;
        r.x += clamp(hao-dao,0.0,1.0) * (1.0-f);
        r.y += clamp(hc+dc,0.0,1.0) * (1.0-f);
    }    
    r.x = pow(clamp(1.0-r.x*INV_AO_SAMPLES*AO_PARAM.y,0.0,1.0),0.5);
    r.y = clamp(r.y*INV_AO_SAMPLES*CORNER_PARAM.y,0.0,1.0);
    return r;
}

vec2 spheretracing(vec3 ori, vec3 dir, out vec3 p) {
    vec2 td = vec2(0.0);
    for(int i = 0; i < NUM_STEPS; i++) {
        p = ori + dir * td.x;
        td.y = map(p);
        if(td.y < TRESHOLD) break;
        td.x += (td.y-TRESHOLD) * 0.9;
    }
    return td;
}

// stone
vec3 getStoneColor(vec3 p, float c, vec3 l, vec3 n, vec3 e) {
    c = min(c + pow(noise_3(vec3(p.x*20.0,0.0,p.z*20.0)),70.0) * 8.0, 1.0);
    float ic = pow(1.0-c,0.5);
    vec3 base = vec3(0.42,0.3,0.2) * 0.6;
    vec3 sand = vec3(0.51,0.41,0.32);
    vec3 color = mix(base,sand,c);

    float f = pow(1.0 - max(dot(n,-e),0.0), 1.5) * 0.75 * ic;
    color = mix(color,vec3(1.0),f);    
    color += vec3(diffuse(n,l,0.5) * WHITE);
    color += vec3(specular(n,l,e,8.0) * WHITE * 1.5 * ic);
    n = normalize(n - normalize(p) * 0.4);    
    color += vec3(specular(n,l,e,80.0) * WHITE * 1.5 * ic);    
    return color;
}

// main
void main(void) {
    vec2 iuv = gl_FragCoord.xy / iResolution.xy * 2.0 - 1.0;
    vec2 uv = iuv;
    uv.x *= iResolution.x / iResolution.y;    
    float time = iGlobalTime * 0.3;

    // ray
    vec3 ang = vec3(0.0,0.2,time);
    if(iMouse.z > 0.0) ang = vec3(0.0,clamp(2.0-iMouse.y*0.01,0.0,3.1415),iMouse.x*0.01);
    mat3 rot = fromEuler(ang);

    vec3 ori = vec3(0.0,0.0,2.8);
    vec3 dir = normalize(vec3(uv.xy,-2.0));    
    ori = ori * rot;
    dir = dir * rot;

    // tracing
    vec3 p;
    vec2 td = spheretracing(ori,dir,p);
    vec3 n = getNormal(p,td.y);
    vec2 occ = getOcclusion(p,n);
    vec3 light = normalize(vec3(0.0,1.0,0.0)); 

    // color
    vec3 color = vec3(1.0);    
    if(td.x < 3.5 && p.y > -0.89) color = getStoneColor(p,occ.y,light,n,dir);
    color *= occ.x;

    // background
    color = mix(vec3(1.0),color,step(td.y,1.0));

    // post
    float vgn = smoothstep(1.2,0.7,abs(iuv.y)) * smoothstep(1.1,0.8,abs(iuv.x));
    color *= 1.0 - (1.0 - vgn) * 0.15;  
    gl_FragColor = vec4(color,1.0);
}
Tags : #shader

STEP 1. Shader code 직접 넣어보기

Glsl sandbox는 glsl의 온라인상에서 Pixel Shader를 테스트하는 곳이라고 할 수 있다. 접속해서 Create new effect! 버튼을 누르면 다음의 화면이 나온다.

image

마우스의 움직임에 따라 패턴이 달라지는 기본 코드인데, 지금 이해하기에는 어려움이 있으니 아래의 코드를 복사해 넣자.
다음의 기본적인 코드를 복사해 붙여넣자.

#ifdef GL_ES
precision mediump float;
#endif

uniform float time;
uniform vec2 resolution;

void main( void ) {
    vec2 position = ( gl_FragCoord.xy / resolution.xy );
    gl_FragColor = vec4( 1, 1, 1, 1 );
}

흰색 화면이 나온다. 가장 마지막줄의 gl_FragColor 를 바꿔보자

gl_FragColor = vec4( 0, 0, 0, 1 );

검은 화면이 나온다. 0.5를 넣어주면 회색이 나온다. 다양한 숫자를 넣어보자.
gl_FragColor은 화면의 색상을 나타내고 vec4 는 4가지의 구성요소를 갖는다고 할 수 있다.

gl_FragColor = vec4( R, G, B, A );

이런 형식으로 값을 입력을 받고, glsl에서 색상의 범위는 0~255가 아닌 0~1이다. R, G, B자리에 원하는 숫자를 넣어보자. 단색은 너무 지루하니 변화를 줘보도록 하자. 그라데이션은 어떨까. 그라데이션을 위해 position을 이용해 보자.

vec2 position = ( gl_FragCoord.xy / resolution.xy );

position을 정의한 부분을 보자. 이것을 풀어서 쓰면

position.x = gl_FragCoord.x / resolution.x;
position.y = gl_FragCoord.y / resolution.y;

라고 할 수 있는데 glsl의 간편한 언어의 특징이라고 생각하자. 이 부분을 보면 gl_FragCoord를 resolution으로 나누고 있다. gl_FragCoord는 현재 frame buffer안의 픽셀 조각들의 좌표를 가리키는데, 쉽게 말해 픽셀의 위치를 나타낸다고 할 수 있다. 왼쪽 위부터 1부터 오른쪽 끝으로 갈수록 400, 500증가할것이다. resolution은 말 그대로 현재 화면의 크기이다.

즉, vec2 position = gl_FragCoord.xy / resolution.x 이 값은 화면 어디에서나 0~1사이의 값을 갖는 점의 집합이라고 할 수 있겠다.

image

한번 이를 확인해 보도록 하자. gl_FragColor의 R, G, B에 position.x를 넣어보자.

gl_FragColor = vec4( position.x, position.x, position.x, 1 );

image

좌에서 우로 그라데이션이 생겼다. 반대의 그라데이션을 만들려면 어떻게 해야할까? 그렇다.
다음과 같이 하면 된다.

gl_FragColor = vec4( 1- position.x, 1- position.x, 1- position.x, 1 );

하지만 에러가 생긴다. 이는 position.x값이 실수이기 때문에 1(정수)에서 position.x(실수)를 뺄 수 없기 때문이다. 이럴 땐 1.0으로 바꿔주면 된다.

gl_FragColor = vec4( 1.0- position.x, 1.0- position.x, 1.0- position.x, 1 );

가끔씩 glslsandbox에서 에러가 날 때가 있는데 딱히 이유나 지점을 표시해 주지 않기 때문에 알 수 없는 일이 있다. 이럴 땐 실수가 들어가야 하는 곳에 정수가 들어간 것은 아닌지 의심해 보자.

STEP 2. position 을 이용한 색 변형

‘position’을 이용해서 다음처럼 여러가지로 바꿔보는게 가능하다.

gl_FragColor = vec4( position.x, position.y, position.x, 1 );

image

이런식으로 sin이나 cos을 이용하는 것도 가능하다.
gl_FragColor = vec4( sin(position.y), cos(position.x), position.x, 1 );

image

sin이나 cos을 이용할 때 재밌는 것은 인자를 아주 큰 수로 만들어주면 반복이 된다는 것이다.
gl_FragColor = vec4( sin(position.y*20.0), cos(position.x*12.0), tan(position.x), 1 );

image

숫자를 바꿔가며 자신만의 이미지를 만들어보자.

Tags : #shader

http://glsl.heroku.com/e#19224.0 공부해봄
image

#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 <20; i++){
        float f = float(i);
        p +=  // 뒤에 나올 컬러값을 pixel값에 더해 해상도를 높인다. 이부분을 주석처리 해보면 어떤 역할을 하는지 알 수 있다.
        c += max(0.5 - length(vec2(rand(vec2(f, 2.0)), rand(vec2(-1.0, f))) * 2.0 - 1.0 - p), 0.0); 
        // c에 랜덤한 벡터와 원점 사이의 위치값을 반환한다. - 원 그리기
        // max를 이용해 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 ); // 적색 그라데이션
//  gl_FragColor = vec4(vec3(c, c, c), 1.0 ); // 흑백

}
Tags : #shader

원 그리기

Glsl Sandbox에 접속해서 Create new effect! 버튼을 눌러 다음의 코드를 넣자.

마우스의 움직임에 따라 패턴이 달라지는 기본 코드인데, 지금 이해하기에는 어려움이 있으니 아래의 코드를 복사해 넣자.
다음의 기본적인 코드를 복사해 붙여넣자.

#ifdef GL_ES
precision mediump float;
#endif

uniform float time;
uniform vec2 resolution;

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

    float color = 0.0;
    float d = length(position);
    d = distance(position, vec2(0,0));
    color = d;
    gl_FragColor = vec4( color, color, color, 1 );
}

image

이런 화면이 나올 것이다. 한줄씩 침착하게 나아가자. 한줄씩 지워가며 속성을 이해해 볼건데, 실제로 지워버리면 나중에 다시 써야하니 주석으로 막으면서 해보도록 하겠다.

10번째 줄과 11번째 줄의 앞에 ‘//’를 넣어보자

//position = 2.0 * position - 1.0;
//position.x *= resolution.x / resolution.y;

해당 줄을 주석으로 바꾼 것이다. 다시 ‘//’를 제거하면 다시 원래대로 동작하니 모르는 코드가 있을 때 하나하나 스위치를 꺼고 켜듯이 주석처리를 해서 이해해 볼 수 있다.

Tags : #shader

2014-09-27_13-06-54

http://glslsandbox.com/e#20203.2

#ifdef GL_ES
precision mediump float;
#endif

uniform float time;
uniform vec2 resolution;

void main( void ) {

     vec2 p = ( gl_FragCoord.xy / resolution.xy );
     p = 2.0 * p - 1.0;
     p.x *= resolution.x / resolution.y;

     vec3 bg = vec3(1);
     vec3 color = vec3(0.0);

     // 적색원
     vec3 c1 = vec3(.8, 0, 0); // 색상
     float timev = mod(time / 2.0, 0.5); // 시간1
     vec2 m1 = vec2(timev, timev); // 원의 위치
     float d1 = distance(p, m1); // 모든 점에 대하여 원의 위치까지의 거리 ; 원의 줌심이 1, 멀어질수록 0이 되는 그라데이션값
     d1 = smoothstep(0.2, 0.25, d1); // 그라데이션을 제한하여 원처럼 보이게 한다.

     // 녹색원
     vec3 c2 = vec3(0, .8, 0); // 색상
     float timev2 = mod(time, 0.5); // 시간1
     vec2 m2 = vec2(timev, 0); // 원의 위치
     float d2 = distance(p, m2); // 모든 점에 대하여 원의 위치까지의 거리 ; 원의 줌심이 1, 멀어질수록 0이 되는 그라데이션값
     d2 = smoothstep(0.3, 0.35, d2); // 그라데이션을 제한하여 원처럼 보이게 한다.

     color = mix(bg, c1, 1.0 - d1); // 배경색과 적색을 합성하고 그 범위를 적색원 만큼 채운다
     color = mix(color, c2, 1.0 - d2); // 적색과 녹색을 을 합성하고 그 범위를 녹색원 만큼 채운다

     gl_FragColor = vec4( color, 1.0 );

}

2014-09-27_13-01-08

http://glslsandbox.com/e#20203.1


#ifdef GL_ES
precision mediump float;
#endif

uniform float time;
uniform vec2 resolution;

float hash(float n){
    return fract(sin(n) * 45323.2);
}

void main( void ) {

    vec2 p = ( gl_FragCoord.xy / resolution.xy );
    p = 2.0 * p - 1.0;
    p.x *= resolution.x / resolution.y;

    vec3 bg = vec3(1);
    vec3 color = vec3(0.0);

    for(int i = 0; i < 10; i ++){

        vec3 c1 = vec3(1, 0, 0); // 공의 색상
        float t = mod(time, 5.0); // time%5초 - 시간

        float vx = hash(float(i))*t; // 점 마다의 속력 hash에 넣어 랜덤하게 생성
        float px = 0.0 + vx-1.0;  // 점의 x위치
        float py = float(i)/10.0-.5; // 점의 y위치

        vec2 m1 = vec2(px, py); // vec2에 저장된 위치

        float d1 = distance(p, m1); // 중심점과 모든 픽셀과의 거리 : 중심은 1로, 멀어질수록 0이 되는 그라디언트가 된다.
        float r = hash(float(i))/5.0; // hashing된 반지름 
        d1 = smoothstep(r, r+0.01, d1); // 그라디언트의 범위를 줄여 원으로 보이게 만든다.

        color = mix(color, c1, 1.0 - d1); 
        // 모든 색상값을 합친다. 모든 원들이 한번에 보일수 있게 한다. 기존의 색상에 새 색상을 합쳐고, 마스킹을 새 색상의 범위(새 원)만큼 제한한다.
    }
    gl_FragColor = vec4( color, 1.0 );
}
Tags : #shader

2014-09-27_13-06-54

http://glslsandbox.com/e#20203.2

#ifdef GL_ES
precision mediump float;
#endif

uniform float time;
uniform vec2 resolution;

void main( void ) {

     vec2 p = ( gl_FragCoord.xy / resolution.xy );
     p = 2.0 * p - 1.0;
     p.x *= resolution.x / resolution.y;

     vec3 bg = vec3(1);
     vec3 color = vec3(0.0);

     // 적색원
     vec3 c1 = vec3(.8, 0, 0); // 색상
     float timev = mod(time / 2.0, 0.5); // 시간1
     vec2 m1 = vec2(timev, timev); // 원의 위치
     float d1 = distance(p, m1); // 모든 점에 대하여 원의 위치까지의 거리 ; 원의 줌심이 1, 멀어질수록 0이 되는 그라데이션값
     d1 = smoothstep(0.2, 0.25, d1); // 그라데이션을 제한하여 원처럼 보이게 한다.

     // 녹색원
     vec3 c2 = vec3(0, .8, 0); // 색상
     float timev2 = mod(time, 0.5); // 시간1
     vec2 m2 = vec2(timev, 0); // 원의 위치
     float d2 = distance(p, m2); // 모든 점에 대하여 원의 위치까지의 거리 ; 원의 줌심이 1, 멀어질수록 0이 되는 그라데이션값
     d2 = smoothstep(0.3, 0.35, d2); // 그라데이션을 제한하여 원처럼 보이게 한다.

     color = mix(bg, c1, 1.0 - d1); // 배경색과 적색을 합성하고 그 범위를 적색원 만큼 채운다
     color = mix(color, c2, 1.0 - d2); // 적색과 녹색을 을 합성하고 그 범위를 녹색원 만큼 채운다

     gl_FragColor = vec4( color, 1.0 );

}

2014-09-27_13-01-08

http://glslsandbox.com/e#20203.1


#ifdef GL_ES
precision mediump float;
#endif

uniform float time;
uniform vec2 resolution;

float hash(float n){
    return fract(sin(n) * 45323.2);
}

void main( void ) {

    vec2 p = ( gl_FragCoord.xy / resolution.xy );
    p = 2.0 * p - 1.0;
    p.x *= resolution.x / resolution.y;

    vec3 bg = vec3(1);
    vec3 color = vec3(0.0);

    for(int i = 0; i < 10; i ++){

        vec3 c1 = vec3(1, 0, 0); // 공의 색상
        float t = mod(time, 5.0); // time%5초 - 시간

        float vx = hash(float(i))*t; // 점 마다의 속력 hash에 넣어 랜덤하게 생성
        float px = 0.0 + vx-1.0;  // 점의 x위치
        float py = float(i)/10.0-.5; // 점의 y위치

        vec2 m1 = vec2(px, py); // vec2에 저장된 위치

        float d1 = distance(p, m1); // 중심점과 모든 픽셀과의 거리 : 중심은 1로, 멀어질수록 0이 되는 그라디언트가 된다.
        float r = hash(float(i))/5.0; // hashing된 반지름 
        d1 = smoothstep(r, r+0.01, d1); // 그라디언트의 범위를 줄여 원으로 보이게 만든다.

        color = mix(color, c1, 1.0 - d1); 
        // 모든 색상값을 합친다. 모든 원들이 한번에 보일수 있게 한다. 기존의 색상에 새 색상을 합쳐고, 마스킹을 새 색상의 범위(새 원)만큼 제한한다.
    }
    gl_FragColor = vec4( color, 1.0 );
}
Tags : #shader

2014-09-14_21-50-06

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

// Coffee & Tablet - @P_Malin

#ifdef GL_ES
precision highp float;
#endif

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

uniform sampler2D backbuffer;

#define PI 3.141592654

#define ENABLE_MONTE_CARLO
#define ENABLE_PERLIN_NOISE
#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()
{
    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

#ifdef ENABLE_PERLIN_NOISE

#define NOISE_TILE_SIZE 64.0
#define NOISE_TILE_COUNT 4.0

#define kNoisePersistence 2.0
#define kNoiseAmplitude 0.04

float GetNoise( const in vec2 vPos )
{
    return fract(sin(vPos.x * 324.324234) * 234.324 + sin(vPos.y * 323.324234) * 122.324);
}

float GetSmoothNoise(const in vec2 vCoord, const in float fWrap)
{
    vec2 vCoordFloor = floor(vCoord);
    vec2 vCoordFract = fract(vCoord);

    vec2 vICoordFract = 1.0 - vCoordFract;

    vec4 vCoordPacked =  vCoordFloor.xyxy;
    vCoordPacked.zw += 1.0;
    vCoordPacked = mod(vCoordPacked, fWrap);

    float tl = GetNoise( vCoordPacked.xy );
    float tr = GetNoise( vCoordPacked.zy );
    float bl = GetNoise( vCoordPacked.xw );
    float br = GetNoise( vCoordPacked.zw );

    return     tl * vICoordFract.x * vICoordFract.y
                    + tr * vCoordFract.x  * vICoordFract.y
                    + bl * vICoordFract.x * vCoordFract.y
                    + br * vCoordFract.x  * vCoordFract.y;
}

// we store the noise texture in the backbuffer alpha channel
float CalculateNoiseTexture()
{
    vec2 vTileIndex = floor(gl_FragCoord.xy / NOISE_TILE_SIZE);
    if(vTileIndex.y > 0.0)
    {
        return 1.0;
    }

    if(vTileIndex.x > NOISE_TILE_COUNT)
    {
        return 0.0;         
    }

    float fFrequency = pow(0.5, vTileIndex.x);

    float fThisNoise = GetSmoothNoise( gl_FragCoord.xy * fFrequency, NOISE_TILE_SIZE * fFrequency);

    float fSampledNoise = texture2D(backbuffer, (gl_FragCoord.xy + vec2(NOISE_TILE_SIZE, 0.0)) / resolution ).a;

    float fAmplitude = kNoiseAmplitude * pow(kNoisePersistence, vTileIndex.x);
    return fThisNoise * fAmplitude + fSampledNoise;
}

float SampleNoiseTexture( vec2 vUV )
{
    return texture2D(backbuffer, (fract(vUV) * NOISE_TILE_SIZE) / resolution ).a;
}
#else
float SampleNoiseTexture( vec2 vUV )
{
    return dot(sin(vUV * vec2(8.0,8.0)), vec2(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 / (PI * 2.0);
    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;
}

float GetDistanceMug( const in vec3 vPos )
{
    float fDistCylinderOutside = length(vPos.xz) - 1.0;
    float fDistCylinderInterior = length(vPos.xz) - 0.9;
    float fTop = vPos.y - 1.0;

    float r1 = 0.6;
    float r2 = 0.15;
    vec2 q = vec2(length(vPos.xy + vec2(1.2, -0.1))-r1,vPos.z);
    float fDistHandle = length(q)-r2;

    float fDistMug = max(max(min(fDistCylinderOutside, fDistHandle), fTop), -fDistCylinderInterior);
    return fDistMug;
}

float GetDistanceCoffee( const in vec3 vPos )
{
    float fTopCoffee = vPos.y - 0.7;
    float fDistCylinderCoffee = length(vPos.xz) - 0.95;

    float fDistCoffee = max(fTopCoffee, fDistCylinderCoffee);
    return fDistCoffee;
}

vec4 GetDistanceTablet( const in vec3 vPos )
{             
    vec3 vBevelPos = vPos - vec3(0.0, 1.71, 0.0);
    float r = 1.0;
    float fBevelDist = GetDistanceRoundedBox( vBevelPos, vec3(1.5, 1.0, 2.0), r );

    vec3 vCasePos = vPos - vec3(0.0, 0.0, 0.0);
    float fCaseDist = GetDistanceRoundedBox( vCasePos, vec3(1.5, 1.0, 2.0), 0.5 );

    vec4 vResult = vec4(max(fBevelDist, fCaseDist), 4.0, vPos.xz);

    vec4 vScreenDist = vec4(-vPos.y, 5.0, vPos.xz);
    vResult = DistCombineSubtract(vResult, vScreenDist);

    vec4 vButtonDist = vec4( length(vPos + vec3(0.0, -0.25, 2.1)) - 0.3, 5.0, vPos.xz);
    vResult = DistCombineSubtract(vResult, vButtonDist);

    return vResult;
}

// 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 vMugDomain = vPos + vec3(2.4, 0.0, -2.0);
    vMugDomain = RotateY(vMugDomain, 1.0);

    vec4 vDistMug = vec4( GetDistanceMug(vMugDomain), 2.0, vMugDomain.xy);
    vResult = DistCombineUnion(vResult, vDistMug);

    vec4 vDistCoffee = vec4( GetDistanceCoffee(vMugDomain), 3.0, vMugDomain.xz);
    vResult = DistCombineUnion(vResult, vDistCoffee);

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

    vec3 vTabletDomain = vPos;
    vTabletDomain += vec3(-0.8, 0.7, 0.0);
    vTabletDomain = RotateY(vTabletDomain, -1.0);
    vec4 vDistTablet = GetDistanceTablet(vTabletDomain);
    vResult = DistCombineUnion(vResult, vDistTablet);

    return vResult;
}

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

    if(vObjId.x < 1.5)
    {
        // floor
        float fBlend = SampleNoiseTexture(vPos.xz * 0.2 + vec2(0.0, sin(mod(vPos.x,4.0))));                    
        mat.fR0 = 0.02;
        mat.fSmoothness = fBlend;
        mat.cAlbedo = mix(vec3(0.7, 0.8, 0.3), vec3(0.5, 0.3, 0.1), fBlend);
    }
    else
    if(vObjId.x < 2.5)
    {
        // mug
        mat.fR0 = 0.05;
        mat.fSmoothness = 0.9;
        mat.cAlbedo = vec3(0.05, 0.35, 0.75);
    }
    else
    if(vObjId.x < 3.5)
    {
        // coffee
        mat.fR0 = 0.01;
        mat.fSmoothness = 1.0;
        mat.cAlbedo = vec3(0.5, 0.3, 0.2);
    }
    else
    if(vObjId.x < 4.5)
    {
        // tablet back
        mat.fR0 = 0.25;
        mat.fSmoothness = 0.0;
        mat.cAlbedo = vec3(0.8, 0.8, 0.8);                            
    }
    else
    {
        // tablet screen
        mat.fR0 = 0.01;
        mat.fSmoothness = 1.0;                               
        mat.cAlbedo = vec3(0.025);
    }

    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);
}

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.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;

    // emmissive glow from screen
    if(intersection.vObjectId.x > 4.5)
    {
        vec2 vScreenPos = intersection.vObjectId.zy * vec2(0.25, -0.3) + vec2(0.46, 0.5);

        vec2 vMul = step(vScreenPos, vec2(1.0)) * step(vec2(0.0), vScreenPos);
        float fMul = vMul.x * vMul.y * 0.8;
        vDiffuseReflection += texture2D(backbuffer, vScreenPos).xyz * fMul;
    }

    #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 Tonemap( const in vec3 cCol )
{
    // simple Reinhard tonemapping operator      
    return cCol / (1.0 + cCol);
}

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

    C_Ray ray;

    vec3 vCameraPos = OrbitPoint(-mouse.x * 7.0, mouse.y * PI * 0.5) * 7.0 - vec3(0.0, 0.9, 0.0);
    #ifdef ENABLE_MONTE_CARLO              
    float fDepthOfField = 0.1;
    vCameraPos += gRandomNormal * 0.05;
    #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;
    vec3 cCurr = Tonemap(cScene );

    #ifdef ENABLE_MONTE_CARLO                              
    vec3 cPrev = texture2D(backbuffer, gl_FragCoord.xy / resolution).xyz;
    // would be nice to combine before tonemap but undoing a gamma=2.0 will do instead
    cPrev = cPrev * cPrev;
    // add noise to pixel value (helps values converge)
    cPrev += (gPixelRandom.xyz - 0.5) * (1.0 / 255.0);
    cCurr = cCurr * cCurr;
    // converge speed
    vec3 cFinal = mix(cPrev, cCurr, 8.0/255.0);
    // re-apply gamma 2.0
    cFinal = sqrt(cFinal);
    #else
    vec3 cFinal = cCurr;
    #endif

    float fAlpha = 1.0;
    #ifdef ENABLE_PERLIN_NOISE
    fAlpha = CalculateNoiseTexture();          
    #endif

    gl_FragColor = vec4( cFinal, fAlpha );

    //gl_FragColor = vec4(CalculateNoiseTexture()); // output noise texture
}

2014-09-14_21-50-58

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

// 704 Remake - @PauloFalcao
// based on Blank Slate - @P_Malin (http://glsl.heroku.com/e#2540.09)
//
// Tonight was very tired from work, and decided to do some graphics fun to clear the mind! :)
// I opened the http://glsl.heroku.com/ and saw a copy of @P_Malin framework
// I Remembered my old 704 (http://www.backtothepixel.com/demos/js/webgl/704_webgl.html)
// and thought... how it would look like if i used the 704 object...
// I loved the results!!! @P_Malin framework is awesome!!!
// Very complete, with nice variable names, really nice! :)
// Colors, and the object are the same as the original 704,
// but time is slower to give to the stuff time to cook... ;)
//

#ifdef GL_ES
precision highp float;
#endif

uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;
uniform sampler2D backbuffer;

// 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;

// Removed so that it works again
//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);

    float oP=length(vPos);
    vec3 vSphereDomain=vPos;
    float tt=time*0.05+10.0;
    vSphereDomain.x=sin(vSphereDomain.x)+sin(tt);
    vSphereDomain.z=sin(vSphereDomain.z)+cos(tt);

    vec4 vDistSphere = vec4( length(length(vSphereDomain))-1.5-sin(oP-tt*4.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.01;
        mat.fSmoothness = 0.0;
        if (fract(vPos.x*.5)>.5)
            if (fract(vPos.z*.5)>.5)
                mat.cAlbedo=vec3(0,0,0);
            else
                mat.cAlbedo=vec3(1,1,1);
            else
            if (fract(vPos.z*.5)>.5)
                mat.cAlbedo = vec3(1,1,1);
            else
                mat.cAlbedo = vec3(0,0,0);
    }
    else
    if(vObjId.x < 2.5)
    {
        // sphere
        mat.fR0 = 0.5;
        mat.fSmoothness = 0.9;
        float tt=time*0.05+10.0;
        float d=length(vPos);
        mat.cAlbedo = vec3((sin(d*.25-tt*4.0)+1.0)/2.0,(sin(tt)+1.0)/2.0,(sin(d-tt*4.0)+1.0)/2.0);
    }

    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.5, 0.6, 0.7), fBlend);
}
vec3 GetLightPos()
{
    vec3 vLightPos = vec3(2.0, 9.0, 2.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.035
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, 60.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 = 0.5;
    const float fCamreaInitialElevation = 0.5;
    const float fCamreaInitialDist = 20.0;
    const float fCameraHeight = 0.01;
    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(0.0, -fCameraHeight, 0.0);
    #ifdef ENABLE_MONTE_CARLO             
    float fDepthOfField = 0.1;
    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 = 3.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 speep
    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 );
}
Tags : #shader

2007년에 제작된 177kb밖에 안되는 데모.
와 정말 입이 딱 벌어진다.

farbrausch라는 팀에서 만들었고, 제작툴까지 오픈해놓았네. 링크

세상엔 정말 엄청난 사람들이 많다.

Tags : #shader
Tags : #shader

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

precision highp float;
uniform vec2 resolution;
uniform float time;
uniform vec2 mouse;

float hash11(float p) {
    return fract(sin(p)*45768.23);
}

float hash21(vec2 p) {
    return fract(sin(p.x * 15.23 + p.y * 32.12) * 45768.23);
}

float hash31(vec3 p) {
    return fract(sin(p.x *15.23 + p.y * 35.87 + p.z * 75.53) * 45768.23);
}

vec2 hash22(vec2 p) {
    mat2 m = mat2(15.23, 32.12, 71.23, 152.31);
    return fract(sin(m*p)*45768.23);
}

vec3 hash33(vec3 p) {
    mat3 m = mat3(15.23, 35.11, 70.24, 151.22, 301.11 , 612.23, 1345.17, 2678.98, 5371.13);
    return fract(sin(m*p)*45768.23);
}

float value_noise(vec3 p) {
    vec3 g = floor(p);
    vec3 f = fract(p);
    float fbl = hash31(g + vec3(0.0, 0.0, 0.0));
    float fbr = hash31(g + vec3(1.0, 0.0, 0.0));
    float ftl = hash31(g + vec3(0.0, 1.0, 0.0));
    float ftr = hash31(g + vec3(1.0, 1.0, 0.0));
    float bbl = hash31(g + vec3(0.0, 0.0, 1.0));
    float bbr = hash31(g + vec3(1.0, 0.0, 1.0));
    float btl = hash31(g + vec3(0.0, 1.0, 1.0));
    float btr = hash31(g + vec3(1.0, 1.0, 1.0));
    
    float fb = mix(fbl, fbr, f.x);
    float ft = mix(ftl, ftr, f.x);
    float fres = mix(fb, ft, f.y);
    float bb = mix(bbl, bbr, f.x);
    float bt = mix(btl, btr, f.x);
    float bres = mix(bb, bt, f.y);
    
    float res = mix(fres, bres, f.z);
    return res;
}

float sdPlane(in vec3 p) {
    return p.y + value_noise(p);
    // return p.y;
}

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

float map(in vec3 p) {
    float d = sdPlane(p);
    d = min(d, sdSphere(p - vec3(0.0, 0.25, 0.0), 0.25)); // find surface compare 
    return d;
}

vec3 calcNormal(in vec3 p) {
    // calculate all surface`s normal
    vec3 e = vec3(0.001, 0.0, 0.0);
    vec3 nor = vec3(
        map(p + e.xyy) - map(p - e.xyy),
        map(p + e.yxy) - map(p - e.yxy),
        map(p + e.yyx) - map(p - e.yyx)
    );
    return normalize(nor);
}

float castRay(in vec3 cameraPosition, in vec3 renderVector, in float maxt) {
    // find surface
    float precis = 0.001;
    float h = precis * 2.0;
    float t = 0.0;
    for(int i = 0; i < 60; i++) {
        if(abs(h) < precis || t > maxt) continue;
        h = map(cameraPosition + renderVector * t);
        t += h;
    }
    return t;
}

float softshadow(in vec3 cameraPosition, in vec3 renderVector, in float mint, in float maxt, in float k) {
    float sh = 1.0;
    float t = mint;
    float h = 0.0;
    for(int i = 0; i < 30; i++) {
        if(t > maxt) continue;
        h = map(cameraPosition + renderVector * t);
        sh = min(sh, k * h / t);
        t += h;
    }
    return sh;
}

vec3 render(in vec3 cameraPosition, in vec3 renderVector) {
    vec3 col = vec3(1.0);
    float distanceFromCamera = castRay(cameraPosition, renderVector, 20.0); // distance camera to target
    vec3 pos = cameraPosition + renderVector * distanceFromCamera; //surface`s point?
    vec3 nor = calcNormal(pos); // calculate all surface`s normal
    vec3 lig = normalize(vec3(-0.4, 0.7, 0.5)); // light`s vector
    float dif = clamp(dot(lig, nor), 0.0, 1.0); // light`s strenght -> color
    float spec = pow(clamp(dot(reflect(renderVector, nor), lig), 0.0, 1.0), 16.0);
    float sh = softshadow(pos, lig, 0.02, 20.0, 7.0);
    col = col * (dif + spec) * sh;
    return col;
}

void main() {
    vec2 uv = gl_FragCoord.xy / resolution.xy;
    vec2 p = uv * 2.0 - 1.0;
    p.x *= resolution.x / resolution.y;
    // vec3 cameraPosition = vec3(1.0, 1.0, 3.0); //camera ray origin
    vec3 cameraPosition = vec3( mouse.x*4.0, 1.0, 3.0); //camera ray origin
    vec3 targetOrigin = vec3(0.0, 0.0, 0.0); //target
    vec3 eyeToTarget = normalize(targetOrigin - cameraPosition); //eye to target vector
    vec3 upVector = vec3(0.0, 1.0, 0.0); //up vector
    vec3 targetUpVector = normalize(cross(eyeToTarget, upVector)); // target`s right coorenderVector 
    vec3 targetRightVector = normalize(cross(targetUpVector, eyeToTarget)); // target`s up coorenderVector  
    vec3 renderVector = normalize(p.x * targetUpVector + p.y * targetRightVector + mouse.y*2.5 * eyeToTarget); //viewer`s vector
    vec3 col = render(cameraPosition, renderVector);
    
    gl_FragColor = vec4(col, 1.0);
}
Tags : #shader

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 );
}
Tags : #shader

셰이더 Shader는 무엇인가

Shader 온라인 툴들

Intro to Pixel Shaders in Three.js

Tags : #shader