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