From 984a15f4cd1899706d65d94fabf377de0e627359 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Teemu=20J=C3=A4rvisalo?= Date: Tue, 22 Jul 2025 00:15:44 +0300 Subject: [PATCH] uusi engine --- src/shaders/fragment.frag | 979 +++++++++++++++++++++++++------------- src/shaders/fragment.inl | 434 ++++++++++++----- 2 files changed, 970 insertions(+), 443 deletions(-) diff --git a/src/shaders/fragment.frag b/src/shaders/fragment.frag index 78359b1..8b53088 100644 --- a/src/shaders/fragment.frag +++ b/src/shaders/fragment.frag @@ -1,351 +1,694 @@ #version 460 + precision mediump float; out vec4 o; -const float PI = 3.14159265; -const float TAU = (2. * PI); -const float PHI = sqrt(5.) * 0.5 + 0.5; layout(location = 0) uniform float syncs[7]; layout(location = 8) uniform float fft_output[512]; // FFT_SIZE / 4 -float u_time = syncs[0]; +//float u_time = syncs[0]; + +float iTime = syncs[0]; + +/** +* Creative Commons CC0 1.0 Universal (CC-0) +* +* Contains all the helper functions used by Buffer A for the area lights. +* +*/ + +#define saturate(x) clamp(x, 0., 1.) +#define dot2(x) dot(x, x) + +float EPS = .0002; +float SMOL_EPS = .0000002; + +float PI = 3.1415926535; +float TWO_PI = 6.283185307; +float PI_INV = .3183098861; + +// enable/disable these for floor normal map and roughness + +float T = (iTime * .25); + +float SPHERE_LIGHT_RADIUS = (sin(T) * .5 + .7); + +vec3 SPHERE_LIGHT_POS = vec3(9. * cos(T), 6. * abs(sin(T)) / -.75 + SPHERE_LIGHT_RADIUS, 1.); +float SPHERE_LIGHT_VOLUME_RADIUS = 20.; +float SPHERE_LIGHT_INTENSITY = 256.; + +float LINE_LIGHT_RADIUS = (sin(T) * .075 + .125); +float LINE_LIGHT_VOLUME_RADIUS = 20.; +float LINE_LIGHT_INTENSITY = 512.; + +float RECT_LIGHT_RADIUS = 4.; +float RECT_LIGHT_INTENSITY = 64.; + +vec3 LIGHT_COLOR = vec3(1., .6, .3); + +vec3 SPHERE_ALBEDO = vec3(.2, .01, .6); +int REFLECTION_STEPS = 8; + +vec3 SILVER_F0 = vec3(.95, .93, .88); +vec3 PLASTIC_F0 = vec3(.05); + +vec3 CAMERA_POS = vec3(0., 9., 21.); +float CAMERA_FAR = 100.; + +struct Ray +{ + vec3 origin, direction; +}; + +struct Rect +{ + vec3 center, side1, side2, side3, side4; + vec3 up, right, front; + vec2 halfSize; +}; + +float hash12(vec2 p) +{ + uvec2 q = uvec2(ivec2(p)) * uvec2(1597334673U, 3812015801U); + uint n = (q.x ^ q.y) * 1597334673U; + return float(n) * (1. / float(0xffffffffU)); +} + +mat3 rotZ(float a) +{ + return mat3(cos(a), -sin(a), 0., + sin(a), cos(a), 0., + 0., 0., 1.); +} + +vec3 rotateAround(vec3 v, vec3 k, float theta) +{ + return v * cos(theta) + cross(k, v) * sin(theta) + k * dot(k, v) * (1. - cos(theta)); +} + +mat3 getCameraMatrix(vec3 origin, vec3 target) +{ + vec3 lookAt = normalize(target - origin); + vec3 right = normalize(cross(lookAt, vec3(0., 1., 0.))); + vec3 up = normalize(cross(right, lookAt)); + return mat3(right, up, lookAt); +} + +Ray getCameraRay(vec2 uv) +{ + vec3 origin = CAMERA_POS; + vec3 target = vec3(0., 1., 0.); + mat3 camera = getCameraMatrix(origin, target); + vec3 direction = normalize(camera * vec3(uv, 2.5)); + return Ray(origin, direction); +} + +void initRect(out Rect rect, float t) +{ + rect.up = vec3(0., 0., 1.); + rect.right = vec3(1., 0., 0.); + rect.front = normalize(cross(rect.right, rect.up)); + vec2 widthScale = vec2(cos(t), sin(t)) * .25 + .75; + rect.halfSize = vec2(2.5, 1.5) * widthScale; + + rect.center = vec3(0., 6., sin(t) * 4. - 1.5); + + rect.side1 = rect.center + rect.halfSize.x * rect.right + rect.halfSize.y * rect.up; + rect.side2 = rect.center - rect.halfSize.x * rect.right + rect.halfSize.y * rect.up; + rect.side3 = rect.center - rect.halfSize.x * rect.right - rect.halfSize.y * rect.up; + rect.side4 = rect.center + rect.halfSize.x * rect.right - rect.halfSize.y * rect.up; +} + + +// Based on the technique in EA's frostbite engine +float rectSolidAngle(vec3 p, vec3 v0, vec3 v1, vec3 v2, vec3 v3) +{ + vec3 n0 = normalize(cross(v0, v1)); + vec3 n1 = normalize(cross(v1, v2)); + vec3 n2 = normalize(cross(v2, v3)); + vec3 n3 = normalize(cross(v3, v0)); + + float g0 = acos(dot(-n0, n1)); + float g1 = acos(dot(-n1, n2)); + float g2 = acos(dot(-n2, n3)); + float g3 = acos(dot(-n3, n0)); + + return g0 + g1 + g2 + g3 - 2. * PI; +} vec2 getUV() { const vec2 scale = vec2(0.00104166667, 0.00185185185); return gl_FragCoord.xy * scale - 1.0; } -float noise(in vec2 xy, in float seed) { - return fract(tan(distance(xy * PHI, xy) * seed) * xy.x); -} - -// Hexagonal prism, circumcircle variant -float fHexagonCircumcircle(vec3 p, vec2 h) { - vec3 q = abs(p); - return max(q.y - h.y, max(q.x * sqrt(3.) * 0.5 + q.z * 0.5, q.z) - h.x); - //this is mathematically equivalent to this line, but less efficient: - //return max(q.y - h.y, max(dot(vec2(cos(PI/3), sin(PI/3)), q.zx), q.z) - h.x); -} - -float sdHex(vec3 pos, float i, float angle) { - float d1 = fHexagonCircumcircle(pos, vec2(0.86, i)); - return d1; -} - -float getScaledFFT(int index, float scale, float offset) { - // Clamp index to valid range - index = clamp(index, 0, 511); - - // Get raw FFT value - float raw = fft_output[index]; - - // Apply logarithmic scaling: log(1 + value * scale) + offset - return log(1.0 + raw * scale) + offset; -} - -// Modify your mapScene function -vec2 mapScene(in vec3 p) { - float mat = 0.; - float d = 1e9; - float a = 0.; - - vec2 rippleCenter = vec2(7.,7.); - float rippleSpeed = 4.0; - float rippleFreq = 1.0; - float rippleDecay = 0.25; - - // Hexagonal grid - float hexGap = 0.2; - - for(float j = 0.; j < 16.; j++) { - vec3 po = p; - po += vec3((1.6 + hexGap) * 8, -5., -(1.88 + hexGap) * 10); - po += vec3(0, 0., (1.88 + hexGap) * j); - - for(float i = 0.; i < 16.; i++) { - if(mod(i, 2.) == 0.) { - po -= vec3(1.6 + hexGap, 0., 1.); - } else { - po += vec3(-(1.6 + hexGap), 0., 1.); - } - - // Add individual hexagon ripples based on distance from center - int hexDist = int(length(vec2(i, j) - rippleCenter.xy)); - - //float wave = sin(hexDist * rippleFreq - u_time * rippleSpeed) * exp(-hexDist * rippleDecay); - - // Apply ripple to hexagon size and position - - // float hexSize = fft_output[int(i+1)*int(j+1)]*5.0; // sin(1.5*u_time)+ wave - //float hexSize = fft_output[hexDist] * 5.0; - float hexSize = getScaledFFT(hexDist, 15.0, 0.0) * 2.0; // Adjusted multiplier - a = sdHex(po, 1. + hexSize, 0.); - d = min(d, a); - - if(d == a) { - mat = 1.; - } - } - } - - return vec2(d, mat); -} - -vec3 castRay(vec3 ro, vec3 rd, inout vec3 pos) { - float t = 0.; - float mat = 0.; - float hit = 0.; - // Reduced from 40 to 24 steps - for(int i = 0; i < 30; i++) { - pos = ro + rd * t; - vec2 res = mapScene(pos); - // Increase step size multiplier for faster marching - t += res.x; - mat = res.y; - if(t > 100.) { // Reduced max distance - break; - } - if(res.x < 0.001 * t) { // Less precise hit detection - hit = 1.; - break; - } - } - if (t > 100.) - t = 0.; - - return vec3(t, mat, hit); -} - -float softshadow(in vec3 ro, in vec3 rd, float mint, float maxt, float w) { - float res = 1.0; - float t = mint; - for(int i = 0; i < 6; i++) { - if(t > maxt) - break; - float h = mapScene(ro + t * rd).x; - res = min(res, h / (w * t)); - t += clamp(h, 0.1, 0.80); - if(res < -1.0) - break; - } - res = max(res, -1.0); - return 0.25 * (1.0 + res) * (1.0 + res) * (2.0 - res); -} - -vec3 calcNormal(vec3 pos) { - vec2 e = vec2(.01, 0.); - vec3 n = vec3(mapScene(pos + e.xyy).x - mapScene(pos - e.xyy).x, mapScene(pos + e.yxy).x - mapScene(pos - e.yxy).x, mapScene(pos + e.yyx).x - mapScene(pos - e.yyx).x); - return normalize(n); -} - -vec3 addPointLight(vec3 lightPos, vec3 lightColor, float intensity, vec3 worldPos, vec3 viewDir, vec3 normal, float roughness) { - // Light vector from surface to light - vec3 lightDir = lightPos - worldPos; - float lightDistance = length(lightDir); - lightDir = normalize(lightDir); - - // Attenuation (quadratic falloff) - float attenuation = intensity / (1.0 + 0.09 * lightDistance + 0.032 * lightDistance * lightDistance); - - // Diffuse lighting (Lambert) - float NdotL = max(dot(normal, lightDir), 0.0); - vec3 diffuse = lightColor * NdotL * attenuation; - - // Specular lighting (Blinn-Phong) - vec3 halfDir = normalize(lightDir + (-viewDir)); - float NdotH = max(dot(normal, halfDir), 0.0); - float shininess = mix(128.0, 8.0, roughness); // Convert roughness to shininess - vec3 specular = lightColor * pow(NdotH, shininess) * attenuation; - - // Fresnel effect - vec3 F0 = vec3(0.04); // Base reflectance for dielectrics - vec3 fresnel = F0 + (1.0 - F0) * pow(clamp(1.0 - max(dot(halfDir, lightDir), 0.0), 0.0, 1.0), 5.0); - - // Soft shadows - float shadow = softshadow(worldPos + normal * 0.01, lightDir, 0.02, lightDistance, 4.0); - - // Combine diffuse and specular with shadow - return (diffuse + specular * fresnel) * shadow; -} - -/*vec3 addPointLight(vec3 lightPos, vec3 lightColor, float intensity, vec3 worldPos, vec3 viewDir, vec3 normal) { - vec3 lightDir = normalize(lightPos - worldPos); - float lightDistance = length(lightPos - worldPos); - - // Attenuation - float attenuation = intensity / (1.0 + 0.1 * lightDistance + 0.01 * lightDistance * lightDistance); - - // Diffuse - float NdotL = max(dot(normal, lightDir), 0.0); - - // Specular (Blinn-Phong) - vec3 halfDir = normalize(lightDir - viewDir); - float NdotH = max(dot(normal, halfDir), 0.0); - float specular = pow(NdotH, 32.0); - - // Shadow - float shadow = softshadow(worldPos + normal * 0.01, lightDir, 0.01, lightDistance, 8.0); - - return lightColor * (NdotL + specular * 0.5) * attenuation * shadow; -} +/** +* Creative Commons CC0 1.0 Universal (CC-0) +* +* My implementation of 3 types of area light sources (sphere, line, and rectangle). Based on most +* representative point techniques by Brian Karis (Epic) and Sébastien Lagarde (Unity). The general +* idea is to calculate the location of a point light on the surface of the light source and use that +* point as the light direction to calculate the diffuse and specular components of the area light. +* +* https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf +* https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf +* */ -float getAmbientOcc(vec3 p, vec3 n) { - float occ = 0.; - float weight = 1.; - for(int i = 0; i < 8; i++) { - float len = 0.01 + 0.02 * float(i * i); - float dist = mapScene(p + n * len).x; - occ += (len - dist) * weight; - weight *= 0.85; - } - return 1.0 - clamp(0.6 * occ, 0., 1.); +vec3 lineStart, lineEnd; +Rect rect; + +vec2 sdUnion(vec2 a, vec2 b) +{ + return a.x < b.x ? a : b; } -vec3 shading(vec3 v, vec3 n, vec3 dir, float material) { - float shininess = 0.01; +float sdPlane(vec3 pos, float height) +{ + float plane = pos.y - height; - vec3 outMaterial = vec3(0.0, 0.0, 0.0); + return plane; +} - if(material == 0.) { - outMaterial = vec3(0.8314, 0.2941, 0.2941); - shininess = 0.1; - } else if(material == 1.) { - outMaterial = vec3(0.6196, 0.6118, 0.6118); - shininess = .7; - } else if(material == 2.) { - outMaterial = vec3(0.3255, 0.4784, 0.3255); - shininess = .2; - } else if(material == 3.) { - outMaterial = vec3(0.2471, 0.3059, 0.6314); - shininess = 1.0; - } else if(material == 4.) { - outMaterial = vec3(0.9961, 1.0, 0.9922); - shininess = .1; - } else if(material == 5.) { - outMaterial = vec3(0.9961, 1.0, 0.9922); - shininess = .3; +float sdPlaneNoDisplacement(vec3 pos, float height) +{ + return pos.y - height; +} + +float sdSphere(vec3 position, vec3 center, float radius) +{ + return length(position - center) - radius; +} + +float sdCapsule(vec3 position, vec3 start, vec3 end, float radius) +{ + vec3 pa = position - start, ba = end - start; + float h = saturate(dot(pa, ba) / dot(ba, ba)); + return length(pa - ba * h) - radius; +} + +float sdRect(vec3 p, vec3 a, vec3 b, vec3 c, vec3 d) +{ + vec3 ba = b - a; vec3 pa = p - a; + vec3 cb = c - b; vec3 pb = p - b; + vec3 dc = d - c; vec3 pc = p - c; + vec3 ad = a - d; vec3 pd = p - d; + vec3 nor = cross(ba, ad); + + return sqrt( + (sign(dot(cross(ba, nor), pa)) + + sign(dot(cross(cb, nor), pb)) + + sign(dot(cross(dc, nor), pc)) + + sign(dot(cross(ad, nor), pd)) < 3.) + + ? + + min(min(min( + dot2(ba * clamp(dot(ba, pa) / dot2(ba), 0., 1.) - pa), + dot2(cb * clamp(dot(cb, pb) / dot2(cb), 0., 1.) - pb)), + dot2(dc * clamp(dot(dc, pc) / dot2(dc), 0., 1.) - pc)), + dot2(ad * clamp(dot(ad, pd) / dot2(ad), 0., 1.) - pd)) + + : + + dot(nor, pa) * dot(nor, pa) / dot2(nor) + ); +} + +vec2 sdScene(vec3 pos) +{ + vec2 result = sdUnion(vec2(sdPlaneNoDisplacement(pos, -.75), 3.), + vec2(sdSphere(pos, vec3(-4.5, .75, 0.), 1.5), 1.05)); + + result = sdUnion(result, vec2(sdSphere(pos, vec3(-1.5, .75,0.), 1.5), 1.25)); + + result = sdUnion(result, vec2(sdSphere(pos, vec3(1.5, .75, 0.), 1.5), 1.45)); + + result = sdUnion(result, vec2(sdSphere(pos, vec3(4.5, .75, 0.), 1.5), 1.65)); + + + result = sdUnion(result, vec2(sdSphere(pos, SPHERE_LIGHT_POS, SPHERE_LIGHT_RADIUS), + 0.)); + + result = sdUnion(result, vec2(sdCapsule(pos, lineStart, lineEnd, + LINE_LIGHT_RADIUS), 0.)); + + result = sdUnion(result, vec2(sdRect(pos, rect.side1, rect.side2, rect.side3, rect.side4), 0.)); + + + return result; +} + +vec2 sdSceneNormal(vec3 pos) +{ + vec2 result = sdUnion(vec2(sdPlane(pos, -.75), 3.), + vec2(sdSphere(pos, vec3(-4.5, .75, 0.), 1.5), 1.05)); + + result = sdUnion(result, vec2(sdSphere(pos, vec3(-1.5, .75, 0.), 1.5), 1.25)); + + result = sdUnion(result, vec2(sdSphere(pos, vec3(1.5, .75, 0.), 1.5), 1.45)); + + result = sdUnion(result, vec2(sdSphere(pos, vec3(4.5, .75, 0.), 1.5), 1.65)); + + return result; +} + +vec2 sdSceneNoLights(vec3 pos) +{ + vec2 result = sdUnion(vec2(sdPlaneNoDisplacement(pos, -.75), 3.), + vec2(sdSphere(pos, vec3(-4.5, .75, 0.), 1.5), 1.05)); + + result = sdUnion(result, vec2(sdSphere(pos, vec3(-1.5, .75, 0.), 1.5), 1.25)); + + result = sdUnion(result, vec2(sdSphere(pos, vec3(1.5, .75, 0.), 1.5), 1.45)); + + result = sdUnion(result, vec2(sdSphere(pos, vec3(4.5, .75, 0.), 1.5), 1.65)); + + return result; +} + +vec3 calculateNormal(vec3 pos) +{ + vec2 eps = vec2(EPS, 0.); + return normalize(vec3(sdSceneNormal(pos + eps.xyy).x, + sdSceneNormal(pos + eps.yxy).x, + sdSceneNormal(pos + eps.yyx).x) + - sdSceneNormal(pos).x); +} + +vec2 rayMarch(Ray ray) +{ + float dist = 0.; + vec2 result = vec2(-1.); + for(int i = 0; i < 128; ++i) + { + result = sdScene(ray.origin + ray.direction * dist); + if (result.x < EPS * dist || dist >= CAMERA_FAR) break; + dist += result.x; } - vec3 lights = vec3(0.); - lights += addPointLight(vec3(-10., 10.0, 0.), vec3(0.77, 0.26, 0.73), 3.0, v, dir, n, shininess); - lights += addPointLight(vec3(0., 10.0, -5.0), vec3(0.08, 0.62, 0.75), 3.0, v, dir, n, shininess); - lights += addPointLight(vec3(0., 25.0, 0.0), vec3(0.5137, 0.1961, 0.7725), 3.0, v, dir, n, shininess); - - vec3 lightDir = vec3(0., 1., -3); - //float sun_dif = clamp(dot(n, lightDir), 0., 1.); - //float shadow = softshadow(v + n * 0.01, lightDir, .01, 30., 18.); - //lights += vec3(0.6431, 0.7804, 0.8588) * sun_dif * shadow * occ; - - float ind = clamp(dot(n, normalize(lightDir * vec3(.0, -1.0, -2.0))), 0.0, 1.0); - lights += vec3(0.08, 0.62, 0.75) * ind * 0.8; - - return outMaterial * max(vec3(0.), lights); + if (dist >= CAMERA_FAR) result.y = -1.; + return vec2(dist, result.y); } -vec3 postProcess(vec3 col) { - // float random = noise(gl_FragCoord.xy, 0.01+u_time); - // float random2 = noise(gl_FragCoord.xy, .2+u_time); - //col += 0.075*clamp(vec3(0.5*random, 0.5*random2, 0.5*random), 0.02, 1.); // dither - - // Normalized pixel coordinates (from 0 to 1) - vec2 screenCoord = getUV(); - - // Vignette - float radius = 0.8; - float d = smoothstep(radius, radius - 0.4, length(screenCoord - vec2(0.5))); - col = mix(col, col * d, 1.); - - // Contrast - float contrast = .75; - col = mix(col, smoothstep(0.0, 1.0, col), contrast); - - // Colour mapping - col *= vec3(1.0, 1.0, 1.0); - - col = pow(col, vec3(0.4545)); // gamma - - // fade in at the beginning - //col*=vec3(clamp((u_time-1.8)*0.5,0., 1.)); - - // fade out at the end - // col*=vec3(clamp((120.-u_time)*.35, 0., 1.)); - - return col; -} - -vec3 getCameraRay(vec2 uv, vec3 camPos, vec3 camTarget, float fov) { - // Calculate camera's orthonormal basis - vec3 camForward = normalize(camTarget - camPos); - vec3 camRight = normalize(cross(vec3(0.0, 1.0, 0.0), camForward)); - vec3 camUp = normalize(cross(camForward, camRight)); - - vec3 rayDir = normalize(uv.x * camRight + uv.y * camUp + camForward * fov); - - return rayDir; -} - -// Camera positioning function -vec3 getCameraPosition(float time, int cameraMode) { - vec3 camPos; - camPos = vec3(0.0, 30.0, -10.0); - - if(cameraMode == 1) { - // Orbiting camera - vec3 camTarget = vec3(0.0, 0.0, -20.0); - float orbitRadius = 20.0; - float orbitSpeed = 0.2; - float orbitHeight = 10.0; - float angle = time * orbitSpeed; - camPos = camTarget + vec3(cos(angle) * orbitRadius, orbitHeight + sin(time * 0.8) * 2.0, sin(angle) * orbitRadius); - } else if(cameraMode == 2) { - // Smooth camera movement - float t = time * 0.06; - camPos = vec3(sin(t) * 15.0, 30.0 + cos(t * 0.5) * 5.0, cos(t) * 15.0); - } else if(cameraMode == 3) { - // First person style movement - float walkSpeed = 2.0; - camPos = vec3(sin(time * walkSpeed) * 0.1, 8.0 + sin(time * walkSpeed * 2.0) * 0.05, time * 0.5); +vec2 rayMarchNoLights(Ray ray) +{ + float dist = 0.; + vec2 result = vec2(-1.); + for(int i = 0; i < 64; ++i) + { + result = sdSceneNoLights(ray.origin + ray.direction * dist); + if (result.x < EPS * dist || dist >= CAMERA_FAR) break; + dist += result.x; } - return camPos; + if (dist >= CAMERA_FAR) result.y = -1.; + return vec2(dist, result.y); } - -// Main camera function that combines everything -vec3 setupCamera(vec2 uv, float time, int positionMode) { - vec3 camPos = getCameraPosition(time, positionMode); - vec3 camTarget = vec3(0.0, -1.0, 10.0); // Adjust target as needed - float fov = 1.; - - return getCameraRay(uv, camPos, camTarget, fov); -} - -// Simplified version of your render function using the new camera system -vec3 render(vec2 uv) { - // Choose camera modes: - // Position: 0=static, 1=orbit, 2=smooth, 3=walk - // Ray: 0=standard, 1=zoom, 2=dof - int positionMode = 2; // Static - - vec3 rayDir = setupCamera(uv, u_time, positionMode); - vec3 camPos = getCameraPosition(u_time, positionMode); - - vec3 col = vec3(0.102, 0.2431, 0.3412); - vec3 hitPos = vec3(0); - vec3 t = castRay(camPos, rayDir, hitPos); - - if(t.x > 0.0) { - vec3 nor = calcNormal(hitPos); - col = shading(hitPos, nor, rayDir, t.y); +#if 1 +float softShadow(Ray ray) +{ + float shadow = 1., dist = 0.; + for (int i = 0; i < 64; ++i) + { + vec2 result = sdSceneNoLights(ray.origin + ray.direction * dist); + if (result.y > 0.) + { + // iq's soft shadow hack + shadow = min(shadow, .5 + .5 * result.x / (.125 * dist)); + if (shadow < 0.) break; + dist += clamp(result.x, .005, .5); + } } + return smoothstep(0., 1., max(shadow, 0.)); +} +#else +float softShadow(Ray ray) +{ + float t = 0.; + for(int i = 0; i < 64; ++i) + { + float h = sdSceneNoLights(ray.origin + ray.direction * t).x; + if (h < EPS) + return 0.0; + t += h; + } + return 1.0; +} +#endif - return col; +float normalDistributionGGXSphere(float NdotH, float alpha, float alphaPrime) +{ + float alpha2 = alpha * alpha; + float alphaPrime2 = alphaPrime * alphaPrime; + float NdotH2 = NdotH * NdotH; + + return + (alpha2 * alphaPrime2) + / /*----------------------------------------*/ + pow(NdotH2 * (alpha2 - 1.) + 1., 2.); } -void main() { +float normalDistributionGGXLine(float NdotH, float alpha, float alphaPrime) +{ + float alpha2 = alpha * alpha; + float alphaPrime2 = alphaPrime * alphaPrime; + float NdotH2 = NdotH * NdotH; + + return + (alpha2 * alphaPrime) + / /*----------------------------------------*/ + pow(NdotH2 * (alpha2 - 1.) + 1., 2.); +} - vec3 finalColor = render(getUV()); +float normalDistributionGGXRect(float NdotH, float alpha, float alphaPrime) +{ + float alpha2 = alpha * alpha; + float alpha4 = alpha2 * alpha2; + float alphaPrime3 = alphaPrime * alphaPrime * alphaPrime; + float NdotH2 = NdotH * NdotH; + + return + (alpha2 * alphaPrime3) + / /*-------------------------------------------------*/ + (pow(NdotH2 * (alpha2 - 1.) + 1., 2.)); +} - //finalColor = postProcess(finalColor); +// Schlick-Beckmann GGX approximation used for smith's method +float geometrySchlickGGX(float NdotX, float k) +{ + return + NdotX + / /*----------------------------------------*/ + max(NdotX * (1. - k) + k, SMOL_EPS); +} - o = vec4(finalColor, 1.); +float geometrySmith(float NdotV, float NdotL, float roughness) +{ + float roughnessplusone = roughness + 1.; + float k = roughnessplusone * roughnessplusone / 8.; + + return geometrySchlickGGX(NdotV, k) * geometrySchlickGGX(NdotL, k); +} +// Schlick's approximation for Fresnel equation +vec3 fresnelSchlick(vec3 F0, float dotProd) +{ + return F0 + (1. - F0) * pow(1. - dotProd, 5.); +} + +vec3 Irradiance_SphericalHarmonics(const vec3 n) { + // Irradiance from "Ditch River" IBL (http://www.hdrlabs.com/sibl/archive.html) + // Generated using google filament cmgen tool + return max( + vec3( .754554516862612, .748542953903366, .790921515418539) + + vec3(-.083856548007422, .092533500963210, .322764661032516) * (n.y) + + vec3( .308152705331738, .366796330467391, .466698181299906) * (n.z) + + vec3(-.188884931542396, -.277402551592231, -.377844212327557) * (n.x) + , 0.0); +} + +vec2 PrefilteredDFG_Karis(float roughness, float NoV) { + // Karis 2014, "Physically Based Material on Mobile" + // https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile + const vec4 c0 = vec4(-1., -.0275, -.572, .022); + const vec4 c1 = vec4( 1., .0425, 1.040, -.040); + + vec4 r = roughness * c0 + c1; + float a004 = min(r.x * r.x, exp2(-9.28 * NoV)) * r.x + r.y; + + return vec2(-1.04, 1.04) * a004 + r.zw; +} + +vec4 sphereLight(vec3 p, vec3 n, vec3 v, vec3 r, vec3 f0, float NdotV, float roughness, + float metalness, out vec3 fresnel, out float attenuation) +{ + vec3 L = (SPHERE_LIGHT_POS - p); + vec3 centerToRay = dot(L, r) * r - L; + vec3 closestPoint = L + centerToRay * saturate(SPHERE_LIGHT_RADIUS + / length(centerToRay)); + vec3 l = normalize(closestPoint); + vec3 h = normalize(v + l); + float lightDist = length(closestPoint); + + float NdotL = max(dot(n, l), 0.); + float NdotH = max(dot(n, h), 0.); + float VdotH = max(dot(h, v), 0.); + + attenuation = pow(saturate(1. - pow(lightDist / SPHERE_LIGHT_VOLUME_RADIUS, 4.)), 2.) + / (lightDist * lightDist + 1.); + + attenuation *= softShadow(Ray(p + n * EPS, l)); + + float alpha = roughness * roughness; + float alphaPrime = saturate(alpha + (SPHERE_LIGHT_RADIUS / (2. * lightDist))); + + fresnel = fresnelSchlick(f0, VdotH); + vec3 specular = normalDistributionGGXSphere(NdotH, alpha, alphaPrime) + * geometrySmith(NdotV, NdotL, roughness) + * fresnel; + + return vec4(specular, NdotL); +} + +vec4 lineLight(vec3 p, vec3 n, vec3 v, vec3 r, vec3 f0, float NdotV, float roughness, + float metalness, out vec3 fresnel, out float attenuation) +{ + vec4 result = vec4(0.); + vec3 l0 = lineStart - p, l1 = lineEnd - p; + float lengthL0 = length(l0), lengthL1 = length(l1); + float NdotL0 = dot(n, l0) / (2. * lengthL0); + float NdotL1 = dot(n, l1) / (2. * lengthL1); + result.w = (2. * saturate(NdotL0 + NdotL1)) / + (lengthL0 * lengthL1 + dot(l0, l1) + 2.); // NdotL + + vec3 ld = l1 - l0; + float RdotL0 = dot(r, l0); + float RdotLd = dot(r, ld); + float L0dotLd = dot(l0, ld); + float distLd = length(ld); + + float t = (RdotL0 * RdotLd - L0dotLd ) / (distLd * distLd - RdotLd * RdotLd); + + // point on the line + vec3 closestPoint = l0 + ld * saturate(t); + // point on the tube based on its radius + vec3 centerToRay = dot(closestPoint, r) * r - closestPoint; + closestPoint = closestPoint + centerToRay * saturate(LINE_LIGHT_RADIUS + / length(centerToRay)); + vec3 l = normalize(closestPoint); + vec3 h = normalize(v + l); + float lightDist = length(closestPoint); + + float NdotH = max(dot(n, h), 0.); + float VdotH = dot(h, v); + + float denom = lightDist / LINE_LIGHT_VOLUME_RADIUS; + attenuation = 1. / (denom * denom + 1.); + + attenuation *= softShadow(Ray(p + n * EPS, normalize(l0 + ld * .5))); + + float alpha = roughness * roughness; + float alphaPrime = saturate(alpha + (LINE_LIGHT_RADIUS / (2. * lightDist))); + + fresnel = fresnelSchlick(f0, VdotH); + result.xyz = normalDistributionGGXLine(NdotH, alpha, alphaPrime) + * geometrySmith(NdotV, result.w, roughness) + * fresnel; + + return result; +} + +vec3 rayPlaneIntersect(Ray ray) +{ + return ray.origin + ray.direction * (dot(rect.front, rect.center - ray.origin) + / dot(rect.front, ray.direction)); +} + +vec4 rectLight(vec3 p, vec3 n, vec3 v, vec3 r, vec3 f0, float NdotV, float roughness, + float metalness, out vec3 fresnel, out float attenuation) +{ + vec4 result = vec4(0.); + + // facing side check + float windingCheck = dot(cross(rect.right, rect.up), rect.center - p); + if (windingCheck > 0.) + return result; + + vec3 v0 = rect.side1 - p; + vec3 v1 = rect.side2 - p; + vec3 v2 = rect.side3 - p; + vec3 v3 = rect.side4 - p; + + float solidAngle = rectSolidAngle(p, v0, v1, v2, v3); + + // diffuse + result.w = solidAngle * .2 * ( + saturate(dot(normalize(v0), n)) + + saturate(dot(normalize(v1), n)) + + saturate(dot(normalize(v2), n)) + + saturate(dot(normalize(v3), n)) + + saturate(dot(normalize(rect.center - p), n))); + + attenuation = softShadow(Ray(p + n * EPS, normalize(rect.center))); + + // specular + Ray rectRay = Ray(p, r); + vec3 planePointCenter = rayPlaneIntersect(rectRay) - rect.center; + // project point on the plane on which the rectangle lies + vec2 planePointProj = vec2(dot(planePointCenter, rect.right), + dot(planePointCenter, rect.up)); + // translate the point to the top-right quadrant of the rectangle, project it on + // the rectangle or its edge and translate back using sign of the original point. + vec2 c = min(abs(planePointProj), rect.halfSize) * sign(planePointProj); + vec3 L = rect.center + rect.right * c.x + rect.up * c.y - p; + + vec3 l = normalize(L); + vec3 h = normalize(v + l); + float lightDist = length(L); + + float NdotH = max(dot(n, h), 0.); + float VdotH = dot(h, v); + + float alpha = roughness * roughness; + float alphaPrime = saturate(alpha + (RECT_LIGHT_RADIUS / (2. * lightDist))); + + fresnel = fresnelSchlick(f0, VdotH); + result.xyz = normalDistributionGGXRect(NdotH, alpha, alphaPrime) + * geometrySmith(NdotV, result.w, roughness) + * fresnel; + + return result; +} + +vec3 renderScene(Ray ray) +{ + // update line light position & rotation + //float t = iTime * .25; + vec3 lineRotation = vec3(2., 0., 0.) * rotZ(T); + vec3 linePosition = vec3(6. * sin(T), 3., 5.); + lineStart = linePosition - lineRotation; + lineEnd = linePosition + lineRotation; + + initRect(rect, T); + + vec3 col = vec3(0.); + vec2 marchResult = rayMarch(ray); + vec3 position = ray.origin + ray.direction * marchResult.x; + vec3 normal = calculateNormal(position); + vec3 viewDirection = -ray.direction; + vec3 reflectDirection = reflect(ray.direction, normal); + + float NdotV = max(dot(normal, viewDirection), 0.); + + vec3 albedo = SPHERE_ALBEDO; + + float roughness = fract(marchResult.y), metalness = .88; + vec3 reflectance = SILVER_F0; + + if (marchResult.y > -1.) + { + if (marchResult.y > 2.) + { + // albedo = pow(textureLod(iChannel0, position.xz * .18, 0.).rgb, vec3(2.2)); + albedo = vec3(0.31, 0.62, 0.47); + + roughness = max(0.05, albedo.r * .5); + + //roughness = .05; + + metalness = .05; + reflectance = PLASTIC_F0; + } + else if (marchResult.y < .5) + return LIGHT_COLOR * RECT_LIGHT_INTENSITY; + + vec3 F0 = mix(reflectance, albedo, metalness); + + vec3 sphereLightFresnel = vec3(0.); + float sphereLightAttenuation = 1.; + vec4 sphereLightDiffSpec = sphereLight(position, normal, viewDirection, + reflectDirection, F0, NdotV, roughness, metalness, sphereLightFresnel, + sphereLightAttenuation); + vec3 sphereLightKd = 1. - sphereLightFresnel; + sphereLightKd *= 1. - metalness; + + vec3 lineLightFresnel = vec3(0.); + float lineLightAttenuation = 1.; + vec4 lineLightDiffSpec = lineLight(position, normal, viewDirection, + reflectDirection, F0, NdotV, roughness, metalness, lineLightFresnel, + lineLightAttenuation); + vec3 lineLightKd = 1. - lineLightFresnel; + lineLightKd *= 1. - metalness; + + vec3 rectLightFresnel = vec3(0.); + float rectLightAttenuation = 1.; + vec4 rectLightDiffSpec = rectLight(position, normal, viewDirection, + reflectDirection, F0, NdotV, roughness, metalness, rectLightFresnel, + rectLightAttenuation); + vec3 rectLightKd = 1. - rectLightFresnel; + rectLightKd *= 1. - metalness; + + col += (sphereLightKd * PI_INV * albedo + sphereLightDiffSpec.xyz) + * SPHERE_LIGHT_INTENSITY * sphereLightDiffSpec.w * sphereLightAttenuation; + + col += (lineLightKd * PI_INV * albedo + lineLightDiffSpec.xyz) + * LINE_LIGHT_INTENSITY * lineLightDiffSpec.w * lineLightAttenuation; + + col += (rectLightKd * PI_INV * albedo + rectLightDiffSpec.xyz) + * RECT_LIGHT_INTENSITY * rectLightDiffSpec.w * rectLightAttenuation; + + col += albedo * .025; // global ambient + + // calculate glossy reflection + ibl + float glossiness = roughness * roughness; + vec3 indirectSpecular = vec3(.1125, .1875, .25) + reflectDirection.y * .35; + Ray reflectRay = Ray(position, vec3(0.)); + for (int i = 0; i < REFLECTION_STEPS; ++i) + { + float percentage = float(i) / float(REFLECTION_STEPS); + vec3 delta = rotateAround(vec3(0., 1., 0.), reflectDirection, + TWO_PI * percentage); + reflectRay.direction = normalize(delta * glossiness + reflectDirection); + vec2 indirectMarchResult = rayMarchNoLights(reflectRay); + + if (floor(indirectMarchResult.y) == 3.) + { + vec3 indirectPosition = position + indirectMarchResult.x + * reflectRay.direction; + //indirectSpecular += textureLod(iChannel0, indirectPosition.xz * .18, 0.).rgb; + indirectSpecular = vec3(0.1, 0.3, 0.2); + } + else if(floor(indirectMarchResult.y) == 1.) + indirectSpecular += SPHERE_ALBEDO; + + } + + indirectSpecular /= float(REFLECTION_STEPS); + + vec2 dfg = PrefilteredDFG_Karis(roughness, NdotV); + vec3 specularColor = F0 * dfg.x + dfg.y; + vec3 ibl = indirectSpecular * specularColor + + Irradiance_SphericalHarmonics(normal) * PI_INV * albedo; + + col += ibl * .84; + col *= LIGHT_COLOR; + } + + // fog + return mix(col, vec3(.01, .006, .004), // brown-ish fog color + clamp(1. - exp(-marchResult.x * .08), 0., 1.)); +} + +void main() +{ + vec2 iResolution = vec2(1920,1080); + + // vec2 blueNoise = texelFetch(iChannel1, + // (iFrame * ivec2(113, 127)) & 63, 0).rg; + vec2 uv = (2. * gl_FragCoord.xy - iResolution.xy) / iResolution.y; + //vec2 st = fragCoord / iResolution.xy; + + Ray ray = getCameraRay(uv); + + vec3 col = renderScene(ray); + + o = vec4(col, 1.); } \ No newline at end of file diff --git a/src/shaders/fragment.inl b/src/shaders/fragment.inl index bcae441..03cf46f 100644 --- a/src/shaders/fragment.inl +++ b/src/shaders/fragment.inl @@ -1,152 +1,336 @@ // Generated with Shader Minifier 1.5.1 (https://github.com/laurentlb/Shader_Minifier/) #ifndef FRAGMENT_INL_ # define FRAGMENT_INL_ -# define VAR_fft_output "n" -# define VAR_o "f" -# define VAR_syncs "m" +# define VAR_fft_output "f" +# define VAR_o "v" +# define VAR_syncs "n" const char *fragment_frag = "#version 460\n" "precision mediump float;" - "out vec4 f;" - "const float i=2.*acos(-1.),v=sqrt(5.)*.5+.5;" - "layout(location=0)uniform float m[7];" - "layout(location=8)uniform float n[512];" - "float c=m[0];" - "float t(vec3 v,vec2 i)" + "out vec4 v;" + "layout(location=0)uniform float n[7];" + "layout(location=8)uniform float f[512];" + "float m=n[0];\n" + "#define saturate(x)clamp(x,0.,1.)\n" + "#define dot2(x)dot(x,x)\n" + "float d=m*.25,s=sin(d)*.5+.7;" + "vec3 e=vec3(9.*cos(d),6.*abs(sin(d))/-.75+s,1);" + "float c=sin(d)*.075+.125;" + "vec3 x=vec3(1,.6,.3),o=vec3(.2,.01,.6),p=vec3(.95,.93,.88),l=vec3(.05),r=vec3(0,9,21);" + "struct Ray{vec3 origin,direction;};" + "struct Rect{vec3 center,side1,side2,side3,side4;vec3 up,right,front;vec2 halfSize;};" + "mat3 t()" "{" - "v=abs(v);" - "return max(v.y-i.y,max(v.x*sqrt(3.)*.5+v.z*.5,v.z)-i.x);" + "float v=d;" + "return mat3(cos(v),-sin(v),0.,sin(v),cos(v),0.,0.,0.,1.);" "}" - "float t(int v)" + "vec3 t(vec3 v,float d)" "{" - "v=clamp(v,0,511);" - "float i=n[v];" - "return log(1.+i*15.);" + "vec3 f=vec3(0,1,0);" + "return f*cos(d)+cross(v,f)*sin(d)+v*dot(v,f)*(1.-cos(d));" "}" - "vec2 t(vec3 v)" + "mat3 t(vec3 v)" "{" - "float i=0.,f=1e9,m=0.;" - "vec2 n=vec2(7);" - "for(float r=0.;r<16.;r++)" + "v=normalize(vec3(0,1,0)-v);" + "vec3 d=normalize(cross(v,vec3(0,1,0)));" + "return mat3(d,normalize(cross(d,v)),v);" + "}" + "Ray t(vec2 v)" + "{" + "vec3 d=r;" + "return Ray(d,normalize(t(d)*vec3(v,2.5)));" + "}" + "void t(out Rect v)" + "{" + "float f=d;" + "v.up=vec3(0,0,1);" + "v.right=vec3(1,0,0);" + "v.front=normalize(cross(v.right,v.up));" + "v.halfSize=vec2(2.5,1.5)*(vec2(cos(f),sin(f))*.25+.75);" + "v.center=vec3(0,6,sin(f)*4.-1.5);" + "v.side1=v.center+v.halfSize.x*v.right+v.halfSize.y*v.up;" + "v.side2=v.center-v.halfSize.x*v.right+v.halfSize.y*v.up;" + "v.side3=v.center-v.halfSize.x*v.right-v.halfSize.y*v.up;" + "v.side4=v.center+v.halfSize.x*v.right-v.halfSize.y*v.up;" + "}" + "float t(vec3 v,vec3 d,vec3 f,vec3 i,vec3 c)" + "{" + "v=normalize(cross(d,f));" + "f=normalize(cross(f,i));" + "i=normalize(cross(i,c));" + "d=normalize(cross(c,d));" + "return acos(dot(-v,f))+acos(dot(-f,i))+acos(dot(-i,d))+acos(dot(-d,v))-2.*acos(-1.);" + "}" + "vec3 R,y;" + "Rect i;" + "vec2 t(vec2 v,vec2 i)" + "{" + "return v.x=1e2)" + "break;" + "d+=f.x;" + "}" + "if(d>=1e2)" + "f.y=-1.;" + "return vec2(d,f.y);" + "}" + "vec2 a(Ray v)" + "{" + "float d=0.;" + "vec2 f=vec2(-1);" + "for(int i=0;i<64;++i)" + "{" + "f=u(v.origin+v.direction*d);" + "if(f.x<2e-4*d||d>=1e2)" + "break;" + "d+=f.x;" + "}" + "if(d>=1e2)" + "f.y=-1.;" + "return vec2(d,f.y);" + "}\n" + "#if 1\n" + "float h(Ray v)" + "{" + "float d=1.,f=0.;" + "for(int i=0;i<64;++i)" + "{" + "vec2 c=u(v.origin+v.direction*f);" + "if(c.y>0.)" "{" - "c=mod(v,2.)==0.?" - "c-vec3(1.8,0,1):" - "c+vec3(-1.8,0,1);" - "int y=int(length(vec2(v,r)-n.xy));" - "m=t(c,vec2(.86,1.+t(y)*2.));" - "f=min(f,m);" - "if(f==m)" - "i=1.;" + "d=min(d,.5+.5*c.x/(.125*f));" + "if(d<0.)" + "break;" + "f+=clamp(c.x,.005,.5);" "}" "}" - "return vec2(f,i);" - "}" - "vec3 t(vec3 v,vec3 i,inout vec3 f)" + "return smoothstep(0.,1.,max(d,0.));" + "}\n" + "#else\n" + "float h(Ray v)" "{" - "float r=0.,m=0.,y=0.;" - "for(int c=0;c<30;c++)" + "float f=0.;" + "for(int d=0;d<64;++d)" "{" - "f=v+i*r;" - "vec2 n=t(f);" - "r+=n.x;" - "m=n.y;" - "if(r>1e2)" - "break;" - "if(n.x<.001*r)" + "float i=u(v.origin+v.direction*f).x;" + "if(i<2e-4)" + "return 0.;" + "f+=i;" + "}" + "return 1.;" + "}\n" + "#endif\n" + "float C(float v,float d,float f)" + "{" + "d*=d;" + "return f*f*d/pow(v*v*(d-1.)+1.,2.);" + "}" + "float a(float v,float d,float f)" + "{" + "d*=d;" + "return d*f/pow(v*v*(d-1.)+1.,2.);" + "}" + "float h(float v,float d,float f)" + "{" + "d*=d;" + "return f*f*f*d/pow(v*v*(d-1.)+1.,2.);" + "}" + "float C(float v,float d)" + "{" + "return v/max(v*(1.-d)+d,2e-7);" + "}" + "float t(float v,float d,float f)" + "{" + "f+=1.;" + "f=f*f/8.;" + "return C(v,f)*C(d,f);" + "}" + "vec3 C(vec3 v,float d)" + "{" + "return v+(1.-v)*pow(1.-d,5.);" + "}" + "vec2 a(float v,float d)" + "{" + "vec4 i=v*vec4(-1,-.0275,-.572,.022)+vec4(1,.0425,1.04,-.04);" + "return vec2(-1.04,1.04)*(min(i.x*i.x,exp2(-9.28*d))*i.x+i.y)+i.zw;" + "}" + "vec4 C(vec3 v,vec3 d,vec3 f,vec3 i,vec3 c,float x,float n,float R,out vec3 r,out float y)" + "{" + "vec3 m=e-v,o=dot(m,i)*i-m;" + "i=m+o*saturate(s/length(o));" + "o=normalize(i);" + "m=normalize(f+o);" + "R=length(i);" + "float p=max(dot(d,o),0.);" + "y=pow(saturate(1.-pow(R/20.,4.)),2.)/(R*R+1.);" + "y*=h(Ray(v+d*2e-4,o));" + "float a=n*n;" + "R=saturate(a+s/(2.*R));" + "r=C(c,max(dot(m,f),0.));" + "m=C(max(dot(d,m),0.),a,R)*t(x,p,n)*r;" + "return vec4(m,p);" + "}" + "vec4 a(vec3 v,vec3 d,vec3 f,vec3 i,vec3 x,float m,float n,float s,out vec3 r,out float o)" + "{" + "vec4 e=vec4(0);" + "vec3 p=R-v,l=y-v;" + "s=length(p);" + "float w=length(l);" + "e.w=2.*saturate(dot(d,p)/(2.*s)+dot(d,l)/(2.*w))/(s*w+dot(p,l)+2.);" + "l-=p;" + "w=dot(i,l);" + "s=length(l);" + "vec3 z=p+l*saturate((dot(i,p)*w-dot(p,l))/(s*s-w*w));" + "i=dot(z,i)*i-z;" + "z+=i*saturate(c/length(i));" + "i=normalize(f+normalize(z));" + "w=length(z);" + "s=w/20.;" + "o=1./(s*s+1.);" + "o*=h(Ray(v+d*2e-4,normalize(p+l*.5)));" + "s=n*n;" + "w=saturate(s+c/(2.*w));" + "r=C(x,dot(i,f));" + "e.xyz=a(max(dot(d,i),0.),s,w)*t(m,e.w,n)*r;" + "return e;" + "}" + "vec4 h(vec3 v,vec3 d,vec3 f,vec3 s,vec3 c,float x,float n,float R,out vec3 r,out float y)" + "{" + "vec4 e=vec4(0);" + "R=dot(cross(i.right,i.up),i.center-v);" + "if(R>0.)" + "return e;" + "vec3 m=i.side1-v,o=i.side2-v,p=i.side3-v,l=i.side4-v;" + "e.w=t(v,m,o,p,l)*.2*(saturate(dot(normalize(m),d))+saturate(dot(normalize(o),d))+saturate(dot(normalize(p),d))+saturate(dot(normalize(l),d))+saturate(dot(normalize(i.center-v),d)));" + "y=h(Ray(v+d*2e-4,normalize(i.center)));" + "Ray w=Ray(v,s);" + "m=w.origin+w.direction*(dot(i.front,i.center-w.origin)/dot(i.front,w.direction))-i.center;" + "vec2 z=vec2(dot(m,i.right),dot(m,i.up));" + "z=min(abs(z),i.halfSize)*sign(z);" + "m=i.center+i.right*z.x+i.up*z.y-v;" + "o=normalize(f+normalize(m));" + "R=n*n;" + "float a=saturate(R+4./(2.*length(m)));" + "r=C(c,dot(o,f));" + "e.xyz=h(max(dot(d,o),0.),R,a)*t(x,e.w,n)*r;" + "return e;" + "}" + "vec3 t(Ray v)" + "{" + "vec3 f=vec3(2,0,0)*t(),s=vec3(6.*sin(d),3,5);" + "R=s-f;" + "y=s+f;" + "t(i);" + "f=vec3(0);" + "vec2 c=C(v);" + "s=v.origin+v.direction*c.x;" + "vec3 m=C(s),n=-v.direction,e=reflect(v.direction,m);" + "float w=max(dot(m,n),0.);" + "vec3 r=o;" + "float z=fract(c.y),F=.88;" + "vec3 u=p;" + "if(c.y>-1.)" + "{" + "if(c.y>2.)" + "r=vec3(.31,.62,.47),z=max(.05,r.x*.5),F=.05,u=l;" + "else if(c.y<.5)" + "return x*64.;" + "vec3 v=mix(u,r,F),d=vec3(0);" + "float i=1.;" + "vec4 R=C(s,m,n,e,v,w,z,F,d,i);" + "d=(1.-d)*(1.-F);" + "vec3 y=vec3(0);" + "float p=1.;" + "vec4 g=a(s,m,n,e,v,w,z,F,y,p);" + "y=(1.-y)*(1.-F);" + "vec3 b=vec3(0);" + "float A=1.;" + "vec4 B=h(s,m,n,e,v,w,z,F,b,A);" + "b=(1.-b)*(1.-F);" + "f=f+(d*.3183098861*r+R.xyz)*256.*R.w*i+(y*.3183098861*r+g.xyz)*512.*g.w*p+(b*.3183098861*r+B.xyz)*64.*B.w*A+r*.025;" + "A=z*z;" + "b=vec3(.1125,.1875,.25)+e.y*.35;" + "Ray D=Ray(s,vec3(0));" + "for(int v=0;v<8;++v)" "{" - "y=1.;" - "break;" + "float d=float(v)/float(8);" + "D.direction=normalize(t(e,2.*acos(-1.)*d)*A+e);" + "vec2 i=a(D);" + "if(floor(i.y)==3.)" + "b=vec3(.1,.3,.2);" + "else if(floor(i.y)==1.)" + "b+=o;" "}" + "b/=float(8);" + "vec2 E=a(z,w);" + "b=b*(v*E.x+E.y)+max(vec3(.754554516862612,.748542953903366,.790921515418539)+vec3(-.083856548007422,.09253350096321,.322764661032516)*m.y+vec3(.308152705331738,.366796330467391,.466698181299906)*m.z+vec3(-.188884931542396,-.277402551592231,-.377844212327557)*m.x,0.)*.3183098861*r;" + "f=(f+b*.84)*x;" "}" - "if(r>1e2)" - "r=0.;" - "return vec3(r,m,y);" - "}" - "float t(vec3 v,vec3 i,float y)" - "{" - "float f=1.,r=.02;" - "for(int c=0;c<6;c++)" - "{" - "if(r>y)" - "break;" - "float m=t(v+r*i).x;" - "f=min(f,m/(4.*r));" - "r+=clamp(m,.1,.8);" - "if(f<-1.)" - "break;" - "}" - "f=max(f,-1.);" - "return.25*(1.+f)*(1.+f)*(2.-f);" - "}" - "vec3 e(vec3 v)" - "{" - "vec2 i=vec2(.01,0);" - "return normalize(vec3(t(v+i.xyy).x-t(v-i.xyy).x,t(v+i.yxy).x-t(v-i.yxy).x,t(v+i.yyx).x-t(v-i.yyx).x));" - "}" - "vec3 e(vec3 v,vec3 i,vec3 f,vec3 r,vec3 c,float m)" - "{" - "v-=f;" - "float y=length(v);" - "v=normalize(v);" - "float n=3./(1.+.09*y+.032*y*y),p=max(dot(c,v),0.);" - "r=normalize(v-r);" - "vec3 e=vec3(.04);" - "e+=(1.-e)*pow(clamp(1.-max(dot(r,v),0.),0.,1.),5.);" - "y=t(f+c*.01,v,y);" - "return(i*p*n+i*pow(max(dot(c,r),0.),mix(128.,8.,m))*n*e)*y;" - "}" - "vec3 e(vec3 v,vec3 f,vec3 i,float y)" - "{" - "float m=.01;" - "vec3 c=vec3(0);" - "if(y==0.)" - "c=vec3(.8314,.2941,.2941),m=.1;" - "else if(y==1.)" - "c=vec3(.6196,.6118,.6118),m=.7;" - "else if(y==2.)" - "c=vec3(.3255,.4784,.3255),m=.2;" - "else if(y==3.)" - "c=vec3(.2471,.3059,.6314),m=1.;" - "else if(y==4.)" - "c=vec3(.9961,1,.9922),m=.1;" - "else if(y==5.)" - "c=vec3(.9961,1,.9922),m=.3;" - "v=vec3(0)+e(vec3(-10,10,0),vec3(.77,.26,.73),v,i,f,m)+e(vec3(0,10,-5),vec3(.08,.62,.75),v,i,f,m)+e(vec3(0,25,0),vec3(.5137,.1961,.7725),v,i,f,m)+vec3(.08,.62,.75)*clamp(dot(f,normalize(vec3(0,1,-3)*vec3(0,-1,-2))),0.,1.)*.8;" - "return c*max(vec3(0),v);" - "}" - "vec3 e(vec2 v,vec3 f)" - "{" - "f=normalize(vec3(0,-1,10)-f);" - "vec3 m=normalize(cross(vec3(0,1,0),f));" - "return normalize(v.x*m+v.y*normalize(cross(f,m))+f);" - "}" - "vec3 e()" - "{" - "vec3 f;" - "{" - "float v=c*.06;" - "f=vec3(sin(v)*15.,30.+cos(v*.5)*5.,cos(v)*15.);" - "}" - "return f;" - "}" - "vec3 e(vec2 v)" - "{" - "vec3 f=e(v,e()),m=vec3(.102,.2431,.3412),y=vec3(0),i=t(e(),f,y);" - "if(i.x>0.)" - "{" - "vec3 v=e(y);" - "m=e(y,v,f,i.y);" - "}" - "return m;" + "return mix(f,vec3(.01,.006,.004),clamp(1.-exp(-c.x*.08),0.,1.));" "}" "void main()" "{" - "vec3 v=e(gl_FragCoord.xy*vec2(.00104166667,.00185185185)-1.);" - "f=vec4(v,1);" + "vec2 d=vec2(1920,1080);" + "d=(2.*gl_FragCoord.xy-d.xy)/d.y;" + "Ray f=t(d);" + "vec3 i=t(f);" + "v=vec4(i,1);" "}"; #endif // FRAGMENT_INL_