Skip to content

Instantly share code, notes, and snippets.

@cabbibo
Created March 21, 2017 06:48
Show Gist options
  • Save cabbibo/31c536498f35116c42e66808ea5f0cca to your computer and use it in GitHub Desktop.
Save cabbibo/31c536498f35116c42e66808ea5f0cca to your computer and use it in GitHub Desktop.
// Trying to understand the code from
// http://lgdv.cs.fau.de/get/2234
const float t_min = .00001;
const float t_max = 35.;
const int MAX_ITERATIONS = 200;
const float infinite = 100000.;
const float PI = 3.14159;
const float MAX_TRACE_DISTANCE = 40.0; // max trace distance
const float INTERSECTION_PRECISION = 0.001; // precision of the intersection
const int NUM_OF_TRACE_STEPS = 1000;
const bool forceHit = false;
float pixelRadius;
float cycleTime;
vec4 grow = vec4( 1. );
vec3 lightPos = vec3( 0. , 6. , 0.);
#define time iGlobalTime
vec3 hsv(float h, float s, float v){
return mix( vec3( 1.0 ), clamp( ( abs( fract(
h + vec3( 3.0, 2.0, 1.0 ) / 3.0 ) * 6.0 - 3.0 ) - 1.0 ), 0.0, 1.0 ), s ) * v;
}
//----
// Camera Stuffs
//----
mat3 calcLookAtMatrix( in vec3 ro, in vec3 ta, in float roll ){
vec3 ww = normalize( ta - ro );
vec3 uu = normalize( cross(ww,vec3(sin(roll),cos(roll),0.0) ) );
vec3 vv = normalize( cross(uu,ww));
return mat3( uu, vv, ww );
}
void doCamera( float radius , out vec3 camPos, out vec3 camTar, in float time, in vec2 mouse ){
float an = 0.3 + 10.0*mouse.x;
camPos = vec3(radius*sin(an),2.,radius*cos(an));
camTar = vec3(0.0,1.0,0.0);
}
float hash( float n ) { return fract(sin(n)*753.5453123); }
float noise( in vec3 x ){
vec3 p = floor(x);
vec3 f = fract(x);
f = f*f*(3.0-2.0*f);
float n = p.x + p.y*157.0 + 113.0*p.z;
return mix(mix(mix( hash(n+ 0.0), hash(n+ 1.0),f.x),
mix( hash(n+157.0), hash(n+158.0),f.x),f.y),
mix(mix( hash(n+113.0), hash(n+114.0),f.x),
mix( hash(n+270.0), hash(n+271.0),f.x),f.y),f.z);
}
float fNoise( vec3 p ){
float n;
n += noise( p * 20. ) * .5;
n += noise( p * 200. ) * .1;
n += noise( p * 60. ) * .3;
n += noise( p * 5. );
n /= 2.;
return n;
}
// ROTATION FUNCTIONS TAKEN FROM
//https://www.shadertoy.com/view/XsSSzG
vec3 xrotate(vec3 pos , float t) {
return mat3(1.0, 0.0, 0.0,
0.0, cos(t), -sin(t),
0.0, sin(t), cos(t)) * pos;
}
vec3 yrotate(vec3 pos , float t) {
return mat3(cos(t), 0.0, -sin(t),
0.0, 1.0, 0.0,
sin(t), 0.0, cos(t)) * pos;
}
vec3 zrotate(vec3 pos , float t) {
return mat3(cos(t), -sin(t), 0.0,
sin(t), cos(t), 0.0,
0.0, 0.0, 1.0) * pos;
}
float sdPlane( vec3 p, vec4 n ){
// n must be normalized
return dot(p,n.xyz) + n.w;
}
float sdCone( vec3 p, vec2 c ){
// c must be normalized
float q = length(p.xy);
return dot(c,vec2(q,p.z));
}
float sdCappedCone( in vec3 p, in vec3 c ){
vec2 q = vec2( length(p.xz), p.y );
vec2 v = vec2( c.z*c.y/c.x, -c.z );
vec2 w = v - q;
vec2 vv = vec2( dot(v,v), v.x*v.x );
vec2 qv = vec2( dot(v,w), v.x*w.x );
vec2 d = max(qv,0.0)*qv/vv;
return sqrt( dot(w,w) - max(d.x,d.y) )* sign(max(q.y*v.x-q.x*v.y,w.y));
}
float sdHexPrism( vec3 p, vec2 h ){
vec3 q = abs(p);
return max(q.z-h.y,max((q.x*0.866025+q.y*0.5),q.y)-h.x);
}
float sdSphere( vec3 p, float s ){
return length(p)-s;
}
float sdCappedCylinder( vec3 p, vec2 h ){
vec2 d = abs(vec2(length(p.xz),p.y)) - h;
return min(max(d.x,d.y),0.0) + length(max(d,0.0));
}
float opS( float d1, float d2 ){
return max(-d1,d2);
}
vec2 opS( vec2 d1, vec2 d2 ){
return -d1.x > d2.x ? vec2(-d1.x , d1.y) : d2 ;
}
float opU( float d1, float d2 ){
return d1 < d2 ? d1 : d2 ;
}
vec2 opU( vec2 d1, vec2 d2 ){
return d1.x < d2.x ? d1 : d2 ;
}
vec2 smoothU( vec2 d1, vec2 d2, float k){
float a = d1.x;
float b = d2.x;
float h = clamp(0.5+0.5*(b-a)/k, 0.0, 1.0);
return vec2( mix(b, a, h) - k*h*(1.0-h), mix(d2.y, d1.y, pow(h, 2.0)));
}
float opRepSphere( vec3 p, vec3 c , float r){
vec3 q = mod(p,c)-0.5*c;
return sdSphere( q , r );
}
float cBase( vec3 pos ){
float c = sdCone( pos , normalize(vec2( 1. , 1. )));
float s = sdPlane( pos , vec4( 0 , 0. , 1. , 1.4 ) );
return opS( s , c );
}
// give a base ID to pass out of
// first build the fields
// than connnect to ID numbers, using by passing through baseID
// write out baseID for later use.
vec2 body( vec3 pos , out float baseID ){
float c = sdSphere( pos* vec3( 1. , .55 , 1. ) , 1. );
float p = sdPlane( pos * vec3( 1. , .5 , 1. ), vec4( -1. , 0. , 0. , 0. ) );
//baseID += 1.;
vec2 torso = opS( vec2( p , baseID + 1. ) , vec2( c , baseID + 1. ) );
//float cb = sdCappedCone( pos - vec3( 1. ) , normalize(vec3( 1. , 1. , 1. )));
vec3 q = xrotate( pos - vec3( -.2 , -.8 , 0. ) , -PI / 2. );
float cb = cBase( q );
vec2 cloakBase = vec2( cb , baseID + 0. );
// head
float n = 0.;// abs( noise( pos * 10.1 + time * .5 ));
vec2 h = vec2( sdSphere( pos - vec3( 0.2 , 1.2 , 0. ) , .45 - n * .05 ) , baseID + 7. );
vec2 bod = smoothU( cloakBase, torso ,.9);
// float n2 = abs( noise( pos * 3. + time * .5 ));
//bod.x -= n2 * .06;
vec2 fullBod = smoothU( bod , h , .3 );
float b1 = sdSphere( pos - vec3( 0.3 , 1.2 , 0.1 ) , .32);
float b2 = sdSphere( pos - vec3( 0.3 , 1.2 , -0.1 ) , .32);
float balls= opU( b1, b2 );
vec2 eyes = vec2( balls , baseID + 8.);
return opS( eyes ,smoothU( bod , h , .3 ));
//return vec2( c , 1. );
}
vec3 mapP( vec3 p )
{
p.xyz += .400*sin( 3.*p.yzx )*grow.x;
p.xyz += 0.300*sin( 6.0*p.yzx )*grow.y;
p.xyz += 0.250*sin( 8.0*p.yzx )*grow.z;
p.xyz += 0.100*sin( 20.0*p.yzx )*grow.w;
return p;
}
//--------------------------------
// Modelling
//--------------------------------
vec2 map( vec3 pos , float io){
float id = 0.;
vec2 res = vec2( 100000. , -1.);
vec3 p2 = pos;// - vec3( -4. , 0., 0.);
//pos.x = mod( pos.x , 1.5 );
float degree = atan( p2.x , p2.z );
float ogD = degree;
///degree += iGlobalTime;// * (1. + lor * .2);
float l = length( p2.xz );
degree = mod( degree - 3.14159 / 8. , 3.14159 / 4. );
p2.x = l * sin( degree );
p2.z = l * cos( degree );
//bodys
res = body( yrotate( p2 - vec3(3. , 0., 6.) ,-PI/2.) , id );
float n = noise( pos + vec3( 0. , iGlobalTime , 0.) ) + noise( pos * 2. + vec3( 0. , iGlobalTime * 1.4 , 0.) ) ;
// Shrine
res = smoothU( res , vec2( sdPlane( pos , vec4( 0., 1. , 0. , 2.)) , id + 3. ) , 1. );
res = smoothU( res , vec2( -sdSphere( pos - vec3( 0. , -16. , 0.) , 23. ) , id + 4.) ,1.);
//light
res = smoothU( res , vec2( (sdSphere( pos - lightPos , 3. ) + n * .8) , id+5.) , 2.5);
// res = smoothU( res , vec2( (sdSphere( pos - lightPos - vec3( 0. , 1.5 , 0.) , 1. )) , id+5.) , .0);
// Pedestal
vec3 q = xrotate( pos - vec3( 0 , -1.2, 0.) , -PI / 2. );
res = smoothU( res , vec2( sdHexPrism(q , vec2( .5 , 1. ) ) , id + 5.) ,.6);
//JEWEL
q = mapP( pos + vec3( 0. , -1. , 0.) );
//res = opU( res , vec2( (length(q)-(.4 + .6 * -cycleTime) ) * .1, id + 7.) );
res = opU( res , vec2( (length(q)-.4) * .1, id + 7.) );
vec2 eyes = vec2( length(pos + vec3( 0. , -1. , 0.))-(.3 + .15 * -cycleTime) , id + 8. );
eyes.x += noise( pos * 20.) * .04;
res = opS( eyes ,res);
eyes = vec2( length(pos + vec3( 0. , -1. , 0.))-(.2 + .1 * -cycleTime) , id + 6. );
eyes.x += noise( pos * 20.) * .04;
res = opU( eyes ,res);
//res = opS(vec2(sdSphere( pos - vec3( 0. , -1. , 0.) , 1.3 ), id + 7. ), res );
// Inside trace function
if( io < 0. ){
res = vec2( -(sdSphere( pos - lightPos , 3. ) - n * .8) * .1 , id+5.);
}
return res;
}
vec2 calcIntersection( in vec3 ro, in vec3 rd , float io ){
float h = INTERSECTION_PRECISION*2.0;
float t = 0.0;
float res = -1.0;
float id = -1.;
for( int i=0; i< NUM_OF_TRACE_STEPS ; i++ ){
if( h < INTERSECTION_PRECISION || t > MAX_TRACE_DISTANCE ) break;
vec2 m = map( ro+rd*t , io );
h = m.x;
t += h;
id = m.y;
}
if( t < MAX_TRACE_DISTANCE ) res = t;
if( t > MAX_TRACE_DISTANCE ) id =-1.0;
return vec2( res , id );
}
//From
//http://lgdv.cs.fau.de/get/2234
vec2 calcIntersection( vec3 ro , vec3 rd , float io , float TAKEMEEOUT){
// o, d : ray origin, direction (normalized)
// t_min, t_max: minimum, maximum
// pixelRadius: radius of a pixel
// forceHit: boolean enforcing to
// candidate_t value as result
float omega = 1.2;
float t = t_min;
float candidate_error = infinite;
float candidate_t = t_min;
float previousRadius = 0.;
float stepLength = 0.;
float id = -10.;
// are we inside or outside the object?
// if inside reverse the field!
float functionSign = map(ro, io).x < 0. ? -1. : 1.;
// functionSign = 1.;
for (int i = 0; i < MAX_ITERATIONS; i++ ) {
vec2 mapVal = map(rd*t + ro,io);
id = mapVal.y;
float signedRadius = functionSign * mapVal.x;
float radius = abs(signedRadius);
bool sorFail = omega > 1. && (radius + previousRadius) < stepLength;
if (sorFail) {
stepLength -= omega * stepLength;
omega = 1.;
} else {
stepLength = signedRadius * omega;
}
previousRadius = radius;
float error = radius / t;
if (!sorFail && error < candidate_error) {
candidate_t = t;
candidate_error = error;
}
if (!sorFail && error < pixelRadius || t > t_max) break;
t += stepLength;
}
if ((t > t_max || abs(candidate_error) > pixelRadius) && !forceHit){
// return vec2( infinite , -1. );
}
return vec2( candidate_t , id );
}
// Calculates the normal by taking a very small distance,
// remapping the function, and getting normal for that
vec3 calcNormal( in vec3 pos , float io ){
vec3 eps = vec3( 0.001, 0.0, 0.0 );
vec3 nor = vec3(
map(pos+eps.xyy,io).x - map(pos-eps.xyy,io).x,
map(pos+eps.yxy,io).x - map(pos-eps.yxy,io).x,
map(pos+eps.yyx,io).x - map(pos-eps.yyx,io).x );
return normalize(nor);
}
vec3 doMonkCol( vec3 rd , vec3 p , vec3 n , float match, vec2 res){
vec3 color;
float fN = (noise( p * 20. ) * .6 + noise( p * 2. ) * .3 + noise( p * .5) + noise( p * .1) + noise( p * 5. ));
vec3 nNorm = n +.3 * normalize(vec3( noise( p * 20. ) , noise( p * 25. ), noise( p * 19. )));
vec3 refl = reflect( rd , nNorm );
vec3 cubeCol = texture( iChannel2 ,refl ).xyz;
vec3 buildingCol = cubeCol * vec3( 1. , .6 , .4 ) * 2.;//vec3( match ) * fN * fN *fN * .1 * ;
color = mix(cubeCol * vec3( 0.6 , .6 , 1. ) * 2.,buildingCol, p.y * 2. );
float eyeM = dot( rd , n );
vec3 lightDir = p - vec3( 0.,1. ,0.);
vec3 refl2 = reflect( normalize( lightDir ) , normalize(nNorm) );
float rMatch = dot( refl2, rd );
color += 2. * vec3( .5 , .2 , .1 ) * max( 0. , pow(rMatch,15.));
color += pow( rMatch , 40. ) * vec3( 1. , .1 , .2 );
vec4 tCol = texture( iChannel0 , vec2( -rMatch,0. ) );
color *= (tCol.x+.2);
//color += (1.-tCol.x* 2.) * vec3( .3 , .5 , 1. );
float v = pow((1.+eyeM),5.);
color += vec3(1. , .2 , 0.) * v;
if( res.y == 2. ){
color = vec3( 1. , 0., 0.);
}else if( res.y == 3. ){
//color = n * .5 + .5;
}
return color;// * (n * .5 + .5);
}
vec3 doSecondColor(vec2 res, vec3 rd , vec3 p , vec3 n ){
vec3 color;
vec3 lightDir = normalize(p - lightPos);
float match = dot( -lightDir , n );
// MONKS
if( res.y < 2.4 ){
color = doMonkCol( rd, p , n , match, res );
}
//Building
if( res.y >= 2.4 && res.y < 6. ){
color = vec3(match);
float fN = (noise( p * 20. ) * .6 + noise( p * 2. ) * .3 + noise( p * .5) + noise( p * .1) + noise( p * 5. ));
vec3 refl = reflect( rd , n );
vec3 cubeCol = texture( iChannel2 ,refl ).xyz;
vec3 buildingCol = cubeCol * vec3( 0.2 , .4 , 1. ) * 2.;
buildingCol = match * match * fN * fN * vec3( 1. , .4 , .2 );//vec3( match ) * fN * fN *fN * .1 * ;
color = buildingCol;
}
return color;
}
vec3 doLightCol( vec3 rd , vec3 p , vec3 n ){
vec3 refr = refract( rd , n , .9 );
vec2 res = calcIntersection( p + refr * .1 , refr , -1.);
if( res.y > -.5 ){
vec3 p2 = p + refr * ( res.x + .1);
vec3 n2 = calcNormal( p2 , -1. );
if( res.y < 5.){
return vec3( 1. );
}
vec3 refr2 = refract( refr , n2 , .9 );
vec2 res2 = calcIntersection( p2 + refr2 * .1 , refr2, 1.);
if( res2.y >-.5){
vec3 p3 = p2 + refr2 * ( res2.x + .1 );
vec3 n3 = calcNormal( p3 , 1. );
return doSecondColor( res2 , refr2,p3,n3);
}else{
return vec3( 1. , 0. , 0.);
}
}else{
return vec3( 1. ,0., 0.);
}
}
vec3 doColor(vec2 res, vec3 rd , vec3 p , vec3 n , float skip){
vec3 color;
vec3 lightDir = normalize(p - lightPos);
float match = dot( -lightDir , n );
// MONKS
if( res.y < 2.4 ){
color = doMonkCol( rd, p , n , match, res );
}
//Building
if( res.y >= 2.4 && res.y < 6. ){
color = vec3(match);
float fN = noise( p * 2. ) * .4 + noise( p * .5) + noise( p * .1) ;
// vec3 buildingCol = vec3(1. - fN * fN * .03 , .5 , .4) * vec3( match ) * fN * fN *fN * .1;
n = normalize( n + .3 * vec3( noise( p * 2. + iGlobalTime) , noise( p * 2. + 100. + iGlobalTime) ,noise( p * 2. + 400.+ iGlobalTime )));
vec3 refl = reflect( rd , n );
vec3 cubeCol = texture( iChannel2 ,refl ).xyz;
vec3 buildingCol = cubeCol * vec3( 0.2 , .4 , 1. ) * 2.;//vec3( match ) * fN * fN *fN * .1 * ;
if( skip == 0. ){
vec3 lightCol = doLightCol( rd, p , n );
float mixVal = clamp( (res.y - 4.4) * 5. , 0. , 1.);
if( p.y < 1. ){ mixVal = 0.; }
color = mix( buildingCol , lightCol , mixVal );
}else{
color = buildingCol;
}
vec3 monkCol = doMonkCol( rd, p , n , match, res );
color = mix( monkCol, color , clamp((res.y - 2.4) *.6 , 0., 1.) );
}
//Pedestal
if( res.y >= 6. && res.y < 7. ){
float fN = noise( p * 2. ) * .4 + noise( p * .5) + noise( p * .1) ;
color = vec3(1. - fN * fN * .03 , .5 , .4) * fN * fN *fN * .1;
//n = normalize( n + .3 * vec3( noise( p * 20. + iGlobalTime) , noise( p * 20. + 100. + iGlobalTime) ,noise( p * 20. + 400.+ iGlobalTime )));
vec3 refl = reflect( rd , n );
vec3 cubeCol = texture( iChannel2 ,refl ).xyz;
color = (cubeCol * dot( -n , rd )) + texture( iChannel2 ,refract(rd, n,.8)).xyz;
color *= vec3( 1. , .8 , .3 );
}
if( res.y >= 7. && res.y < 8. ){
//float fN = (noise( p * 20. ) * .6 + noise( p * 2. ) * .3 + noise( p * .5) + noise( p * .1) + noise( p * 5. ));
//vec3 buildingCol = vec3(1. - fN * fN * .03 , .5 , .4) * vec3( match ) * fN * fN *fN * .1;
vec3 nNorm = n;// n +.3 * normalize(vec3( hash( p.x * 100. ) , hash(p.y * 20. ), hash( p.z * 100.)));
vec3 refl = reflect( lightDir , normalize(nNorm) );
float m = dot( refl , -rd );
vec3 refr = refract(rd , n,.4 );
vec3 cubeMap = texture( iChannel2 , refl ).xyz;
float refrMatch = dot( lightDir , refr );
vec3 aCol = texture( iChannel0 , vec2( abs( match )* .2, 0. )).xyz;
//
//pow( m , 21. ) *
color =cubeMap * hsv( aCol.x * .2 , 1. , 1.);// + max( pow(m , 11. ) ,0.) * vec3( 1. , .5 , 0.) + match * vec3( .6 , .3 , .2 ) ;
}
if( res.y >= 8. ){
vec3 refl = reflect( lightDir , normalize(n) );
vec3 cubeMap = texture( iChannel2 , refl ).xyz;
color = cubeMap * vec3( 1.4 , .2 , 1. ) * 2.;
}
return color;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord ){
vec2 p = (-iResolution.xy + 2.0*fragCoord.xy)/iResolution.y;
vec2 m = iMouse.xy/iResolution.xy;
vec3 ro = vec3( 0., 0., 10.);
vec3 ta = vec3( 0. , 0. , 0. );
cycleTime = sin( iGlobalTime * .6 );
grow.x = .1 * (1. - cycleTime);
grow.y = .6 * (1. - cycleTime);
grow.z = .4 * (1. - cycleTime);
grow.w = .6 * (1. - cycleTime);
vec2 mPos = vec2( iGlobalTime * .03 , 0.);
doCamera( ( cycleTime + 1.3) * 6. , ro , ta , time , mPos );
// camera matrix
mat3 camMat = calcLookAtMatrix( ro, ta, 0.0 ); // 0.0 is the camera roll
// create view ray
vec3 rd = normalize( camMat * vec3(p.xy,2.0) ); // 2.0 is the lens length
float pixel = .5 / iResolution.y;
vec3 rdu = normalize( camMat * vec3(p.xy + vec2(pixel, 0.) ,2.0) );
vec3 rdd = normalize( camMat * vec3(p.xy - vec2(pixel, 0.),2.0) );
vec3 pu = ro + rdu;
vec3 pd = ro + rdd;
// Can probably alter this for a speed up too
pixelRadius = length( pu - pd ) / 1.;
vec2 res = calcIntersection( ro , rd , 1.);
vec3 color = vec3( 1. );
if( res.y > -.5 ){
vec3 pos = ro + rd * res.x;
vec3 n = calcNormal( pos , 1.);
color = doColor( res , rd , pos , n , 0. );
float moreCenter = clamp( 1.0 - (length(pos - vec3( 0. , 1. , 0.)) * (.5 + .5 * -cycleTime)) * .2 , 0. , 1.);
color *= moreCenter;
}
fragColor = vec4(color,1.0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment