shadertoy-shaders/path_march v4/common.frag

505 lines
16 KiB
GLSL

//////// ================================
//////// SETTINGS: Settings
//////// ================================
//
// If you don't feel like tweaking settings, try one of these presets:
//
// 0: Maximize FPS at the cost of image quality. (DEFAULT)
// 1: A balance between image quality and FPS.
// 2: Just render a pretty static image.
// 3: Demonstrate off the weird tiling render feature.
//
// The user settings below will override whatever preset you use.
//
#define PRESET 2
//
// Scenes:
//
// 1: A glossy rotating orange ball with two divets and blue floor.
// 2:
//
#define SCENE 1
//////// --------------------------------
//////// Scene settings
//////// --------------------------------
// 0: circle around the origin
// 1: portrait
// 2: profile
// 3: 3/4
//#define SCENE2_CAMERA 0
//////// --------------------------------
//////// User settings
//////// --------------------------------
//////// Tweak these according to your preferences and the power of your graphics card.
//////// Comment out a setting to restore it to its default value.
//// ********************************
//// Sample settings
//// ********************************
// The number of color samples taken per pixel. Increasing this has a dramatic effect on
// image quality, reducing graininess and preventing overly-bright pixels ("fireflies").
// However, how much GPU power you need to render a frame scales linearly with
// the number of samples.
//#define SAMPLES 1
// The maximum number of times light can reflect or scatter before it is extinguished.
//#define PATH_SEGMENTS 14
//// ********************************
//// Postprocessing settings
//// ********************************
// If a pixel color is too bright for fit in sRGB, there are two ways to handle it:
//
// 1. Clamp the pixel within the limits of sRGB, resulting in (near-)maximum
// brightness at the cost of the color's saturation. (If it's too bright, it'll
// become entirely white.)
// 2. Reduce the brightness of the color until it fits within sRGB, preserving
// the color's saturation, but losing even *more* brightness.
//
// Correction for saturation generally looks better, but isn't usually necessary
// for more than five or so samples (because the bright pixels will average out
// with the dark pixels and fall back within sRGB).
//#define SATURATION_CORRECTION 1
// The dithering looks pretty good. Honestly, at 1440p it makes even
// 3 bits per color channel look *very* convincing. As far as I'm aware
// there are no downsides to leaving it enabled. It would probably help
// reduce color banding and improve color clarity in general.
//#define ENABLE_DITHER 1
// The number of available colors *per channel*.
//define DITHER_COLORS 1<<8
// The size of the Bayer matrix is 2^DITHER_BASE, so e.g. 4 is a 16x16 matrix.
// This can't be larger than 16 because dithering is implemented using a 16-bit bit hack.
//#define DITHER_BASE 16
// Artifically restrict the colors to those specified in DITHER_COLORS.
// If you set DITHER_COLORS to 6 or so and enable DITHER_NEAREST then screenshot
// and convert the image to a GIF* using an appropriate conversion tool,
// it will look exactly the same as it looks on your screen.
// This was the motivating reason for adding dithering, and it looks amazing.
//
// * Pronounced "yif". Fite me.
//#define DITHER_NEAREST 0
//// ********************************
//// Perspective settings
//// ********************************
// This shader natively uses a square (circular?) aspect ratio. With ASPECT_RATIO_CROP
// enabled, if you use a wide aspect ratio, the frame will have its height
// cropped so that the image can take up the full width of the screen.
//#define ASPECT_RATIO_CROP 1
// This setting affects how far you zoom in on the scene.
// Greater values = more zoom. Fractional values zoom out. Negative values mirror the scene.
//#define FOV 1.5
// Camera position and angle. (Feel free to reference `time` here.)
//#define CAMERA_POS vec3(0.)
// (Don't worry, we call `normalize` for you.
//#define CAMERA_DIR vec3(0., 0., 1.)
///
/// TILE_PERSPECTIVE and CLAMP_PERSPECTIVE are only relevant if you zoom out
/// (e.g. an FOV < ~1.15). For more information on how and why these settings
/// behave the way they do, see their extended descriptions in the `project` function.
///
// Points on the screen >1 or <-1 show the portion of the scene *behind* you,
// mirrored so that the edges of each adjacent tile lines up (e.g. tiles above
// and below are mirrored vertically, to the left and right horizontally).
// This tiling is infinite. You might want to combine this with an IMAGE_OFFSET of
// (-1, 0) so that you can see two whole hemispheres instead of one whole hemisphere
// and two halves on opposite sides.
//#define TILE_PERSPECTIVE 0
// Points on the screen outside of the unit circle (within a tile) are clamped
// to the nearest point on the unit circle. This doesn't look very good, but
// might be preferable to just rendering black?
//#define CLAMP_PERSPECTIVE 0
// Slide the image around on the screen. Each time is `2x2` centered on the
// origin, so an offset of e.g. (2,0) with TILE_PERSPECTIVE enabled
// will show you the portion of the scene *behind* you.
//#define IMAGE_OFFSET vec2(0., 0.)
//// ********************************
//// Simulation settings
//// ********************************
// The maximum number of steps a ray can take during marching before giving up
// and colliding with nothing. This prevents scenes from taking infinite time to render.
//#define MAX_STEPS 200
// The maximum distance a ray can travel before we give up and just say it collides
// with nothing. This helps prevent the background from appearing warped by the foreground
// due to rays which march close to a foreground object run out of steps before
// reaching their destination when slightly farther rays do reach their target.
//#define MAX_DIST 20.
// Average the color across frames by storing them in the buffer.
// This is like supersampling, but across frames instead of within a pixel,
// which lets you render with thousands of samples without crashing.
// It's strongly advised that you enable FREEZE_TIME when this is enabled!
// This uses iFrame, so if you want to enable this, make sure you hit the
// "reset time" function or things will get screwed up.
//#define AVERAGE_FRAMES 1
// Set a time in seconds. The simulation will be frozen at this point in time every frame.
// Comment this out to allow time to pass normally.
//#define FREEZE_TIME 2.75
// Loop time over an interval of this duration, beginning at FREEZE_TIME,
// or 0, if FREEZE_TIME is not set.
//#define LOOP_TIME 0.
// Set the maximum duration of temporal antialiasing (i.e. how much time
// motion blur smears across). Note that this is a *maximum* time, and motion
// blur will never be greater than the duration of a frame. That said, when rendering
// a still image with FREEZE_TIME you probably want this set to 0., and if you're
// stuttering a lot, the large variance in frame times can make objects in the image
// appear to jerk back and forth, so this probably shouldn't be any higher
// than (the reciprocal of) your average framerate. Comment this out to
// remove any cap on the amount of motion blur.
//#define MAX_TAA_DIFF (1./30.)
//////// --------------------------------
//////// Internal settings
//////// --------------------------------
//////// If you're just viewing the shader, you shouldn't usually need to tweak these.
// The minimum distance between two points before they are considered the same point.
// Setting lower values increases the sharpness of the image at the cost of performance
// and rounding errors at objects very far from 0.
//
// Ray marching halves the distance to the surface of an object each iteration, but the
// end goal of ray marching is to pass slightly *inside* the object. Setting a minimum
// distance prevents zeno's paradox. This also serves as a optimization
// because the number of steps increases logarithmically as you decrease the minimum distance.
//
// Chosen to be 2^(-9), or about ~2mm, because that's the largest you can set it before
// the quality of the image is significantly effected. You can set it as low as about
// 2^(-19) before things begin to break. It's good to experiment with both high and low
// values to help find bugs in the numerical precision of the light simulation.
// If you have precision bugs, the simulation ends up getting affected pretty dramatically
// by changes to MIN_DIST, whereas a numerically stable simulation is not affected much at all.
//
// I expect that a minimum distance of 2^(-9) would work until about 10km from the origin
// with 32-bit floating point before starting to break down, but I have not tested it.
//#define MIN_DIST (0.001953125)
// The distance between samples when estimating a surface's normal. Smaller values result
// in more precise calculations, but are more sensitive to numerical imprecision.
// This should probably be less than MIN_DIST.
//#define NORMAL_DELTA (MIN_DIST/4.)
// Only march this much of MIN_DIST at a time to account for imprecision in the distance
// calculations. Chosen by experimentation. If you have to set this low, that often means
// that there's a bug somewhere (e.g. you forgot to call `normalize`).
//
// Right now, the simulation is numerically stable and I don't have to use it at all!
// But I often find that it's necessary to set this to around ~0.92 when debugging
// numerical issues.
//#define IMPRECISION_FACTOR 1.
//////// --------------------------------
//////// Default settings & presets
//////// --------------------------------
//////// So you can restore a setting to its default value by commenting it out.
#ifndef PRESET
#define PRESET 0
#endif
#ifndef SCENE
#define SCENE 2
#endif
//// ********************************
//// Scene 2
//// ********************************
#if SCENE == 2
#ifndef SCENE2_CAMERA
#define SCENE2_CAMERA 1
#endif
#ifndef FOV
#define FOV 1.2
#endif
#if SCENE2_CAMERA == 1
#ifndef CAMERA_POS
#define CAMERA_POS vec3(0., -0.1, -0.5)
#endif
#ifndef CAMERA_DIR
#define CAMERA_DIR vec3(0., 0., 1.)
#endif
#elif SCENE2_CAMERA == 2
#ifndef CAMERA_POS
#define CAMERA_POS vec3(0.5, -0.1, 0.0)
#endif
#ifndef CAMERA_DIR
#define CAMERA_DIR vec3(-1.0, 0.0, 0.0)
#endif
#elif SCENE2_CAMERA == 3
#ifndef CAMERA_POS
#define CAMERA_POS vec3(-sqrt(0.5/4.), -0.1, -sqrt(0.5/4.))
#endif
#ifndef CAMERA_DIR
#define CAMERA_DIR vec3(sqrt(0.5), 0., sqrt(0.5))
#endif
#else
#ifndef CAMERA_POS
#define CAMERA_POS vec3(sin(-time)*0.5, -0.1, cos(-time)*0.5)
#endif
#ifndef CAMERA_DIR
#define CAMERA_DIR vec3(-sin(-time), 0., -cos(-time))
#endif
#endif
#endif
//// ********************************
//// Preset 1
//// ********************************
#if PRESET == 1
#ifndef SAMPLES
#define SAMPLES 6
#endif
#ifndef PATH_SEGMENTS
#define PATH_SEGMENTS 16
#endif
#ifndef MAX_TAA_DIFF
#define MAX_TAA_DIFF (1./30.)
#endif
//// ********************************
//// Preset 2
//// ********************************
#elif PRESET == 2
#ifndef PATH_SEGMENTS
#define PATH_SEGMENTS 10
#endif
#ifndef MAX_STEPS
#define MAX_STEPS 300
#endif
#ifndef MAX_DIST
#define MAX_DIST 50.
#endif
#ifndef MIN_DIST
#define MIN_DIST (0.001953125/128.)
#endif
#ifndef MAX_TAA_DIFF
#define MAX_TAA_DIFF 0.
#endif
#ifndef AVERAGE_FRAMES
#define AVERAGE_FRAMES 1
#endif
#ifndef FREEZE_TIME
#if SCENE == 1
#define FREEZE_TIME 2.75
#elif SCENE == 2
#define FREEZE_TIME 2.3
#else
#define FREEZE_TIME 0.
#endif
#endif
//// ********************************
//// Preset 3
//// ********************************
#elif PRESET == 3
#ifndef FOV
#define FOV 0.5
#endif
#ifndef TILE_PERSPECTIVE
#define TILE_PERSPECTIVE 1
#endif
#ifndef CLAMP_PERSPECTIVE
#define CLAMP_PERSPECTIVE 1
#endif
#ifndef IMAGE_OFFSET
#define IMAGE_OFFSET vec2(0., 0.)
#endif
#endif
//// ********************************
//// Preset 0 (defaults)
//// ********************************
#ifndef SAMPLES
#define SAMPLES 1
#endif
#ifndef PATH_SEGMENTS
#define PATH_SEGMENTS 10
#endif
#ifndef SATURATION_CORRECTION
#define SATURATION_CORRECTION 1
#endif
#ifndef ENABLE_DITHER
#define ENABLE_DITHER 1
#endif
#ifndef DITHER_BASE
#define DITHER_BASE 16
#endif
#ifndef DITHER_COLORS
#define DITHER_COLORS (1<<8)
#endif
#ifndef DITHER_NEAREST
#define DITHER_NEAREST 0
#endif
#ifndef FOV
#define FOV 1.5
#endif
#ifndef CAMERA_POS
#define CAMERA_POS vec3(0.)
#endif
#ifndef CAMERA_DIR
#define CAMERA_DIR vec3(0., 0., 1.)
#endif
#ifndef ASPECT_RATIO_CROP
#define ASPECT_RATIO_CROP 1
#endif
#ifndef TILE_PERSPECTIVE
#define TILE_PERSPECTIVE 0
#endif
#ifndef CLAMP_PERSPECTIVE
#define CLAMP_PERSPECTIVE 0
#endif
#ifndef IMAGE_OFFSET
#define IMAGE_OFFSET vec2(0., 0.)
#endif
#ifndef MAX_STEPS
#define MAX_STEPS 200
#endif
#ifndef MAX_DIST
#define MAX_DIST 20.
#endif
#ifndef AVERAGE_FRAMES
#define AVERAGE_FRAMES 0
#endif
// FREEZE_TIME, LOOP_TIME, and MAX_TAA_DIFF are *undefined* by default.
#ifndef MIN_DIST
#define MIN_DIST (0.001953125/8.)
#endif
#ifndef NORMAL_DELTA
#define NORMAL_DELTA (MIN_DIST/4.)
#endif
#ifndef IMPRECISION_FACTOR
#define IMPRECISION_FACTOR 1.
#endif
//////// ================================
//////// DOCS: Declarations & documentation
//////// ================================
/// Convert a color from linear RGB to the sRGB color space.
vec3 linear2srgb(vec3 color);
/// Convert a color from RGB (Red/Green/Blue) to HSV (Hue/Saturation/Value).
vec3 rgb2hsv(vec3 rgb);
/// Convert a color from HSV (Hue/Saturation/Value) to RGB (Red/Green/Blue).
vec3 hsv2rgb(vec3 hsv);
/// Return a random number between 0 and 1 (with uniform distribution);
float rand();
/// Use the fragment coordinate and current frame to seed the random number generator.
void seed_randoms(vec3 seed);
// Convenience definitions
#define INF (1./0.)
// NOTE: I used to use `sqrt(-1)`, but apparently that doesn't evaluate to NaN????
// This makes me wonder if NaN isn't portable due to constant folding or something.
#define NAN (0./0.)
//////// ================================
//////// VENDOR: Vendored code
//////// ================================
////
//// AUTHOR: unknown
////
vec3 linear2srgb(vec3 linear_rgb) {
// I believe the first version is technically more accurate,
// but the difference is usually negligable in practice.
#if 1
// copied from somewhere on the internet
bvec3 cutoff = lessThan(linear_rgb, vec3(0.0031308));
vec3 higher = vec3(1.055)*pow(linear_rgb, vec3(1.0/2.4)) - vec3(0.055);
vec3 lower = linear_rgb * vec3(12.92);
return mix(higher, lower, cutoff);
// end copied from somewhere on the internet
#else
return pow(linear_rgb, vec3(1./2.2));
#endif
}
////
//// AUTHOR: Sam Hocevar (http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl)
////
vec3 rgb2hsv(vec3 c) {
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
vec3 hsv2rgb(vec3 c) {
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
////
//// AUTHOR: iq
////
// Randoms (https://www.shadertoy.com/view/4sfGzS))
// oldschool rand() from Visual Studio
int _seed = 1;
int irand(void) { _seed = _seed*0x343fd+0x269ec3; return (_seed>>16)&32767; }
float rand(void) { return float(irand())/32767.0; }
// hash to initialize the random sequence (copied from Hugo Elias)
int hash( int n )
{
n = (n << 13) ^ n;
return n * (n * n * 15731 + 789221) + 1376312589;
}
void seed_randoms(vec3 s) {
ivec3 q = ivec3(s);
_seed = hash(q.x+hash(q.y+hash(q.z)));
}