1// Compatibility #ifdefs needed for parameters
2#ifdef GL_ES
3#define COMPAT_PRECISION mediump
4#else
5#define COMPAT_PRECISION
6#endif
7
8// Parameter lines go here:
9#pragma parameter RETRO_PIXEL_SIZE "Retro Pixel Size" 0.84 0.0 1.0 0.01
10#ifdef PARAMETER_UNIFORM
11// All parameter floats need to have COMPAT_PRECISION in front of them
12uniform COMPAT_PRECISION float RETRO_PIXEL_SIZE;
13#else
14#define RETRO_PIXEL_SIZE 0.84
15#endif
16
17#if defined(VERTEX)
18
19#if __VERSION__ >= 130
20#define COMPAT_VARYING out
21#define COMPAT_ATTRIBUTE in
22#define COMPAT_TEXTURE texture
23#else
24#define COMPAT_VARYING varying
25#define COMPAT_ATTRIBUTE attribute
26#define COMPAT_TEXTURE texture2D
27#endif
28
29#ifdef GL_ES
30#define COMPAT_PRECISION mediump
31#else
32#define COMPAT_PRECISION
33#endif
34
35COMPAT_ATTRIBUTE vec4 VertexCoord;
36COMPAT_ATTRIBUTE vec4 COLOR;
37COMPAT_ATTRIBUTE vec4 TexCoord;
38COMPAT_VARYING vec4 COL0;
39COMPAT_VARYING vec4 TEX0;
40// out variables go here as COMPAT_VARYING whatever
41
42vec4 _oPosition1;
43uniform mat4 MVPMatrix;
44uniform COMPAT_PRECISION int FrameDirection;
45uniform COMPAT_PRECISION int FrameCount;
46uniform COMPAT_PRECISION vec2 OutputSize;
47uniform COMPAT_PRECISION vec2 TextureSize;
48uniform COMPAT_PRECISION vec2 InputSize;
49
50// compatibility #defines
51#define vTexCoord TEX0.xy
52#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
53#define OutSize vec4(OutputSize, 1.0 / OutputSize)
54
55void main()
56{
57    gl_Position = MVPMatrix * VertexCoord;
58    TEX0.xy = VertexCoord.xy;
59// Paste vertex contents here:
60}
61
62#elif defined(FRAGMENT)
63
64#if __VERSION__ >= 130
65#define COMPAT_VARYING in
66#define COMPAT_TEXTURE texture
67out vec4 FragColor;
68#else
69#define COMPAT_VARYING varying
70#define FragColor gl_FragColor
71#define COMPAT_TEXTURE texture2D
72#endif
73
74#ifdef GL_ES
75#ifdef GL_FRAGMENT_PRECISION_HIGH
76precision highp float;
77#else
78precision mediump float;
79#endif
80#define COMPAT_PRECISION mediump
81#else
82#define COMPAT_PRECISION
83#endif
84
85uniform COMPAT_PRECISION int FrameDirection;
86uniform COMPAT_PRECISION int FrameCount;
87uniform COMPAT_PRECISION vec2 OutputSize;
88uniform COMPAT_PRECISION vec2 TextureSize;
89uniform COMPAT_PRECISION vec2 InputSize;
90uniform sampler2D Texture;
91COMPAT_VARYING vec4 TEX0;
92// in variables go here as COMPAT_VARYING whatever
93
94// compatibility #defines
95#define Source Texture
96#define vTexCoord TEX0.xy
97
98#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
99#define OutSize vec4(OutputSize, 1.0 / OutputSize)
100
101// delete all 'params.' or 'registers.' or whatever in the fragment
102float iGlobalTime = float(FrameCount)*0.025;
103vec2 iResolution = OutputSize.xy;
104
105/*
106	Raymarched Reflections
107	----------------------
108
109	A very basic demonstration of raymarching a distance field with reflections
110	and reasonably passable shadows. Definitely not cutting edge, but hopefully,
111	interesting to anyone who isn't quite familiar with the process.
112
113	Reflections are pretty easy: Raymarch to the hit point, then obtain the color
114	at that point. Continue on from the hit point in the direction of the reflected
115	ray until you reach a new hit point. Obtain the color at the new point, then
116	add a portion of it to your original color. Repeat the process.
117
118	Unfortunately, the extra work can slow things down, especially when you apply
119	shadows, which is probably why you don't see too many shadowed,	reflected
120	examples. However, for relatively simple distance fields, it's pretty doable.
121
122	It was tempting to do this up, but I figured a simpler example would be more
123	helpful. Take away the rambling comments, and there isn't a great deal of code.
124	I'll post a more sophisticated one later.
125
126    // Reasonably simple examples featuring reflection:
127
128    To the road of ribbon - XT95
129    https://www.shadertoy.com/view/MsfGzr
130
131    704.2 - PauloFalcao
132    https://www.shadertoy.com/view/Xdj3Dt
133
134    // Reflections and refraction. Really cool.
135    Glass Polyhedron - Nrx
136    https://www.shadertoy.com/view/4slSzj
137
138*/
139
140#define FAR 30.
141
142// Distance function. This one is pretty simple. I chose rounded
143// spherical boxes, because they're cheap and they display the
144// reflections reasonably well.
145float map(vec3 p)
146{
147
148    // Positioning the rounded cubes a little off center, in order
149    // to break up the space a little.
150    //
151    // "floor(p)" represents a unique number (ID) for each cube
152    // (based on its unique position). Take that number and produce
153    // a randomized 3D offset, then add it to it's regular position.
154    // Simple.
155    float n = sin(dot(floor(p), vec3(7, 157, 113)));
156    vec3 rnd = fract(vec3(2097152, 262144, 32768)*n)*.16-.08;
157
158    // Repeat factor. If irregularity isn't your thing, you can get
159    // rid of "rnd" to line things up again.
160    p = fract(p + rnd) - .5;
161
162
163    // Rounded spherical boxes. The following is made up, but kind of
164    // makes sense. Box, minus a bit of sphericalness, gives you a
165    // rounded box.
166    p = abs(p);
167    return max(p.x, max(p.y, p.z)) - 0.25 + dot(p, p)*0.5;
168
169    //return length(p) - 0.225; // Just spheres.
170}
171
172// Standard raymarching routine.
173float trace(vec3 ro, vec3 rd){
174
175    float t = 0., d;
176
177    for (int i = 0; i < 96; i++){
178
179        d = map(ro + rd*t);
180
181        if(abs(d)<.002 || t>FAR) break; // Normally just "d<.0025"
182
183        t += d*.75;  // Using more accuracy, in the first pass.
184    }
185
186    return t;
187}
188
189// Second pass, which is the first, and only, reflected bounce.
190// Virtually the same as above, but with fewer iterations and less
191// accuracy.
192//
193// The reason for a second, virtually identical equation is that
194// raymarching is usually a pretty expensive exercise, so since the
195// reflected ray doesn't require as much detail, you can relax things
196// a bit - in the hope of speeding things up a little.
197float traceRef(vec3 ro, vec3 rd){
198
199    float t = 0., d;
200
201    for (int i = 0; i < 48; i++){
202
203        d = map(ro + rd*t);
204
205        if(abs(d)<.0025 || t>FAR) break;
206
207        t += d;
208    }
209
210    return t;
211}
212
213
214// Cheap shadows are hard. In fact, I'd almost say, shadowing repeat objects - in a setting like this - with limited
215// iterations is impossible... However, I'd be very grateful if someone could prove me wrong. :)
216float softShadow(vec3 ro, vec3 lp, float k){
217
218    // More would be nicer. More is always nicer, but not really affordable... Not on my slow test machine, anyway.
219    const int maxIterationsShad = 24;
220
221    vec3 rd = (lp-ro); // Unnormalized direction ray.
222
223    float shade = 1.;
224    float dist = .005;
225    float end = max(length(rd), 0.001);
226    float stepDist = end/float(maxIterationsShad);
227
228    rd /= end;
229
230    // Max shadow iterations - More iterations make nicer shadows, but slow things down. Obviously, the lowest
231    // number to give a decent shadow is the best one to choose.
232    for (int i=0; i<maxIterationsShad; i++){
233
234        float h = map(ro + rd*dist);
235        //shade = min(shade, k*h/dist);
236        shade = min(shade, smoothstep(0.0, 1.0, k*h/dist)); // Subtle difference. Thanks to IQ for this tidbit.
237        // So many options here, and none are perfect: dist += min(h, .2), dist += clamp(h, .01, .2),
238        // clamp(h, .02, stepDist*2.), etc.
239        dist += clamp(h, .02, .2);
240
241        // Early exits from accumulative distance function calls tend to be a good thing.
242        if (h<0.0 || dist > end) break;
243        //if (h<0.001 || dist > end) break; // If you're prepared to put up with more artifacts.
244    }
245
246    // I've added 0.5 to the final shade value, which lightens the shadow a bit. It's a preference thing.
247    // Really dark shadows look too brutal to me.
248    return min(max(shade, 0.) + 0.25, 1.0);
249}
250
251/*
252// Standard normal function. It's not as fast as the tetrahedral calculation, but more symmetrical. Due to
253// the intricacies of this particular scene, it's kind of needed to reduce jagged effects.
254vec3 getNormal(in vec3 p) {
255	const vec2 e = vec2(0.002, 0);
256	return normalize(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)));
257}
258*/
259
260// Tetrahedral normal, to save a couple of "map" calls. Courtesy of IQ.
261vec3 getNormal( in vec3 p ){
262
263    // Note the slightly increased sampling distance, to alleviate
264    // artifacts due to hit point inaccuracies.
265    vec2 e = vec2(0.0035, -0.0035);
266    return normalize(
267        e.xyy * map(p + e.xyy) +
268        e.yyx * map(p + e.yyx) +
269        e.yxy * map(p + e.yxy) +
270        e.xxx * map(p + e.xxx));
271}
272
273// Alternating the cube colors in a 3D checkered arrangement.
274// You could just return a single color, if you wanted, but I
275// thought I'd mix things up a bit.
276//
277// Color scheme mildly influenced by: Sound Experiment 3 - aiekick
278// https://www.shadertoy.com/view/Ml2XWt
279vec3 getObjectColor(vec3 p){
280
281    vec3 col = vec3(1);
282
283    // "floor(p)" is analogous to a unique ID - based on position.
284    // This could be stepped, but it's more intuitive this way.
285    if(fract(dot(floor(p), vec3(.5))) > 0.001) col = vec3(0.6, 0.3, 1.0);
286
287    return col;
288
289}
290
291// Using the hit point, unit direction ray, etc, to color the
292// scene. Diffuse, specular, falloff, etc. It's all pretty
293// standard stuff.
294vec3 doColor(in vec3 sp, in vec3 rd, in vec3 sn, in vec3 lp){
295
296    vec3 ld = lp-sp; // Light direction vector.
297    float lDist = max(length(ld), 0.001); // Light to surface distance.
298    ld /= lDist; // Normalizing the light vector.
299
300    // Attenuating the light, based on distance.
301    float atten = 1. / (1.0 + lDist*0.2 + lDist*lDist*0.1);
302
303    // Standard diffuse term.
304    float diff = max(dot(sn, ld), 0.);
305    // Standard specualr term.
306    float spec = pow(max( dot( reflect(-ld, sn), -rd ), 0.0 ), 8.0);
307
308    // Coloring the object. You could set it to a single color, to
309    // make things simpler, if you wanted.
310    vec3 objCol = getObjectColor(sp);
311
312    // Combining the above terms to produce the final scene color.
313    vec3 sceneCol = (objCol*(diff + 0.15) + vec3(1., .6, .2)*spec*2.) * atten;
314
315
316    // Return the color. Performed once every pass... of which there are
317    // only two, in this particular instance.
318    return sceneCol;
319
320}
321
322void mainImage( out vec4 fragColor, in vec2 fragCoord ){
323
324    // Screen coordinates.
325	vec2 uv = (fragCoord.xy - iResolution.xy*.5) / iResolution.y;
326
327    // Unit direction ray.
328    vec3 rd = normalize(vec3(uv, 1.0));
329
330
331    // Some cheap camera movement, for a bit of a look around. I use this far
332    // too often. I'm even beginning to bore myself, at this point. :)
333    float cs = cos(iGlobalTime * 0.25), si = sin(iGlobalTime * 0.25);
334    rd.xy = mat2(cs, si, -si, cs)*rd.xy;
335    rd.xz = mat2(cs, si, -si, cs)*rd.xz;
336
337    // Ray origin. Doubling as the surface position, in this particular example.
338    // I hope that doesn't confuse anyone.
339    vec3 ro = vec3(0., 0., iGlobalTime*1.5);
340
341    // Light position. Set in the vicinity the ray origin.
342    vec3 lp = ro + vec3(0., 1., -.5);
343
344
345    // FIRST PASS.
346
347    float t = trace(ro, rd);
348
349    // Fog based off of distance from the camera.
350    float fog = smoothstep(0., .95, t/FAR);
351
352    // Advancing the ray origin, "ro," to the new hit point.
353    ro += rd*t;
354
355    // Retrieving the normal at the hit point.
356    vec3 sn = getNormal(ro);
357
358    // Retrieving the color at the hit point, which is now "ro." I agree, reusing
359    // the ray origin to describe the surface hit point is kind of confusing. The reason
360    // we do it is because the reflective ray will begin from the hit point in the
361    // direction of the reflected ray. Thus the new ray origin will be the hit point.
362    // See "traceRef" below.
363    vec3 sceneColor = doColor(ro, rd, sn, lp);
364
365    // Checking to see if the surface is in shadow. Ideally, you'd also check to
366    // see if the reflected surface is in shadow. However, shadows are expensive, so
367    // it's only performed on the first pass. If you pause and check the reflections,
368    // you'll see that they're not shadowed. OMG! - Better call the shadow police. :)
369    float sh = softShadow(ro, lp, 16.);
370
371
372    // SECOND PASS - REFLECTED RAY
373
374    // Standard reflected ray, which is just a reflection of the unit
375    // direction ray off of the intersected surface. You use the normal
376    // at the surface point to do that. Hopefully, it's common sense.
377    rd = reflect(rd, sn);
378
379
380    // The reflected pass begins where the first ray ended, which is the suface
381    // hit point, or in a few cases, beyond the far plane. By the way, for the sake
382    // of simplicity, we'll perform a reflective pass for non hit points too. Kind
383    // of wasteful, but not really noticeable. The direction of the new ray will
384    // obviously be in the direction of the reflected ray. See just above.
385    //
386    // To anyone who's new to this, don't forgot to nudge the ray off of the
387    // initial surface point. Otherwise, you'll intersect with the surface
388    // you've just hit. After years of doing this, I still forget on occasion.
389    t = traceRef(ro +  rd*.01, rd);
390
391    // Advancing the ray origin, "ro," to the new reflected hit point.
392    ro += rd*t;
393
394    // Retrieving the normal at the reflected hit point.
395    sn = getNormal(ro);
396
397    // Coloring the reflected hit point, then adding a portion of it to the final scene color.
398    // How much you add is up to you, but I'm going with 35 percent.
399    sceneColor += doColor(ro, rd, sn, lp)*.35;
400
401
402    // APPLYING SHADOWS
403    //
404    // Multiply the shadow from the first pass by the final scene color. Ideally, you'd check to
405    // see if the reflected point was in shadow, and incorporate that too, but we're cheating to
406    // save cycles and skipping it. It's not really noticeable anyway. By the way, ambient
407    // occlusion would make it a little nicer, but we're saving cycles and keeping things simple.
408    sceneColor *= sh;
409
410    // Technically, it should be applied on the reflection pass too, but it's not that
411    // noticeable, in this case.
412    sceneColor = mix(sceneColor, vec3(0), fog);
413
414
415
416
417    // Clamping the scene color, performing some rough gamma correction (the "sqrt" bit), then
418    // presenting it to the screen.
419	fragColor = vec4(sqrt(clamp(sceneColor, 0.0, 1.0)), 1.0);
420}
421
422 void main(void)
423{
424  //just some shit to wrap shadertoy's stuff
425  vec2 FragCoord = vTexCoord.xy*OutputSize.xy;
426  mainImage(FragColor,FragCoord);
427}
428#endif
429