1#version 450 2// A lot of spheres. Created by Reinder Nijhoff 2013 3// @reindernijhoff 4// 5// https://www.shadertoy.com/view/lsX3WH 6// 7 8layout(std140, set = 0, binding = 0) uniform UBO 9{ 10 mat4 MVP; 11 vec4 OutputSize; 12 vec4 OriginalSize; 13 vec4 SourceSize; 14 uint FrameCount; 15} global; 16 17#pragma stage vertex 18layout(location = 0) in vec4 Position; 19layout(location = 1) in vec2 TexCoord; 20layout(location = 0) out vec2 vTexCoord; 21const vec2 madd = vec2(0.5, 0.5); 22void main() 23{ 24 gl_Position = global.MVP * Position; 25 vTexCoord = gl_Position.xy; 26} 27 28#pragma stage fragment 29layout(location = 0) in vec2 vTexCoord; 30layout(location = 0) out vec4 FragColor; 31float iGlobalTime = float(global.FrameCount)*0.025; 32vec2 iResolution = global.OutputSize.xy; 33 34#define SHADOW 35#define REFLECTION 36 37 38#define RAYCASTSTEPS 40 39 40#define EXPOSURE 0.9 41#define EPSILON 0.0001 42#define MAXDISTANCE 400. 43#define GRIDSIZE 8. 44#define GRIDSIZESMALL 5. 45#define MAXHEIGHT 10. 46#define SPEED 0.5 47 48#define time iGlobalTime 49 50// 51// math functions 52// 53 54const mat2 mr = mat2 (0.84147, 0.54030, 55 0.54030, -0.84147 ); 56float hash( float n ) { 57 return fract(sin(n)*43758.5453); 58} 59vec2 hash2( float n ) { 60 return fract(sin(vec2(n,n+1.0))*vec2(2.1459123,3.3490423)); 61} 62vec2 hash2( vec2 n ) { 63 return fract(sin(vec2( n.x*n.y, n.x+n.y))*vec2(2.1459123,3.3490423)); 64} 65vec3 hash3( float n ) { 66 return fract(sin(vec3(n,n+1.0,n+2.0))*vec3(3.5453123,4.1459123,1.3490423)); 67} 68vec3 hash3( vec2 n ) { 69 return fract(sin(vec3(n.x, n.y, n+2.0))*vec3(3.5453123,4.1459123,1.3490423)); 70} 71// 72// intersection functions 73// 74 75bool intersectPlane(vec3 ro, vec3 rd, float height, out float dist) { 76 if (rd.y==0.0) { 77 return false; 78 } 79 80 float d = -(ro.y - height)/rd.y; 81 d = min(100000.0, d); 82 if( d > 0. ) { 83 dist = d; 84 return true; 85 } 86 return false; 87} 88 89bool intersectUnitSphere ( in vec3 ro, in vec3 rd, in vec3 sph, out float dist, out vec3 normal ) { 90 vec3 ds = ro - sph; 91 float bs = dot( rd, ds ); 92 float cs = dot( ds, ds ) - 1.0; 93 float ts = bs*bs - cs; 94 95 if( ts > 0.0 ) { 96 ts = -bs - sqrt( ts ); 97 if( ts>0. ) { 98 normal = normalize( (ro+ts*rd)-sph ); 99 dist = ts; 100 return true; 101 } 102 } 103 104 return false; 105} 106 107// 108// Scene 109// 110 111void getSphereOffset( vec2 grid, inout vec2 center ) { 112 center = (hash2( grid+vec2(43.12,1.23) ) - vec2(0.5) )*(GRIDSIZESMALL); 113} 114void getMovingSpherePosition( vec2 grid, vec2 sphereOffset, inout vec3 center ) { 115 // falling? 116 float s = 0.1+hash( grid.x*1.23114+5.342+754.324231*grid.y ); 117 float t = 14.*s + time/s; 118 119 float y = s * MAXHEIGHT * abs( cos( t ) ); 120 vec2 offset = grid + sphereOffset; 121 122 center = vec3( offset.x, y, offset.y ) + 0.5*vec3( GRIDSIZE, 2., GRIDSIZE ); 123} 124void getSpherePosition( vec2 grid, vec2 sphereOffset, inout vec3 center ) { 125 vec2 offset = grid + sphereOffset; 126 center = vec3( offset.x, 0., offset.y ) + 0.5*vec3( GRIDSIZE, 2., GRIDSIZE ); 127} 128vec3 getSphereColor( vec2 grid ) { 129 return normalize( hash3( grid+vec2(43.12*grid.y,12.23*grid.x) ) ); 130} 131 132vec3 trace(vec3 ro, vec3 rd, out vec3 intersection, out vec3 normal, out float dist, out int material) { 133 material = 0; // sky 134 dist = MAXDISTANCE; 135 float distcheck; 136 137 vec3 sphereCenter, col, normalcheck; 138 139 if( intersectPlane( ro, rd, 0., distcheck) && distcheck < MAXDISTANCE ) { 140 dist = distcheck; 141 material = 1; 142 normal = vec3( 0., 1., 0. ); 143 col = vec3( 1. ); 144 } else { 145 col = vec3( 0. ); 146 } 147 148 149 // trace grid 150 vec3 pos = floor(ro/GRIDSIZE)*GRIDSIZE; 151 vec3 ri = 1.0/rd; 152 vec3 rs = sign(rd) * GRIDSIZE; 153 vec3 dis = (pos-ro + 0.5 * GRIDSIZE + rs*0.5) * ri; 154 vec3 mm = vec3(0.0); 155 vec2 offset; 156 157 for( int i=0; i<RAYCASTSTEPS; i++ ) { 158 if( material > 1 || distance( ro.xz, pos.xz ) > dist+GRIDSIZE ) break; 159 vec2 offset; 160 getSphereOffset( pos.xz, offset ); 161 162 getMovingSpherePosition( pos.xz, -offset, sphereCenter ); 163 164 if( intersectUnitSphere( ro, rd, sphereCenter, distcheck, normalcheck ) && distcheck < dist ) { 165 dist = distcheck; 166 normal = normalcheck; 167 material = 2; 168 } 169 170 getSpherePosition( pos.xz, offset, sphereCenter ); 171 if( intersectUnitSphere( ro, rd, sphereCenter, distcheck, normalcheck ) && distcheck < dist ) { 172 dist = distcheck; 173 normal = normalcheck; 174 col = vec3( 2. ); 175 material = 3; 176 } 177 mm = step(dis.xyz, dis.zyx); 178 dis += mm * rs * ri; 179 pos += mm * rs; 180 } 181 182 vec3 color = vec3( 0. ); 183 if( material > 0 ) { 184 intersection = ro + rd*dist; 185 vec2 map = floor(intersection.xz/GRIDSIZE)*GRIDSIZE; 186 187 if( material == 1 || material == 3 ) { 188 // lightning 189 vec3 c = vec3( -GRIDSIZE,0., GRIDSIZE ); 190 for( int x=0; x<3; x++ ) { 191 for( int y=0; y<3; y++ ) { 192 vec2 mapoffset = map+vec2( c[x], c[y] ); 193 vec2 offset; 194 getSphereOffset( mapoffset, offset ); 195 vec3 lcolor = getSphereColor( mapoffset ); 196 vec3 lpos; 197 getMovingSpherePosition( mapoffset, -offset, lpos ); 198 199 float shadow = 1.; 200#ifdef SHADOW 201 if( material == 1 ) { 202 for( int sx=0; sx<3; sx++ ) { 203 for( int sy=0; sy<3; sy++ ) { 204 if( shadow < 1. ) continue; 205 206 vec2 smapoffset = map+vec2( c[sx], c[sy] ); 207 vec2 soffset; 208 getSphereOffset( smapoffset, soffset ); 209 vec3 slpos, sn; 210 getSpherePosition( smapoffset, soffset, slpos ); 211 float sd; 212 if( intersectUnitSphere( intersection, normalize( lpos - intersection ), slpos, sd, sn ) ) { 213 shadow = 0.; 214 } 215 } 216 } 217 } 218#endif 219 color += col * lcolor * ( shadow * max( dot( normalize(lpos-intersection), normal ), 0.) * 220 (1. - clamp( distance( lpos, intersection )/GRIDSIZE, 0., 1.) ) ); 221 } 222 } 223 } else { 224 // emitter 225 color = (1.5+dot(normal, vec3( 0.5, 0.5, -0.5) )) *getSphereColor( map ); 226 } 227 } 228 return color; 229} 230 231 232void mainImage( out vec4 fragColor, in vec2 fragCoord ) { 233 vec2 q = fragCoord.xy/iResolution.xy; 234 vec2 p = -1.0+2.0*q; 235 p.x *= iResolution.x/iResolution.y; 236 237 // camera 238 vec3 ce = vec3( cos( 0.232*time) * 10., 6.+3.*cos(0.3*time), GRIDSIZE*(time/SPEED) ); 239 vec3 ro = ce; 240 vec3 ta = ro + vec3( -sin( 0.232*time) * 10., -2.0+cos(0.23*time), 10.0 ); 241 242 float roll = -0.15*sin(0.5*time); 243 244 // camera tx 245 vec3 cw = normalize( ta-ro ); 246 vec3 cp = vec3( sin(roll), cos(roll),0.0 ); 247 vec3 cu = normalize( cross(cw,cp) ); 248 vec3 cv = normalize( cross(cu,cw) ); 249 vec3 rd = normalize( p.x*cu + p.y*cv + 1.5*cw ); 250 251 // raytrace 252 int material; 253 vec3 normal, intersection; 254 float dist; 255 256 vec3 col = trace(ro, rd, intersection, normal, dist, material); 257 258#ifdef REFLECTION 259 if( material > 0 ) { 260 vec3 ro = intersection + EPSILON*normal; 261 rd = reflect( rd, normal ); 262 col += 0.05 * trace(ro, rd, intersection, normal, dist, material); 263 } 264#endif 265 266 col = pow( col, vec3(EXPOSURE, EXPOSURE, EXPOSURE) ); 267 col = clamp(col, 0.0, 1.0); 268 269 // vigneting 270 col *= 0.25+0.75*pow( 16.0*q.x*q.y*(1.0-q.x)*(1.0-q.y), 0.15 ); 271 272 fragColor = vec4( col,1.0); 273} 274 275void main(void) 276{ 277 //just some shit to wrap shadertoy's stuff 278 vec2 FragmentCoord = vTexCoord.xy*global.OutputSize.xy; 279 FragmentCoord.y = -FragmentCoord.y; 280 mainImage(FragColor,FragmentCoord); 281} 282