| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361 |
- #version 430 core
- #pragma debug(on)
- //#extension GL_NV_shadow_samplers_cube : enable
- //#extension ARB_program_interface_query : enable
- #extension GL_ARB_bindless_texture: require
- layout(location = 0) out vec4 a_outColor;
- layout(location = 1) out vec4 a_outBloom;
- noperspective in vec2 v_texCoords;
- uniform isampler2D u_normals;
- uniform samplerCube u_skyboxFiltered;
- uniform samplerCube u_skyboxIradiance;
- uniform sampler2D u_brdfTexture;
- uniform sampler2DArrayShadow u_cascades;
- uniform sampler2DArrayShadow u_spotShadows;
- uniform samplerCubeArrayShadow u_pointShadows;
- uniform isampler2D u_materialIndex;
- uniform sampler2D u_textureUV;
- uniform sampler2D u_lastFrameTexture;
- uniform sampler2D u_positionViewSpace;
- uniform isampler2D u_textureDerivates;
- uniform int u_hasLastFrameTexture;
- //uniform sampler2D u_textureDerivates;
- uniform mat4 u_cameraProjection;
- uniform mat4 u_view;
- uniform mat4 u_inverseView;
- uniform vec3 u_eyePosition;
- uniform int u_transparentPass;
- struct MaterialStruct
- {
- vec4 kd;
- vec4 rma; //last component emmisive
-
- //float kdr; //= 1;
- //float kdg; //= 1;
- //float kdb; //= 1;
- //float roughness;
- //float metallic;
- //float ao; //one means full light
- //layout(bindless_sampler) sampler2D albedoSampler;
- //layout(bindless_sampler) sampler2D rmaSampler;
- //layout(bindless_sampler) sampler2D emmissiveSampler;
- //vec2 notUsed;
- uvec4 firstBIndlessSamplers; // xy albedoSampler, zw rmaSampler
- uvec2 secondBIndlessSamplers; // xy emmissiveSampler
- int rmaLoaded;
- int notUsed;
- };
- readonly layout(std140) buffer u_material
- {
- MaterialStruct mat[];
- };
- layout (std140) uniform u_lightPassData
- {
- vec4 ambientColor;
- float bloomTresshold;
- int lightSubScater;
- float exposure;
- int skyBoxPresent;
- float SSR_minRayStep;
- int SSR_maxSteps;
- int SSR_numBinarySearchSteps;
- float SSR_maxRayStep;
- float SSR_maxRayDelta;
- }lightPassData;
- struct PointLight
- {
- vec3 positions;
- float dist;
- vec3 color;
- float attenuation;
- int castShadowsIndex;
- float hardness;
- int castShadows;
- int changedThisFrame;
- };
- readonly restrict layout(std140) buffer u_pointLights
- {
- PointLight light[];
- };
- uniform int u_pointLightCount;
- struct DirectionalLight
- {
- vec3 direction;
- int castShadowsIndex;
- int changedThisFrame; //not used here
- int castShadows;
- int notUsed1;
- int notUsed2;
- vec4 color; //w is a hardness exponent
- mat4 firstLightSpaceMatrix;
- mat4 secondLightSpaceMatrix;
- mat4 thirdLightSpaceMatrix;
- };
- readonly restrict layout(std140) buffer u_directionalLights
- {
- DirectionalLight dLight[];
- };
- uniform int u_directionalLightCount;
- struct SpotLight
- {
- vec4 position; //w = cos(half angle)
- vec4 direction; //w dist
- vec4 color; //w attenuation
- float hardness;
- int shadowIndex;
- int castShadows;
- int changedThisFrame; //not used in the gpu
- float near;
- float far;
- float notUsed1;
- float notUsed2;
- mat4 lightSpaceMatrix;
- };
- readonly restrict layout(std140) buffer u_spotLights
- {
- SpotLight spotLights[];
- };
- uniform int u_spotLightCount;
- const float PI = 3.14159265359;
- //todo reduce
- const float randomNumbers[100] = float[100](
- 0.05535, 0.22262, 0.93768, 0.80063, 0.40089, 0.49459, 0.44997, 0.27060, 0.58789, 0.61765,
- 0.87949, 0.38913, 0.23154, 0.27249, 0.93448, 0.71567, 0.26940, 0.32226, 0.73918, 0.30905,
- 0.98754, 0.82585, 0.84031, 0.60059, 0.56027, 0.10819, 0.55848, 0.95612, 0.88034, 0.94950,
- 0.53892, 0.86421, 0.84131, 0.39158, 0.25861, 0.10192, 0.19673, 0.25165, 0.68675, 0.79157,
- 0.94730, 0.36948, 0.27978, 0.66377, 0.38935, 0.93795, 0.83168, 0.01452, 0.51242, 0.12272,
- 0.61045, 0.34752, 0.13781, 0.92361, 0.73422, 0.31213, 0.55513, 0.81074, 0.56166, 0.31797,
- 0.09507, 0.50049, 0.44248, 0.38244, 0.58468, 0.32327, 0.61830, 0.67908, 0.16011, 0.82861,
- 0.36502, 0.12052, 0.28872, 0.73448, 0.51443, 0.99355, 0.75244, 0.22432, 0.95501, 0.90914,
- 0.37992, 0.61330, 0.49202, 0.69464, 0.14831, 0.51697, 0.34620, 0.55315, 0.41602, 0.49807,
- 0.15133, 0.07372, 0.75259, 0.59642, 0.35652, 0.60051, 0.08879, 0.59271, 0.29388, 0.69505
- );
- const float INFINITY = 1.f/0.f;
- float attenuationFunctionNotClamped(float x, float r, float p)
- {
- float p4 = p*p*p*p;
- float power = pow(x/r, p4);
- float rez = (1-power);
- rez = rez * rez;
-
- return rez;
- }
- //n normal
- //h halfway vector
- //a roughness (1 rough, 0 glossy)
- //this gets the amount of specular light reflected
- float DistributionGGX(vec3 N, vec3 H, float roughness)
- {
- //GGX/Trowbridge-Reitz
- // a^2
- // ------------------------
- // PI ((N*H)^2 (a^2-1)+1)^2
- float a = roughness*roughness;
- float a2 = a*a;
- float NdotH = max(dot(N, H), 0.0);
- float NdotH2 = NdotH*NdotH;
-
- float denom = (NdotH2 * (a2 - 1.0) + 1.0);
- denom = PI * denom * denom;
-
- return a2 / max(denom, 0.0000001);
- }
- float GeometrySchlickGGX(float NdotV, float roughness)
- {
- //float r = (roughness + 1.0);
- //float k = (r*r) / 8.0; //disney
- float k = roughness*roughness / 2;
- float num = NdotV;
- float denom = NdotV * (1.0 - k) + k;
-
- return num / max(denom, 0.0000001);
- }
-
- //oclude light that is hidded begind small geometry roughnesses
- float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
- {
- float NdotV = max(dot(N, V), 0.0);
- float NdotL = max(dot(N, L), 0.0);
- float ggx2 = GeometrySchlickGGX(NdotV, roughness);
- float ggx1 = GeometrySchlickGGX(NdotL, roughness);
-
- return ggx1 * ggx2;
- }
- //cosTheta is the dot between the normal and halfway
- //ratio between specular and diffuse reflection
- vec3 fresnelSchlick(float cosTheta, vec3 F0)
- {
- return F0 + (1.0 - F0) * pow(max(1.0 - cosTheta, 0.0), 5.0);
- }
- vec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness)
- {
- return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(max(1.0 - cosTheta, 0.0), 5.0);
- }
- vec3 fSpecular(vec3 normal, vec3 halfwayVec, vec3 viewDir,
- vec3 lightDirection, float dotNVclamped, float roughness, vec3 F)
- {
- //fCook-Torrance
- float NDF = DistributionGGX(normal, halfwayVec, roughness);
- float G = GeometrySmith(normal, viewDir, lightDirection, roughness);
- float denominator = 4.0 * dotNVclamped
- * max(dot(normal, lightDirection), 0.0);
- vec3 specular = (NDF * G * F) / max(denominator, 0.001);
- return specular;
- }
- vec3 fDiffuse(vec3 color)
- {
- //fLambert
- return color.rgb / PI;
- }
- vec3 fDiffuseOrenNayar(vec3 color, float roughness, vec3 L, vec3 V, vec3 N)
- {
- float a = roughness;
- float a2 = a*a;
- float cosi = max(dot(L, N), 0);
- float cosr = max(dot(V, N), 0);
- float sini = sqrt(1-cosi*cosi);
- float sinr = sqrt(1-cosr*cosr);
- float tani = sini/cosi;
- float tanr = sinr/cosr;
- float A = 1 - 0.5 * a2/(a2 + 0.33);
- float B = 0.45*a2/(a2+0.09);
-
- float sinAlpha = max(sini, sinr);
- float tanBeta = min(tani, tanr);
- return color.rgb * (A + (B* max(0, dot(L,reflect(V,N))) * sinAlpha * tanBeta )) / PI;
- }
- //https://mimosa-pudica.net/improved-oren-nayar.html
- vec3 fDiffuseOrenNayar2(vec3 color, float roughness, vec3 L, vec3 V, vec3 N)
- {
- float a = roughness;
- float a2 = a*a;
- //vec3 A = 1.f/PI * (1 - 0.5 * a2/(a2 + 0.33) + 0.17*color*a2/(a2+0.13));
- //float B = 0.45*a2/(a2+0.09);
- float A = 1.0/(PI+(PI/2.0-2/3.0)*a);
- float B = PI/(PI+(PI/2.0-2/3.0)*a);
- float s = dot(L,N) - dot(N,L)*dot(N,V);
- float t;
- if(s <= 0)
- t = 1;
- else
- t = max(dot(N,L), dot(N,V));
- return color * (A + B * s/t);
- }
- vec3 computePointLightSource(vec3 lightDirection, float metallic, float roughness, in vec3 lightColor, in vec3 worldPosition,
- in vec3 viewDir, in vec3 color, in vec3 normal, in vec3 F0)
- {
- //lightDirection = direction to light
- //vec3 lightDirection = normalize(lightPosition - worldPosition);
- float dotNVclamped = clamp(dot(normal, viewDir), 0.0, 0.99);
- vec3 halfwayVec = normalize(lightDirection + viewDir);
-
- vec3 radiance = lightColor; //here the first component is the light color
-
- vec3 F = fresnelSchlick(max(dot(halfwayVec, viewDir), 0.0), F0);
- vec3 specular = fSpecular(normal, halfwayVec, viewDir, lightDirection, dotNVclamped, roughness, F);
- vec3 kS = F; //this is the specular contribution
- vec3 kD = vec3(1.0) - kS; //the difuse is the remaining specular
- kD *= 1.0 - metallic; //metallic surfaces are darker
-
- //vec3 diffuse = fDiffuse(color.rgb);
- //vec3 diffuse = fDiffuseOrenNayar(color.rgb, roughness, lightDirection, viewDir, normal);
- vec3 diffuse = fDiffuseOrenNayar2(color.rgb, roughness, lightDirection, viewDir, normal);
-
- float NdotL = max(dot(normal, lightDirection), 0.0);
- return (kD * diffuse + specular) * radiance * NdotL;
- }
- float testShadowValue(sampler2DArrayShadow map, vec2 coords, float currentDepth, float bias, int index)
- {
- //float closestDepth = texture(map, coords).r;
- //return (currentDepth - bias) < closestDepth ? 1.0 : 0.0;
- return texture(map, vec4(coords, index, currentDepth-bias)).r;
- }
- //https://www.youtube.com/watch?v=yn5UJzMqxj0&ab_channel=thebennybox
- //float sampleShadowLinear(sampler2DArrayShadow map, vec2 coords, vec2 texelSize, float currentDepth, float bias)
- //{
- //
- // vec2 pixelPos = coords / texelSize + vec2(0.5);
- // vec2 fracPart = fract(pixelPos);
- // vec2 startTexel = (pixelPos-fracPart) * texelSize;
- //
- // float blTexture = testShadowValue(map, startTexel, currentDepth, bias).r;
- // float brTexture = testShadowValue(map, startTexel + vec2(texelSize.x, 0), currentDepth, bias).r;
- // float tlTexture = testShadowValue(map, startTexel + vec2(0, texelSize.y), currentDepth, bias).r;
- // float trTexture = testShadowValue(map, startTexel + texelSize, currentDepth, bias).r;
- //
- // float mixA = mix(blTexture, tlTexture, fracPart.y);
- // float mixB = mix(brTexture, trTexture, fracPart.y);
- //
- // return mix(mixA, mixB, fracPart.x);
- //}
- //https://developer.download.nvidia.com/cg/sincos.html
- void sincos(float a, out float s, out float c)
- {
- s = sin(a);
- c = cos(a);
- }
- //https://www.gamedev.net/tutorials/programming/graphics/contact-hardening-soft-shadows-made-fast-r4906/
- vec2 vogelDiskSample(int sampleIndex, int samplesCount, float phi)
- {
- float GoldenAngle = 2.4f;
- float r = sqrt(sampleIndex + 0.5f) / sqrt(samplesCount);
- float theta = sampleIndex * GoldenAngle + phi;
- float sine, cosine;
- sincos(theta, sine, cosine);
-
- return vec2(r * cosine, r * sine);
- }
- //https://www.gamedev.net/tutorials/programming/graphics/contact-hardening-soft-shadows-made-fast-r4906/
- float InterleavedGradientNoise(vec2 position_screen)
- {
- vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f);
- return fract(magic.z * fract(dot(position_screen, magic.xy)));
- }
- float shadowCalculation(vec3 projCoords, float bias, sampler2DArrayShadow shadowMap, int index)
- {
- // keep the shadow at 1.0 when outside or close to the far_plane region of the light's frustum.
- if(projCoords.z > 0.99995)
- return 1.f;
- //if(projCoords.z < 0)
- // return 1.f;
- //float closestDepth = texture(shadowMap, projCoords.xy).r;
- float currentDepth = projCoords.z;
- //todo move
- vec2 texelSize = 1.0 / textureSize(shadowMap, 0).xy;
- float shadow = 0.0;
- bool fewSamples = false;
- int kernelHalf = 1;
- int kernelSize = kernelHalf*2 + 1;
- int kernelSize2 = kernelSize*kernelSize;
- //float receiverDepth = currentDepth;
- //float averageBlockerDepth = texture(sampler2DArray(shadowMap), vec3(projCoords.xy, index)).r;
- //float penumbraSize = 4.f * (receiverDepth - averageBlockerDepth) / averageBlockerDepth;
- float penumbraSize = 1.f;
- //standard implementation
- if(false)
- {
- float shadowValueAtCentre = 0;
- //optimization
- if(false)
- {
- float offsetSize = kernelSize/2;
- const int OFFSETS = 4;
- vec2 offsets[OFFSETS] =
- {
- vec2(offsetSize,offsetSize),
- vec2(-offsetSize,offsetSize),
- vec2(offsetSize,-offsetSize),
- vec2(-offsetSize,-offsetSize),
- };
- fewSamples = true;
-
- float s1 = testShadowValue(shadowMap, projCoords.xy,
- currentDepth, bias, index);
- shadowValueAtCentre = s1;
- for(int i=0;i<OFFSETS; i++)
- {
- float s2 = testShadowValue(shadowMap, projCoords.xy + offsets[i] * texelSize * 2,
- currentDepth, bias, index);
- if(s1 != s2)
- {
- fewSamples = false;
- break;
- }
- s1 = s2;
- }
- }
- if(fewSamples)
- {
-
- shadow = shadowValueAtCentre;
- }else
- {
- for(int y = -kernelHalf; y <= kernelHalf; ++y)
- {
- for(int x = -kernelHalf; x <= kernelHalf; ++x)
- {
- vec2 offset = vec2(x, y);
-
- if(false)
- {
- int randomOffset1 = (x*kernelSize) + y;
- int randomOffset2 = randomOffset1 + kernelSize2;
- offset += vec2(randomNumbers[randomOffset1, randomOffset2]);
- }
-
- if(false)
- {
- float u = (offset.x + kernelHalf)/float(kernelSize-1);
- float v = (offset.y + kernelHalf)/float(kernelSize-1);
- offset.x = sqrt(v) * cos(2*PI * u)* kernelHalf;
- offset.y = sqrt(v) * sin(2*PI * u)* kernelHalf;
- }
-
- vec2 finalOffset = offset * texelSize * penumbraSize;
- //float newDepth = sqrt(currentDepth*currentDepth + finalOffset.x*finalOffset.x + finalOffset.y * finalOffset.y);
-
- float s = testShadowValue(shadowMap, projCoords.xy + finalOffset,
- currentDepth, bias, index);
-
- //float s = sampleShadowLinear(shadowMap, projCoords.xy + vec2(x, y) * offset,
- // texelSize, currentDepth, bias);
-
- shadow += s;
- }
- }
- shadow /= kernelSize2;
- // texture(map, vec4(coords, index, currentDepth-bias)).r;
- //for(int y = -kernelHalf; y <= kernelHalf; ++y)
- //{
- // for(int x = -kernelHalf; x <= kernelHalf; ++x)
- // {
- // vec2 offset = vec2(x, y);
- // vec2 finalOffset = offset * texelSize * 2;
- //
- // vec4 shadowGather =
- // textureGather(shadowMap, vec3(projCoords.xy+finalOffset,
- // index), currentDepth-bias);
- //
- // shadow += shadowGather.r;
- // shadow += shadowGather.g;
- // shadow += shadowGather.b;
- // shadow += shadowGather.a;
- //
- // }
- //}
- //
- //shadow /= 4*kernelSize2;
-
- }
- }else
- {
-
- int sampleSize = 9;
- int checkSampleSize = 5;
- float size = 1.5;
- float noise = InterleavedGradientNoise(v_texCoords) * 2 * PI;
- for(int i=sampleSize-1; i>=sampleSize-checkSampleSize; i--)
- {
- vec2 offset = vogelDiskSample(i, sampleSize, noise);
- vec2 finalOffset = offset * texelSize * size;
-
- float s = testShadowValue(shadowMap, projCoords.xy + finalOffset,
- currentDepth, bias, index);
- shadow += s;
- }
- //optimization
- if(true && (shadow == 0 || shadow == checkSampleSize))
- {
- shadow /= checkSampleSize;
- }else
- {
- for(int i=sampleSize-checkSampleSize-1; i>=0; i--)
- {
- vec2 offset = vogelDiskSample(i, sampleSize, noise);
- vec2 finalOffset = offset * texelSize * size;
-
- float s = testShadowValue(shadowMap, projCoords.xy + finalOffset,
- currentDepth, bias, index);
- shadow += s;
- }
- shadow /= sampleSize;
- }
- }
-
- return clamp(shadow, 0, 1);
- }
- float shadowCalculationLinear(vec3 projCoords, vec3 normal, vec3 lightDir, sampler2DArrayShadow shadowMap, int index)
- {
- float bias = max((10.f/1024.f) * (1.0 - dot(normal, -lightDir)), 3.f/1024.f);
- return shadowCalculation(projCoords, bias, shadowMap, index);
- }
- float linearizeDepth(float depth, float near, float far)
- {
- float z = depth * 2.0 - 1.0; // Back to NDC
- return (2.0 * near * far) / (far + near - z * (far - near));
- }
- float nonLinearDepth(float depth, float near, float far)
- {
- return ((1.f/depth) - (1.f/near)) / ((1.f/far) - (1.f/near));
- }
- //https://developer.nvidia.com/gpugems/gpugems2/part-ii-shading-lighting-and-shadows/chapter-17-efficient-soft-edged-shadows-using
- float shadowCalculationLogaritmic(vec3 projCoords, vec3 normal, vec3 lightDir,
- sampler2DArrayShadow shadowMap, int index, float near, float far)
- {
- //float bias = max((0.00005) * (1.0 - dot(normal, -lightDir)), 0.00001);
- float bias = max((0.01f) * (1.0 - dot(normal, -lightDir)), 0.001f);
-
- //bias = nonLinearDepth(bias, near, far);
- float currentDepth = projCoords.z;
- float liniarizedDepth = linearizeDepth(currentDepth, near, far);
- liniarizedDepth += bias;
- float biasedLogDepth = nonLinearDepth(liniarizedDepth, near, far);
- bias = biasedLogDepth - currentDepth;
- bias += 0.00003f;
- return shadowCalculation(projCoords, bias, shadowMap, index);
- }
- vec3 getProjCoords(in mat4 matrix, in vec3 pos)
- {
- vec4 p = matrix * vec4(pos,1);
- vec3 r = p .xyz / p .w;
- r = r * 0.5 + 0.5;
- return r;
- }
- void generateTangentSpace(in vec3 v, out vec3 outUp, out vec3 outRight)
- {
- vec3 up = vec3(0.f, 1.f, 0.f);
- if (v == up)
- {
- outRight = vec3(1, 0, 0);
- }
- else
- {
- outRight = normalize(cross(v, up));
- }
- outUp = normalize(cross(outRight, v));
- }
- float pointShadowCalculation(vec3 pos, vec3 normal, int index)
- {
- vec3 fragToLight = pos - light[index].positions;
- vec3 lightDir = normalize(fragToLight);
- //float closestDepth = texture(u_pointShadows, lightDir).r;
- //closestDepth *= light[index].dist; //multiply by far plane
-
- float bias = max((60.f/512.f) * (1.0 - dot(normal, -lightDir)), 35.f/512.f);
- //float shadow = currentDepth - bias < closestDepth ? 1.0 : 0.0;
- float shadow = 0.0;
- vec3 tangent;
- vec3 coTangent;
- generateTangentSpace(lightDir, tangent, coTangent);
- float texel = 1.f / textureSize(u_pointShadows, 0).x;
- //todo fix for even numbers
- int kernel = 5;
- int kernelHalf = kernel/2;
- for(int y = -kernelHalf; y<=kernelHalf; y++)
- {
- for(int x = -kernelHalf; x<=kernelHalf; x++)
- {
- vec3 fragToLight = pos - light[index].positions;
- fragToLight += 6*x * texel * tangent;
- fragToLight += 6*y * texel * coTangent;
- float currentDepth = length(fragToLight);
-
- float value = texture(u_pointShadows,
- vec4(fragToLight, light[index].castShadowsIndex),
- (currentDepth-bias)/light[index].dist ).r;
- shadow += value;
- }
-
- }
- if(shadow <3)
- {
- shadow = 0;
- }
- shadow /= (kernel * kernel);
- //float samples = 5.0;
- //float offset = 0.1;
- //for(float x = -offset; x < offset; x += offset / (samples * 0.5))
- //{
- // for(float y = -offset; y < offset; y += offset / (samples * 0.5))
- // {
- // for(float z = -offset; z < offset; z += offset / (samples * 0.5))
- // {
- // vec3 fragToLight = pos - light[index].positions;
- // float currentDepth = length(fragToLight + vec3(x,y,z));
- //
- //
- // float value = texture(u_pointShadows,
- // vec4(fragToLight + vec3(x, y, z), light[index].castShadowsIndex),
- // (currentDepth-bias)/light[index].dist ).r;
- // shadow += value;
- //
- // }
- // }
- //}
- //shadow /= (samples * samples * samples);
- shadow = clamp(shadow, 0, 1);
- //if(shadow < 0.1)
- //{
- // shadow = 0;
- //}
- return shadow;
- }
- float cascadedShadowCalculation(vec3 pos, vec3 normal, vec3 lightDir, int index)
- {
-
- vec3 firstProjCoords = getProjCoords(dLight[index].firstLightSpaceMatrix, pos);
- vec3 secondProjCoords = getProjCoords(dLight[index].secondLightSpaceMatrix, pos);
- vec3 thirdProjCoords = getProjCoords(dLight[index].thirdLightSpaceMatrix, pos);
- if(
- firstProjCoords.x < 0.98 &&
- firstProjCoords.x > 0.01 &&
- firstProjCoords.y < 0.98 &&
- firstProjCoords.y > 0.01 &&
- firstProjCoords.z < 0.98 &&
- firstProjCoords.z > 0
- )
- {
- //return 0;
- firstProjCoords.y /= 3.f;
- return shadowCalculationLinear(firstProjCoords, normal, lightDir, u_cascades, index);
- }else
- if(
- secondProjCoords.x > 0 &&
- secondProjCoords.x < 1 &&
- secondProjCoords.y > 0 &&
- secondProjCoords.y < 1 &&
- //secondProjCoords.z > 0 &&
- secondProjCoords.z < 0.98
- )
- {
- //return 1;
- secondProjCoords.y /= 3.f;
- secondProjCoords.y += 1.f / 3.f;
- return shadowCalculationLinear(secondProjCoords, normal, lightDir, u_cascades, index);
- }
- else
- {
- //return 2;
- thirdProjCoords.y /= 3.f;
- thirdProjCoords.y += 2.f / 3.f;
- return shadowCalculationLinear(thirdProjCoords, normal, lightDir, u_cascades, index);
- }
- }
- vec4 fromuShortToFloat2(ivec4 a)
- {
- vec4 ret = a;
- //[0 65536] -> [0 1]
- ret /= 65536;
- //[0 1] -> [0 4]
- ret *= 4.f;
- //[0 4] -> [-2 2]
- ret -= 2.f;
- return ret;
- }
- vec3 fromuShortToFloat(ivec3 a)
- {
- vec3 ret = a;
- //[0 65536] -> [0 1]
- ret /= 65536;
- //[0 1] -> [0 2]
- ret *= 2.f;
- //[0 2] -> [-1 1]
- ret -= 1.f;
- return normalize(ret);
- }
- //////////////////////////////////////////////
- //https://imanolfotia.com/blog/1
- //https://github.com/ImanolFotia/Epsilon-Engine/blob/master/bin/Release/shaders/SSR.glsl
- //SSR
- //vec3 PositionFromDepth(float depth) {
- // float z = depth * 2.0 - 1.0;
- //
- // vec4 clipSpacePosition = vec4(TexCoords * 2.0 - 1.0, z, 1.0);
- // vec4 viewSpacePosition = invprojection * clipSpacePosition;
- //
- // // Perspective division
- // viewSpacePosition /= viewSpacePosition.w;
- //
- // return viewSpacePosition.xyz;
- //}
- vec2 BinarySearch(inout vec3 dir, inout vec3 hitCoord,
- inout float dDepth, vec2 oldValue)
- {
- float depth;
- vec4 projectedCoord;
-
- vec2 foundProjectedCoord = oldValue;
- for(int i = 0; i < lightPassData.SSR_numBinarySearchSteps; i++)
- {
- projectedCoord = u_cameraProjection * vec4(hitCoord, 1.0);
- projectedCoord.xy /= projectedCoord.w;
- projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5;
-
- //depth = textureLod(gPosition, projectedCoord.xy, 2).z;
- depth = texture(u_positionViewSpace, projectedCoord.xy).z;
-
- if(depth < -1000) //-INFINITY
- continue;
- foundProjectedCoord = projectedCoord.xy;
- dDepth = hitCoord.z - depth;
- dir *= 0.5;
- if(dDepth > 0.0)
- hitCoord += dir;
- else
- hitCoord -= dir;
- }
- projectedCoord = u_cameraProjection * vec4(hitCoord, 1.0);
- projectedCoord.xy /= projectedCoord.w;
- projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5;
-
- depth = texture(u_positionViewSpace, projectedCoord.xy).z;
-
- if(!(depth < -1000))
- {
- foundProjectedCoord = projectedCoord.xy;
- }
- return foundProjectedCoord.xy;
- }
- vec2 RayMarch(vec3 dir, inout vec3 hitCoord, out float dDepth, vec3 worldNormal, vec3 viewDir)
- {
- dir *= mix(lightPassData.SSR_minRayStep, lightPassData.SSR_maxRayStep, abs(dot(worldNormal, viewDir)));//maxRayStep;
-
- float depth;
- vec4 projectedCoord;
-
- for(int i = 0; i < lightPassData.SSR_maxSteps; i++)
- {
- hitCoord += dir;
-
- projectedCoord = u_cameraProjection * vec4(hitCoord, 1.0);
- projectedCoord.xy /= projectedCoord.w;
- projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5;
-
- if(projectedCoord.x > 1.f || projectedCoord.y > 1.f
- ||projectedCoord.x < -1.f || projectedCoord.y < -1.f
- )
- {
- break;
- }
- //depth = textureLod(gPosition, projectedCoord.xy, 2).z;
- depth = texture(u_positionViewSpace, projectedCoord.xy).z;
- if(depth > 1000.0)
- continue;
-
- if(depth < -1000) //-INFINITY
- continue;
- dDepth = hitCoord.z - depth;
- if((dir.z - dDepth) < lightPassData.SSR_maxRayStep && dDepth <= 0.0)
- {
- vec2 Result;
- Result = BinarySearch(dir, hitCoord, dDepth, projectedCoord.xy);
- //Result = projectedCoord.xy;
- if(dDepth < -lightPassData.SSR_maxRayDelta)
- {
- break; //fail //project to infinity :(((
- }
-
- depth = texture(u_positionViewSpace, Result.xy).z;
- if(depth < -10000)
- {break;}//fail
- return Result;
- }
-
- }
-
- //signal fail
- dDepth = -INFINITY;
- return vec2(0,0);
- }
- uvec3 murmurHash33(uvec3 src) {
- const uint M = 0x5bd1e995u;
- uvec3 h = uvec3(1190494759u, 2147483647u, 3559788179u);
- src *= M; src ^= src>>24u; src *= M;
- h *= M; h ^= src.x; h *= M; h ^= src.y; h *= M; h ^= src.z;
- h ^= h>>13u; h *= M; h ^= h>>15u;
- return h;
- }
- // 3 outputs, 3 inputs
- vec3 hash33(vec3 src) {
- uvec3 h = murmurHash33(floatBitsToUint(src));
- return uintBitsToFloat(h & 0x007fffffu | 0x3f800000u) - 1.0;
- }
- vec3 computeJitt(vec3 wp, vec2 Resolution, vec3 viewNormal, float Roughness)
- {
- vec2 NoiseScale = Resolution / 4.0;
- //vec3 random = hash33(wp + iTime);//vec3(texture(noiseTexture, (TexCoords.xy*10.0) + (1.0 - iTime)).rgb);
- vec3 random = hash33(wp);//vec3(texture(noiseTexture, (TexCoords.xy*10.0) + (1.0 - iTime)).rgb);
- random = dot(random, viewNormal) > 0.0 ? random : -random;
- float factor = Roughness*0.20;
- vec3 hs = random * 2.0 - 1.0;
- vec3 jitt = hs * factor;
- return vec3(jitt);
- }
- vec3 SSR(vec3 viewPos, vec3 N, float metallic, vec3 F,
- out float mixFactor, float roughness, vec3 wp, vec3 viewDir, vec3 viewSpaceNormal, vec2 rezolution)
- {
- mixFactor = 0;
- // Reflection vector
- vec3 reflected = normalize(reflect(normalize(viewPos), viewSpaceNormal));
- //vec3 reflected = R; //todo check
-
- //found = true;
- //return viewPos;
- if(reflected.z > 0){return vec3(0,0,0);}
- vec3 hitPos = viewPos;
- float dDepth;
- //vec3 wp = vec3(vec4(viewPos, 1.0) * invView);
- //vec3 jitt = mix(vec3(0.0), vec3(hash(wp)), spec);
-
- //todo test
- vec3 jitt = computeJitt(wp, rezolution, viewSpaceNormal, roughness); //use roughness for specular factor
- //vec3 jitt = vec3(0.0);
- vec2 coords = RayMarch( normalize((vec3(jitt) + reflected) *
- max(lightPassData.SSR_minRayStep, -viewPos.z)), hitPos, dDepth,
- N, viewDir);
-
- if(dDepth < -1000){return vec3(0);}
- vec2 dCoords = smoothstep(0.2, 0.6, abs(vec2(0.5, 0.5) - coords.xy));
-
- float screenEdgefactor = clamp(1.0 - (dCoords.x + dCoords.y), 0.0, 1.0);
- float ReflectionMultiplier =
- screenEdgefactor *
- -reflected.z;
-
- if(ReflectionMultiplier <= 0.001)
- {
- return vec3(0.f);
- }
- // Get color
- vec3 lastFrameColor = textureLod(u_lastFrameTexture, coords.xy, 0).rgb;
- //vec3 SSR = lastFrameColor * clamp(ReflectionMultiplier, 0.0, 0.9) * F;
- vec3 SSR = lastFrameColor;
- mixFactor = clamp(ReflectionMultiplier, 0.0, 1.f);
- return SSR;
- }
- ////////////////////////////////////////////
- //normal in world space, viewDir, wp = world space position
- //F = freshnell
- //todo send F
- vec3 computeAmbientTerm(vec3 N, vec3 V, vec3 F0, float roughness, vec3 R,
- float metallic, vec3 albedo, vec3 wp, vec3 viewPos, vec3 viewSpaceNormal, vec2 rezolution)
- {
- vec3 gammaAmbient = pow(lightPassData.ambientColor.rgb, vec3(2.2)); //just the static ambient color
- vec3 ambient = vec3(0);
-
- float dotNVClamped = clamp(dot(N, V), 0.0, 0.99);
- vec3 F = fresnelSchlickRoughness(dotNVClamped, F0, roughness);
- vec3 kS = F;
- vec3 irradiance = vec3(0,0,0); //diffuse
- vec3 radiance = vec3(0,0,0); //specular
- vec2 brdf = vec2(0,0);
- vec2 brdfVec = vec2(dotNVClamped, roughness);
- float mixFactor = 0;
- if(u_hasLastFrameTexture != 0) //ssr
- {
- radiance = SSR(viewPos, N, metallic, F, mixFactor, roughness, wp, V, viewSpaceNormal, rezolution);
- }
- if(lightPassData.skyBoxPresent != 0)
- {
-
- irradiance = texture(u_skyboxIradiance, N).rgb * gammaAmbient; //this color is coming directly at the object
- // sample both the pre-filter map and the BRDF lut and combine them together as per the Split-Sum approximation to get the IBL specular part.
- const float MAX_REFLECTION_LOD = 4.0;
-
- if(mixFactor < 0.999)
- {
- radiance = mix(textureLod(u_skyboxFiltered, R, roughness * MAX_REFLECTION_LOD).rgb * gammaAmbient, radiance, mixFactor);
- }
- //brdfVec.y = 1 - brdfVec.y;
- brdf = texture(u_brdfTexture, brdfVec).rg;
-
- }else
- {
-
- radiance = mix(gammaAmbient, radiance, mixFactor);
- irradiance = gammaAmbient ; //this color is coming directly at the object
- //brdfVec.y = 1 - brdfVec.y;
- brdf = texture(u_brdfTexture, brdfVec).rg;
- }
- if(lightPassData.lightSubScater == 0)
- {
- vec3 kD = 1.0 - kS;
- kD *= 1.0 - metallic;
-
- vec3 diffuse = irradiance * albedo;
-
- vec3 specular = radiance * (F * brdf.x + brdf.y);
- //no multiple scattering
- ambient = (kD * diffuse + specular);
- }else
- {
- //http://jcgt.org/published/0008/01/03/
- // Multiple scattering version
- vec3 FssEss = kS * brdf.x + brdf.y;
- float Ess = brdf.x + brdf.y;
- float Ems = 1-Ess;
- vec3 Favg = F0 + (1-F0)/21;
- vec3 Fms = FssEss*Favg/(1-(1-Ess)*Favg);
- // Dielectrics
- vec3 Edss = 1 - (FssEss + Fms * Ems);
- vec3 kD = albedo * Edss;
- // Multiple scattering version
- ambient = FssEss * radiance + (Fms*Ems+kD) * irradiance;
- }
-
- return ambient;
- }
- void main()
- {
- int materialIndex = textureLod(u_materialIndex, v_texCoords, 0).r;
- if(materialIndex == 0)
- {
- //no material, no alpha component that is important
- //discard ??
- //discard;
- if(u_transparentPass != 0)
- {
- discard;
- }else
- {
- a_outColor = vec4(0,0,0,0);
- a_outBloom = vec4(0,0,0,1);
- return;
- }
- //albedoAlpha = vec4(0,0,0,0);
- }
- //vec3 pos = texture(u_positions, v_texCoords).xyz;
- vec3 posViewSpace = texture(u_positionViewSpace, v_texCoords).xyz;
- vec3 pos = vec3(u_inverseView * vec4(posViewSpace,1));
- if(posViewSpace.z == -INFINITY){discard;}
- vec3 normal = fromuShortToFloat(texture(u_normals, v_texCoords).xyz);
- vec3 viewSpaceNormal = normalize( vec3(transpose(inverse(mat3(u_view))) * normal));
- vec2 sampledUV = texture(u_textureUV, v_texCoords).xy;
- ivec4 sampledDerivatesInt = texture(u_textureDerivates, v_texCoords).xyzw;
- vec4 sampledDerivates = fromuShortToFloat2(sampledDerivatesInt);
- //vec4 sampledDerivates = texture(u_textureDerivates, v_texCoords).xyzw;
- vec2 rezolution = textureSize(u_lastFrameTexture, 0);
- vec4 albedoAlpha = vec4(0,0,0,0);
- vec3 emissive = vec3(0,0,0);
-
- //vec4 sampledDerivates = texture(u_textureDerivates, v_texCoords).xyzw;
-
- vec3 material = vec3(0,0,0);
- {
- uvec2 albedoSampler = mat[materialIndex-1].firstBIndlessSamplers.xy;
- if(albedoSampler.x == 0 && albedoSampler.y == 0)
- {
- albedoAlpha.rgba = vec4(1,1,1,1); //multiply after with color;
- }else
- {
- albedoAlpha =
- textureGrad(sampler2D(albedoSampler), sampledUV.xy,
- sampledDerivates.xy, sampledDerivates.zw).rgba;
- }
- albedoAlpha.rgb *= pow( vec3(mat[materialIndex-1].kd), vec3(1.0/2.2) );
- albedoAlpha.a *= mat[materialIndex-1].kd.a;
- uvec2 emmisiveSampler = mat[materialIndex-1].secondBIndlessSamplers.xy;
- if(emmisiveSampler.x == 0 && emmisiveSampler.y == 0)
- {
- emissive.rgb = albedoAlpha.rgb;
- }else
- {
- emissive =
- textureGrad(sampler2D(emmisiveSampler), sampledUV.xy,
- sampledDerivates.xy, sampledDerivates.zw).rgb;
- }
- emissive.rgb *= mat[materialIndex-1].rma.a;
- emissive = pow(emissive , vec3(2.2)).rgb; //gamma corection
-
- uvec2 rmaSampler = mat[materialIndex-1].firstBIndlessSamplers.zw;
- if(rmaSampler.x == 0 && rmaSampler.y == 0 && mat[materialIndex-1].rmaLoaded != 0)
- {
- material.r = mat[materialIndex-1].rma.r;
- material.g = mat[materialIndex-1].rma.g;
- material.b = mat[materialIndex-1].rma.b;
- }
- else
- {
- vec3 materialData = textureGrad(sampler2D(rmaSampler), sampledUV.xy,
- sampledDerivates.xy, sampledDerivates.zw).rgb;
- int roughnessPrezent = mat[materialIndex-1].rmaLoaded & 0x4;
- int metallicPrezent = mat[materialIndex-1].rmaLoaded & 0x2;
- int ambientPrezent = mat[materialIndex-1].rmaLoaded & 0x1;
- if(roughnessPrezent != 0)
- {
- material.r = materialData.r;
- }else
- {
- material.r = mat[materialIndex-1].rma.r;
- }
- if(metallicPrezent != 0)
- {
- material.g = materialData.g;
- }else
- {
- material.g = mat[materialIndex-1].rma.g;
- }
- if(ambientPrezent != 0)
- {
- material.b = materialData.b;
- }else
- {
- material.b = mat[materialIndex-1].rma.b;
- }
- }
- }
-
- //calculate BRDF
- vec3 albedo = albedoAlpha.rgb;
- albedo = pow(albedo , vec3(2.2)).rgb; //gamma corection
- float roughness = clamp(material.r, 0.09, 0.99);
- float metallic = clamp(material.g, 0.0, 0.98);
- float ambientOcclution = material.b;
- vec3 viewDir = normalize(u_eyePosition - pos); //towards hemisphere
- //vec3 I = normalize(pos - u_eyePosition); //looking direction (towards eye)
- vec3 R = reflect(-viewDir, normal); //reflected vector
- //vec3 skyBoxSpecular = texture(u_skybox, R).rgb; //this is the reflected color
- vec3 Lo = vec3(0,0,0); //this is the accumulated light
-
- vec3 F0 = vec3(0.04);
- F0 = mix(F0, albedo.rgb, vec3(metallic));
- //foreach point light
- for(int i=0; i<u_pointLightCount;i++)
- {
- vec3 lightPosition = light[i].positions.xyz;
- vec3 lightColor = light[i].color.rgb;
- vec3 lightDirection = normalize(lightPosition - pos);
- float currentDist = distance(lightPosition, pos);
- if(currentDist >= light[i].dist)
- {
- continue;
- }
- float attenuation = attenuationFunctionNotClamped(currentDist, light[i].dist, light[i].attenuation);
- float shadow = 1.f;
- if(light[i].castShadows != 0)
- {
- shadow = pointShadowCalculation(pos, normal, i);
- shadow = pow(shadow, light[i].hardness);
- }
- Lo += computePointLightSource(lightDirection, metallic, roughness, lightColor,
- pos, viewDir, albedo, normal, F0) * attenuation * shadow;
- }
- for(int i=0; i<u_directionalLightCount; i++)
- {
-
- vec3 lightDirection = dLight[i].direction.xyz;
- vec3 lightColor = dLight[i].color.rgb;
- float shadow = 1;
-
- if(dLight[i].castShadows != 0)
- {
- int castShadowInd = dLight[i].castShadowsIndex;
- shadow = cascadedShadowCalculation(pos, normal, lightDirection, castShadowInd);
- shadow = pow(shadow, dLight[i].color.w);
- }
- //if(shadow == 0)
- //{
- // albedo.rgb = vec3(1,0,0);
- //}else if(shadow >= 0.9 && shadow <= 1.1)
- //{
- // albedo.rgb = vec3(0,1,0);
- //}else
- //{
- // albedo.rgb = vec3(0,0,1);
- //}
- //shadow = 1;
- Lo += computePointLightSource(-lightDirection, metallic, roughness, lightColor,
- pos, viewDir, albedo, normal, F0) * shadow;
- }
- for(int i=0; i<u_spotLightCount; i++)
- {
- vec3 lightPosition = spotLights[i].position.xyz;
- vec3 lightColor = spotLights[i].color.rgb;
- vec3 spotLightDirection = spotLights[i].direction.xyz;
- vec3 lightDirection = -normalize(lightPosition - pos);
- float angle = spotLights[i].position.w;
- float dist = spotLights[i].direction.w;
- float at = spotLights[i].color.w;
- float dotAngle = dot(normalize(vec3(pos - lightPosition)), spotLightDirection);
- float currentDist = distance(lightPosition, pos);
- if(currentDist >= dist)
- {
- continue;
- }
- if(dotAngle > angle && dotAngle > 0)
- {
- float attenuation = attenuationFunctionNotClamped(currentDist, dist, at);
- //attenuation = 1;
- float smoothingVal = 0.01; //
- float innerAngle = angle + smoothingVal;
- float smoothing = clamp((dotAngle-angle)/smoothingVal,0.0,1.0);
- //smoothing = 1;
- vec3 shadowProjCoords = getProjCoords(spotLights[i].lightSpaceMatrix, pos);
-
- float shadow = 1;
-
- if(spotLights[i].castShadows != 0)
- {
- shadow = shadowCalculationLogaritmic(shadowProjCoords, normal, lightDirection,
- u_spotShadows, spotLights[i].shadowIndex, spotLights[i].near, spotLights[i].far);
- shadow = pow(shadow, spotLights[i].hardness);
- }
- smoothing = pow(smoothing, spotLights[i].hardness);
- Lo += computePointLightSource(-lightDirection, metallic, roughness, lightColor,
- pos, viewDir, albedo, normal, F0) * smoothing * attenuation * shadow;
- }
- }
- vec3 color = Lo + computeAmbientTerm(normal, viewDir, F0, roughness, R, metallic,
- albedo, pos, posViewSpace, viewSpaceNormal, rezolution)
- * ambientOcclution;
- //vec3 hdrCorrectedColor = color;
- //hdrCorrectedColor.rgb = vec3(1.0) - exp(-hdrCorrectedColor.rgb * lightPassData.exposure);
- //hdrCorrectedColor.rgb = pow(hdrCorrectedColor.rgb, vec3(1.0/2.2));
- //float lightIntensity = dot(hdrCorrectedColor.rgb, vec3(0.2126, 0.7152, 0.0722));
- ////float lightIntensity = dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));
- //gama correction and hdr is done and applied in the post process step
- if(u_transparentPass != 0)
- {
- float a = albedoAlpha.a;
- a = 1-a;
- a *= dot(viewDir, normal);
- a = 1-a;
- a_outColor = vec4(color.rgb + emissive.rgb, a);
- a_outBloom = vec4(emissive.rgb, a);
- }else
- {
- a_outColor = vec4(color.rgb + emissive.rgb, 1);
- a_outBloom = vec4(emissive.rgb, 1);
- }
-
-
- //a_outColor.rgb = vec3(albedoAlpha);
- //a_outColor.rgb = material.bbb;
- //a_outColor.rgba = vec4(albedoAlpha.aaa, 1);
- //a_outColor.rgb = vec3(ssaof, ssaof, ssaof);
- }
|