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