diff --git a/lib/linguist/languages.yml b/lib/linguist/languages.yml index 87db679f..74094e7f 100755 --- a/lib/linguist/languages.yml +++ b/lib/linguist/languages.yml @@ -4014,6 +4014,13 @@ Self: tm_scope: none ace_mode: text language_id: 345 +ShaderLab: + type: programming + extensions: + - ".shader" + ace_mode: text + tm_scope: source.shaderlab + language_id: 664257356 Shell: type: programming color: "#89e051" diff --git a/samples/GLSL/SyLens.shader b/samples/GLSL/SyLens.shader new file mode 100644 index 00000000..7e9ec456 --- /dev/null +++ b/samples/GLSL/SyLens.shader @@ -0,0 +1,161 @@ +#version 120 + +/* + Original Lens Distortion Algorithm from SSontech (Syntheyes) + http://www.ssontech.com/content/lensalg.htm + + r2 is radius squared. + + r2 = image_aspect*image_aspect*u*u + v*v + f = 1 + r2*(k + kcube*sqrt(r2)) + u' = f*u + v' = f*v + +*/ + +// Controls +uniform float kCoeff, kCube, uShift, vShift; +uniform float chroma_red, chroma_green, chroma_blue; +uniform bool apply_disto; + +// Uniform inputs +uniform sampler2D input1; +uniform float adsk_input1_w, adsk_input1_h, adsk_input1_aspect, adsk_input1_frameratio; +uniform float adsk_result_w, adsk_result_h; + +float distortion_f(float r) { + float f = 1 + (r*r)*(kCoeff + kCube * r); + return f; +} + + +float inverse_f(float r) +{ + + // Build a lookup table on the radius, as a fixed-size table. + // We will use a vec3 since we will store the multipled number in the Z coordinate. + // So to recap: x will be the radius, y will be the f(x) distortion, and Z will be x * y; + vec3[48] lut; + + // Since out LUT is shader-global check if it's been computed alrite + // Flame has no overflow bbox so we can safely max out at the image edge, plus some cushion + float max_r = sqrt((adsk_input1_frameratio * adsk_input1_frameratio) + 1) + 0.1; + float incr = max_r / 48; + float lut_r = 0; + float f; + for(int i=0; i < 48; i++) { + f = distortion_f(lut_r); + lut[i] = vec3(lut_r, f, lut_r * f); + lut_r += incr; + } + + float t; + // Now find the nehgbouring elements + // only iterate to 46 since we will need + // 47 as i+1 + for(int i=0; i < 47; i++) { + if(lut[i].z < r && lut[i+1].z > r) { + // BAM! our value is between these two segments + // get the T interpolant and mix + t = (r - lut[i].z) / (lut[i+1].z - lut[i]).z; + return mix(lut[i].y, lut[i+1].y, t ); + } + } +} + +float aberrate(float f, float chroma) +{ + return f + (f * chroma); +} + +vec3 chromaticize_and_invert(float f) +{ + vec3 rgb_f = vec3(aberrate(f, chroma_red), aberrate(f, chroma_green), aberrate(f, chroma_blue)); + // We need to DIVIDE by F when we redistort, and x / y == x * (1 / y) + if(apply_disto) { + rgb_f = 1 / rgb_f; + } + return rgb_f; +} + +void main(void) +{ + vec2 px, uv; + float f = 1; + float r = 1; + + px = gl_FragCoord.xy; + + // Make sure we are still centered + px.x -= (adsk_result_w - adsk_input1_w) / 2; + px.y -= (adsk_result_h - adsk_input1_h) / 2; + + // Push the destination coordinates into the [0..1] range + uv.x = px.x / adsk_input1_w; + uv.y = px.y / adsk_input1_h; + + + // And to Syntheyes UV which are [1..-1] on both X and Y + uv.x = (uv.x *2 ) - 1; + uv.y = (uv.y *2 ) - 1; + + // Add UV shifts + uv.x += uShift; + uv.y += vShift; + + // Make the X value the aspect value, so that the X coordinates go to [-aspect..aspect] + uv.x = uv.x * adsk_input1_frameratio; + + // Compute the radius + r = sqrt(uv.x*uv.x + uv.y*uv.y); + + // If we are redistorting, account for the oversize plate in the input, assume that + // the input aspect is the same + if(apply_disto) { + r = r / (float(adsk_input1_w) / float(adsk_result_w)); + } + + // Apply or remove disto, per channel honoring chromatic aberration + if(apply_disto) { + f = inverse_f(r); + } else { + f = distortion_f(r); + } + + vec2[3] rgb_uvs = vec2[](uv, uv, uv); + + // Compute distortions per component + vec3 rgb_f = chromaticize_and_invert(f); + + // Apply the disto coefficients, per component + rgb_uvs[0] = rgb_uvs[0] * rgb_f.rr; + rgb_uvs[1] = rgb_uvs[1] * rgb_f.gg; + rgb_uvs[2] = rgb_uvs[2] * rgb_f.bb; + + // Convert all the UVs back to the texture space, per color component + for(int i=0; i < 3; i++) { + uv = rgb_uvs[i]; + + // Back from [-aspect..aspect] to [-1..1] + uv.x = uv.x / adsk_input1_frameratio; + + // Remove UV shifts + uv.x -= uShift; + uv.y -= vShift; + + // Back to OGL UV + uv.x = (uv.x + 1) / 2; + uv.y = (uv.y + 1) / 2; + + rgb_uvs[i] = uv; + } + + // Sample the input plate, per component + vec4 sampled; + sampled.r = texture2D(input1, rgb_uvs[0]).r; + sampled.g = texture2D(input1, rgb_uvs[1]).g; + sampled.b = texture2D(input1, rgb_uvs[2]).b; + + // and assign to the output + gl_FragColor.rgba = vec4(sampled.rgb, 1.0 ); +} \ No newline at end of file diff --git a/samples/GLSL/islandScene.shader b/samples/GLSL/islandScene.shader new file mode 100644 index 00000000..f417b220 --- /dev/null +++ b/samples/GLSL/islandScene.shader @@ -0,0 +1,630 @@ +//// High quality (Some browsers may freeze or crash) +//#define HIGHQUALITY + +//// Medium quality (Should be fine on all systems, works on Intel HD2000 on Win7 but quite slow) +//#define MEDIUMQUALITY + +//// Defaults +//#define REFLECTIONS +#define SHADOWS +//#define GRASS +//#define SMALL_WAVES +#define RAGGED_LEAVES +//#define DETAILED_NOISE +//#define LIGHT_AA // 2 sample SSAA +//#define HEAVY_AA // 2x2 RG SSAA +//#define TONEMAP + +//// Configurations +#ifdef MEDIUMQUALITY + #define SHADOWS + #define SMALL_WAVES + #define RAGGED_LEAVES + #define TONEMAP +#endif + +#ifdef HIGHQUALITY + #define REFLECTIONS + #define SHADOWS + //#define GRASS + #define SMALL_WAVES + #define RAGGED_LEAVES + #define DETAILED_NOISE + #define LIGHT_AA + #define TONEMAP +#endif + +// Constants +const float eps = 1e-5; +const float PI = 3.14159265359; + +const vec3 sunDir = vec3(0.79057,-0.47434, 0.0); +const vec3 skyCol = vec3(0.3, 0.5, 0.8); +const vec3 sandCol = vec3(0.9, 0.8, 0.5); +const vec3 treeCol = vec3(0.8, 0.65, 0.3); +const vec3 grassCol = vec3(0.4, 0.5, 0.18); +const vec3 leavesCol = vec3(0.3, 0.6, 0.2); +const vec3 leavesPos = vec3(-5.1,13.4, 0.0); + +#ifdef TONEMAP +const vec3 sunCol = vec3(1.8, 1.7, 1.6); +#else +const vec3 sunCol = vec3(0.9, 0.85, 0.8); +#endif + +const float exposure = 1.1; // Only used when tonemapping + +// Description : Array and textureless GLSL 2D/3D/4D simplex +// noise functions. +// Author : Ian McEwan, Ashima Arts. +// License : Copyright (C) 2011 Ashima Arts. All rights reserved. +// Distributed under the MIT License. See LICENSE file. +// https://github.com/ashima/webgl-noise +vec3 mod289(vec3 x) { + return x - floor(x * (1.0 / 289.0)) * 289.0; +} + +vec4 mod289(vec4 x) { + return x - floor(x * (1.0 / 289.0)) * 289.0; +} + +vec4 permute(vec4 x) { + return mod289(((x*34.0)+1.0)*x); +} + +vec4 taylorInvSqrt(vec4 r) { + return 1.79284291400159 - 0.85373472095314 * r; +} + +float snoise(vec3 v) { + const vec2 C = vec2(1.0/6.0, 1.0/3.0) ; + const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); + +// First corner + vec3 i = floor(v + dot(v, C.yyy) ); + vec3 x0 = v - i + dot(i, C.xxx) ; + +// Other corners + vec3 g = step(x0.yzx, x0.xyz); + vec3 l = 1.0 - g; + vec3 i1 = min( g.xyz, l.zxy ); + vec3 i2 = max( g.xyz, l.zxy ); + + // x0 = x0 - 0.0 + 0.0 * C.xxx; + // x1 = x0 - i1 + 1.0 * C.xxx; + // x2 = x0 - i2 + 2.0 * C.xxx; + // x3 = x0 - 1.0 + 3.0 * C.xxx; + vec3 x1 = x0 - i1 + C.xxx; + vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y + vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y + +// Permutations + i = mod289(i); + vec4 p = permute( permute( permute( + i.z + vec4(0.0, i1.z, i2.z, 1.0 )) + + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) + + i.x + vec4(0.0, i1.x, i2.x, 1.0 )); + +// Gradients: 7x7 points over a square, mapped onto an octahedron. +// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) + float n_ = 0.142857142857; // 1.0/7.0 + vec3 ns = n_ * D.wyz - D.xzx; + + vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7) + + vec4 x_ = floor(j * ns.z); + vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N) + + vec4 x = x_ *ns.x + ns.yyyy; + vec4 y = y_ *ns.x + ns.yyyy; + vec4 h = 1.0 - abs(x) - abs(y); + + vec4 b0 = vec4( x.xy, y.xy ); + vec4 b1 = vec4( x.zw, y.zw ); + + //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; + //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; + vec4 s0 = floor(b0)*2.0 + 1.0; + vec4 s1 = floor(b1)*2.0 + 1.0; + vec4 sh = -step(h, vec4(0.0)); + + vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ; + vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ; + + vec3 p0 = vec3(a0.xy,h.x); + vec3 p1 = vec3(a0.zw,h.y); + vec3 p2 = vec3(a1.xy,h.z); + vec3 p3 = vec3(a1.zw,h.w); + +//Normalise gradients + vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); + p0 *= norm.x; + p1 *= norm.y; + p2 *= norm.z; + p3 *= norm.w; + +// Mix final noise value + vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); + m = m * m; + return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1), + dot(p2,x2), dot(p3,x3) ) ); +} + + + +// Main +float fbm(vec3 p) +{ + float final = snoise(p); + p *= 1.94; final += snoise(p) * 0.5; + #ifdef DETAILED_NOISE + p *= 3.75; final += snoise(p) * 0.25; + return final / 1.75; + #else + return final / 1.5; + #endif +} + +float waterHeight(vec3 p) +{ + float d = length(p.xz); + float h = sin(d * 1.5 + iGlobalTime * 3.0) * 12.0 / d; // Island waves + #ifdef SMALL_WAVES + h += fbm(p*0.5); // Other waves + #endif + return h; +} + +vec3 bump(vec3 pos, vec3 rayDir) +{ + float s = 2.0; + + // Fade out waves to reduce aliasing + float dist = dot(pos, rayDir); + s *= dist < 2.0 ? 1.0 : 1.4142 / sqrt(dist); + + // Calculate normal from heightmap + vec2 e = vec2(1e-2, 0.0); + vec3 p = vec3(pos.x, iGlobalTime*0.5, pos.z)*0.7; + float m = waterHeight(p)*s; + return normalize(vec3( + waterHeight(p+e.xyy)*s-m, + 1.0, + waterHeight(p+e.yxy)*s-m + )); +} + +// Ray intersections +vec4 intersectSphere(vec3 rpos, vec3 rdir, vec3 pos, float rad) +{ + vec3 op = pos - rpos; + float b = dot(op, rdir); + float det = b*b - dot(op, op) + rad*rad; + + if (det > 0.0) + { + det = sqrt(det); + float t = b - det; + if (t > eps) + return vec4(-normalize(rpos+rdir*t-pos), t); + } + + return vec4(0.0); +} + +vec4 intersectCylinder(vec3 rpos, vec3 rdir, vec3 pos, float rad) +{ + vec3 op = pos - rpos; + vec2 rdir2 = normalize(rdir.yz); + float b = dot(op.yz, rdir2); + float det = b*b - dot(op.yz, op.yz) + rad*rad; + + if (det > 0.0) + { + det = sqrt(det); + float t = b - det; + if (t > eps) + return vec4(-normalize(rpos.yz+rdir2*t-pos.yz), 0.0, t); + t = b + det; + if (t > eps) + return vec4(-normalize(rpos.yz+rdir2*t-pos.yz), 0.0, t); + } + + return vec4(0.0); +} + +vec4 intersectPlane(vec3 rayPos, vec3 rayDir, vec3 n, float d) +{ + float t = -(dot(rayPos, n) + d) / dot(rayDir, n); + return vec4(n * sign(dot(rayDir, n)), t); +} + +// Helper functions +vec3 rotate(vec3 p, float theta) +{ + float c = cos(theta), s = sin(theta); + return vec3(p.x * c + p.z * s, p.y, + p.z * c - p.x * s); +} + +float impulse(float k, float x) // by iq +{ + float h = k*x; + return h * exp(1.0 - h); +} + +// Raymarched parts of scene +float grass(vec3 pos) +{ + float h = length(pos - vec3(0.0, -7.0, 0.0)) - 8.0; + + if (h > 2.0) return h; // Optimization (Avoid noise if too far away) + + return h + snoise(pos * 3.0) * 0.1 + pos.y * 0.9; +} + +float tree(vec3 pos) +{ + pos.y -= 0.5; + float s = sin(pos.y*0.03); + float c = cos(pos.y*0.03); + mat2 m = mat2(c, -s, s, c); + vec3 p = vec3(m*pos.xy, pos.z); + + float width = 1.0 - pos.y * 0.02 - clamp(sin(pos.y * 8.0) * 0.1, 0.05, 0.1); + + return max(length(p.xz) - width, pos.y - 12.5); +} + +vec2 scene(vec3 pos) +{ + float vtree = tree(pos); + #ifdef GRASS + float vgrass = grass(pos); + float v = min(vtree, vgrass); + #else + float v = vtree; + #endif + return vec2(v, v == vtree ? 2.0 : 1.0); +} + +vec3 normal(vec3 pos) +{ + vec2 eps = vec2(1e-3, 0.0); + float h = scene(pos).x; + return normalize(vec3( + scene(pos-eps.xyy).x-h, + scene(pos-eps.yxy).x-h, + scene(pos-eps.yyx).x-h + )); +} + +float plantsShadow(vec3 rayPos, vec3 rayDir) +{ + // Soft shadow taken from iq + float k = 6.0; + float t = 0.0; + float s = 1.0; + for (int i = 0; i < 30; i++) + { + vec3 pos = rayPos+rayDir*t; + vec2 res = scene(pos); + if (res.x < 0.001) return 0.0; + s = min(s, k*res.x/t); + t += max(res.x, 0.01); + } + + return s*s*(3.0 - 2.0*s); +} + +// Ray-traced parts of scene +vec4 intersectWater(vec3 rayPos, vec3 rayDir) +{ + float h = sin(20.5 + iGlobalTime * 2.0) * 0.03; + float t = -(rayPos.y + 2.5 + h) / rayDir.y; + return vec4(0.0, 1.0, 0.0, t); +} + +vec4 intersectSand(vec3 rayPos, vec3 rayDir) +{ + return intersectSphere(rayPos, rayDir, vec3(0.0,-24.1,0.0), 24.1); +} + +vec4 intersectTreasure(vec3 rayPos, vec3 rayDir) +{ + return vec4(0.0); +} + +vec4 intersectLeaf(vec3 rayPos, vec3 rayDir, float openAmount) +{ + vec3 dir = normalize(vec3(0.0, 1.0, openAmount)); + float offset = 0.0; + + vec4 res = intersectPlane(rayPos, rayDir, dir, 0.0); + vec3 pos = rayPos+rayDir*res.w; + #ifdef RAGGED_LEAVES + offset = snoise(pos*0.8) * 0.3; + #endif + if (pos.y > 0.0 || length(pos * vec3(0.9, 2.0, 1.0)) > 4.0 - offset) res.w = 0.0; + + vec4 res2 = intersectPlane(rayPos, rayDir, vec3(dir.xy, -dir.z), 0.0); + pos = rayPos+rayDir*res2.w; + #ifdef RAGGED_LEAVES + offset = snoise(pos*0.8) * 0.3; + #endif + if (pos.y > 0.0 || length(pos * vec3(0.9, 2.0, 1.0)) > 4.0 - offset) res2.w = 0.0; + + if (res2.w > 0.0 && res2.w < res.w || res.w <= 0.0) + res = res2; + + return res; +} + +vec4 leaves(vec3 rayPos, vec3 rayDir) +{ + float t = 1e20; + vec3 n = vec3(0.0); + + rayPos -= leavesPos; + + float sway = impulse(15.0, fract(iGlobalTime / PI * 0.125)); + float upDownSway = sway * -sin(iGlobalTime) * 0.06; + float openAmount = sway * max(-cos(iGlobalTime) * 0.4, 0.0); + + float angleOffset = -0.1; + for (float k = 0.0; k < 6.2; k += 0.75) + { + // Left-right + float alpha = k + (k - PI) * sway * 0.015; + vec3 p = rotate(rayPos, alpha); + vec3 d = rotate(rayDir, alpha); + + // Up-down + angleOffset *= -1.0; + float theta = -0.4 + + angleOffset + + cos(k) * 0.35 + + upDownSway + + sin(iGlobalTime+k*10.0) * 0.03 * (sway + 0.2); + + p = rotate(p.xzy, theta).xzy; + d = rotate(d.xzy, theta).xzy; + + // Shift + p -= vec3(5.4, 0.0, 0.0); + + // Intersect individual leaf + vec4 res = intersectLeaf(p, d, 1.0+openAmount); + if (res.w > 0.0 && res.w < t) + { + t = res.w; + n = res.xyz; + } + } + + return vec4(n, t); +} + +// Lighting +float shadow(vec3 rayPos, vec3 rayDir) +{ + float s = 1.0; + + // Intersect sand + //vec4 resSand = intersectSand(rayPos, rayDir); + //if (resSand.w > 0.0) return 0.0; + + // Intersect plants + s = min(s, plantsShadow(rayPos, rayDir)); + if (s < 0.0001) return 0.0; + + // Intersect leaves + vec4 resLeaves = leaves(rayPos, rayDir); + if (resLeaves.w > 0.0 && resLeaves.w < 1e7) return 0.0; + + return s; +} + +vec3 light(vec3 p, vec3 n) +{ + float s = 1.0; + + #ifdef SHADOWS + s = shadow(p-sunDir*0.01, -sunDir); + #endif + + vec3 col = sunCol * min(max(dot(n, sunDir), 0.0), s); + col += skyCol * (-n.y * 0.5 + 0.5) * 0.3; + return col; +} + +vec3 lightLeaves(vec3 p, vec3 n) +{ + float s = 1.0; + + #ifdef SHADOWS + s = shadow(p-sunDir*0.01, -sunDir); + #endif + + float ao = min(length(p - leavesPos) * 0.1, 1.0); + + float ns = dot(n, sunDir); + float d = sqrt(max(ns, 0.0)); + vec3 col = sunCol * min(d, s); + col += sunCol * max(-ns, 0.0) * vec3(0.3, 0.3, 0.1) * ao; + col += skyCol * (-n.y * 0.5 + 0.5) * 0.3 * ao; + return col; +} + +vec3 sky(vec3 n) +{ + return skyCol * (1.0 - n.y * 0.8); +} + +// Ray-marching +vec4 plants(vec3 rayPos, vec3 rayDir) +{ + float t = 0.0; + + for (int i = 0; i < 40; i++) + { + vec3 pos = rayPos+rayDir*t; + vec2 res = scene(pos); + float h = res.x; + + if (h < 0.001) + { + vec3 col = res.y == 2.0 ? treeCol : grassCol; + float uvFact = res.y == 2.0 ? 1.0 : 10.0; + + vec3 n = normal(pos); + vec2 uv = vec2(n.x, pos.y * 0.5) * 0.2 * uvFact; + vec3 tex = texture2D(iChannel0, uv).rgb * 0.6 + 0.4; + float ao = min(length(pos - leavesPos) * 0.1, 1.0); + return vec4(col * light(pos, n) * ao * tex, t); + } + + t += h; + } + + return vec4(sky(rayDir), 1e8); +} + +// Final combination +vec3 traceReflection(vec3 rayPos, vec3 rayDir) +{ + vec3 col = vec3(0.0); + float t = 1e20; + + // Intersect plants + vec4 resPlants = plants(rayPos, rayDir); + if (resPlants.w > 0.0 && resPlants.w < t) + { + t = resPlants.w; + col = resPlants.xyz; + } + + // Intersect leaves + vec4 resLeaves = leaves(rayPos, rayDir); + if (resLeaves.w > 0.0 && resLeaves.w < t) + { + vec3 pos = rayPos + rayDir * resLeaves.w; + vec2 uv = (pos.xz - leavesPos.xz) * 0.3; + float tex = texture2D(iChannel0, uv).r * 0.6 + 0.5; + + t = resLeaves.w; + col = leavesCol * lightLeaves(pos, resLeaves.xyz) * tex; + } + + if (t > 1e7) return sky(rayDir); + + return col; +} + +vec3 trace(vec3 rayPos, vec3 rayDir) +{ + vec3 col = vec3(0.0); + float t = 1e20; + + // Intersect sand + vec4 resSand = intersectSand(rayPos, rayDir); + if (resSand.w > 0.0) + { + vec3 pos = rayPos + rayDir * resSand.w; + t = resSand.w; + + col = sandCol * light(pos, resSand.xyz); + } + + // Intersect treasure chest + vec4 resTreasure = intersectTreasure(rayPos, rayDir); + if (resTreasure.w > 0.0 && resTreasure.w < t) + { + vec3 pos = rayPos + rayDir * resTreasure.w; + t = resTreasure.w; + col = leavesCol * light(pos, resTreasure.xyz); + } + + // Intersect leaves + vec4 resLeaves = leaves(rayPos, rayDir); + if (resLeaves.w > 0.0 && resLeaves.w < t) + { + vec3 pos = rayPos + rayDir * resLeaves.w; + vec2 uv = (pos.xz - leavesPos.xz) * 0.3; + float tex = texture2D(iChannel0, uv).r * 0.6 + 0.5; + + t = resLeaves.w; + col = leavesCol * lightLeaves(pos, resLeaves.xyz) * tex; + } + + // Intersect plants + vec4 resPlants = plants(rayPos, rayDir); + if (resPlants.w > 0.0 && resPlants.w < t) + { + t = resPlants.w; + col = resPlants.xyz; + } + + // Intersect water + vec4 resWater = intersectWater(rayPos, rayDir); + if (resWater.w > 0.0 && resWater.w < t) + { + vec3 pos = rayPos + rayDir * resWater.w; + float dist = t - resWater.w; + vec3 n = bump(pos, rayDir); + + float ct = -min(dot(n,rayDir), 0.0); + float fresnel = 0.9 - 0.9 * pow(1.0 - ct, 5.0); + + vec3 trans = col * exp(-dist * vec3(1.0, 0.7, 0.4) * 3.0); + vec3 reflDir = normalize(reflect(rayDir, n)); + vec3 refl = sky(reflDir); + + #ifdef REFLECTIONS + if (dot(pos, rayDir) < -2.0) + refl = traceReflection(pos, reflDir).rgb; + #endif + + t = resWater.t; + col = mix(refl, trans, fresnel); + } + + if (t > 1e7) return sky(rayDir); + + return col; +} + +// Ray-generation +vec3 camera(vec2 px) +{ + vec2 rd = (px / iResolution.yy - vec2(iResolution.x/iResolution.y*0.5-0.5, 0.0)) * 2.0 - 1.0; + float t = sin(iGlobalTime * 0.1) * 0.2; + vec3 rayDir = normalize(vec3(rd.x, rd.y, 1.0)); + vec3 rayPos = vec3(0.0, 3.0, -18.0); + return trace(rayPos, rayDir); +} + +void main(void) +{ + #ifdef HEAVY_AA + vec3 col = camera(gl_FragCoord.xy+vec2(0.0,0.5))*0.25; + col += camera(gl_FragCoord.xy+vec2(0.25,0.0))*0.25; + col += camera(gl_FragCoord.xy+vec2(0.5,0.75))*0.25; + col += camera(gl_FragCoord.xy+vec2(0.75,0.25))*0.25; + #else + vec3 col = camera(gl_FragCoord.xy); + #ifdef LIGHT_AA + col = col * 0.5 + camera(gl_FragCoord.xy+vec2(0.5,0.5))*0.5; + #endif + #endif + + #ifdef TONEMAP + // Optimized Haarm-Peter Duiker’s curve + vec3 x = max(vec3(0.0),col*exposure-0.004); + col = (x*(6.2*x+.5))/(x*(6.2*x+1.7)+0.06); + #else + col = pow(col, vec3(0.4545)); + #endif + + gl_FragColor = vec4(col, 1.0); +} \ No newline at end of file diff --git a/samples/ShaderLab/DepthOfField.shader b/samples/ShaderLab/DepthOfField.shader new file mode 100644 index 00000000..4e64f94a --- /dev/null +++ b/samples/ShaderLab/DepthOfField.shader @@ -0,0 +1,95 @@ +// From https://github.com/Unity-Technologies/PostProcessing, +// licensed under MIT licence. + +Shader "Hidden/Post FX/Depth Of Field" +{ + Properties + { + _MainTex ("", 2D) = "black" + } + + CGINCLUDE + #pragma exclude_renderers d3d11_9x + #pragma target 3.0 + ENDCG + + SubShader + { + Cull Off ZWrite Off ZTest Always + + // (0) Downsampling, prefiltering & CoC + Pass + { + CGPROGRAM + #pragma multi_compile __ UNITY_COLORSPACE_GAMMA + #pragma vertex VertDOF + #pragma fragment FragPrefilter + #include "DepthOfField.cginc" + ENDCG + } + + // (1) Pass 0 + temporal antialiasing + Pass + { + CGPROGRAM + #pragma vertex VertDOF + #pragma fragment FragPrefilter + #define PREFILTER_TAA + #include "DepthOfField.cginc" + ENDCG + } + + // (2-5) Bokeh filter with disk-shaped kernels + Pass + { + CGPROGRAM + #pragma vertex VertDOF + #pragma fragment FragBlur + #define KERNEL_SMALL + #include "DepthOfField.cginc" + ENDCG + } + + Pass + { + CGPROGRAM + #pragma vertex VertDOF + #pragma fragment FragBlur + #define KERNEL_MEDIUM + #include "DepthOfField.cginc" + ENDCG + } + + Pass + { + CGPROGRAM + #pragma vertex VertDOF + #pragma fragment FragBlur + #define KERNEL_LARGE + #include "DepthOfField.cginc" + ENDCG + } + + Pass + { + CGPROGRAM + #pragma vertex VertDOF + #pragma fragment FragBlur + #define KERNEL_VERYLARGE + #include "DepthOfField.cginc" + ENDCG + } + + // (6) Postfilter blur + Pass + { + CGPROGRAM + #pragma vertex VertDOF + #pragma fragment FragPostBlur + #include "DepthOfField.cginc" + ENDCG + } + } + + FallBack Off +} \ No newline at end of file diff --git a/samples/ShaderLab/Fog.shader b/samples/ShaderLab/Fog.shader new file mode 100644 index 00000000..55f94945 --- /dev/null +++ b/samples/ShaderLab/Fog.shader @@ -0,0 +1,112 @@ +// From https://github.com/Unity-Technologies/PostProcessing, +// licensed under MIT licence. + +Shader "Hidden/Post FX/Fog" +{ + Properties + { + _MainTex("Main Texture", 2D) = "white" {} + } + + CGINCLUDE + + #pragma multi_compile __ FOG_LINEAR FOG_EXP FOG_EXP2 + #include "UnityCG.cginc" + #include "Common.cginc" + + #define SKYBOX_THREASHOLD_VALUE 0.9999 + + struct Varyings + { + float2 uv : TEXCOORD0; + float4 vertex : SV_POSITION; + }; + + Varyings VertFog(AttributesDefault v) + { + Varyings o; + o.vertex = UnityObjectToClipPos(v.vertex); + o.uv = UnityStereoScreenSpaceUVAdjust(v.texcoord, _MainTex_ST); + return o; + } + + sampler2D _CameraDepthTexture; + + half4 _FogColor; + float _Density; + float _Start; + float _End; + + half ComputeFog(float z) + { + half fog = 0.0; + #if FOG_LINEAR + fog = (_End - z) / (_End - _Start); + #elif FOG_EXP + fog = exp2(-_Density * z); + #else // FOG_EXP2 + fog = _Density * z; + fog = exp2(-fog * fog); + #endif + return saturate(fog); + } + + float ComputeDistance(float depth) + { + float dist = depth * _ProjectionParams.z; + dist -= _ProjectionParams.y; + return dist; + } + + half4 FragFog(Varyings i) : SV_Target + { + half4 color = tex2D(_MainTex, i.uv); + + float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv); + depth = Linear01Depth(depth); + float dist = ComputeDistance(depth) - _Start; + half fog = 1.0 - ComputeFog(dist); + + return lerp(color, _FogColor, fog); + } + + half4 FragFogExcludeSkybox(Varyings i) : SV_Target + { + half4 color = tex2D(_MainTex, i.uv); + + float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv); + depth = Linear01Depth(depth); + float skybox = depth < SKYBOX_THREASHOLD_VALUE; + float dist = ComputeDistance(depth) - _Start; + half fog = 1.0 - ComputeFog(dist); + + return lerp(color, _FogColor, fog * skybox); + } + + ENDCG + + SubShader + { + Cull Off ZWrite Off ZTest Always + + Pass + { + CGPROGRAM + + #pragma vertex VertFog + #pragma fragment FragFog + + ENDCG + } + + Pass + { + CGPROGRAM + + #pragma vertex VertFog + #pragma fragment FragFogExcludeSkybox + + ENDCG + } + } +} \ No newline at end of file diff --git a/samples/ShaderLab/Uber.shader b/samples/ShaderLab/Uber.shader new file mode 100644 index 00000000..b69ee8c3 --- /dev/null +++ b/samples/ShaderLab/Uber.shader @@ -0,0 +1,337 @@ +// From https://github.com/Unity-Technologies/PostProcessing, +// licensed under MIT licence. + +Shader "Hidden/Post FX/Uber Shader" +{ + Properties + { + _MainTex ("Texture", 2D) = "white" {} + _AutoExposure ("", 2D) = "" {} + _BloomTex ("", 2D) = "" {} + _Bloom_DirtTex ("", 2D) = "" {} + _GrainTex ("", 2D) = "" {} + _LogLut ("", 2D) = "" {} + _UserLut ("", 2D) = "" {} + _Vignette_Mask ("", 2D) = "" {} + _ChromaticAberration_Spectrum ("", 2D) = "" {} + _DitheringTex ("", 2D) = "" {} + } + + CGINCLUDE + + #pragma target 3.0 + + #pragma multi_compile __ UNITY_COLORSPACE_GAMMA + #pragma multi_compile __ EYE_ADAPTATION + #pragma multi_compile __ CHROMATIC_ABERRATION + #pragma multi_compile __ DEPTH_OF_FIELD DEPTH_OF_FIELD_COC_VIEW + #pragma multi_compile __ BLOOM + #pragma multi_compile __ BLOOM_LENS_DIRT + #pragma multi_compile __ COLOR_GRADING COLOR_GRADING_LOG_VIEW + #pragma multi_compile __ USER_LUT + #pragma multi_compile __ GRAIN + #pragma multi_compile __ VIGNETTE_CLASSIC VIGNETTE_ROUND VIGNETTE_MASKED + #pragma multi_compile __ DITHERING + + #include "UnityCG.cginc" + #include "Bloom.cginc" + #include "ColorGrading.cginc" + #include "UberSecondPass.cginc" + + // Auto exposure / eye adaptation + sampler2D _AutoExposure; + + // Chromatic aberration + half _ChromaticAberration_Amount; + sampler2D _ChromaticAberration_Spectrum; + + // Depth of field + sampler2D_float _CameraDepthTexture; + sampler2D _DepthOfFieldTex; + float4 _DepthOfFieldTex_TexelSize; + float2 _DepthOfFieldParams; // x: distance, y: f^2 / (N * (S1 - f) * film_width * 2) + + // Bloom + sampler2D _BloomTex; + float4 _BloomTex_TexelSize; + half2 _Bloom_Settings; // x: sampleScale, y: bloom.intensity + + sampler2D _Bloom_DirtTex; + half _Bloom_DirtIntensity; + + // Color grading & tonemapping + sampler2D _LogLut; + half3 _LogLut_Params; // x: 1 / lut_width, y: 1 / lut_height, z: lut_height - 1 + half _ExposureEV; // EV (exp2) + + // User lut + sampler2D _UserLut; + half4 _UserLut_Params; // @see _LogLut_Params + + // Vignette + half3 _Vignette_Color; + half2 _Vignette_Center; // UV space + half3 _Vignette_Settings; // x: intensity, y: smoothness, z: roundness + sampler2D _Vignette_Mask; + half _Vignette_Opacity; // [0;1] + + struct VaryingsFlipped + { + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; + float2 uvSPR : TEXCOORD1; // Single Pass Stereo UVs + float2 uvFlipped : TEXCOORD2; // Flipped UVs (DX/MSAA/Forward) + float2 uvFlippedSPR : TEXCOORD3; // Single Pass Stereo flipped UVs + }; + + VaryingsFlipped VertUber(AttributesDefault v) + { + VaryingsFlipped o; + o.pos = UnityObjectToClipPos(v.vertex); + o.uv = v.texcoord.xy; + o.uvSPR = UnityStereoScreenSpaceUVAdjust(v.texcoord.xy, _MainTex_ST); + o.uvFlipped = v.texcoord.xy; + + #if UNITY_UV_STARTS_AT_TOP + if (_MainTex_TexelSize.y < 0.0) + o.uvFlipped.y = 1.0 - o.uvFlipped.y; + #endif + + o.uvFlippedSPR = UnityStereoScreenSpaceUVAdjust(o.uvFlipped, _MainTex_ST); + + return o; + } + + half4 FragUber(VaryingsFlipped i) : SV_Target + { + float2 uv = i.uv; + half autoExposure = 1.0; + + // Store the auto exposure value for later + #if EYE_ADAPTATION + { + autoExposure = tex2D(_AutoExposure, uv).r; + } + #endif + + half3 color = (0.0).xxx; + #if DEPTH_OF_FIELD && CHROMATIC_ABERRATION + half4 dof = (0.0).xxxx; + #endif + + // + // HDR effects + // --------------------------------------------------------- + + // Chromatic Aberration + // Inspired by the method described in "Rendering Inside" [Playdead 2016] + // https://twitter.com/pixelmager/status/717019757766123520 + #if CHROMATIC_ABERRATION + { + float2 coords = 2.0 * uv - 1.0; + float2 end = uv - coords * dot(coords, coords) * _ChromaticAberration_Amount; + + float2 diff = end - uv; + int samples = clamp(int(length(_MainTex_TexelSize.zw * diff / 2.0)), 3, 16); + float2 delta = diff / samples; + float2 pos = uv; + half3 sum = (0.0).xxx, filterSum = (0.0).xxx; + + #if DEPTH_OF_FIELD + float2 dofDelta = delta; + float2 dofPos = pos; + if (_MainTex_TexelSize.y < 0.0) + { + dofDelta.y = -dofDelta.y; + dofPos.y = 1.0 - dofPos.y; + } + half4 dofSum = (0.0).xxxx; + #endif + + for (int i = 0; i < samples; i++) + { + half t = (i + 0.5) / samples; + half3 s = tex2Dlod(_MainTex, float4(UnityStereoScreenSpaceUVAdjust(pos, _MainTex_ST), 0, 0)).rgb; + half3 filter = tex2Dlod(_ChromaticAberration_Spectrum, float4(t, 0, 0, 0)).rgb; + + sum += s * filter; + filterSum += filter; + pos += delta; + + #if DEPTH_OF_FIELD + half4 sdof = tex2Dlod(_DepthOfFieldTex, float4(UnityStereoScreenSpaceUVAdjust(dofPos, _MainTex_ST), 0, 0)).rgba; + dofSum += sdof * half4(filter, 1); + dofPos += dofDelta; + #endif + } + + color = sum / filterSum; + #if DEPTH_OF_FIELD + dof = dofSum / half4(filterSum, samples); + #endif + } + #else + { + color = tex2D(_MainTex, i.uvSPR).rgb; + } + #endif + + // Apply auto exposure if any + color *= autoExposure; + + // Gamma space... Gah. + #if UNITY_COLORSPACE_GAMMA + { + color = GammaToLinearSpace(color); + } + #endif + + // Depth of field + #if DEPTH_OF_FIELD + { + #if !CHROMATIC_ABERRATION + half4 dof = tex2D(_DepthOfFieldTex, i.uvFlippedSPR); + #endif + color = color * dof.a + dof.rgb * autoExposure; + } + #elif DEPTH_OF_FIELD_COC_VIEW + { + // Calculate the radiuses of CoC. + half4 src = tex2D(_DepthOfFieldTex, uv); + float depth = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uvFlippedSPR)); + float coc = (depth - _DepthOfFieldParams.x) * _DepthOfFieldParams.y / depth; + coc *= 80; + + // Visualize CoC (white -> red -> gray) + half3 rgb = lerp(half3(1, 0, 0), half3(1.0, 1.0, 1.0), saturate(-coc)); + rgb = lerp(rgb, half3(0.4, 0.4, 0.4), saturate(coc)); + + // Black and white image overlay + rgb *= AcesLuminance(color) + 0.5; + + // Gamma correction + #if !UNITY_COLORSPACE_GAMMA + { + rgb = GammaToLinearSpace(rgb); + } + #endif + + color = rgb; + } + #endif + + // HDR Bloom + #if BLOOM + { + half3 bloom = UpsampleFilter(_BloomTex, i.uvFlippedSPR, _BloomTex_TexelSize.xy, _Bloom_Settings.x) * _Bloom_Settings.y; + color += bloom; + + #if BLOOM_LENS_DIRT + { + half3 dirt = tex2D(_Bloom_DirtTex, i.uvFlipped).rgb * _Bloom_DirtIntensity; + color += bloom * dirt; + } + #endif + } + #endif + + // Procedural vignette + #if VIGNETTE_CLASSIC + { + half2 d = abs(uv - _Vignette_Center) * _Vignette_Settings.x; + d = pow(d, _Vignette_Settings.z); // Roundness + half vfactor = pow(saturate(1.0 - dot(d, d)), _Vignette_Settings.y); + color *= lerp(_Vignette_Color, (1.0).xxx, vfactor); + } + + // Perfectly round vignette + #elif VIGNETTE_ROUND + { + half2 d = abs(uv - _Vignette_Center) * _Vignette_Settings.x; + d.x *= _ScreenParams.x / _ScreenParams.y; + half vfactor = pow(saturate(1.0 - dot(d, d)), _Vignette_Settings.y); + color *= lerp(_Vignette_Color, (1.0).xxx, vfactor); + } + + // Masked vignette + #elif VIGNETTE_MASKED + { + half vfactor = tex2D(_Vignette_Mask, uv).a; + half3 new_color = color * lerp(_Vignette_Color, (1.0).xxx, vfactor); + color = lerp(color, new_color, _Vignette_Opacity); + } + #endif + + // HDR color grading & tonemapping + #if COLOR_GRADING + { + color *= _ExposureEV; // Exposure is in ev units (or 'stops') + + half3 colorLogC = saturate(LinearToLogC(color)); + color = ApplyLut2d(_LogLut, colorLogC, _LogLut_Params); + } + #elif COLOR_GRADING_LOG_VIEW + { + color *= _ExposureEV; + color = saturate(LinearToLogC(color)); + } + #endif + + // + // All the following effects happen in LDR + // --------------------------------------------------------- + + color = saturate(color); + + // Back to gamma space if needed + #if UNITY_COLORSPACE_GAMMA + { + color = LinearToGammaSpace(color); + } + #endif + + // LDR user lut + #if USER_LUT + { + color = saturate(color); + half3 colorGraded; + + #if !UNITY_COLORSPACE_GAMMA + { + colorGraded = ApplyLut2d(_UserLut, LinearToGammaSpace(color), _UserLut_Params.xyz); + colorGraded = GammaToLinearSpace(colorGraded); + } + #else + { + colorGraded = ApplyLut2d(_UserLut, color, _UserLut_Params.xyz); + } + #endif + + color = lerp(color, colorGraded, _UserLut_Params.w); + } + #endif + + color = UberSecondPass(color, uv); + + // Done ! + return half4(color, 1.0); + } + + ENDCG + + SubShader + { + Cull Off ZWrite Off ZTest Always + + // (0) + Pass + { + CGPROGRAM + + #pragma vertex VertUber + #pragma fragment FragUber + + ENDCG + } + } +} \ No newline at end of file