1#version 130 2// Compatibility #ifdefs needed for parameters 3#ifdef GL_ES 4#define COMPAT_PRECISION mediump 5#else 6#define COMPAT_PRECISION 7#endif 8 9// Parameter lines go here: 10#pragma parameter RETRO_PIXEL_SIZE "Retro Pixel Size" 0.84 0.0 1.0 0.01 11#ifdef PARAMETER_UNIFORM 12// All parameter floats need to have COMPAT_PRECISION in front of them 13uniform COMPAT_PRECISION float RETRO_PIXEL_SIZE; 14#else 15#define RETRO_PIXEL_SIZE 0.84 16#endif 17 18#if defined(VERTEX) 19 20#if __VERSION__ >= 130 21#define COMPAT_VARYING out 22#define COMPAT_ATTRIBUTE in 23#define COMPAT_TEXTURE texture 24#else 25#define COMPAT_VARYING varying 26#define COMPAT_ATTRIBUTE attribute 27#define COMPAT_TEXTURE texture2D 28#endif 29 30#ifdef GL_ES 31#define COMPAT_PRECISION mediump 32#else 33#define COMPAT_PRECISION 34#endif 35 36COMPAT_ATTRIBUTE vec4 VertexCoord; 37COMPAT_ATTRIBUTE vec4 COLOR; 38COMPAT_ATTRIBUTE vec4 TexCoord; 39COMPAT_VARYING vec4 COL0; 40COMPAT_VARYING vec4 TEX0; 41// out variables go here as COMPAT_VARYING whatever 42 43vec4 _oPosition1; 44uniform mat4 MVPMatrix; 45uniform COMPAT_PRECISION int FrameDirection; 46uniform COMPAT_PRECISION int FrameCount; 47uniform COMPAT_PRECISION vec2 OutputSize; 48uniform COMPAT_PRECISION vec2 TextureSize; 49uniform COMPAT_PRECISION vec2 InputSize; 50 51// compatibility #defines 52#define vTexCoord TEX0.xy 53#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize 54#define OutSize vec4(OutputSize, 1.0 / OutputSize) 55 56void main() 57{ 58 gl_Position = MVPMatrix * VertexCoord; 59 TEX0.xy = VertexCoord.xy; 60// Paste vertex contents here: 61} 62 63#elif defined(FRAGMENT) 64 65#if __VERSION__ >= 130 66#define COMPAT_VARYING in 67#define COMPAT_TEXTURE texture 68out vec4 FragColor; 69#else 70#define COMPAT_VARYING varying 71#define FragColor gl_FragColor 72#define COMPAT_TEXTURE texture2D 73#endif 74 75#ifdef GL_ES 76#ifdef GL_FRAGMENT_PRECISION_HIGH 77precision highp float; 78#else 79precision mediump float; 80#endif 81#define COMPAT_PRECISION mediump 82#else 83#define COMPAT_PRECISION 84#endif 85 86uniform COMPAT_PRECISION int FrameDirection; 87uniform COMPAT_PRECISION int FrameCount; 88uniform COMPAT_PRECISION vec2 OutputSize; 89uniform COMPAT_PRECISION vec2 TextureSize; 90uniform COMPAT_PRECISION vec2 InputSize; 91uniform sampler2D Texture; 92uniform sampler2D iChannel0; 93uniform sampler2D iChannel1; 94vec2 iChannelResolution = vec2(64.0, 64.0); 95COMPAT_VARYING vec4 TEX0; 96// in variables go here as COMPAT_VARYING whatever 97 98// compatibility #defines 99#define Source Texture 100#define vTexCoord TEX0.xy 101 102#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize 103#define OutSize vec4(OutputSize, 1.0 / OutputSize) 104 105// delete all 'params.' or 'registers.' or whatever in the fragment 106float iGlobalTime = float(FrameCount)*0.025; 107vec2 iResolution = OutputSize.xy; 108 109#define PI 3.14159 110 111#define VOXEL_NONE 0 112#define VOXEL_WATER 1 113#define VOXEL_SAND 2 114#define VOXEL_EARTH 3 115#define VOXEL_STONE 4 116#define VOXEL_GRASS 5 117 118// from https://www.shadertoy.com/view/4sfGzS 119float noise( in vec3 x ) 120{ 121 vec3 p = floor(x); 122 vec3 f = fract(x); 123 f = f*f*(3.0-2.0*f); 124 125 vec2 uv = p.xy + f.xy; 126 vec2 rg = vec2(texture( iChannel0, (uv+vec2(37.0,17.0)*p.z+0.5)/256.0, -100.0 ).x, 127 texture( iChannel0, (uv+vec2(37.0,17.0)*(p.z+1.0)+0.5)/256.0, -100.0 ).x ); 128 return mix( rg.x, rg.y, f.z ); 129} 130 131int getVoxelAndFogAt(ivec3 ip, out float fogStrength) 132{ 133 float cloudiness = noise(vec3(ip)/8.0); 134 fogStrength = smoothstep(0.6, 0.7, cloudiness)*0.3 + 0.1; 135 136 if (ip.y <= 0) return VOXEL_WATER; 137 138 // so this is like, grabbing the texture as a heightmap and 139 // then like twisting it in random directions as it goes up 140 // umm... 141 vec3 p = vec3(vec3(ip) + 0.5); 142 float theta = noise(p / 16.0) * PI * 2.0; 143 vec2 disp = vec2(cos(theta), sin(theta)) * p.y; 144 vec3 terr = texture(iChannel1, (p.xz + disp) / 128.0).rgb; 145 146 bvec3 contains = lessThanEqual(vec3(0.0), (terr - p.y/16.0)); 147 if (contains.x && contains.y && !contains.z) return VOXEL_SAND; 148 if (contains.x && contains.z) return VOXEL_GRASS; 149 if (contains.y && contains.z && !contains.x) return VOXEL_STONE; 150 if (contains.x || contains.y || contains.z) return VOXEL_EARTH; 151 152 return VOXEL_NONE; 153} 154 155float dfVoxel(vec3 p, int voxelType) 156{ 157 float r = 0.1; 158 if (voxelType == VOXEL_WATER) r = 0.0; 159 return length(max(abs(p)-vec3(0.5-r),0.0))-r; 160} 161 162vec3 nrmVoxel(vec3 p, int voxelType) 163{ 164 vec2 dd = vec2(0.001,0.0); 165 float base = dfVoxel(p, voxelType); 166 return normalize(vec3( 167 dfVoxel(p+dd.xyy, voxelType) - base, 168 dfVoxel(p+dd.yxy, voxelType) - base, 169 dfVoxel(p+dd.yyx, voxelType) - base 170 )); 171} 172 173void voxelMarch(vec3 ro, vec3 rd, out ivec3 hitVoxels[4], out float fogAccums[5], out int hitCount) 174{ 175 hitCount = 0; 176 177 ivec3 mapPos = ivec3(floor(ro)); 178 vec3 deltaDist = abs(vec3(length(rd)) / rd); 179 ivec3 rayStep = ivec3(sign(rd)); 180 vec3 sideDist = (sign(rd) * (vec3(mapPos) - ro) + (sign(rd) * 0.5) + 0.5) * deltaDist; 181 bvec3 mask; 182 float fogAccum = 0.0; 183 float prevDist = 0.0; 184 185 for (int i = 0; i < 96; i++) { 186 187 // check current position for voxel 188 float fogStrength; 189 if (getVoxelAndFogAt(mapPos, fogStrength) != VOXEL_NONE) { 190 // no non-const indexing? :< 191 if (hitCount == 0) { hitVoxels[0] = mapPos; fogAccums[0] = fogAccum; } 192 else if (hitCount == 1) { hitVoxels[1] = mapPos; fogAccums[1] = fogAccum; } 193 else if (hitCount == 2) { hitVoxels[2] = mapPos; fogAccums[2] = fogAccum; } 194 else if (hitCount == 3) { hitVoxels[3] = mapPos; fogAccums[3] = fogAccum; } 195 hitCount++; 196 if (hitCount == 4) return; 197 } 198 199 // march forward to next position by discrete digital analyzer 200 float newDist = min( sideDist.x, min(sideDist.y, sideDist.z )); 201 vec3 mi = step( sideDist.xyz, sideDist.yzx ); 202 vec3 mm = mi*(1.0-mi.zxy); 203 sideDist += mm * vec3(rayStep) / rd; 204 mapPos += ivec3(mm)*rayStep; 205 206 fogAccum += fogStrength * (newDist - prevDist); 207 prevDist = newDist; 208 } 209 210 // did not intersect. 211 fogAccums[4] = fogAccum; 212} 213 214void resolveHitVoxels( 215 vec3 ro, vec3 rd, ivec3 hitVoxels[4], float fogAccums[5], int hitCount, 216 out ivec3 hitVoxel, out vec3 hit, out int terrainType, out float fogAccum) 217{ 218 for (int i=0; i<4; i++) { 219 if (i == hitCount) { 220 terrainType = VOXEL_NONE; 221 fogAccum = fogAccums[4]; 222 return; // less than four hits, none intersected 223 } 224 225 hitVoxel = hitVoxels[i]; float tmp; 226 terrainType = getVoxelAndFogAt(hitVoxel, tmp); 227 fogAccum = fogAccums[i]; 228 vec3 hitVoxelCenter = vec3(hitVoxel) + 0.5; 229 230 // intersect with voxel cube 231 vec3 cubeIntersect = (hitVoxelCenter - ro - 0.5*sign(rd))/rd; 232 float d = max(cubeIntersect.x, max(cubeIntersect.y, cubeIntersect.z)); 233 234 // fallback in case of four no distance intersection 235 hit = ro + rd * (d - 0.01) - hitVoxelCenter; 236 237 // attempt better intersect with distance marching 238 float diff; 239 vec3 p = ro + rd * d; 240 for (int j=0; j<4; j++) { 241 diff = dfVoxel(p - hitVoxelCenter, terrainType); 242 d += diff; 243 p = ro + rd * d; 244 } 245 if (diff < 0.05) { // good enough distance marched intersection 246 hit = p - hitVoxelCenter; 247 return; 248 } 249 } 250 // four hits, none intersected. Use the intersection with the cube to pretend we hit the last one. 251} 252 253vec3 doColoring(vec3 hit, int terrainType, vec3 hitGlobal, vec3 ldir) 254{ 255 vec3 n = nrmVoxel(hit, terrainType); 256 float diffuse = max(dot(-ldir, n), 0.1); 257 258 float f1 = noise(hitGlobal*19.0); 259 float f2 = noise(hitGlobal*33.0); 260 float f3 = noise(hitGlobal*71.0); 261 262 // render 263 vec3 color = vec3(0.0); 264 if (terrainType == VOXEL_WATER) { 265 color = vec3(0.4, 0.4, 0.8) * (0.8 + f1*0.1 + f2*0.05 + f3*0.05); 266 } else if (terrainType == VOXEL_EARTH) { 267 color = vec3(1.0, 0.7, 0.3) * (f1*0.33 + f2*0.33 + f3*0.33); 268 } else if (terrainType == VOXEL_SAND) { 269 color = vec3(1.0, 1.0, 0.6) * (f1*0.1 + f2*0.1 + f3*0.5 + 0.3); 270 } else if (terrainType == VOXEL_STONE) { 271 color = vec3(0.5) * (f1*0.3 + f2*0.1 + 0.6); 272 } else if (terrainType == VOXEL_GRASS) { 273 color = vec3(0.3, 0.7, 0.4) * (f1*0.2 + f3*0.5 + 0.3); 274 } 275 276 color *= diffuse; 277 278 return color; 279} 280 281void mainImage( out vec4 fragColor, in vec2 fragCoord ) 282{ 283 // camera stolen from Shane :) https://www.shadertoy.com/view/ll2SRy 284 vec2 uv = (fragCoord - iResolution.xy*.5 )/iResolution.y; 285 vec3 rd = normalize(vec3(uv, (1.-dot(uv, uv)*.5)*.5)); 286 vec3 ro = vec3(0., 10., iGlobalTime*10.0); 287 float t = sin(iGlobalTime * 0.2) + noise(ro/32.0); 288 ro.y += 4.0*t; 289 float cs = cos( t ), si = sin( t ); 290 rd.yz = mat2(cs, si,-si, cs)*rd.yz; 291 rd.xz = mat2(cs, si,-si, cs)*rd.xz; 292 293 // voxel march into the scene storing up to four intersections 294 int hitCount; 295 ivec3 hitVoxels[4]; 296 float fogAccums[5]; 297 voxelMarch(ro, rd, hitVoxels, fogAccums, hitCount); 298 299 // resolve to one accurate intersection by distance marching 300 int terrainType = VOXEL_NONE; 301 ivec3 hitVoxel; 302 vec3 hit; 303 float fogAccum; 304 resolveHitVoxels(ro, rd, hitVoxels, fogAccums, hitCount, hitVoxel, hit, terrainType, fogAccum); 305 306 vec3 hitGlobal = vec3(hitVoxel) + hit; 307 float dist = length(hitGlobal - ro); 308 309 // color 310 vec3 color; 311 if (terrainType == VOXEL_NONE) // sky 312 { 313 color = vec3 (0.5, 0.5, 0.6); 314 dist = 1000.0; 315 } else { 316 vec3 ldir = normalize(hitGlobal - ro); 317 color = doColoring(hit, terrainType, hitGlobal, ldir); 318 } 319 320 // fog 321 float fog = smoothstep(0.0, 10.0, fogAccum); 322 color = mix(color, vec3(0.6), fog); 323 324 fragColor = vec4(color,1.0); 325} 326 327 void main(void) 328{ 329 //just some shit to wrap shadertoy's stuff 330 vec2 FragCoord = vTexCoord.xy*OutputSize.xy; 331 mainImage(FragColor,FragCoord); 332} 333#endif 334