diff --git a/.gitignore b/.gitignore index def65a2a..3ff62272 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ -armorpaint.blend1 -build_armorpaint/ build/ -khafile.js -Sources/Main.hx -*.pyc .vscode +Assets/blend/scene.blend1 +Assets/blend/khafile.js +Assets/blend/build_scene +Assets/blend/Sources diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..e442d57d --- /dev/null +++ b/.gitmodules @@ -0,0 +1,15 @@ +[submodule "Libraries/armory"] + path = Libraries/armory + url = https://github.com/armory3d/armory +[submodule "Libraries/iron"] + path = Libraries/iron + url = https://github.com/armory3d/iron +[submodule "Libraries/iron_format"] + path = Libraries/iron_format + url = https://github.com/armory3d/iron_format +[submodule "Libraries/zui"] + path = Libraries/zui + url = https://github.com/armory3d/zui +[submodule "Kha"] + path = Kha + url = https://github.com/armory3d/Kha diff --git a/Libraries/paint/blender.py b/Assets/blend/Libraries/paint/blender.py similarity index 100% rename from Libraries/paint/blender.py rename to Assets/blend/Libraries/paint/blender.py diff --git a/armorpaint.blend b/Assets/blend/scene.blend similarity index 100% rename from armorpaint.blend rename to Assets/blend/scene.blend diff --git a/Kha b/Kha new file mode 160000 index 00000000..7ee54c73 --- /dev/null +++ b/Kha @@ -0,0 +1 @@ +Subproject commit 7ee54c73fd81c28f1f73c80ab730621971674855 diff --git a/Libraries/armory b/Libraries/armory new file mode 160000 index 00000000..585abb1b --- /dev/null +++ b/Libraries/armory @@ -0,0 +1 @@ +Subproject commit 585abb1b902e47c698906e9749347b6f4c667a3a diff --git a/Libraries/iron b/Libraries/iron new file mode 160000 index 00000000..6b916442 --- /dev/null +++ b/Libraries/iron @@ -0,0 +1 @@ +Subproject commit 6b916442248424c2c95de7d37e36f658bec60718 diff --git a/Libraries/iron_format b/Libraries/iron_format new file mode 160000 index 00000000..99cbb8ca --- /dev/null +++ b/Libraries/iron_format @@ -0,0 +1 @@ +Subproject commit 99cbb8ca69436b25404e27d2918ccf45e53c976d diff --git a/Libraries/zui b/Libraries/zui new file mode 160000 index 00000000..ec127beb --- /dev/null +++ b/Libraries/zui @@ -0,0 +1 @@ +Subproject commit ec127bebc28f4fd986522508b4ce51d2741b88c0 diff --git a/Sources/Main.hx b/Sources/Main.hx new file mode 100644 index 00000000..1f649f49 --- /dev/null +++ b/Sources/Main.hx @@ -0,0 +1,22 @@ +package ; +class Main { + public static inline var projectName = 'ArmorPaint'; + public static inline var projectPackage = 'arm'; + public static inline var voxelgiVoxelSize = 2.0 / 256; + public static inline var voxelgiHalfExtents = 1; + public static function main() { + iron.object.BoneAnimation.skinMaxBones = 50; + armory.system.Starter.main( + 'Scene', + 0, + true, + true, + true, + 1600, + 900, + 1, + true, + arm.renderpath.RenderPathCreator.get + ); + } +} diff --git a/compiled/Assets/Scene.arm b/compiled/Assets/Scene.arm new file mode 100644 index 00000000..28a0591d Binary files /dev/null and b/compiled/Assets/Scene.arm differ diff --git a/compiled/Hlsl/Material_voxel.vert.glsl b/compiled/Hlsl/Material_voxel.vert.glsl new file mode 100644 index 00000000..b04e4247 Binary files /dev/null and b/compiled/Hlsl/Material_voxel.vert.glsl differ diff --git a/compiled/Hlsl/Material_voxel.vert.hlsl b/compiled/Hlsl/Material_voxel.vert.hlsl new file mode 100644 index 00000000..ef31bf74 --- /dev/null +++ b/compiled/Hlsl/Material_voxel.vert.hlsl @@ -0,0 +1,9 @@ + uniform float4x4 W; + struct SPIRV_Cross_Input { float4 pos : TEXCOORD0; }; + struct SPIRV_Cross_Output { float4 svpos : SV_POSITION; }; + SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) { + SPIRV_Cross_Output stage_output; + stage_output.svpos.xyz = mul(float4(stage_input.pos.xyz, 1.0), W).xyz / float3(1, 1, 1); + stage_output.svpos.w = 1.0; + return stage_output; + } diff --git a/compiled/Hlsl/armdefault_voxel.frag.glsl b/compiled/Hlsl/armdefault_voxel.frag.glsl new file mode 100644 index 00000000..81ef8494 Binary files /dev/null and b/compiled/Hlsl/armdefault_voxel.frag.glsl differ diff --git a/compiled/Hlsl/armdefault_voxel.frag.hlsl b/compiled/Hlsl/armdefault_voxel.frag.hlsl new file mode 100644 index 00000000..ab150d24 --- /dev/null +++ b/compiled/Hlsl/armdefault_voxel.frag.hlsl @@ -0,0 +1,8 @@ + RWTexture3D voxels; + struct SPIRV_Cross_Input { float3 wpos : TEXCOORD0; }; + struct SPIRV_Cross_Output { float4 FragColor : SV_TARGET0; }; + void main(SPIRV_Cross_Input stage_input) { + if (abs(stage_input.wpos.z) > 1.0 || abs(stage_input.wpos.x) > 1 || abs(stage_input.wpos.y) > 1) return; + voxels[int3(256, 256, 256) * (stage_input.wpos * 0.5 + 0.5)] = 1.0; + + } diff --git a/compiled/Hlsl/armdefault_voxel.geom.glsl b/compiled/Hlsl/armdefault_voxel.geom.glsl new file mode 100644 index 00000000..55486399 Binary files /dev/null and b/compiled/Hlsl/armdefault_voxel.geom.glsl differ diff --git a/compiled/Hlsl/armdefault_voxel.geom.hlsl b/compiled/Hlsl/armdefault_voxel.geom.hlsl new file mode 100644 index 00000000..fffa7273 --- /dev/null +++ b/compiled/Hlsl/armdefault_voxel.geom.hlsl @@ -0,0 +1,22 @@ + struct SPIRV_Cross_Input { float4 svpos : SV_POSITION; }; + struct SPIRV_Cross_Output { float3 wpos : TEXCOORD0; float4 svpos : SV_POSITION; }; + [maxvertexcount(3)] + void main(triangle SPIRV_Cross_Input stage_input[3], inout TriangleStream output) { + float3 p1 = stage_input[1].svpos.xyz - stage_input[0].svpos.xyz; + float3 p2 = stage_input[2].svpos.xyz - stage_input[0].svpos.xyz; + float3 p = abs(cross(p1, p2)); + for (int i = 0; i < 3; ++i) { + SPIRV_Cross_Output stage_output; + stage_output.wpos = stage_input[i].svpos.xyz; + if (p.z > p.x && p.z > p.y) { + stage_output.svpos = float4(stage_input[i].svpos.x, stage_input[i].svpos.y, 0.0, 1.0); + } + else if (p.x > p.y && p.x > p.z) { + stage_output.svpos = float4(stage_input[i].svpos.y, stage_input[i].svpos.z, 0.0, 1.0); + } + else { + stage_output.svpos = float4(stage_input[i].svpos.x, stage_input[i].svpos.z, 0.0, 1.0); + } + output.Append(stage_output); + } + } diff --git a/compiled/Hlsl/armdefault_voxel.vert.glsl b/compiled/Hlsl/armdefault_voxel.vert.glsl new file mode 100644 index 00000000..b04e4247 Binary files /dev/null and b/compiled/Hlsl/armdefault_voxel.vert.glsl differ diff --git a/compiled/Hlsl/armdefault_voxel.vert.hlsl b/compiled/Hlsl/armdefault_voxel.vert.hlsl new file mode 100644 index 00000000..ef31bf74 --- /dev/null +++ b/compiled/Hlsl/armdefault_voxel.vert.hlsl @@ -0,0 +1,9 @@ + uniform float4x4 W; + struct SPIRV_Cross_Input { float4 pos : TEXCOORD0; }; + struct SPIRV_Cross_Output { float4 svpos : SV_POSITION; }; + SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) { + SPIRV_Cross_Output stage_output; + stage_output.svpos.xyz = mul(float4(stage_input.pos.xyz, 1.0), W).xyz / float3(1, 1, 1); + stage_output.svpos.w = 1.0; + return stage_output; + } diff --git a/compiled/Shaders/Gizmo_overlay.frag.glsl b/compiled/Shaders/Gizmo_overlay.frag.glsl new file mode 100644 index 00000000..e6a5d9ab --- /dev/null +++ b/compiled/Shaders/Gizmo_overlay.frag.glsl @@ -0,0 +1,23 @@ +#version 450 +#include "compiled.inc" +in vec3 vcolor; +in vec3 wnormal; +out vec4 fragColor; +void main() { +vec3 n = normalize(wnormal); + vec3 basecol; + float roughness; + float metallic; + float occlusion; + float specular; + float emission; + vec3 Attribute_Color_res = vcolor; + basecol = Attribute_Color_res; + roughness = 0.0; + metallic = 0.0; + occlusion = 1.0; + specular = 0.0; + emission = 0.0; + fragColor = vec4(basecol, 1.0); + fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2)); +} diff --git a/compiled/Shaders/Gizmo_overlay.vert.glsl b/compiled/Shaders/Gizmo_overlay.vert.glsl new file mode 100644 index 00000000..e3b26770 --- /dev/null +++ b/compiled/Shaders/Gizmo_overlay.vert.glsl @@ -0,0 +1,14 @@ +#version 450 +in vec4 pos; +in vec2 nor; +in vec4 col; +out vec3 vcolor; +out vec3 wnormal; +uniform mat3 N; +uniform mat4 WVP; +void main() { +vec4 spos = vec4(pos.xyz, 1.0); +vcolor = col.rgb; + wnormal = normalize(N * vec3(nor.xy, pos.w)); + gl_Position = WVP * spos; +} diff --git a/compiled/Shaders/Material2_mesh.frag.glsl b/compiled/Shaders/Material2_mesh.frag.glsl new file mode 100644 index 00000000..0fe559b6 --- /dev/null +++ b/compiled/Shaders/Material2_mesh.frag.glsl @@ -0,0 +1,31 @@ +#version 450 +#include "compiled.inc" +#include "std/gbuffer.glsl" +in vec3 wnormal; +in vec4 wvpposition; +in vec4 prevwvpposition; +out vec4 fragColor[3]; +void main() { +vec3 n = normalize(wnormal); + vec3 basecol; + float roughness; + float metallic; + float occlusion; + float specular; + float emission; + basecol = vec3(0.800000011920929, 0.800000011920929, 0.800000011920929); + roughness = 0.0; + metallic = 0.0; + occlusion = 1.0; + specular = 0.0; + emission = 0.0; + n /= (abs(n.x) + abs(n.y) + abs(n.z)); + n.xy = n.z >= 0.0 ? n.xy : octahedronWrap(n.xy); + float matid = 0.0; + if (emission > 0) { basecol *= emission; matid = 1.0; } + fragColor[0] = vec4(n.xy, packFloat(metallic, roughness), matid); + fragColor[1] = vec4(basecol, packFloat2(occlusion, specular)); + vec2 posa = (wvpposition.xy / wvpposition.w) * 0.5 + 0.5; + vec2 posb = (prevwvpposition.xy / prevwvpposition.w) * 0.5 + 0.5; + fragColor[2].rg = vec2(posa - posb); +} diff --git a/compiled/Shaders/Material_mesh.frag.glsl b/compiled/Shaders/Material_mesh.frag.glsl new file mode 100644 index 00000000..0c841f72 --- /dev/null +++ b/compiled/Shaders/Material_mesh.frag.glsl @@ -0,0 +1,38 @@ +#version 450 +#include "compiled.inc" +#include "std/gbuffer.glsl" +in vec2 texCoord; +in vec3 wnormal; +in vec4 wvpposition; +in vec4 prevwvpposition; +out vec4 fragColor[3]; +uniform sampler2D ImageTexture; +void main() { +vec3 n = normalize(wnormal); + vec3 basecol; + float roughness; + float metallic; + float occlusion; + float specular; + float emission; + float Mix_fac = 0.0; + vec3 RGB_Color_res = vec3(0.2176000028848648, 0.2176000028848648, 0.2176000028848648); + vec4 ImageTexture_store = texture(ImageTexture, texCoord.xy); + vec3 ImageTexture_Color_res = ImageTexture_store.rgb; + vec3 Mix_Color_res = mix(RGB_Color_res, ImageTexture_Color_res, Mix_fac); + basecol = Mix_Color_res; + roughness = 0.4000000059604645; + metallic = 0.0; + occlusion = 1.0; + specular = 1.0; + emission = 0.0; + n /= (abs(n.x) + abs(n.y) + abs(n.z)); + n.xy = n.z >= 0.0 ? n.xy : octahedronWrap(n.xy); + float matid = 0.0; + if (emission > 0) { basecol *= emission; matid = 1.0; } + fragColor[0] = vec4(n.xy, packFloat(metallic, roughness), matid); + fragColor[1] = vec4(basecol, packFloat2(occlusion, specular)); + vec2 posa = (wvpposition.xy / wvpposition.w) * 0.5 + 0.5; + vec2 posb = (prevwvpposition.xy / prevwvpposition.w) * 0.5 + 0.5; + fragColor[2].rg = vec2(posa - posb); +} diff --git a/compiled/Shaders/Material_mesh.vert.glsl b/compiled/Shaders/Material_mesh.vert.glsl new file mode 100644 index 00000000..3f361a14 --- /dev/null +++ b/compiled/Shaders/Material_mesh.vert.glsl @@ -0,0 +1,20 @@ +#version 450 +in vec4 pos; +in vec2 nor; +in vec2 tex; +out vec2 texCoord; +out vec3 wnormal; +out vec4 wvpposition; +out vec4 prevwvpposition; +uniform mat3 N; +uniform mat4 WVP; +uniform float texUnpack; +uniform mat4 prevWVP; +void main() { +vec4 spos = vec4(pos.xyz, 1.0); +texCoord = tex * texUnpack; + wnormal = normalize(N * vec3(nor.xy, pos.w)); + gl_Position = WVP * spos; + wvpposition = gl_Position; + prevwvpposition = prevWVP * spos; +} diff --git a/compiled/Shaders/armdefault_mesh.frag.glsl b/compiled/Shaders/armdefault_mesh.frag.glsl new file mode 100644 index 00000000..f20f1fae --- /dev/null +++ b/compiled/Shaders/armdefault_mesh.frag.glsl @@ -0,0 +1,31 @@ +#version 450 +#include "compiled.inc" +#include "std/gbuffer.glsl" +in vec3 wnormal; +in vec4 wvpposition; +in vec4 prevwvpposition; +out vec4 fragColor[3]; +void main() { +vec3 n = normalize(wnormal); + vec3 basecol; + float roughness; + float metallic; + float occlusion; + float specular; + float emission; + basecol = vec3(0.800000011920929, 0.800000011920929, 0.800000011920929); + roughness = 0.25; + metallic = 0.0; + occlusion = 1.0; + specular = 0.5; + emission = 0.0; + n /= (abs(n.x) + abs(n.y) + abs(n.z)); + n.xy = n.z >= 0.0 ? n.xy : octahedronWrap(n.xy); + float matid = 0.0; + if (emission > 0) { basecol *= emission; matid = 1.0; } + fragColor[0] = vec4(n.xy, packFloat(metallic, roughness), matid); + fragColor[1] = vec4(basecol, packFloat2(occlusion, specular)); + vec2 posa = (wvpposition.xy / wvpposition.w) * 0.5 + 0.5; + vec2 posb = (prevwvpposition.xy / prevwvpposition.w) * 0.5 + 0.5; + fragColor[2].rg = vec2(posa - posb); +} diff --git a/compiled/Shaders/armdefault_mesh.vert.glsl b/compiled/Shaders/armdefault_mesh.vert.glsl new file mode 100644 index 00000000..67b451ef --- /dev/null +++ b/compiled/Shaders/armdefault_mesh.vert.glsl @@ -0,0 +1,16 @@ +#version 450 +in vec4 pos; +in vec2 nor; +out vec3 wnormal; +out vec4 wvpposition; +out vec4 prevwvpposition; +uniform mat3 N; +uniform mat4 WVP; +uniform mat4 prevWVP; +void main() { +vec4 spos = vec4(pos.xyz, 1.0); + wnormal = normalize(N * vec3(nor.xy, pos.w)); + gl_Position = WVP * spos; + wvpposition = gl_Position; + prevwvpposition = prevWVP * spos; +} diff --git a/compiled/Shaders/bloom_pass.frag.glsl b/compiled/Shaders/bloom_pass.frag.glsl new file mode 100644 index 00000000..e4862975 --- /dev/null +++ b/compiled/Shaders/bloom_pass.frag.glsl @@ -0,0 +1,19 @@ +#version 450 + +#include "compiled.inc" + +uniform sampler2D tex; + +in vec2 texCoord; +out vec4 fragColor; + +void main() { + vec3 col = textureLod(tex, texCoord, 0.0).rgb; + float brightness = dot(col, vec3(0.2126, 0.7152, 0.0722)); + if (brightness > bloomThreshold) { + fragColor.rgb = col; + } + else { + fragColor.rgb = vec3(0.0); + } +} diff --git a/compiled/Shaders/blur_adaptive_pass.frag.glsl b/compiled/Shaders/blur_adaptive_pass.frag.glsl new file mode 100644 index 00000000..5af30a67 --- /dev/null +++ b/compiled/Shaders/blur_adaptive_pass.frag.glsl @@ -0,0 +1,32 @@ +// Exclusive to SSR for now +#version 450 + +#include "compiled.inc" +#include "std/gbuffer.glsl" + +uniform sampler2D tex; +uniform sampler2D gbuffer0; // Roughness + +uniform vec2 dirInv; + +in vec2 texCoord; +out vec4 fragColor; + +void main() { + float roughness = unpackFloat(textureLod(gbuffer0, texCoord, 0.0).b).y; + // if (roughness == 0.0) { // Always blur for now, non blured output can produce noise + // fragColor.rgb = textureLod(tex, texCoord).rgb; + // return; + // } + if (roughness >= 0.8) { // No reflections + fragColor.rgb = textureLod(tex, texCoord, 0.0).rgb; + return; + } + + fragColor.rgb = textureLod(tex, texCoord + dirInv * 2.5, 0.0).rgb; + fragColor.rgb += textureLod(tex, texCoord + dirInv * 1.5, 0.0).rgb; + fragColor.rgb += textureLod(tex, texCoord, 0.0).rgb; + fragColor.rgb += textureLod(tex, texCoord - dirInv * 1.5, 0.0).rgb; + fragColor.rgb += textureLod(tex, texCoord - dirInv * 2.5, 0.0).rgb; + fragColor.rgb /= vec3(5.0); +} diff --git a/compiled/Shaders/blur_edge_pass.frag.glsl b/compiled/Shaders/blur_edge_pass.frag.glsl new file mode 100644 index 00000000..20bea605 --- /dev/null +++ b/compiled/Shaders/blur_edge_pass.frag.glsl @@ -0,0 +1,44 @@ +// Exclusive to SSAO for now +#version 450 + +#include "compiled.inc" +#include "std/gbuffer.glsl" + +uniform sampler2D tex; +uniform sampler2D gbuffer0; + +uniform vec2 dirInv; // texStep + +in vec2 texCoord; +out float fragColor; + +// const float blurWeights[5] = float[] (0.227027, 0.1945946, 0.1216216, 0.054054, 0.016216); +const float blurWeights[10] = float[] (0.132572, 0.125472, 0.106373, 0.08078, 0.05495, 0.033482, 0.018275, 0.008934, 0.003912, 0.001535); +const float discardThreshold = 0.95; + +void main() { + vec3 nor = getNor(textureLod(gbuffer0, texCoord, 0.0).rg); + + fragColor = textureLod(tex, texCoord, 0.0).r * blurWeights[0]; + float weight = blurWeights[0]; + + for (int i = 1; i < 8; ++i) { + float posadd = i;// + 0.5; + + vec3 nor2 = getNor(textureLod(gbuffer0, texCoord + i * dirInv, 0.0).rg); + float influenceFactor = step(discardThreshold, dot(nor2, nor)); + float col = textureLod(tex, texCoord + posadd * dirInv, 0.0).r; + float w = blurWeights[i] * influenceFactor; + fragColor += col * w; + weight += w; + + nor2 = getNor(textureLod(gbuffer0, texCoord - i * dirInv, 0.0).rg); + influenceFactor = step(discardThreshold, dot(nor2, nor)); + col = textureLod(tex, texCoord - posadd * dirInv, 0.0).r; + w = blurWeights[i] * influenceFactor; + fragColor += col * w; + weight += w; + } + + fragColor = fragColor / weight; +} \ No newline at end of file diff --git a/compiled/Shaders/blur_gaus_pass.frag.glsl b/compiled/Shaders/blur_gaus_pass.frag.glsl new file mode 100644 index 00000000..dc77e839 --- /dev/null +++ b/compiled/Shaders/blur_gaus_pass.frag.glsl @@ -0,0 +1,26 @@ +// Exclusive to bloom for now +#version 450 + +#include "compiled.inc" + +uniform sampler2D tex; +uniform vec2 dir; +uniform vec2 screenSize; + +in vec2 texCoord; +out vec4 fragColor; + +const float weight[10] = float[] (0.132572, 0.125472, 0.106373, 0.08078, 0.05495, 0.033482, 0.018275, 0.008934, 0.003912, 0.001535); + +void main() { + vec2 step = (dir / screenSize.xy) * bloomRadius; + fragColor.rgb = textureLod(tex, texCoord, 0.0).rgb * weight[0]; + for (int i = 1; i < 10; i++) { + vec2 s = step * (float(i) + 0.5); + fragColor.rgb += textureLod(tex, texCoord + s, 0.0).rgb * weight[i]; + fragColor.rgb += textureLod(tex, texCoord - s, 0.0).rgb * weight[i]; + } + + fragColor.rgb *= bloomStrength / 5; + fragColor.rgb = min(fragColor.rgb, 64.0); +} diff --git a/compiled/Shaders/compiled.inc b/compiled/Shaders/compiled.inc new file mode 100644 index 00000000..70de4aa5 --- /dev/null +++ b/compiled/Shaders/compiled.inc @@ -0,0 +1,53 @@ +#ifndef _COMPILED_GLSL_ +#define _COMPILED_GLSL_ +#define _EnvTex +#define _EnvStr +#define _Irr +#define _EnvStr +#define _MicroShadowing +#define _Deferred +#define _VoxelCones5 +#define _VoxelShadow +#define _LTC +#define _SinglePoint +#define _SMAA +#define _Veloc +#define _SSAO +#define _gbuffer2 +#define _CGrainStatic +#define _Emission +#define _Brdf +#define _Irr +#define _Rad +#define _CToneFilmic +#define _CVignette +const float PI = 3.1415926535; +const float PI2 = PI * 2.0; +const vec2 shadowmapSize = vec2(0, 0); +const float shadowmapCubePcfSize = 0.001; +const int shadowmapCascades = 1; +const float ssaoRadius = 1.0; +const float ssaoStrength = 1.0; +const float ssaoScale = 20.0; +const int ssgiMaxSteps = 8; +const float ssgiRayStep = 0.005 * 2.0; +const float ssgiStrength = 1.0; +const float bloomThreshold = 1.5; +const float bloomStrength = 3.5; +const float bloomRadius = 3.0; +const float ssrRayStep = 0.04; +const float ssrMinRayStep = 0.05; +const float ssrSearchDist = 5.0; +const float ssrFalloffExp = 5.0; +const float ssrJitter = 0.6; +const float compoVignetteStrength = 0.4; +const ivec3 voxelgiResolution = ivec3(256, 256, 256); +const vec3 voxelgiHalfExtents = vec3(1, 1, 1); +const float voxelgiOcc = 1.0; +const float voxelgiStep = 1.0; +const float voxelgiRange = 2.0; +const float voxelgiOffset = 1.5; +const float voxelgiAperture = 1.2; +const int skinMaxBones = 50; + +#endif // _COMPILED_GLSL_ diff --git a/compiled/Shaders/compositor_pass.frag.glsl b/compiled/Shaders/compositor_pass.frag.glsl new file mode 100644 index 00000000..169defc6 --- /dev/null +++ b/compiled/Shaders/compositor_pass.frag.glsl @@ -0,0 +1,344 @@ +#version 450 + +#include "compiled.inc" +#include "std/tonemap.glsl" +#include "std/math.glsl" +#ifdef _CDOF +#include "std/dof.glsl" +#endif + +uniform sampler2D tex; +#ifdef _CDepth +uniform sampler2D gbufferD; +#endif + +#ifdef _CLensTex +uniform sampler2D lensTexture; +#endif + +#ifdef _CLUT +uniform sampler2D lutTexture; +#endif + +#ifdef _AutoExposure +uniform sampler2D histogram; +#endif + +// #ifdef _CPos +// uniform vec3 eye; +// uniform vec3 eyeLook; +// #endif + +#ifdef _CGlare +uniform vec3 light; +uniform mat4 VP; +uniform vec3 eye; +uniform vec3 eyeLook; +uniform float aspectRatio; +#endif + +#ifdef _CTexStep +uniform vec2 texStep; +#endif + +#ifdef _CGrain +uniform float time; +#endif + +#ifdef _DynRes +uniform float dynamicScale; +#endif + +#ifdef _CCameraProj +uniform vec2 cameraProj; +#endif + +in vec2 texCoord; +// #ifdef _CPos + // in vec3 viewRay; +// #endif +out vec4 fragColor; + +#ifdef _CFog +// const vec3 compoFogColor = vec3(0.5, 0.6, 0.7); +// const float compoFogAmountA = 1.0; // b = 0.01 +// const float compoFogAmountB = 1.0; // c = 0.1 +// vec3 applyFog(vec3 rgb, // original color of the pixel + // float distance, // camera to point distance + // vec3 rayOri, // camera position + // vec3 rayDir) { // camera to point vector + // float fogAmount = compoFogAmountB * exp(-rayOri.y * compoFogAmountA) * (1.0 - exp(-distance * rayDir.y * compoFogAmountA)) / rayDir.y; + // return mix(rgb, compoFogColor, fogAmount); +// } +vec3 applyFog(vec3 rgb, float distance) { + // float fogAmount = 1.0 - exp(-distance * compoFogAmountA); + float fogAmount = 1.0 - exp(-distance * (compoFogAmountA / 100)); + return mix(rgb, compoFogColor, fogAmount); +} +#endif + +vec4 LUTlookup(in vec4 textureColor, in sampler2D lookupTable) { + + //Clamp to prevent weird results + textureColor = clamp(textureColor, 0.0, 1.0); + + mediump float blueColor = textureColor.b * 63.0; + mediump vec2 quad1; + + quad1.y = floor(floor(blueColor) / 8.0); + quad1.x = floor(blueColor) - (quad1.y * 8.0); + + mediump vec2 quad2; + quad2.y = floor(ceil(blueColor) / 8.0); + quad2.x = ceil(blueColor) - (quad2.y * 8.0); + + highp vec2 texelPosition1; + texelPosition1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r); + texelPosition1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g); + + highp vec2 texelPosition2; + texelPosition2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r); + texelPosition2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g); + + lowp vec4 newColor1 = textureLod(lookupTable, texelPosition1, 0.0); + lowp vec4 newColor2 = textureLod(lookupTable, texelPosition2, 0.0); + + lowp vec4 colorGradedResult = mix(newColor1, newColor2, fract(blueColor)); + + return colorGradedResult; + +} + +#ifdef _CVignette +float vignette() { + return (1.0 - compoVignetteStrength) + compoVignetteStrength * pow(16.0 * texCoord.x * texCoord.y * (1.0 - texCoord.x) * (1.0 - texCoord.y), 0.2); +} +#endif + +#ifdef _CGlare +// Based on lense flare implementation by musk +// https://www.shadertoy.com/view/4sX3Rs +vec3 lensflare(vec2 uv, vec2 pos) { + vec2 uvd = uv * (length(uv)); + float f2 = max(1.0/(1.0+32.0*pow(length(uvd+0.8*pos),2.0)),0.0)*0.25; + float f22 = max(1.0/(1.0+32.0*pow(length(uvd+0.85*pos),2.0)),0.0)*0.23; + float f23 = max(1.0/(1.0+32.0*pow(length(uvd+0.9*pos),2.0)),0.0)*0.21; + + vec2 uvx = mix(uv, uvd, -0.5); + float f4 = max(0.01-pow(length(uvx+0.4*pos),2.4),0.0)*6.0; + float f42 = max(0.01-pow(length(uvx+0.45*pos),2.4),0.0)*5.0; + float f43 = max(0.01-pow(length(uvx+0.5*pos),2.4),0.0)*3.0; + + uvx = mix(uv, uvd, -0.4); + float f5 = max(0.01-pow(length(uvx+0.2*pos),5.5),0.0)*2.0; + float f52 = max(0.01-pow(length(uvx+0.4*pos),5.5),0.0)*2.0; + float f53 = max(0.01-pow(length(uvx+0.6*pos),5.5),0.0)*2.0; + + uvx = mix(uv, uvd, -0.5); + float f6 = max(0.01-pow(length(uvx-0.3*pos),1.6),0.0)*6.0; + float f62 = max(0.01-pow(length(uvx-0.325*pos),1.6),0.0)*3.0; + float f63 = max(0.01-pow(length(uvx-0.35*pos),1.6),0.0)*5.0; + + vec3 c = vec3(0.0); + c.r += f2 + f4 + f5 + f6; + c.g += f22 + f42 + f52 + f62; + c.b += f23 + f43 + f53 + f63; + return c; +} +#endif + +void main() { + vec2 texCo = texCoord; +#ifdef _DynRes + texCo *= dynamicScale; +#endif + +#ifdef _CFishEye + const float fishEyeStrength = -0.01; + const vec2 m = vec2(0.5, 0.5); + vec2 d = texCo - m; + float r = sqrt(dot(d, d)); + float power = (2.0 * PI / (2.0 * sqrt(dot(m, m)))) * fishEyeStrength; + float bind; + if (power > 0.0) { bind = sqrt(dot(m, m)); } + else { bind = m.x; } + if (power > 0.0) { + texCo = m + normalize(d) * tan(r * power) * bind / tan(bind * power); + } + else { + texCo = m + normalize(d) * atan(r * -power * 10.0) * bind / atan(-power * bind * 10.0); + } +#endif + +#ifdef _CDepth + float depth = textureLod(gbufferD, texCo, 0.0).r * 2.0 - 1.0; +#endif + +#ifdef _CFXAA + const float FXAA_REDUCE_MIN = 1.0 / 128.0; + const float FXAA_REDUCE_MUL = 1.0 / 8.0; + const float FXAA_SPAN_MAX = 8.0; + + vec2 tcrgbNW = (texCo + vec2(-1.0, -1.0) * texStep); + vec2 tcrgbNE = (texCo + vec2(1.0, -1.0) * texStep); + vec2 tcrgbSW = (texCo + vec2(-1.0, 1.0) * texStep); + vec2 tcrgbSE = (texCo + vec2(1.0, 1.0) * texStep); + vec2 tcrgbM = vec2(texCo); + + vec3 rgbNW = textureLod(tex, tcrgbNW, 0.0).rgb; + vec3 rgbNE = textureLod(tex, tcrgbNE, 0.0).rgb; + vec3 rgbSW = textureLod(tex, tcrgbSW, 0.0).rgb; + vec3 rgbSE = textureLod(tex, tcrgbSE, 0.0).rgb; + vec3 rgbM = textureLod(tex, tcrgbM, 0.0).rgb; + vec3 luma = vec3(0.299, 0.587, 0.114); + float lumaNW = dot(rgbNW, luma); + float lumaNE = dot(rgbNE, luma); + float lumaSW = dot(rgbSW, luma); + float lumaSE = dot(rgbSE, luma); + float lumaM = dot(rgbM, luma); + float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); + float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); + + vec2 dir; + dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); + dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); + + float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * + (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); + + float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); + dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), + max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), + dir * rcpDirMin)) * texStep; + + vec3 rgbA = 0.5 * ( + textureLod(tex, texCo + dir * (1.0 / 3.0 - 0.5), 0.0).rgb + + textureLod(tex, texCo + dir * (2.0 / 3.0 - 0.5), 0.0).rgb); + vec3 rgbB = rgbA * 0.5 + 0.25 * ( + textureLod(tex, texCo + dir * -0.5, 0.0).rgb + + textureLod(tex, texCo + dir * 0.5, 0.0).rgb); + + float lumaB = dot(rgbB, luma); + if ((lumaB < lumaMin) || (lumaB > lumaMax)) fragColor = vec4(rgbA, 1.0); + else fragColor = vec4(rgbB, 1.0); + +#else + + #ifdef _CDOF + fragColor = vec4(dof(texCo, depth, tex, gbufferD, texStep, cameraProj), 1.0); + #else + fragColor = textureLod(tex, texCo, 0.0); + #endif + +#endif + +#ifdef _CSharpen + vec3 col1 = textureLod(tex, texCo + vec2(-texStep.x, -texStep.y) * 1.5, 0.0).rgb; + vec3 col2 = textureLod(tex, texCo + vec2(texStep.x, -texStep.y) * 1.5, 0.0).rgb; + vec3 col3 = textureLod(tex, texCo + vec2(-texStep.x, texStep.y) * 1.5, 0.0).rgb; + vec3 col4 = textureLod(tex, texCo + vec2(texStep.x, texStep.y) * 1.5, 0.0).rgb; + vec3 colavg = (col1 + col2 + col3 + col4) * 0.25; + fragColor.rgb += (fragColor.rgb - colavg) * compoSharpenStrength; +#endif + +#ifdef _CFog + // if (depth < 1.0) { + // vec3 pos = getPos(depth, cameraProj); + // float dist = distance(pos, eye); + float dist = linearize(depth, cameraProj); + // vec3 eyedir = eyeLook;// normalize(eye + pos); + // fragColor.rgb = applyFog(fragColor.rgb, dist, eye, eyedir); + fragColor.rgb = applyFog(fragColor.rgb, dist); + // } +#endif + +#ifdef _CGlare + if (dot(light, eyeLook) > 0.0) { // Facing light + vec4 lndc = VP * vec4(light, 1.0); + lndc.xy /= lndc.w; + vec2 lss = lndc.xy * 0.5 + 0.5; + float lssdepth = linearize(textureLod(gbufferD, lss, 0.0).r * 2.0 - 1.0, cameraProj); + float lightDistance = distance(eye, light); + if (lightDistance <= lssdepth) { + vec2 lensuv = texCo * 2.0 - 1.0; + lensuv.x *= aspectRatio; + vec3 lensflarecol = vec3(1.4, 1.2, 1.0) * lensflare(lensuv, lndc.xy); + fragColor.rgb += lensflarecol; + } + } +#endif + +#ifdef _CGrain + // const float compoGrainStrength = 4.0; + float x = (texCo.x + 4.0) * (texCo.y + 4.0) * (time * 10.0); + fragColor.rgb += vec3(mod((mod(x, 13.0) + 1.0) * (mod(x, 123.0) + 1.0), 0.01) - 0.005) * compoGrainStrength; +#endif + +#ifdef _CGrainStatic + float x = (texCo.x + 4.0) * (texCo.y + 4.0) * 10.0; + fragColor.rgb += vec3(mod((mod(x, 13.0) + 1.0) * (mod(x, 123.0) + 1.0), 0.01) - 0.005) * 0.09; +#endif + +#ifdef _CVignette + fragColor.rgb *= vignette(); +#endif + +#ifdef _CExposure + fragColor.rgb += fragColor.rgb * compoExposureStrength; +#endif + +#ifdef _AutoExposure + float expo = 2.0 - clamp(length(textureLod(histogram, vec2(0.5, 0.5), 0).rgb), 0.0, 1.0); + fragColor.rgb *= pow(expo, autoExposureStrength * 2.0); +#endif + +#ifdef _CToneFilmic + fragColor.rgb = tonemapFilmic(fragColor.rgb); // With gamma +#endif +#ifdef _CToneFilmic2 + fragColor.rgb = acesFilm(fragColor.rgb); + fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2)); +#endif +#ifdef _CToneReinhard + fragColor.rgb = tonemapReinhard(fragColor.rgb); + fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2)); +#endif +#ifdef _CToneUncharted + fragColor.rgb = tonemapUncharted2(fragColor.rgb); + fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2)); // To gamma +#endif +#ifdef _CToneNone + fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2)); // To gamma +#endif + +#ifdef _CBW + // fragColor.rgb = vec3(clamp(dot(fragColor.rgb, fragColor.rgb), 0.0, 1.0)); + fragColor.rgb = vec3((fragColor.r * 0.3 + fragColor.g * 0.59 + fragColor.b * 0.11) / 3.0) * 2.5; +#endif + +// #ifdef _CContrast + // -0.5 - 0.5 + // const float compoContrast = 0.2; + // fragColor.rgb = ((fragColor.rgb - 0.5) * max(compoContrast + 1.0, 0.0)) + 0.5; +// #endif + +// #ifdef _CBrighness + // fragColor.rgb += compoBrightness; +// #endif + +#ifdef _CLensTex + fragColor.rgb += textureLod(lensTexture, texCo, 0.0).rgb; +#endif + +#ifdef _CLetterbox + // const float compoLetterboxSize = 0.1; + fragColor.rgb *= 1.0 - step(0.5 - compoLetterboxSize, abs(0.5 - texCo.y)); +#endif + +//3D LUT Implementation from GPUGems 2 by Nvidia +//https://developer.nvidia.com/gpugems/GPUGems2/gpugems2_chapter24.html + +#ifdef _CLUT + fragColor = LUTlookup(fragColor, lutTexture); +#endif +} diff --git a/compiled/Shaders/compositor_pass.vert.glsl b/compiled/Shaders/compositor_pass.vert.glsl new file mode 100644 index 00000000..8e3089f8 --- /dev/null +++ b/compiled/Shaders/compositor_pass.vert.glsl @@ -0,0 +1,34 @@ +#version 450 + +#include "compiled.inc" + +// #ifdef _CPos + // uniform mat4 invVP; + // uniform vec3 eye; +// #endif + +in vec2 pos; + +out vec2 texCoord; +// #ifdef _CPos + // out vec3 viewRay; +// #endif + +void main() { + // Scale vertex attribute to [0-1] range + const vec2 madd = vec2(0.5, 0.5); + texCoord = pos.xy * madd + madd; + #ifdef HLSL + texCoord.y = 1.0 - texCoord.y; + #endif + + gl_Position = vec4(pos.xy, 0.0, 1.0); + +// #ifdef _CPos + // NDC (at the back of cube) + // vec4 v = vec4(pos.xy, 1.0, 1.0); + // v = vec4(invVP * v); + // v.xyz /= v.w; + // viewRay = v.xyz - eye; +// #endif +} diff --git a/compiled/Shaders/copy_mrt3_pass.frag.glsl b/compiled/Shaders/copy_mrt3_pass.frag.glsl new file mode 100644 index 00000000..ce240842 --- /dev/null +++ b/compiled/Shaders/copy_mrt3_pass.frag.glsl @@ -0,0 +1,14 @@ +#version 450 + +uniform sampler2D tex0; +uniform sampler2D tex1; +uniform sampler2D tex2; + +in vec2 texCoord; +out vec4 fragColor[3]; + +void main() { + fragColor[0] = textureLod(tex0, texCoord, 0.0); + fragColor[1] = textureLod(tex1, texCoord, 0.0); + fragColor[2] = textureLod(tex2, texCoord, 0.0); +} diff --git a/compiled/Shaders/deferred_light.frag.glsl b/compiled/Shaders/deferred_light.frag.glsl new file mode 100644 index 00000000..5915a22e --- /dev/null +++ b/compiled/Shaders/deferred_light.frag.glsl @@ -0,0 +1,414 @@ +#version 450 + +#include "compiled.inc" +#include "std/gbuffer.glsl" +#include "std/light.glsl" +#ifdef _Clusters +#include "std/clusters.glsl" +#endif +#ifdef _Irr +#include "std/shirr.glsl" +#endif +#ifdef _VoxelAOvar +#include "std/conetrace.glsl" +#endif +#ifdef _SSS +#include "std/sss.glsl" +#endif +#ifdef _SSRS +#include "std/ssrs.glsl" +#endif + +uniform sampler2D gbufferD; +uniform sampler2D gbuffer0; +uniform sampler2D gbuffer1; + +#ifdef _VoxelAOvar +uniform sampler3D voxels; +#endif +#ifdef _VoxelGITemporal +uniform sampler3D voxelsLast; +uniform float voxelBlend; +#endif +#ifdef _VoxelGICam +uniform vec3 eyeSnap; +#endif + +uniform float envmapStrength; +#ifdef _Irr +//!uniform vec4 shirr[7]; +#endif +#ifdef _Brdf +uniform sampler2D senvmapBrdf; +#endif +#ifdef _Rad +uniform sampler2D senvmapRadiance; +uniform int envmapNumMipmaps; +#endif +#ifdef _EnvCol +uniform vec3 backgroundCol; +#endif + +#ifdef _SSAO +uniform sampler2D ssaotex; +#endif + +#ifdef _SSS +uniform vec2 lightPlane; +#endif + +#ifdef _SSRS +//!uniform mat4 VP; +uniform mat4 invVP; +#endif + +#ifdef _LightIES +//!uniform sampler2D texIES; +#endif + +#ifdef _SMSizeUniform +//!uniform vec2 smSizeUniform; +#endif + +#ifdef _LTC +//!uniform vec3 lightArea0; +//!uniform vec3 lightArea1; +//!uniform vec3 lightArea2; +//!uniform vec3 lightArea3; +//!uniform sampler2D sltcMat; +//!uniform sampler2D sltcMag; +#ifdef _ShadowMap + #ifdef _SinglePoint + //!uniform sampler2DShadow shadowMapSpot[1]; + //!uniform mat4 LWVPSpot0; + #endif + #ifdef _Clusters + //!uniform sampler2DShadow shadowMapSpot[4]; + //!uniform mat4 LWVPSpot0; + //!uniform mat4 LWVPSpot1; + //!uniform mat4 LWVPSpot2; + //!uniform mat4 LWVPSpot3; + #endif +#endif +#endif + +uniform vec2 cameraProj; +uniform vec3 eye; +uniform vec3 eyeLook; + +#ifdef _Clusters +uniform vec4 lightsArray[maxLights * 2]; + #ifdef _Spot + uniform vec4 lightsArraySpot[maxLights]; + #endif +uniform sampler2D clustersData; +uniform vec2 cameraPlane; +#endif + +#ifdef _ShadowMap +#ifdef _SinglePoint + #ifdef _Spot + //!uniform sampler2DShadow shadowMapSpot[1]; + //!uniform mat4 LWVPSpot0; + #else + //!uniform samplerCubeShadow shadowMapPoint[1]; + //!uniform vec2 lightProj; + #endif +#endif +#ifdef _Clusters + //!uniform samplerCubeShadow shadowMapPoint[4]; + //!uniform vec2 lightProj; + #ifdef _Spot + //!uniform sampler2DShadow shadowMapSpot[4]; + //!uniform mat4 LWVPSpot0; + //!uniform mat4 LWVPSpot1; + //!uniform mat4 LWVPSpot2; + //!uniform mat4 LWVPSpot3; + #endif +#endif +#endif + +#ifdef _Sun +uniform vec3 sunDir; +uniform vec3 sunCol; + #ifdef _ShadowMap + uniform sampler2DShadow shadowMap; + uniform float shadowsBias; + #ifdef _CSM + //!uniform vec4 casData[shadowmapCascades * 4 + 4]; + #else + uniform mat4 LWVP; + #endif + #endif // _ShadowMap +#endif + +#ifdef _SinglePoint // Fast path for single light +uniform vec3 pointPos; +uniform vec3 pointCol; + #ifdef _ShadowMap + uniform float pointBias; + #endif + #ifdef _Spot + uniform vec3 spotDir; + uniform vec2 spotData; + #endif +#endif + +#ifdef _LightClouds +uniform sampler2D texClouds; +uniform float time; +#endif + +in vec2 texCoord; +in vec3 viewRay; +out vec4 fragColor; + +void main() { + vec4 g0 = textureLod(gbuffer0, texCoord, 0.0); // Normal.xy, metallic/roughness, matid + + vec3 n; + n.z = 1.0 - abs(g0.x) - abs(g0.y); + n.xy = n.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy); + n = normalize(n); + + vec2 metrough = unpackFloat(g0.b); + vec4 g1 = textureLod(gbuffer1, texCoord, 0.0); // Basecolor.rgb, spec/occ + vec2 occspec = unpackFloat2(g1.a); + vec3 albedo = surfaceAlbedo(g1.rgb, metrough.x); // g1.rgb - basecolor + vec3 f0 = surfaceF0(g1.rgb, metrough.x); + + float depth = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0; + vec3 p = getPos(eye, eyeLook, normalize(viewRay), depth, cameraProj); + vec3 v = normalize(eye - p); + float dotNV = max(dot(n, v), 0.0); + +#ifdef _MicroShadowing + occspec.x = mix(1.0, occspec.x, dotNV); // AO Fresnel +#endif + +#ifdef _Brdf + vec2 envBRDF = textureLod(senvmapBrdf, vec2(metrough.y, 1.0 - dotNV), 0.0).xy; +#endif + + // Envmap +#ifdef _Irr + vec3 envl = shIrradiance(n); + #ifdef _EnvTex + envl /= PI; + #endif +#else + vec3 envl = vec3(1.0); +#endif + +#ifdef _Rad + vec3 reflectionWorld = reflect(-v, n); + float lod = getMipFromRoughness(metrough.y, envmapNumMipmaps); + vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(reflectionWorld), lod).rgb; +#endif + +#ifdef _EnvLDR + envl.rgb = pow(envl.rgb, vec3(2.2)); + #ifdef _Rad + prefilteredColor = pow(prefilteredColor, vec3(2.2)); + #endif +#endif + + envl.rgb *= albedo; + +#ifdef _Rad // Indirect specular + envl.rgb += prefilteredColor * (f0 * envBRDF.x + envBRDF.y) * 1.5 * occspec.y; +#else + #ifdef _EnvCol + envl.rgb += backgroundCol * surfaceF0(g1.rgb, metrough.x); // f0 + #endif +#endif + + envl.rgb *= envmapStrength * occspec.x; + +#ifdef _VoxelAOvar + + #ifdef _VoxelGICam + vec3 voxpos = (p - eyeSnap) / voxelgiHalfExtents; + #else + vec3 voxpos = p / voxelgiHalfExtents; + #endif + + #ifndef _VoxelAONoTrace + #ifdef _VoxelGITemporal + envl.rgb *= 1.0 - (traceAO(voxpos, n, voxels) * voxelBlend + + traceAO(voxpos, n, voxelsLast) * (1.0 - voxelBlend)); + #else + envl.rgb *= 1.0 - traceAO(voxpos, n, voxels); + #endif + #endif + +#endif + + fragColor.rgb = envl; + +#ifdef _SSAO + // #ifdef _RTGI + // fragColor.rgb *= textureLod(ssaotex, texCoord, 0.0).rgb; + // #else + fragColor.rgb *= textureLod(ssaotex, texCoord, 0.0).r; + // #endif +#endif + +#ifdef _Emission + if (g0.a == 1.0) { + fragColor.rgb += g1.rgb; // materialid + albedo = vec3(0.0); + } +#endif + + // Show voxels + // vec3 origin = vec3(texCoord * 2.0 - 1.0, 0.99); + // vec3 direction = vec3(0.0, 0.0, -1.0); + // vec4 color = vec4(0.0f); + // for(uint step = 0; step < 400 && color.a < 0.99f; ++step) { + // vec3 point = origin + 0.005 * step * direction; + // color += (1.0f - color.a) * textureLod(voxels, point * 0.5 + 0.5, 0); + // } + // fragColor.rgb += color.rgb; + + // Show SSAO + // fragColor.rgb = texture(ssaotex, texCoord).rrr; + +#ifdef _Sun + vec3 sh = normalize(v + sunDir); + float sdotNH = dot(n, sh); + float sdotVH = dot(v, sh); + float sdotNL = dot(n, sunDir); + float svisibility = 1.0; + vec3 sdirect = lambertDiffuseBRDF(albedo, sdotNL) + + specularBRDF(f0, metrough.y, sdotNL, sdotNH, dotNV, sdotVH) * occspec.y; + + #ifdef _ShadowMap + #ifdef _CSM + svisibility = shadowTestCascade(shadowMap, eye, p + n * shadowsBias * 10, shadowsBias); + #else + vec4 lPos = LWVP * vec4(p + n * shadowsBias * 100, 1.0); + if (lPos.w > 0.0) svisibility = shadowTest(shadowMap, lPos.xyz / lPos.w, shadowsBias); + #endif + #endif + + #ifdef _VoxelAOvar + #ifdef _VoxelShadow + svisibility *= 1.0 - traceShadow(voxels, voxpos, sunDir); + #endif + #endif + + #ifdef _SSRS + float tvis = traceShadowSS(-sunDir, p, gbufferD, invVP, eye); + // vec2 coords = getProjectedCoord(hitCoord); + // vec2 deltaCoords = abs(vec2(0.5, 0.5) - coords.xy); + // float screenEdgeFactor = clamp(1.0 - (deltaCoords.x + deltaCoords.y), 0.0, 1.0); + // tvis *= screenEdgeFactor; + svisibility *= tvis; + #endif + + #ifdef _LightClouds + svisibility *= textureLod(texClouds, vec2(p.xy / 100.0 + time / 80.0), 0.0).r * dot(n, vec3(0,0,1)); + #endif + + #ifdef _MicroShadowing + svisibility *= sdotNL + 2.0 * occspec.x * occspec.x - 1.0; + #endif + + fragColor.rgb += sdirect * svisibility * sunCol; + +// #ifdef _Hair // Aniso +// if (g0.a == 2.0) { +// const float shinyParallel = metrough.y; +// const float shinyPerpendicular = 0.1; +// const vec3 v = vec3(0.99146, 0.11664, 0.05832); +// vec3 T = abs(dot(n, v)) > 0.99999 ? cross(n, vec3(0.0, 1.0, 0.0)) : cross(n, v); +// fragColor.rgb = orenNayarDiffuseBRDF(albedo, metrough.y, dotNV, dotNL, dotVH) + wardSpecular(n, h, dotNL, dotNV, dotNH, T, shinyParallel, shinyPerpendicular) * spec; +// } +// #endif + + #ifdef _SSS + if (g0.a == 2.0) { + #ifdef _CSM + int casi, casindex; + mat4 LWVP = getCascadeMat(distance(eye, p), casi, casindex); + #endif + fragColor.rgb += fragColor.rgb * SSSSTransmittance(LWVP, p, n, sunDir, lightPlane.y, shadowMap); + } + #endif + +#endif // _Sun + +#ifdef _SinglePoint + + fragColor.rgb += sampleLight( + p, n, v, dotNV, pointPos, pointCol, albedo, metrough.y, occspec.y, f0 + #ifdef _ShadowMap + , 0, pointBias + #endif + #ifdef _Spot + , true, spotData.x, spotData.y, spotDir + #endif + #ifdef _VoxelAOvar + #ifdef _VoxelShadow + , voxels, voxpos + #endif + #endif + #ifdef _MicroShadowing + , occspec.x + #endif + ); + + #ifdef _Spot + #ifdef _SSS + if (g0.a == 2.0) fragColor.rgb += fragColor.rgb * SSSSTransmittance(LWVPSpot0, p, n, normalize(pointPos - p), lightPlane.y, shadowMapSpot[0]); + #endif + #endif + +#endif + +#ifdef _Clusters + float viewz = linearize(depth * 0.5 + 0.5, cameraProj); + int clusterI = getClusterI(texCoord, viewz, cameraPlane); + int numLights = int(texelFetch(clustersData, ivec2(clusterI, 0), 0).r * 255); + + #ifdef HLSL + viewz += textureLod(clustersData, vec2(0.0), 0.0).r * 1e-9; // TODO: krafix bug, needs to generate sampler + #endif + + #ifdef _Spot + int numSpots = int(texelFetch(clustersData, ivec2(clusterI, 1 + maxLightsCluster), 0).r * 255); + int numPoints = numLights - numSpots; + #endif + + for (int i = 0; i < min(numLights, maxLightsCluster); i++) { + int li = int(texelFetch(clustersData, ivec2(clusterI, i + 1), 0).r * 255); + fragColor.rgb += sampleLight( + p, + n, + v, + dotNV, + lightsArray[li * 2].xyz, // lp + lightsArray[li * 2 + 1].xyz, // lightCol + albedo, + metrough.y, + occspec.y, + f0 + #ifdef _ShadowMap + , li, lightsArray[li * 2].w // bias + #endif + #ifdef _Spot + , li > numPoints - 1 + , lightsArray[li * 2 + 1].w // cutoff + , lightsArraySpot[li].w // cutoff - exponent + , lightsArraySpot[li].xyz // spotDir + #endif + #ifdef _MicroShadowing + , occspec.x + #endif + ); + } +#endif // _Clusters + + fragColor.a = 1.0; // Mark as opaque +} diff --git a/compiled/Shaders/deferred_light_VoxelAOvar.frag.glsl b/compiled/Shaders/deferred_light_VoxelAOvar.frag.glsl new file mode 100644 index 00000000..28a00809 --- /dev/null +++ b/compiled/Shaders/deferred_light_VoxelAOvar.frag.glsl @@ -0,0 +1,415 @@ +#version 450 +#define _VoxelAOvar + +#include "compiled.inc" +#include "std/gbuffer.glsl" +#include "std/light.glsl" +#ifdef _Clusters +#include "std/clusters.glsl" +#endif +#ifdef _Irr +#include "std/shirr.glsl" +#endif +#ifdef _VoxelAOvar +#include "std/conetrace.glsl" +#endif +#ifdef _SSS +#include "std/sss.glsl" +#endif +#ifdef _SSRS +#include "std/ssrs.glsl" +#endif + +uniform sampler2D gbufferD; +uniform sampler2D gbuffer0; +uniform sampler2D gbuffer1; + +#ifdef _VoxelAOvar +uniform sampler3D voxels; +#endif +#ifdef _VoxelGITemporal +uniform sampler3D voxelsLast; +uniform float voxelBlend; +#endif +#ifdef _VoxelGICam +uniform vec3 eyeSnap; +#endif + +uniform float envmapStrength; +#ifdef _Irr +//!uniform vec4 shirr[7]; +#endif +#ifdef _Brdf +uniform sampler2D senvmapBrdf; +#endif +#ifdef _Rad +uniform sampler2D senvmapRadiance; +uniform int envmapNumMipmaps; +#endif +#ifdef _EnvCol +uniform vec3 backgroundCol; +#endif + +#ifdef _SSAO +uniform sampler2D ssaotex; +#endif + +#ifdef _SSS +uniform vec2 lightPlane; +#endif + +#ifdef _SSRS +//!uniform mat4 VP; +uniform mat4 invVP; +#endif + +#ifdef _LightIES +//!uniform sampler2D texIES; +#endif + +#ifdef _SMSizeUniform +//!uniform vec2 smSizeUniform; +#endif + +#ifdef _LTC +//!uniform vec3 lightArea0; +//!uniform vec3 lightArea1; +//!uniform vec3 lightArea2; +//!uniform vec3 lightArea3; +//!uniform sampler2D sltcMat; +//!uniform sampler2D sltcMag; +#ifdef _ShadowMap + #ifdef _SinglePoint + //!uniform sampler2DShadow shadowMapSpot[1]; + //!uniform mat4 LWVPSpot0; + #endif + #ifdef _Clusters + //!uniform sampler2DShadow shadowMapSpot[4]; + //!uniform mat4 LWVPSpot0; + //!uniform mat4 LWVPSpot1; + //!uniform mat4 LWVPSpot2; + //!uniform mat4 LWVPSpot3; + #endif +#endif +#endif + +uniform vec2 cameraProj; +uniform vec3 eye; +uniform vec3 eyeLook; + +#ifdef _Clusters +uniform vec4 lightsArray[maxLights * 2]; + #ifdef _Spot + uniform vec4 lightsArraySpot[maxLights]; + #endif +uniform sampler2D clustersData; +uniform vec2 cameraPlane; +#endif + +#ifdef _ShadowMap +#ifdef _SinglePoint + #ifdef _Spot + //!uniform sampler2DShadow shadowMapSpot[1]; + //!uniform mat4 LWVPSpot0; + #else + //!uniform samplerCubeShadow shadowMapPoint[1]; + //!uniform vec2 lightProj; + #endif +#endif +#ifdef _Clusters + //!uniform samplerCubeShadow shadowMapPoint[4]; + //!uniform vec2 lightProj; + #ifdef _Spot + //!uniform sampler2DShadow shadowMapSpot[4]; + //!uniform mat4 LWVPSpot0; + //!uniform mat4 LWVPSpot1; + //!uniform mat4 LWVPSpot2; + //!uniform mat4 LWVPSpot3; + #endif +#endif +#endif + +#ifdef _Sun +uniform vec3 sunDir; +uniform vec3 sunCol; + #ifdef _ShadowMap + uniform sampler2DShadow shadowMap; + uniform float shadowsBias; + #ifdef _CSM + //!uniform vec4 casData[shadowmapCascades * 4 + 4]; + #else + uniform mat4 LWVP; + #endif + #endif // _ShadowMap +#endif + +#ifdef _SinglePoint // Fast path for single light +uniform vec3 pointPos; +uniform vec3 pointCol; + #ifdef _ShadowMap + uniform float pointBias; + #endif + #ifdef _Spot + uniform vec3 spotDir; + uniform vec2 spotData; + #endif +#endif + +#ifdef _LightClouds +uniform sampler2D texClouds; +uniform float time; +#endif + +in vec2 texCoord; +in vec3 viewRay; +out vec4 fragColor; + +void main() { + vec4 g0 = textureLod(gbuffer0, texCoord, 0.0); // Normal.xy, metallic/roughness, matid + + vec3 n; + n.z = 1.0 - abs(g0.x) - abs(g0.y); + n.xy = n.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy); + n = normalize(n); + + vec2 metrough = unpackFloat(g0.b); + vec4 g1 = textureLod(gbuffer1, texCoord, 0.0); // Basecolor.rgb, spec/occ + vec2 occspec = unpackFloat2(g1.a); + vec3 albedo = surfaceAlbedo(g1.rgb, metrough.x); // g1.rgb - basecolor + vec3 f0 = surfaceF0(g1.rgb, metrough.x); + + float depth = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0; + vec3 p = getPos(eye, eyeLook, normalize(viewRay), depth, cameraProj); + vec3 v = normalize(eye - p); + float dotNV = max(dot(n, v), 0.0); + +#ifdef _MicroShadowing + occspec.x = mix(1.0, occspec.x, dotNV); // AO Fresnel +#endif + +#ifdef _Brdf + vec2 envBRDF = textureLod(senvmapBrdf, vec2(metrough.y, 1.0 - dotNV), 0.0).xy; +#endif + + // Envmap +#ifdef _Irr + vec3 envl = shIrradiance(n); + #ifdef _EnvTex + envl /= PI; + #endif +#else + vec3 envl = vec3(1.0); +#endif + +#ifdef _Rad + vec3 reflectionWorld = reflect(-v, n); + float lod = getMipFromRoughness(metrough.y, envmapNumMipmaps); + vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(reflectionWorld), lod).rgb; +#endif + +#ifdef _EnvLDR + envl.rgb = pow(envl.rgb, vec3(2.2)); + #ifdef _Rad + prefilteredColor = pow(prefilteredColor, vec3(2.2)); + #endif +#endif + + envl.rgb *= albedo; + +#ifdef _Rad // Indirect specular + envl.rgb += prefilteredColor * (f0 * envBRDF.x + envBRDF.y) * 1.5 * occspec.y; +#else + #ifdef _EnvCol + envl.rgb += backgroundCol * surfaceF0(g1.rgb, metrough.x); // f0 + #endif +#endif + + envl.rgb *= envmapStrength * occspec.x; + +#ifdef _VoxelAOvar + + #ifdef _VoxelGICam + vec3 voxpos = (p - eyeSnap) / voxelgiHalfExtents; + #else + vec3 voxpos = p / voxelgiHalfExtents; + #endif + + #ifndef _VoxelAONoTrace + #ifdef _VoxelGITemporal + envl.rgb *= 1.0 - (traceAO(voxpos, n, voxels) * voxelBlend + + traceAO(voxpos, n, voxelsLast) * (1.0 - voxelBlend)); + #else + envl.rgb *= 1.0 - traceAO(voxpos, n, voxels); + #endif + #endif + +#endif + + fragColor.rgb = envl; + +#ifdef _SSAO + // #ifdef _RTGI + // fragColor.rgb *= textureLod(ssaotex, texCoord, 0.0).rgb; + // #else + fragColor.rgb *= textureLod(ssaotex, texCoord, 0.0).r; + // #endif +#endif + +#ifdef _Emission + if (g0.a == 1.0) { + fragColor.rgb += g1.rgb; // materialid + albedo = vec3(0.0); + } +#endif + + // Show voxels + // vec3 origin = vec3(texCoord * 2.0 - 1.0, 0.99); + // vec3 direction = vec3(0.0, 0.0, -1.0); + // vec4 color = vec4(0.0f); + // for(uint step = 0; step < 400 && color.a < 0.99f; ++step) { + // vec3 point = origin + 0.005 * step * direction; + // color += (1.0f - color.a) * textureLod(voxels, point * 0.5 + 0.5, 0); + // } + // fragColor.rgb += color.rgb; + + // Show SSAO + // fragColor.rgb = texture(ssaotex, texCoord).rrr; + +#ifdef _Sun + vec3 sh = normalize(v + sunDir); + float sdotNH = dot(n, sh); + float sdotVH = dot(v, sh); + float sdotNL = dot(n, sunDir); + float svisibility = 1.0; + vec3 sdirect = lambertDiffuseBRDF(albedo, sdotNL) + + specularBRDF(f0, metrough.y, sdotNL, sdotNH, dotNV, sdotVH) * occspec.y; + + #ifdef _ShadowMap + #ifdef _CSM + svisibility = shadowTestCascade(shadowMap, eye, p + n * shadowsBias * 10, shadowsBias); + #else + vec4 lPos = LWVP * vec4(p + n * shadowsBias * 100, 1.0); + if (lPos.w > 0.0) svisibility = shadowTest(shadowMap, lPos.xyz / lPos.w, shadowsBias); + #endif + #endif + + #ifdef _VoxelAOvar + #ifdef _VoxelShadow + svisibility *= 1.0 - traceShadow(voxels, voxpos, sunDir); + #endif + #endif + + #ifdef _SSRS + float tvis = traceShadowSS(-sunDir, p, gbufferD, invVP, eye); + // vec2 coords = getProjectedCoord(hitCoord); + // vec2 deltaCoords = abs(vec2(0.5, 0.5) - coords.xy); + // float screenEdgeFactor = clamp(1.0 - (deltaCoords.x + deltaCoords.y), 0.0, 1.0); + // tvis *= screenEdgeFactor; + svisibility *= tvis; + #endif + + #ifdef _LightClouds + svisibility *= textureLod(texClouds, vec2(p.xy / 100.0 + time / 80.0), 0.0).r * dot(n, vec3(0,0,1)); + #endif + + #ifdef _MicroShadowing + svisibility *= sdotNL + 2.0 * occspec.x * occspec.x - 1.0; + #endif + + fragColor.rgb += sdirect * svisibility * sunCol; + +// #ifdef _Hair // Aniso +// if (g0.a == 2.0) { +// const float shinyParallel = metrough.y; +// const float shinyPerpendicular = 0.1; +// const vec3 v = vec3(0.99146, 0.11664, 0.05832); +// vec3 T = abs(dot(n, v)) > 0.99999 ? cross(n, vec3(0.0, 1.0, 0.0)) : cross(n, v); +// fragColor.rgb = orenNayarDiffuseBRDF(albedo, metrough.y, dotNV, dotNL, dotVH) + wardSpecular(n, h, dotNL, dotNV, dotNH, T, shinyParallel, shinyPerpendicular) * spec; +// } +// #endif + + #ifdef _SSS + if (g0.a == 2.0) { + #ifdef _CSM + int casi, casindex; + mat4 LWVP = getCascadeMat(distance(eye, p), casi, casindex); + #endif + fragColor.rgb += fragColor.rgb * SSSSTransmittance(LWVP, p, n, sunDir, lightPlane.y, shadowMap); + } + #endif + +#endif // _Sun + +#ifdef _SinglePoint + + fragColor.rgb += sampleLight( + p, n, v, dotNV, pointPos, pointCol, albedo, metrough.y, occspec.y, f0 + #ifdef _ShadowMap + , 0, pointBias + #endif + #ifdef _Spot + , true, spotData.x, spotData.y, spotDir + #endif + #ifdef _VoxelAOvar + #ifdef _VoxelShadow + , voxels, voxpos + #endif + #endif + #ifdef _MicroShadowing + , occspec.x + #endif + ); + + #ifdef _Spot + #ifdef _SSS + if (g0.a == 2.0) fragColor.rgb += fragColor.rgb * SSSSTransmittance(LWVPSpot0, p, n, normalize(pointPos - p), lightPlane.y, shadowMapSpot[0]); + #endif + #endif + +#endif + +#ifdef _Clusters + float viewz = linearize(depth * 0.5 + 0.5, cameraProj); + int clusterI = getClusterI(texCoord, viewz, cameraPlane); + int numLights = int(texelFetch(clustersData, ivec2(clusterI, 0), 0).r * 255); + + #ifdef HLSL + viewz += textureLod(clustersData, vec2(0.0), 0.0).r * 1e-9; // TODO: krafix bug, needs to generate sampler + #endif + + #ifdef _Spot + int numSpots = int(texelFetch(clustersData, ivec2(clusterI, 1 + maxLightsCluster), 0).r * 255); + int numPoints = numLights - numSpots; + #endif + + for (int i = 0; i < min(numLights, maxLightsCluster); i++) { + int li = int(texelFetch(clustersData, ivec2(clusterI, i + 1), 0).r * 255); + fragColor.rgb += sampleLight( + p, + n, + v, + dotNV, + lightsArray[li * 2].xyz, // lp + lightsArray[li * 2 + 1].xyz, // lightCol + albedo, + metrough.y, + occspec.y, + f0 + #ifdef _ShadowMap + , li, lightsArray[li * 2].w // bias + #endif + #ifdef _Spot + , li > numPoints - 1 + , lightsArray[li * 2 + 1].w // cutoff + , lightsArraySpot[li].w // cutoff - exponent + , lightsArraySpot[li].xyz // spotDir + #endif + #ifdef _MicroShadowing + , occspec.x + #endif + ); + } +#endif // _Clusters + + fragColor.a = 1.0; // Mark as opaque +} diff --git a/compiled/Shaders/deferred_light_VoxelAOvar.vert.glsl b/compiled/Shaders/deferred_light_VoxelAOvar.vert.glsl new file mode 100644 index 00000000..9c9220a4 --- /dev/null +++ b/compiled/Shaders/deferred_light_VoxelAOvar.vert.glsl @@ -0,0 +1,32 @@ +#version 450 +#define _VoxelAOvar + +#include "compiled.inc" + +uniform mat4 invVP; +uniform vec3 eye; + +in vec2 pos; + +out vec2 texCoord; +out vec3 viewRay; + +void main() { + // Scale vertex attribute to [0-1] range + const vec2 madd = vec2(0.5, 0.5); + texCoord = pos.xy * madd + madd; + #ifdef HLSL + texCoord.y = 1.0 - texCoord.y; + #endif + + gl_Position = vec4(pos.xy, 0.0, 1.0); + + // fullscreen triangle: http://de.slideshare.net/DevCentralAMD/vertex-shader-tricks-bill-bilodeau + // gl_Position = vec4((gl_VertexID % 2) * 4.0 - 1.0, (gl_VertexID / 2) * 4.0 - 1.0, 0.0, 1.0); + + // NDC (at the back of cube) + vec4 v = vec4(pos.x, pos.y, 1.0, 1.0); + v = vec4(invVP * v); + v.xyz /= v.w; + viewRay = v.xyz - eye; +} diff --git a/compiled/Shaders/pass.vert.glsl b/compiled/Shaders/pass.vert.glsl new file mode 100644 index 00000000..eececc04 --- /dev/null +++ b/compiled/Shaders/pass.vert.glsl @@ -0,0 +1,18 @@ +#version 450 + +#include "compiled.inc" + +in vec2 pos; + +out vec2 texCoord; + +void main() { + // Scale vertex attribute to 0-1 range + const vec2 madd = vec2(0.5, 0.5); + texCoord = pos.xy * madd + madd; + #ifdef HLSL + texCoord.y = 1.0 - texCoord.y; + #endif + + gl_Position = vec4(pos.xy, 0.0, 1.0); +} diff --git a/compiled/Shaders/pass_copy.frag.glsl b/compiled/Shaders/pass_copy.frag.glsl new file mode 100644 index 00000000..51302dac --- /dev/null +++ b/compiled/Shaders/pass_copy.frag.glsl @@ -0,0 +1,10 @@ +#version 450 + +uniform sampler2D tex; + +in vec2 texCoord; +out vec4 fragColor; + +void main() { + fragColor = textureLod(tex, texCoord, 0.0); +} diff --git a/compiled/Shaders/pass_viewray.vert.glsl b/compiled/Shaders/pass_viewray.vert.glsl new file mode 100644 index 00000000..5c916a4a --- /dev/null +++ b/compiled/Shaders/pass_viewray.vert.glsl @@ -0,0 +1,31 @@ +#version 450 + +#include "compiled.inc" + +uniform mat4 invVP; +uniform vec3 eye; + +in vec2 pos; + +out vec2 texCoord; +out vec3 viewRay; + +void main() { + // Scale vertex attribute to [0-1] range + const vec2 madd = vec2(0.5, 0.5); + texCoord = pos.xy * madd + madd; + #ifdef HLSL + texCoord.y = 1.0 - texCoord.y; + #endif + + gl_Position = vec4(pos.xy, 0.0, 1.0); + + // fullscreen triangle: http://de.slideshare.net/DevCentralAMD/vertex-shader-tricks-bill-bilodeau + // gl_Position = vec4((gl_VertexID % 2) * 4.0 - 1.0, (gl_VertexID / 2) * 4.0 - 1.0, 0.0, 1.0); + + // NDC (at the back of cube) + vec4 v = vec4(pos.x, pos.y, 1.0, 1.0); + v = vec4(invVP * v); + v.xyz /= v.w; + viewRay = v.xyz - eye; +} diff --git a/compiled/Shaders/pass_viewray2.vert.glsl b/compiled/Shaders/pass_viewray2.vert.glsl new file mode 100644 index 00000000..727a42a6 --- /dev/null +++ b/compiled/Shaders/pass_viewray2.vert.glsl @@ -0,0 +1,26 @@ +#version 450 + +#include "compiled.inc" + +uniform mat4 invP; + +in vec2 pos; + +out vec2 texCoord; +out vec3 viewRay; + +void main() { + // Scale vertex attribute to [0-1] range + const vec2 madd = vec2(0.5, 0.5); + texCoord = pos.xy * madd + madd; + #ifdef HLSL + texCoord.y = 1.0 - texCoord.y; + #endif + + gl_Position = vec4(pos.xy, 0.0, 1.0); + + // NDC (at the back of cube) + vec4 v = vec4(pos.x, pos.y, 1.0, 1.0); + v = vec4(invP * v); + viewRay = vec3(v.xy / v.z, 1.0); +} diff --git a/compiled/Shaders/shader_datas.arm b/compiled/Shaders/shader_datas.arm new file mode 100644 index 00000000..bfe22ab2 Binary files /dev/null and b/compiled/Shaders/shader_datas.arm differ diff --git a/compiled/Shaders/smaa_blend_weight.frag.glsl b/compiled/Shaders/smaa_blend_weight.frag.glsl new file mode 100644 index 00000000..db2f6593 --- /dev/null +++ b/compiled/Shaders/smaa_blend_weight.frag.glsl @@ -0,0 +1,456 @@ +#version 450 + +#define SMAA_MAX_SEARCH_STEPS_DIAG 8 +#define SMAA_AREATEX_MAX_DISTANCE 16 +#define SMAA_AREATEX_MAX_DISTANCE_DIAG 20 +#define SMAA_AREATEX_PIXEL_SIZE (1.0 / vec2(160.0, 560.0)) +#define SMAA_AREATEX_SUBTEX_SIZE (1.0 / 7.0) +#define SMAA_SEARCHTEX_SIZE vec2(66.0, 33.0) +#define SMAA_SEARCHTEX_PACKED_SIZE vec2(64.0, 16.0) +#define SMAA_CORNER_ROUNDING 25 +#define SMAA_CORNER_ROUNDING_NORM (float(SMAA_CORNER_ROUNDING) / 100.0) +#define SMAA_AREATEX_SELECT(sample) sample.rg +#define SMAA_SEARCHTEX_SELECT(sample) sample.r +#define mad(a, b, c) (a * b + c) +#define saturate(a) clamp(a, 0.0, 1.0) +#define round(a) floor(a + 0.5) + +uniform sampler2D edgesTex; +uniform sampler2D areaTex; +uniform sampler2D searchTex; + +uniform vec2 screenSize; +uniform vec2 screenSizeInv; + +in vec2 texCoord; +in vec2 pixcoord; +in vec4 offset0; +in vec4 offset1; +in vec4 offset2; +out vec4 fragColor; + +// Blending Weight Calculation Pixel Shader (Second Pass) +vec2 cdw_end; + +vec4 textureLodA(sampler2D tex, vec2 coord, float lod) { + #ifdef HLSL + coord.y = 1.0 - coord.y; + #endif + return textureLod(tex, coord, lod); +} + +#define SMAASampleLevelZeroOffset(tex, coord, offset) textureLodA(tex, coord + offset * screenSizeInv.xy, 0.0) + +//----------------------------------------------------------------------------- +// Diagonal Search Functions + +// #if !defined(SMAA_DISABLE_DIAG_DETECTION) +/** + * Allows to decode two binary values from a bilinear-filtered access. + */ +vec2 SMAADecodeDiagBilinearAccess(vec2 e) { + // Bilinear access for fetching 'e' have a 0.25 offset, and we are + // interested in the R and G edges: + // + // +---G---+-------+ + // | x o R x | + // +-------+-------+ + // + // Then, if one of these edge is enabled: + // Red: (0.75 * X + 0.25 * 1) => 0.25 or 1.0 + // Green: (0.75 * 1 + 0.25 * X) => 0.75 or 1.0 + // + // This function will unpack the values (mad + mul + round): + // wolframalpha.com: round(x * abs(5 * x - 5 * 0.75)) plot 0 to 1 + e.r = e.r * abs(5.0 * e.r - 5.0 * 0.75); + return round(e); +} + +vec4 SMAADecodeDiagBilinearAccess(vec4 e) { + e.rb = e.rb * abs(5.0 * e.rb - 5.0 * 0.75); + return round(e); +} + +/** + * These functions allows to perform diagonal pattern searches. + */ +vec2 SMAASearchDiag1(vec2 texcoord, vec2 dir/*, out vec2 e*/) { + vec4 coord = vec4(texcoord, -1.0, 1.0); + vec3 t = vec3(screenSizeInv.xy, 1.0); + float cw = coord.w; // TODO: krafix hlsl bug + while (coord.z < float(SMAA_MAX_SEARCH_STEPS_DIAG - 1) && cw > 0.9) { + coord.xyz = mad(t, vec3(dir, 1.0), coord.xyz); + cdw_end /*e*/ = textureLodA(edgesTex, coord.xy, 0.0).rg; + cw = dot(cdw_end /*e*/, vec2(0.5, 0.5)); + } + coord.w = cw; + return coord.zw; +} + +vec2 SMAASearchDiag2(vec2 texcoord, vec2 dir) { + vec4 coord = vec4(texcoord, -1.0, 1.0); + coord.x += 0.25 * screenSizeInv.x; // See @SearchDiag2Optimization + vec3 t = vec3(screenSizeInv.xy, 1.0); + float cw = coord.w; // TODO: krafix hlsl bug + while (coord.z < float(SMAA_MAX_SEARCH_STEPS_DIAG - 1) && cw > 0.9) { + coord.xyz = mad(t, vec3(dir, 1.0), coord.xyz); + // @SearchDiag2Optimization + // Fetch both edges at once using bilinear filtering: + cdw_end /*e*/ = textureLodA(edgesTex, coord.xy, 0.0).rg; + cdw_end /*e*/ = SMAADecodeDiagBilinearAccess(cdw_end /*e*/); + cw = dot(cdw_end /*e*/, vec2(0.5, 0.5)); + } + coord.w = cw; + return coord.zw; +} + +/** + * Similar to SMAAArea, this calculates the area corresponding to a certain + * diagonal distance and crossing edges 'e'. + */ +vec2 SMAAAreaDiag(vec2 dist, vec2 e, float offset) { + vec2 texcoord = mad(vec2(SMAA_AREATEX_MAX_DISTANCE_DIAG, SMAA_AREATEX_MAX_DISTANCE_DIAG), e, dist); + + // We do a scale and bias for mapping to texel space: + texcoord = mad(SMAA_AREATEX_PIXEL_SIZE, texcoord, 0.5 * SMAA_AREATEX_PIXEL_SIZE); + + // Diagonal areas are on the second half of the texture: + texcoord.x += 0.5; + + // Move to proper place, according to the subpixel offset: + texcoord.y += SMAA_AREATEX_SUBTEX_SIZE * offset; + + // Do it! + return SMAA_AREATEX_SELECT(textureLod(areaTex, texcoord, 0.0)); +} + +/** + * This searches for diagonal patterns and returns the corresponding weights. + */ +vec2 SMAACalculateDiagWeights(vec2 texcoord, vec2 e, vec4 subsampleIndices) { + vec2 weights = vec2(0.0, 0.0); + + // Search for the line ends: + vec4 d; + if (e.r > 0.0) { + d.xz = SMAASearchDiag1(texcoord, vec2(-1.0, 1.0)/*, cdw_end*/); + float dadd = cdw_end.y > 0.9 ? 1.0 : 0.0; + d.x += dadd; + } + else { + d.xz = vec2(0.0, 0.0); + } + d.yw = SMAASearchDiag1(texcoord, vec2(1.0, -1.0)/*, cdw_end*/); + + //SMAA_BRANCH + if (d.x + d.y > 2.0) { // d.x + d.y + 1 > 3 + // Fetch the crossing edges: + vec4 coords = mad(vec4(-d.x + 0.25, d.x, d.y, -d.y - 0.25), screenSizeInv.xyxy, texcoord.xyxy); + vec4 c; + + c.xy = SMAASampleLevelZeroOffset(edgesTex, coords.xy, ivec2(-1, 0)).rg; + c.zw = SMAASampleLevelZeroOffset(edgesTex, coords.zw, ivec2( 1, 0)).rg; + c.yxwz = SMAADecodeDiagBilinearAccess(c.xyzw); + + // Merge crossing edges at each side into a single value: + vec2 cc = mad(vec2(2.0, 2.0), c.xz, c.yw); + + // Remove the crossing edge if we didn't found the end of the line: + // SMAAMovc(bvec2(step(0.9, d.zw)), cc, vec2(0.0, 0.0)); + float a1condx = step(0.9, d.z); + float a1condy = step(0.9, d.w); + if (a1condx == 1.0) cc.x = 0.0; + if (a1condy == 1.0) cc.y = 0.0; + + // Fetch the areas for this line: + weights += SMAAAreaDiag(d.xy, cc, subsampleIndices.z); + } + + // Search for the line ends: + d.xz = SMAASearchDiag2(texcoord, vec2(-1.0, -1.0)/*, cdw_end*/); + if (SMAASampleLevelZeroOffset(edgesTex, texcoord, ivec2(1, 0)).r > 0.0) { + d.yw = SMAASearchDiag2(texcoord, vec2(1.0, 1.0)/*, cdw_end*/); + float dadd = cdw_end.y > 0.9 ? 1.0 : 0.0; + d.y += dadd; + } + else { + d.yw = vec2(0.0, 0.0); + } + + // SMAA_BRANCH + if (d.x + d.y > 2.0) { // d.x + d.y + 1 > 3 + // Fetch the crossing edges: + vec4 coords = mad(vec4(-d.x, -d.x, d.y, d.y), screenSizeInv.xyxy, texcoord.xyxy); + vec4 c; + c.x = SMAASampleLevelZeroOffset(edgesTex, coords.xy, ivec2(-1, 0)).g; + c.y = SMAASampleLevelZeroOffset(edgesTex, coords.xy, ivec2( 0, -1)).r; + c.zw = SMAASampleLevelZeroOffset(edgesTex, coords.zw, ivec2( 1, 0)).gr; + vec2 cc = mad(vec2(2.0, 2.0), c.xz, c.yw); + + // Remove the crossing edge if we didn't found the end of the line: + // SMAAMovc(bvec2(step(0.9, d.zw)), cc, vec2(0.0, 0.0)); + float a1condx = step(0.9, d.z); + float a1condy = step(0.9, d.w); + if (a1condx == 1.0) cc.x = 0.0; + if (a1condy == 1.0) cc.y = 0.0; + + // Fetch the areas for this line: + weights += SMAAAreaDiag(d.xy, cc, subsampleIndices.w).gr; + } + + return weights; +} +// #endif + +//----------------------------------------------------------------------------- +// Horizontal/Vertical Search Functions + +/** + * This allows to determine how much length should we add in the last step + * of the searches. It takes the bilinearly interpolated edge (see + * @PSEUDO_GATHER4), and adds 0, 1 or 2, depending on which edges and + * crossing edges are active. + */ +float SMAASearchLength(vec2 e, float offset) { + // The texture is flipped vertically, with left and right cases taking half + // of the space horizontally: + vec2 scale = SMAA_SEARCHTEX_SIZE * vec2(0.5, -1.0); + vec2 bias = SMAA_SEARCHTEX_SIZE * vec2(offset, 1.0); + + // Scale and bias to access texel centers: + scale += vec2(-1.0, 1.0); + bias += vec2( 0.5, -0.5); + + // Convert from pixel coordinates to texcoords: + // (We use SMAA_SEARCHTEX_PACKED_SIZE because the texture is cropped) + scale *= 1.0 / SMAA_SEARCHTEX_PACKED_SIZE; + bias *= 1.0 / SMAA_SEARCHTEX_PACKED_SIZE; + + vec2 coord = mad(scale, e, bias); + + // Lookup the search texture: + return SMAA_SEARCHTEX_SELECT(textureLod(searchTex, coord, 0.0)); +} + +/** + * Horizontal/vertical search functions for the 2nd pass. + */ +float SMAASearchXLeft(vec2 texcoord, float end) { + /** + * @PSEUDO_GATHER4 + * This texcoord has been offset by (-0.25, -0.125) in the vertex shader to + * sample between edge, thus fetching four edges in a row. + * Sampling with different offsets in each direction allows to disambiguate + * which edges are active from the four fetched ones. + */ + vec2 e = vec2(0.0, 1.0); + while (texcoord.x > end && + e.g > 0.8281 && // Is there some edge not activated? + e.r == 0.0) { // Or is there a crossing edge that breaks the line? + e = textureLodA(edgesTex, texcoord, 0.0).rg; + texcoord = mad(-vec2(2.0, 0.0), screenSizeInv.xy, texcoord); + } + + float offset = mad(-(255.0 / 127.0), SMAASearchLength(e, 0.0), 3.25); + return mad(screenSizeInv.x, offset, texcoord.x); +} + +float SMAASearchXRight(vec2 texcoord, float end) { + vec2 e = vec2(0.0, 1.0); + while (texcoord.x < end && + e.g > 0.8281 && // Is there some edge not activated? + e.r == 0.0) { // Or is there a crossing edge that breaks the line? + e = textureLodA(edgesTex, texcoord, 0.0).rg; + texcoord = mad(vec2(2.0, 0.0), screenSizeInv.xy, texcoord); + } + + float offset = mad(-(255.0 / 127.0), SMAASearchLength(e, 0.5), 3.25); + return mad(-screenSizeInv.x, offset, texcoord.x); +} + +float SMAASearchYUp(vec2 texcoord, float end) { + vec2 e = vec2(1.0, 0.0); + while (texcoord.y > end && + e.r > 0.8281 && // Is there some edge not activated? + e.g == 0.0) { // Or is there a crossing edge that breaks the line? + e = textureLodA(edgesTex, texcoord, 0.0).rg; + texcoord = mad(-vec2(0.0, 2.0), screenSizeInv.xy, texcoord); + } + float offset = mad(-(255.0 / 127.0), SMAASearchLength(e.gr, 0.0), 3.25); + return mad(screenSizeInv.y, offset, texcoord.y); +} + +float SMAASearchYDown(vec2 texcoord, float end) { + vec2 e = vec2(1.0, 0.0); + while (texcoord.y < end && + e.r > 0.8281 && // Is there some edge not activated? + e.g == 0.0) { // Or is there a crossing edge that breaks the line? + e = textureLodA(edgesTex, texcoord, 0.0).rg; + texcoord = mad(vec2(0.0, 2.0), screenSizeInv.xy, texcoord); + } + float offset = mad(-(255.0 / 127.0), SMAASearchLength(/*searchTex,*/ e.gr, 0.5), 3.25); + return mad(-screenSizeInv.y, offset, texcoord.y); +} + +/** + * Ok, we have the distance and both crossing edges. So, what are the areas + * at each side of current edge? + */ +vec2 SMAAArea(vec2 dist, float e1, float e2, float offset) { + // Rounding prevents precision errors of bilinear filtering: + vec2 texcoord = mad(vec2(SMAA_AREATEX_MAX_DISTANCE, SMAA_AREATEX_MAX_DISTANCE), round(4.0 * vec2(e1, e2)), dist); + + // We do a scale and bias for mapping to texel space: + texcoord = mad(SMAA_AREATEX_PIXEL_SIZE, texcoord, 0.5 * SMAA_AREATEX_PIXEL_SIZE); + + // Move to proper place, according to the subpixel offset: + texcoord.y = mad(SMAA_AREATEX_SUBTEX_SIZE, offset, texcoord.y); + + // Do it! + return SMAA_AREATEX_SELECT(textureLod(areaTex, texcoord, 0.0)); +} + +//----------------------------------------------------------------------------- +// Corner Detection Functions + +vec2 SMAADetectHorizontalCornerPattern(vec2 weights, vec4 texcoord, vec2 d) { + // #if !defined(SMAA_DISABLE_CORNER_DETECTION) + vec2 leftRight = step(d.xy, d.yx); + vec2 rounding = (1.0 - SMAA_CORNER_ROUNDING_NORM) * leftRight; + + rounding /= leftRight.x + leftRight.y; // Reduce blending for pixels in the center of a line. + + vec2 factor = vec2(1.0, 1.0); + factor.x -= rounding.x * SMAASampleLevelZeroOffset(edgesTex, texcoord.xy, ivec2(0, 1)).r; + factor.x -= rounding.y * SMAASampleLevelZeroOffset(edgesTex, texcoord.zw, ivec2(1, 1)).r; + factor.y -= rounding.x * SMAASampleLevelZeroOffset(edgesTex, texcoord.xy, ivec2(0, -2)).r; + factor.y -= rounding.y * SMAASampleLevelZeroOffset(edgesTex, texcoord.zw, ivec2(1, -2)).r; + + weights *= saturate(factor); + return weights; // + // #endif +} + +vec2 SMAADetectVerticalCornerPattern(vec2 weights, vec4 texcoord, vec2 d) { + //#if !defined(SMAA_DISABLE_CORNER_DETECTION) + vec2 leftRight = step(d.xy, d.yx); + vec2 rounding = (1.0 - SMAA_CORNER_ROUNDING_NORM) * leftRight; + + rounding /= leftRight.x + leftRight.y; + + vec2 factor = vec2(1.0, 1.0); + factor.x -= rounding.x * SMAASampleLevelZeroOffset(edgesTex, texcoord.xy, ivec2( 1, 0)).g; + factor.x -= rounding.y * SMAASampleLevelZeroOffset(edgesTex, texcoord.zw, ivec2( 1, 1)).g; + factor.y -= rounding.x * SMAASampleLevelZeroOffset(edgesTex, texcoord.xy, ivec2(-2, 0)).g; + factor.y -= rounding.y * SMAASampleLevelZeroOffset(edgesTex, texcoord.zw, ivec2(-2, 1)).g; + + weights *= saturate(factor); + return weights; // + // #endif +} + + +vec4 SMAABlendingWeightCalculationPS(vec2 texcoord, vec2 pixcoord, + vec4 subsampleIndices) { // Just pass zero for SMAA 1x, see @SUBSAMPLE_INDICES. + vec4 weights = vec4(0.0, 0.0, 0.0, 0.0); + + vec2 e = textureLodA(edgesTex, texcoord, 0.0).rg; + + //SMAA_BRANCH + if (e.g > 0.0) { // Edge at north + //#if !defined(SMAA_DISABLE_DIAG_DETECTION) + // Diagonals have both north and west edges, so searching for them in + // one of the boundaries is enough. + weights.rg = SMAACalculateDiagWeights(texcoord, e, subsampleIndices); + + // We give priority to diagonals, so if we find a diagonal we skip + // horizontal/vertical processing. + //SMAA_BRANCH + if (weights.r == -weights.g) { // weights.r + weights.g == 0.0 + //#endif + + vec2 d; + + // Find the distance to the left: + vec3 coords; + coords.x = SMAASearchXLeft(offset0.xy, offset2.x); + coords.y = offset1.y; // offset[1].y = texcoord.y - 0.25 * screenSizeInv.y (@CROSSING_OFFSET) + d.x = coords.x; + + // Now fetch the left crossing edges, two at a time using bilinear + // filtering. Sampling at -0.25 (see @CROSSING_OFFSET) enables to + // discern what value each edge has: + float e1 = textureLodA(edgesTex, coords.xy, 0.0).r; + + // Find the distance to the right: + coords.z = SMAASearchXRight(offset0.zw, offset2.y); + d.y = coords.z; + + // We want the distances to be in pixel units (doing this here allow to + // better interleave arithmetic and memory accesses): + d = abs(round(mad(screenSize.xx, d, -pixcoord.xx))); + + // SMAAArea below needs a sqrt, as the areas texture is compressed + // quadratically: + vec2 sqrt_d = sqrt(d); + + // Fetch the right crossing edges: + float e2 = SMAASampleLevelZeroOffset(edgesTex, coords.zy, ivec2(1, 0)).r; + + // Ok, we know how this pattern looks like, now it is time for getting + // the actual area: + weights.rg = SMAAArea(sqrt_d, e1, e2, subsampleIndices.y); + + // Fix corners: + coords.y = texcoord.y; + weights.rg = SMAADetectHorizontalCornerPattern(weights.rg, coords.xyzy, d); + + //#if !defined(SMAA_DISABLE_DIAG_DETECTION) + } + else { + e.r = 0.0; // Skip vertical processing. + } + //#endif + } + + //SMAA_BRANCH + if (e.r > 0.0) { // Edge at west + vec2 d; + + // Find the distance to the top: + vec3 coords; + coords.y = SMAASearchYUp(/*edgesTex, searchTex,*/ offset1.xy, offset2.z); + coords.x = offset0.x; // offset[1].x = texcoord.x - 0.25 * screenSizeInv.x; + d.x = coords.y; + + // Fetch the top crossing edges: + float e1 = textureLodA(edgesTex, coords.xy, 0.0).g; + + // Find the distance to the bottom: + coords.z = SMAASearchYDown(offset1.zw, offset2.w); + d.y = coords.z; + + // We want the distances to be in pixel units: + d = abs(round(mad(screenSize.yy, d, -pixcoord.yy))); + + // SMAAArea below needs a sqrt, as the areas texture is compressed + // quadratically: + vec2 sqrt_d = sqrt(d); + + // Fetch the bottom crossing edges: + float e2 = SMAASampleLevelZeroOffset(edgesTex, coords.xz, ivec2(0, 1)).g; + + // Get the area for this direction: + weights.ba = SMAAArea(sqrt_d, e1, e2, subsampleIndices.x); + + // Fix corners: + coords.x = texcoord.x; + weights.ba = SMAADetectVerticalCornerPattern(weights.ba, coords.xyxz, d); + } + + return weights; +} + +void main() { + fragColor = SMAABlendingWeightCalculationPS(texCoord, pixcoord, vec4(0.0)); +} diff --git a/compiled/Shaders/smaa_blend_weight.vert.glsl b/compiled/Shaders/smaa_blend_weight.vert.glsl new file mode 100644 index 00000000..f87139fb --- /dev/null +++ b/compiled/Shaders/smaa_blend_weight.vert.glsl @@ -0,0 +1,36 @@ +#version 450 + +#include "compiled.inc" + +in vec2 pos; + +uniform vec2 screenSize; +uniform vec2 screenSizeInv; + +out vec2 texCoord; +out vec2 pixcoord; +out vec4 offset0; +out vec4 offset1; +out vec4 offset2; + +const int SMAA_MAX_SEARCH_STEPS = 16; + +void main() { + // Scale vertex attribute to [0-1] range + const vec2 madd = vec2(0.5, 0.5); + texCoord = pos.xy * madd + madd; + + // Blend Weight Calculation Vertex Shader + pixcoord = texCoord * screenSize; + + // We will use these offsets for the searches later on (see @PSEUDO_GATHER4): + offset0 = screenSizeInv.xyxy * vec4(-0.25, -0.125, 1.25, -0.125) + texCoord.xyxy; + offset1 = screenSizeInv.xyxy * vec4(-0.125, -0.25, -0.125, 1.25) + texCoord.xyxy; + + // And these for the searches, they indicate the ends of the loops: + offset2 = screenSizeInv.xxyy * + (vec4(-2.0, 2.0, -2.0, 2.0) * float(SMAA_MAX_SEARCH_STEPS)) + + vec4(offset0.xz, offset1.yw); + + gl_Position = vec4(pos.xy, 0.0, 1.0); +} diff --git a/compiled/Shaders/smaa_edge_detect.frag.glsl b/compiled/Shaders/smaa_edge_detect.frag.glsl new file mode 100644 index 00000000..f42f080d --- /dev/null +++ b/compiled/Shaders/smaa_edge_detect.frag.glsl @@ -0,0 +1,207 @@ +/** + * Copyright (C) 2013 Jorge Jimenez (jorge@iryoku.com) + * Copyright (C) 2013 Jose I. Echevarria (joseignacioechevarria@gmail.com) + * Copyright (C) 2013 Belen Masia (bmasia@unizar.es) + * Copyright (C) 2013 Fernando Navarro (fernandn@microsoft.com) + * Copyright (C) 2013 Diego Gutierrez (diegog@unizar.es) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to + * do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. As clarification, there + * is no requirement that the copyright notice and permission be included in + * binary distributions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * _______ ___ ___ ___ ___ + * / || \/ | / \ / \ + * | (---- | \ / | / ^ \ / ^ \ + * \ \ | |\/| | / /_\ \ / /_\ \ + * ----) | | | | | / _____ \ / _____ \ + * |_______/ |__| |__| /__/ \__\ /__/ \__\ + * + * E N H A N C E D + * S U B P I X E L M O R P H O L O G I C A L A N T I A L I A S I N G + * + * http://www.iryoku.com/smaa/ + */ +#version 450 + +#define SMAA_THRESHOLD 0.1 +#define SMAA_DEPTH_THRESHOLD (0.1 * SMAA_THRESHOLD) // For depth edge detection, depends on the depth range of the scene +#define SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR 2.0 + +uniform sampler2D colorTex; + +in vec2 texCoord; +in vec4 offset0; +in vec4 offset1; +in vec4 offset2; +out vec4 fragColor; + +// Misc functions +// Gathers current pixel, and the top-left neighbors. +// vec3 SMAAGatherNeighbours(vec2 texcoord/*, vec4 offset[3], sampler2D tex*/) { + // float P = textureLod(tex, texcoord, 0.0).r; + // float Pleft = textureLod(tex, offset0.xy, 0.0).r; + // float Ptop = textureLod(tex, offset0.zw, 0.0).r; + // return vec3(P, Pleft, Ptop); +// } + +// Edge Detection Pixel Shaders (First Pass) +// Adjusts the threshold by means of predication. +// vec2 SMAACalculatePredicatedThreshold(vec2 texcoord, vec4 offset[3], sampler2D predicationTex) { +// vec3 neighbours = SMAAGatherNeighbours(texcoord, offset, predicationTex); +// vec2 delta = abs(neighbours.xx - neighbours.yz); +// vec2 edges = step(SMAA_PREDICATION_THRESHOLD, delta); +// return SMAA_PREDICATION_SCALE * SMAA_THRESHOLD * (1.0 - SMAA_PREDICATION_STRENGTH * edges); +// } + +// Luma Edge Detection +// IMPORTANT NOTICE: luma edge detection requires gamma-corrected colors, and +// thus 'colorTex' should be a non-sRGB texture. +vec2 SMAALumaEdgeDetectionPS(vec2 texcoord + //#if SMAA_PREDICATION + //, sampler2D predicationTex + //#endif + ) { + // Calculate the threshold: + //#if SMAA_PREDICATION + //vec2 threshold = SMAACalculatePredicatedThreshold(texcoord, offset, SMAATexturePass2D(predicationTex)); + //#else + vec2 threshold = vec2(SMAA_THRESHOLD, SMAA_THRESHOLD); + //#endif + + // Calculate lumas: + vec3 weights = vec3(0.2126, 0.7152, 0.0722); + float L = dot(textureLod(colorTex, texcoord, 0.0).rgb, weights); + + float Lleft = dot(textureLod(colorTex, offset0.xy, 0.0).rgb, weights); + float Ltop = dot(textureLod(colorTex, offset0.zw, 0.0).rgb, weights); + + // We do the usual threshold: + vec4 delta; + delta.xy = abs(L - vec2(Lleft, Ltop)); + vec2 edges = step(threshold, delta.xy); + + // Then discard if there is no edge: + if (dot(edges, vec2(1.0, 1.0)) == 0.0) + discard; + + // Calculate right and bottom deltas: + float Lright = dot(textureLod(colorTex, offset1.xy, 0.0).rgb, weights); + float Lbottom = dot(textureLod(colorTex, offset1.zw, 0.0).rgb, weights); + delta.zw = abs(L - vec2(Lright, Lbottom)); + + // Calculate the maximum delta in the direct neighborhood: + vec2 maxDelta = max(delta.xy, delta.zw); + + // Calculate left-left and top-top deltas: + float Lleftleft = dot(textureLod(colorTex, offset2.xy, 0.0).rgb, weights); + float Ltoptop = dot(textureLod(colorTex, offset2.zw, 0.0).rgb, weights); + delta.zw = abs(vec2(Lleft, Ltop) - vec2(Lleftleft, Ltoptop)); + + // Calculate the final maximum delta: + maxDelta = max(maxDelta.xy, delta.zw); + float finalDelta = max(maxDelta.x, maxDelta.y); + + // Local contrast adaptation: + edges.xy *= step(finalDelta, SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR * delta.xy); + + return edges; +} + +// Color Edge Detection +// IMPORTANT NOTICE: color edge detection requires gamma-corrected colors, and +// thus 'colorTex' should be a non-sRGB texture. +vec2 SMAAColorEdgeDetectionPS(vec2 texcoord + //#if SMAA_PREDICATION + //, sampler2D predicationTex + //#endif + ) { + // Calculate the threshold: + //#if SMAA_PREDICATION + //vec2 threshold = SMAACalculatePredicatedThreshold(texcoord, offset, predicationTex); + //#else + vec2 threshold = vec2(SMAA_THRESHOLD, SMAA_THRESHOLD); + //#endif + + // Calculate color deltas: + vec4 delta; + vec3 C = textureLod(colorTex, texcoord, 0.0).rgb; + + vec3 Cleft = textureLod(colorTex, offset0.xy, 0.0).rgb; + vec3 t = abs(C - Cleft); + delta.x = max(max(t.r, t.g), t.b); + + vec3 Ctop = textureLod(colorTex, offset0.zw, 0.0).rgb; + t = abs(C - Ctop); + delta.y = max(max(t.r, t.g), t.b); + + // We do the usual threshold: + vec2 edges = step(threshold, delta.xy); + + // Then discard if there is no edge: + if (dot(edges, vec2(1.0, 1.0)) == 0.0) + discard; + + // Calculate right and bottom deltas: + vec3 Cright = textureLod(colorTex, offset1.xy, 0.0).rgb; + t = abs(C - Cright); + delta.z = max(max(t.r, t.g), t.b); + + vec3 Cbottom = textureLod(colorTex, offset1.zw, 0.0).rgb; + t = abs(C - Cbottom); + delta.w = max(max(t.r, t.g), t.b); + + // Calculate the maximum delta in the direct neighborhood: + vec2 maxDelta = max(delta.xy, delta.zw); + + // Calculate left-left and top-top deltas: + vec3 Cleftleft = textureLod(colorTex, offset2.xy, 0.0).rgb; + t = abs(C - Cleftleft); + delta.z = max(max(t.r, t.g), t.b); + + vec3 Ctoptop = textureLod(colorTex, offset2.zw, 0.0).rgb; + t = abs(C - Ctoptop); + delta.w = max(max(t.r, t.g), t.b); + + // Calculate the final maximum delta: + maxDelta = max(maxDelta.xy, delta.zw); + float finalDelta = max(maxDelta.x, maxDelta.y); + + // Local contrast adaptation: + edges.xy *= step(finalDelta, SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR * delta.xy); + + return edges; +} + +// Depth Edge Detection +// vec2 SMAADepthEdgeDetectionPS(vec2 texcoord, /*vec4 offset[3],*/ sampler2D depthTex) { + // vec3 neighbours = SMAAGatherNeighbours(texcoord, /*offset,*/ depthTex); + // vec2 delta = abs(neighbours.xx - vec2(neighbours.y, neighbours.z)); + // vec2 edges = step(SMAA_DEPTH_THRESHOLD, delta); + + // if (dot(edges, vec2(1.0, 1.0)) == 0.0) + // discard; + + // return edges; +// } + +void main() { + fragColor.rg = SMAAColorEdgeDetectionPS(texCoord); +} diff --git a/compiled/Shaders/smaa_edge_detect.vert.glsl b/compiled/Shaders/smaa_edge_detect.vert.glsl new file mode 100644 index 00000000..61b3961c --- /dev/null +++ b/compiled/Shaders/smaa_edge_detect.vert.glsl @@ -0,0 +1,33 @@ +#version 450 + +#include "compiled.inc" + +in vec2 pos; + +uniform vec2 screenSizeInv; + +out vec2 texCoord; +out vec4 offset0; +out vec4 offset1; +out vec4 offset2; + +#ifdef HLSL +#define V_DIR(v) -(v) +#else +#define V_DIR(v) v +#endif + +void main() { + // Scale vertex attribute to [0-1] range + const vec2 madd = vec2(0.5, 0.5); + texCoord = pos.xy * madd + madd; + #ifdef HLSL + texCoord.y = 1.0 - texCoord.y; + #endif + + offset0 = screenSizeInv.xyxy * vec4(-1.0, 0.0, 0.0, V_DIR(-1.0)) + texCoord.xyxy; + offset1 = screenSizeInv.xyxy * vec4( 1.0, 0.0, 0.0, V_DIR(1.0)) + texCoord.xyxy; + offset2 = screenSizeInv.xyxy * vec4(-2.0, 0.0, 0.0, V_DIR(-2.0)) + texCoord.xyxy; + + gl_Position = vec4(pos.xy, 0.0, 1.0); +} diff --git a/compiled/Shaders/smaa_neighborhood_blend.frag.glsl b/compiled/Shaders/smaa_neighborhood_blend.frag.glsl new file mode 100644 index 00000000..d307e79d --- /dev/null +++ b/compiled/Shaders/smaa_neighborhood_blend.frag.glsl @@ -0,0 +1,92 @@ +#version 450 + +#include "compiled.inc" + +uniform sampler2D colorTex; +uniform sampler2D blendTex; +#ifdef _Veloc +uniform sampler2D sveloc; +#endif + +uniform vec2 screenSizeInv; + +in vec2 texCoord; +in vec4 offset; +out vec4 fragColor; + +//----------------------------------------------------------------------------- +// Neighborhood Blending Pixel Shader (Third Pass) + +vec4 textureLodA(sampler2D tex, vec2 coords, float lod) { + #ifdef HLSL + coords.y = 1.0 - coords.y; + #endif + return textureLod(tex, coords, lod); +} + +vec4 SMAANeighborhoodBlendingPS(vec2 texcoord, vec4 offset) { + // Fetch the blending weights for current pixel: + vec4 a; + a.x = textureLod(blendTex, offset.xy, 0.0).a; // Right + a.y = textureLod(blendTex, offset.zw, 0.0).g; // Top + a.wz = textureLod(blendTex, texcoord, 0.0).xz; // Bottom / Left + + // Is there any blending weight with a value greater than 0.0? + //SMAA_BRANCH + if (dot(a, vec4(1.0, 1.0, 1.0, 1.0)) < 1e-5) { + vec4 color = textureLod(colorTex, texcoord, 0.0); + +#ifdef _Veloc + vec2 velocity = textureLod(sveloc, texCoord, 0.0).rg; + // Pack velocity into the alpha channel: + color.a = sqrt(5.0 * length(velocity)); +#endif + return color; + } + else { + bool h = max(a.x, a.z) > max(a.y, a.w); // max(horizontal) > max(vertical) + + // Calculate the blending offsets: + vec4 blendingOffset = vec4(0.0, a.y, 0.0, a.w); + vec2 blendingWeight = a.yw; + + if (h) { + blendingOffset.x = a.x; + blendingOffset.y = 0.0; + blendingOffset.z = a.z; + blendingOffset.w = 0.0; + blendingWeight.x = a.x; + blendingWeight.y = a.z; + } + + blendingWeight /= dot(blendingWeight, vec2(1.0, 1.0)); + + // Calculate the texture coordinates: + #ifdef HLSL + vec2 tc = vec2(texcoord.x, 1.0 - texcoord.y); + #else + vec2 tc = texcoord; + #endif + vec4 blendingCoord = blendingOffset * vec4(screenSizeInv.xy, -screenSizeInv.xy) + tc.xyxy; + + // We exploit bilinear filtering to mix current pixel with the chosen + // neighbor: + vec4 color = blendingWeight.x * textureLodA(colorTex, blendingCoord.xy, 0.0); + color += blendingWeight.y * textureLodA(colorTex, blendingCoord.zw, 0.0); + +#ifdef _Veloc + // Antialias velocity for proper reprojection in a later stage: + vec2 velocity = blendingWeight.x * textureLodA(sveloc, blendingCoord.xy, 0.0).rg; + velocity += blendingWeight.y * textureLodA(sveloc, blendingCoord.zw, 0.0).rg; + + // Pack velocity into the alpha channel: + color.a = sqrt(5.0 * length(velocity)); +#endif + return color; + } + return vec4(0.0); +} + +void main() { + fragColor = SMAANeighborhoodBlendingPS(texCoord, offset); +} diff --git a/compiled/Shaders/smaa_neighborhood_blend.vert.glsl b/compiled/Shaders/smaa_neighborhood_blend.vert.glsl new file mode 100644 index 00000000..8d433797 --- /dev/null +++ b/compiled/Shaders/smaa_neighborhood_blend.vert.glsl @@ -0,0 +1,29 @@ +#version 450 + +#include "compiled.inc" + +in vec2 pos; + +uniform vec2 screenSizeInv; + +out vec2 texCoord; +out vec4 offset; + +#ifdef HLSL +#define V_DIR(v) -(v) +#else +#define V_DIR(v) v +#endif + +void main() { + // Scale vertex attribute to [0-1] range + const vec2 madd = vec2(0.5, 0.5); + texCoord = pos.xy * madd + madd; + #ifdef HLSL + texCoord.y = 1.0 - texCoord.y; + #endif + + // Neighborhood Blending Vertex Shader + offset = screenSizeInv.xyxy * vec4(1.0, 0.0, 0.0, V_DIR(1.0)) + texCoord.xyxy; + gl_Position = vec4(pos.xy, 0.0, 1.0); +} diff --git a/compiled/Shaders/ssgi_pass.frag.glsl b/compiled/Shaders/ssgi_pass.frag.glsl new file mode 100644 index 00000000..acc6d341 --- /dev/null +++ b/compiled/Shaders/ssgi_pass.frag.glsl @@ -0,0 +1,107 @@ +#version 450 + +#include "compiled.inc" +#include "std/math.glsl" +#include "std/gbuffer.glsl" + +uniform sampler2D gbufferD; +uniform sampler2D gbuffer0; // Normal +// #ifdef _RTGI +// uniform sampler2D gbuffer1; // Basecol +// #endif +uniform mat4 P; +uniform mat3 V3; + +uniform vec2 cameraProj; + +const float angleMix = 0.5f; +#ifdef _SSGICone9 +const float strength = 2.0 * (1.0 / ssgiStrength); +#else +const float strength = 2.0 * (1.0 / ssgiStrength) * 1.8; +#endif + +in vec3 viewRay; +in vec2 texCoord; +out float fragColor; + +vec3 hitCoord; +vec2 coord; +float depth; +// #ifdef _RTGI +// vec3 col = vec3(0.0); +// #endif +vec3 vpos; + +vec2 getProjectedCoord(vec3 hitCoord) { + vec4 projectedCoord = P * vec4(hitCoord, 1.0); + projectedCoord.xy /= projectedCoord.w; + projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5; + #ifdef HLSL + projectedCoord.y = 1.0 - projectedCoord.y; + #endif + return projectedCoord.xy; +} + +float getDeltaDepth(vec3 hitCoord) { + coord = getProjectedCoord(hitCoord); + depth = textureLod(gbufferD, coord, 0.0).r * 2.0 - 1.0; + vec3 p = getPosView(viewRay, depth, cameraProj); + return p.z - hitCoord.z; +} + +void rayCast(vec3 dir) { + hitCoord = vpos; + dir *= ssgiRayStep * 2; + float dist = 0.15; + for (int i = 0; i < ssgiMaxSteps; i++) { + hitCoord += dir; + float delta = getDeltaDepth(hitCoord); + if (delta > 0.0 && delta < 0.2) { + dist = distance(vpos, hitCoord); + break; + } + } + fragColor += dist; + // #ifdef _RTGI + // col += textureLod(gbuffer1, coord, 0.0).rgb * ((ssgiRayStep * ssgiMaxSteps) - dist); + // #endif +} + +vec3 tangent(const vec3 n) { + vec3 t1 = cross(n, vec3(0, 0, 1)); + vec3 t2 = cross(n, vec3(0, 1, 0)); + if (length(t1) > length(t2)) return normalize(t1); + else return normalize(t2); +} + +void main() { + fragColor = 0; + vec4 g0 = textureLod(gbuffer0, texCoord, 0.0); + float d = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0; + + vec2 enc = g0.rg; + vec3 n; + n.z = 1.0 - abs(enc.x) - abs(enc.y); + n.xy = n.z >= 0.0 ? enc.xy : octahedronWrap(enc.xy); + n = normalize(V3 * n); + + vpos = getPosView(viewRay, d, cameraProj); + + rayCast(n); + vec3 o1 = normalize(tangent(n)); + vec3 o2 = (cross(o1, n)); + vec3 c1 = 0.5f * (o1 + o2); + vec3 c2 = 0.5f * (o1 - o2); + rayCast(mix(n, o1, angleMix)); + rayCast(mix(n, o2, angleMix)); + rayCast(mix(n, -c1, angleMix)); + rayCast(mix(n, -c2, angleMix)); + + #ifdef _SSGICone9 + rayCast(mix(n, -o1, angleMix)); + rayCast(mix(n, -o2, angleMix)); + rayCast(mix(n, c1, angleMix)); + rayCast(mix(n, c2, angleMix)); + #endif +} diff --git a/compiled/Shaders/ssr_pass.frag.glsl b/compiled/Shaders/ssr_pass.frag.glsl new file mode 100644 index 00000000..c5d06198 --- /dev/null +++ b/compiled/Shaders/ssr_pass.frag.glsl @@ -0,0 +1,105 @@ +#version 450 + +#include "compiled.inc" +#include "std/math.glsl" +#include "std/gbuffer.glsl" + +uniform sampler2D tex; +uniform sampler2D gbufferD; +uniform sampler2D gbuffer0; // Normal, roughness +uniform sampler2D gbuffer1; // basecol, spec +uniform mat4 P; +uniform mat3 V3; +uniform vec2 cameraProj; + +in vec3 viewRay; +in vec2 texCoord; +out vec4 fragColor; + +vec3 hitCoord; +float depth; + +const int numBinarySearchSteps = 7; +const int maxSteps = 18; + +vec2 getProjectedCoord(const vec3 hit) { + vec4 projectedCoord = P * vec4(hit, 1.0); + projectedCoord.xy /= projectedCoord.w; + projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5; + #ifdef HLSL + projectedCoord.y = 1.0 - projectedCoord.y; + #endif + return projectedCoord.xy; +} + +float getDeltaDepth(const vec3 hit) { + depth = textureLod(gbufferD, getProjectedCoord(hit), 0.0).r * 2.0 - 1.0; + vec3 viewPos = getPosView(viewRay, depth, cameraProj); + return viewPos.z - hit.z; +} + +vec4 binarySearch(vec3 dir) { + float ddepth; + vec3 start = hitCoord; + for (int i = 0; i < numBinarySearchSteps; i++) { + dir *= 0.5; + hitCoord -= dir; + ddepth = getDeltaDepth(hitCoord); + if (ddepth < 0.0) hitCoord += dir; + } + // Ugly discard of hits too far away + if (abs(ddepth) > ssrSearchDist / 500) return vec4(0.0); + return vec4(getProjectedCoord(hitCoord), 0.0, 1.0); +} + +vec4 rayCast(vec3 dir) { + dir *= ssrRayStep; + for (int i = 0; i < maxSteps; i++) { + hitCoord += dir; + if (getDeltaDepth(hitCoord) > 0.0) return binarySearch(dir); + } + return vec4(0.0); +} + +void main() { + vec4 g0 = textureLod(gbuffer0, texCoord, 0.0); + float roughness = unpackFloat(g0.b).y; + if (roughness == 1.0) { fragColor.rgb = vec3(0.0); return; } + + float spec = fract(textureLod(gbuffer1, texCoord, 0.0).a); + if (spec == 0.0) { fragColor.rgb = vec3(0.0); return; } + + float d = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0; + if (d == 1.0) { fragColor.rgb = vec3(0.0); return; } + + vec2 enc = g0.rg; + vec3 n; + n.z = 1.0 - abs(enc.x) - abs(enc.y); + n.xy = n.z >= 0.0 ? enc.xy : octahedronWrap(enc.xy); + n = normalize(n); + + vec3 viewNormal = V3 * n; + vec3 viewPos = getPosView(viewRay, d, cameraProj); + vec3 reflected = normalize(reflect(viewPos, viewNormal)); + hitCoord = viewPos; + + vec3 dir = reflected * (1.0 - rand(texCoord) * ssrJitter * roughness) * 2.0; + // * max(ssrMinRayStep, -viewPos.z) + vec4 coords = rayCast(dir); + + vec2 deltaCoords = abs(vec2(0.5, 0.5) - coords.xy); + float screenEdgeFactor = clamp(1.0 - (deltaCoords.x + deltaCoords.y), 0.0, 1.0); + + float reflectivity = 1.0 - roughness; + float intensity = pow(reflectivity, ssrFalloffExp) * + screenEdgeFactor * + clamp(-reflected.z, 0.0, 1.0) * + clamp((ssrSearchDist - length(viewPos - hitCoord)) * + (1.0 / ssrSearchDist), 0.0, 1.0) * + coords.w; + + intensity = clamp(intensity, 0.0, 1.0); + vec3 reflCol = textureLod(tex, coords.xy, 0.0).rgb; + reflCol = clamp(reflCol, 0.0, 1.0); + fragColor.rgb = reflCol * intensity * 0.5; +} diff --git a/compiled/Shaders/std/brdf.glsl b/compiled/Shaders/std/brdf.glsl new file mode 100644 index 00000000..c4b6d5e5 --- /dev/null +++ b/compiled/Shaders/std/brdf.glsl @@ -0,0 +1,123 @@ +#ifndef _BRDF_GLSL_ +#define _BRDF_GLSL_ + +// http://xlgames-inc.github.io/posts/improvedibl/ +// http://blog.selfshadow.com/publications/s2013-shading-course/ +vec3 f_schlick(const vec3 f0, const float vh) { + return f0 + (1.0 - f0) * exp2((-5.55473 * vh - 6.98316) * vh); +} + +float v_smithschlick(const float nl, const float nv, const float a) { + return 1.0 / ((nl * (1.0 - a) + a) * (nv * (1.0 - a) + a)); +} + +float d_ggx(const float nh, const float a) { + float a2 = a * a; + float denom = pow(nh * nh * (a2 - 1.0) + 1.0, 2.0); + return a2 * (1.0 / 3.1415926535) / denom; +} + +vec3 specularBRDF(const vec3 f0, const float roughness, const float nl, const float nh, const float nv, const float vh) { + float a = roughness * roughness; + return d_ggx(nh, a) * clamp(v_smithschlick(nl, nv, a), 0.0, 1.0) * f_schlick(f0, vh) / 4.0; +} + +// John Hable - Optimizing GGX Shaders +// http://filmicworlds.com/blog/optimizing-ggx-shaders-with-dotlh/ +vec3 specularBRDFb(const vec3 f0, const float roughness, const float dotNL, const float dotNH, const float dotLH) { + // D + const float pi = 3.1415926535; + float alpha = roughness * roughness; + float alphaSqr = alpha * alpha; + float denom = dotNH * dotNH * (alphaSqr - 1.0) + 1.0; + float D = alphaSqr / (pi * denom * denom); + // F + const float F_a = 1.0; + float F_b = pow(1.0 - dotLH, 5.0); + // V + float vis; + float k = alpha / 2.0; + float k2 = k * k; + float invK2 = 1.0 - k2; + vis = 1.0 / (dotLH * dotLH * invK2 + k2); + vec2 FV_helper = vec2((F_a - F_b) * vis, F_b * vis); + + vec3 FV = f0 * FV_helper.x + FV_helper.y; + vec3 specular = clamp(dotNL, 0.0, 1.0) * D * FV; + return specular / 4.0; // TODO: get rid of / 4.0 +} + +vec3 orenNayarDiffuseBRDF(const vec3 albedo, const float roughness, const float nv, const float nl, const float vh) { + float a = roughness * roughness; + float s = a; + float s2 = s * s; + float vl = 2.0 * vh * vh - 1.0; // Double angle identity + float Cosri = vl - nv * nl; + float C1 = 1.0 - 0.5 * s2 / (s2 + 0.33); + float test = 1.0; + if (Cosri >= 0.0) test = (1.0 / (max(nl, nv))); + float C2 = 0.45 * s2 / (s2 + 0.09) * Cosri * test; + return albedo * max(0.0, nl) * (C1 + C2) * (1.0 + roughness * 0.5); +} + +vec3 lambertDiffuseBRDF(const vec3 albedo, const float nl) { + return albedo * max(0.0, nl); +} + +vec3 surfaceAlbedo(const vec3 baseColor, const float metalness) { + return mix(baseColor, vec3(0.0), metalness); +} + +vec3 surfaceF0(const vec3 baseColor, const float metalness) { + return mix(vec3(0.04), baseColor, metalness); +} + +float getMipFromRoughness(const float roughness, const float numMipmaps) { + // First mipmap level = roughness 0, last = roughness = 1 + return roughness * numMipmaps; +} + +float wardSpecular(vec3 N, vec3 H, float dotNL, float dotNV, float dotNH, vec3 fiberDirection, float shinyParallel, float shinyPerpendicular) { + if(dotNL < 0.0 || dotNV < 0.0) { + return 0.0; + } + // fiberDirection - parse from rotation + // shinyParallel - roughness + // shinyPerpendicular - anisotropy + + vec3 fiberParallel = normalize(fiberDirection); + vec3 fiberPerpendicular = normalize(cross(N, fiberDirection)); + float dotXH = dot(fiberParallel, H); + float dotYH = dot(fiberPerpendicular, H); + const float PI = 3.1415926535; + float coeff = sqrt(dotNL/dotNV) / (4.0 * PI * shinyParallel * shinyPerpendicular); + float theta = (pow(dotXH/shinyParallel, 2.0) + pow(dotYH/shinyPerpendicular, 2.0)) / (1.0 + dotNH); + return clamp(coeff * exp(-2.0 * theta), 0.0, 1.0); +} + +// https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile +// vec3 EnvBRDFApprox(vec3 SpecularColor, float Roughness, float NoV) { +// const vec4 c0 = { -1, -0.0275, -0.572, 0.022 }; +// const vec4 c1 = { 1, 0.0425, 1.04, -0.04 }; +// vec4 r = Roughness * c0 + c1; +// float a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y; +// vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw; +// return SpecularColor * AB.x + AB.y; +// } +// float EnvBRDFApproxNonmetal(float Roughness, float NoV) { +// // Same as EnvBRDFApprox( 0.04, Roughness, NoV ) +// const vec2 c0 = { -1, -0.0275 }; +// const vec2 c1 = { 1, 0.0425 }; +// vec2 r = Roughness * c0 + c1; +// return min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y; +// } +float D_Approx(const float Roughness, const float RoL) { + float a = Roughness * Roughness; + float a2 = a * a; + float rcp_a2 = 1.0 / a2;//rcp(a2); + // 0.5 / ln(2), 0.275 / ln(2) + float c = 0.72134752 * rcp_a2 + 0.39674113; + return rcp_a2 * exp2( c * RoL - c ); +} + +#endif diff --git a/compiled/Shaders/std/clusters.glsl b/compiled/Shaders/std/clusters.glsl new file mode 100644 index 00000000..9da7a450 --- /dev/null +++ b/compiled/Shaders/std/clusters.glsl @@ -0,0 +1,17 @@ + +const int maxLights = 16; +const int maxLightsCluster = 4; // Ensure fast loop unroll before going higher +const float clusterNear = 3.0; +const vec3 clusterSlices = vec3(16, 16, 16); + +int getClusterI(vec2 tc, float viewz, vec2 cameraPlane) { + int sliceZ = 0; + float cnear = clusterNear + cameraPlane.x; + if (viewz >= cnear) { + float z = log(viewz - cnear + 1.0) / log(cameraPlane.y - cnear + 1.0); + sliceZ = int(z * (clusterSlices.z - 1)) + 1; + } + return int(tc.x * clusterSlices.x) + + int(int(tc.y * clusterSlices.y) * clusterSlices.x) + + int(sliceZ * clusterSlices.x * clusterSlices.y); +} diff --git a/compiled/Shaders/std/conetrace.glsl b/compiled/Shaders/std/conetrace.glsl new file mode 100644 index 00000000..7a8188c2 --- /dev/null +++ b/compiled/Shaders/std/conetrace.glsl @@ -0,0 +1,122 @@ + +#ifndef _CONETRACE_GLSL_ +#define _CONETRACE_GLSL_ + +// References +// https://github.com/Friduric/voxel-cone-tracing +// https://github.com/Cigg/Voxel-Cone-Tracing +// https://github.com/GreatBlambo/voxel_cone_tracing/ +// http://simonstechblog.blogspot.com/2013/01/implementing-voxel-cone-tracing.html +// http://leifnode.com/2015/05/voxel-cone-traced-global-illumination/ +// http://www.seas.upenn.edu/%7Epcozzi/OpenGLInsights/OpenGLInsights-SparseVoxelization.pdf +// https://research.nvidia.com/sites/default/files/publications/GIVoxels-pg2011-authors.pdf + +const float MAX_DISTANCE = 1.73205080757 * voxelgiRange; +const float VOXEL_SIZE = (2.0 / voxelgiResolution.x) * voxelgiStep; + +// uniform sampler3D voxels; +// uniform sampler3D voxelsLast; + +// vec3 orthogonal(const vec3 u) { +// // Pass normalized u +// const vec3 v = vec3(0.99146, 0.11664, 0.05832); // Pick any normalized vector +// return abs(dot(u, v)) > 0.99999 ? cross(u, vec3(0.0, 1.0, 0.0)) : cross(u, v); +// } + +vec3 tangent(const vec3 n) { + vec3 t1 = cross(n, vec3(0, 0, 1)); + vec3 t2 = cross(n, vec3(0, 1, 0)); + if (length(t1) > length(t2)) return normalize(t1); + else return normalize(t2); +} + +float traceConeAO(sampler3D voxels, const vec3 origin, vec3 dir, const float aperture, const float maxDist) { + dir = normalize(dir); + float sampleCol = 0.0; + float dist = 1.5 * VOXEL_SIZE * voxelgiOffset; + float diam = dist * aperture; + vec3 samplePos; + while (sampleCol < 1.0 && dist < maxDist) { + samplePos = dir * dist + origin; + float mip = max(log2(diam * voxelgiResolution.x), 0); + float mipSample = textureLod(voxels, samplePos * 0.5 + vec3(0.5), mip).r; + sampleCol += (1 - sampleCol) * mipSample; + dist += max(diam / 2, VOXEL_SIZE); + diam = dist * aperture; + } + return sampleCol; +} + +float traceConeAOShadow(sampler3D voxels, const vec3 origin, vec3 dir, const float aperture, const float maxDist, const float offset) { + dir = normalize(dir); + float sampleCol = 0.0; + float dist = 1.5 * VOXEL_SIZE * voxelgiOffset * 2.5; // + float diam = dist * aperture; + vec3 samplePos; + while (sampleCol < 1.0 && dist < maxDist) { + samplePos = dir * dist + origin; + float mip = max(log2(diam * voxelgiResolution.x), 0); + float mipSample = textureLod(voxels, samplePos * 0.5 + vec3(0.5), mip).r; + sampleCol += (1 - sampleCol) * mipSample; + dist += max(diam / 2, VOXEL_SIZE); + diam = dist * aperture; + } + return sampleCol; +} + +float traceShadow(sampler3D voxels, const vec3 origin, const vec3 dir) { + return traceConeAO(voxels, origin, dir, 0.14 * voxelgiAperture, 2.5 * voxelgiRange); +} + +float traceAO(const vec3 origin, const vec3 normal, sampler3D voxels) { + const float angleMix = 0.5f; + const float aperture = 0.55785173935; + vec3 o1 = normalize(tangent(normal)); + vec3 o2 = normalize(cross(o1, normal)); + vec3 c1 = 0.5f * (o1 + o2); + vec3 c2 = 0.5f * (o1 - o2); + + #ifdef HLSL + const float factor = voxelgiOcc * 0.93; + #else + const float factor = voxelgiOcc * 0.90; + #endif + + #ifdef _VoxelCones1 + return traceConeAO(voxels, origin, normal, aperture, MAX_DISTANCE) * factor; + #endif + + #ifdef _VoxelCones3 + float col = traceConeAO(voxels, origin, normal, aperture, MAX_DISTANCE); + col += traceConeAO(voxels, origin, mix(normal, o1, angleMix), aperture, MAX_DISTANCE); + col += traceConeAO(voxels, origin, mix(normal, -c2, angleMix), aperture, MAX_DISTANCE); + return (col / 3.0) * factor; + #endif + + #ifdef _VoxelCones5 + float col = traceConeAO(voxels, origin, normal, aperture, MAX_DISTANCE); + col += traceConeAO(voxels, origin, mix(normal, o1, angleMix), aperture, MAX_DISTANCE); + col += traceConeAO(voxels, origin, mix(normal, o2, angleMix), aperture, MAX_DISTANCE); + col += traceConeAO(voxels, origin, mix(normal, -c1, angleMix), aperture, MAX_DISTANCE); + col += traceConeAO(voxels, origin, mix(normal, -c2, angleMix), aperture, MAX_DISTANCE); + return (col / 5.0) * factor; + #endif + + #ifdef _VoxelCones9 + float col = traceConeAO(voxels, origin, normal, aperture, MAX_DISTANCE); + col += traceConeAO(voxels, origin, mix(normal, o1, angleMix), aperture, MAX_DISTANCE); + col += traceConeAO(voxels, origin, mix(normal, o2, angleMix), aperture, MAX_DISTANCE); + col += traceConeAO(voxels, origin, mix(normal, -c1, angleMix), aperture, MAX_DISTANCE); + col += traceConeAO(voxels, origin, mix(normal, -c2, angleMix), aperture, MAX_DISTANCE); + + col += traceConeAO(voxels, origin, mix(normal, -o1, angleMix), aperture, MAX_DISTANCE); + col += traceConeAO(voxels, origin, mix(normal, -o2, angleMix), aperture, MAX_DISTANCE); + col += traceConeAO(voxels, origin, mix(normal, c1, angleMix), aperture, MAX_DISTANCE); + col += traceConeAO(voxels, origin, mix(normal, c2, angleMix), aperture, MAX_DISTANCE); + return (col / 9.0) * factor; + #endif + + return 0.0; +} + +#endif diff --git a/compiled/Shaders/std/dof.glsl b/compiled/Shaders/std/dof.glsl new file mode 100644 index 00000000..f1416207 --- /dev/null +++ b/compiled/Shaders/std/dof.glsl @@ -0,0 +1,76 @@ +// DoF with bokeh GLSL shader by Martins Upitis (martinsh) (devlog-martinsh.blogspot.com) +// Creative Commons Attribution 3.0 Unported License + +#include "compiled.inc" +#include "std/math.glsl" + +// const float compoDOFDistance = 10.0; // Focal distance value in meters +// const float compoDOFLength = 160.0; // Focal length in mm 18-200 +// const float compoDOFFstop = 128.0; // F-stop value + +const int samples = 6; // Samples on the first ring +const int rings = 6; // Ring count +const vec2 focus = vec2(0.5, 0.5); +const float coc = 0.11; // Circle of confusion size in mm (35mm film = 0.03mm) +const float maxblur = 1.0; +const float threshold = 0.5; // Highlight threshold +const float gain = 2.0; // Highlight gain +const float bias = 0.5; // Bokeh edge bias +const float fringe = 0.7; // Bokeh chromatic aberration/fringing +const float namount = 0.0001; // Dither amount + +vec3 color(vec2 coords, const float blur, const sampler2D tex, const vec2 texStep) { + vec3 col = vec3(0.0); + col.r = textureLod(tex, coords + vec2(0.0, 1.0) * texStep * fringe * blur, 0.0).r; + col.g = textureLod(tex, coords + vec2(-0.866, -0.5) * texStep * fringe * blur, 0.0).g; + col.b = textureLod(tex, coords + vec2(0.866, -0.5) * texStep * fringe * blur, 0.0).b; + + const vec3 lumcoeff = vec3(0.299, 0.587, 0.114); + float lum = dot(col.rgb, lumcoeff); + float thresh = max((lum - threshold) * gain, 0.0); + return col + mix(vec3(0.0), col, thresh * blur); +} + +vec3 dof(const vec2 texCoord, const float gdepth, const sampler2D tex, const sampler2D gbufferD, const vec2 texStep, const vec2 cameraProj) { + float depth = linearize(gdepth, cameraProj); + // const float fDepth = compoDOFDistance; + float fDepth = linearize(textureLod(gbufferD, focus, 0.0).r * 2.0 - 1.0, cameraProj); // Autofocus + + const float f = compoDOFLength; // Focal length in mm + const float d = fDepth * 1000.0; // Focal plane in mm + float o = depth * 1000.0; // Depth in mm + float a = (o * f) / (o - f); + float b = (d * f) / (d - f); + float c = (d - f) / (d * compoDOFFstop * coc); + float blur = abs(a - b) * c; + blur = clamp(blur, 0.0, 1.0); + + vec2 noise = rand2(texCoord) * namount * blur; + float w = (texStep.x) * blur * maxblur + noise.x; + float h = (texStep.y) * blur * maxblur + noise.y; + vec3 col = vec3(0.0); + if (blur < 0.05) { + col = textureLod(tex, texCoord, 0.0).rgb; + } + else { + col = textureLod(tex, texCoord, 0.0).rgb; + float s = 1.0; + int ringsamples; + + for (int i = 1; i <= rings; ++i) { + ringsamples = i * samples; + for (int j = 0 ; j < ringsamples; ++j) { + float step = PI2 / float(ringsamples); + float pw = (cos(float(j) * step) * float(i)); + float ph = (sin(float(j) * step) * float(i)); + float p = 1.0; + // if (pentagon) p = penta(vec2(pw, ph)); + col += color(texCoord + vec2(pw * w, ph * h), blur, tex, texStep) * mix(1.0, (float(i)) / (float(rings)), bias) * p; + s += 1.0 * mix(1.0, (float(i)) / (float(rings)), bias) * p; + } + } + col /= s; + } + return col; +} + diff --git a/compiled/Shaders/std/filters.glsl b/compiled/Shaders/std/filters.glsl new file mode 100644 index 00000000..d7bc5128 --- /dev/null +++ b/compiled/Shaders/std/filters.glsl @@ -0,0 +1,60 @@ + +vec4 cubicCatmullrom(float x) { + const float s = 0.5; + float x2 = x * x; + float x3 = x2 * x; + vec4 w; + w.x = -s*x3 + 2*s*x2 - s*x + 0; + w.y = (2-s)*x3 + (s-3)*x2 + 1; + w.z = (s-2)*x3 + (3-2*s)*x2 + s*x + 0; + w.w = s*x3 - s*x2 + 0; + return w; +} + +vec4 cubic(float v) { + vec4 n = vec4(1.0, 2.0, 3.0, 4.0) - v; + vec4 s = n * n * n; + float x = s.x; + float y = s.y - 4.0 * s.x; + float z = s.z - 4.0 * s.y + 6.0 * s.x; + float w = 6.0 - x - y - z; + return vec4(x, y, z, w) * (1.0/6.0); +} + +vec3 textureBicubic(sampler2D tex, vec2 tc, vec2 texStep) { + // http://www.java-gaming.org/index.php?topic=35123.0 + vec2 texSize = 1.0 / texStep; + tc = tc * texSize - 0.5; + + vec2 fxy = fract(tc); + tc -= fxy; + vec4 xcubic = cubic(fxy.x); + vec4 ycubic = cubic(fxy.y); + + vec4 c = tc.xxyy + vec2(-0.5, 1.5).xyxy; + vec4 s = vec4(xcubic.xz + xcubic.yw, ycubic.xz + ycubic.yw); + vec4 offset = c + vec4 (xcubic.yw, ycubic.yw) / s; + offset *= texStep.xxyy; + vec3 sample0 = texture(tex, offset.xz).rgb; + vec3 sample1 = texture(tex, offset.yz).rgb; + vec3 sample2 = texture(tex, offset.xw).rgb; + vec3 sample3 = texture(tex, offset.yw).rgb; + + float sx = s.x / (s.x + s.y); + float sy = s.z / (s.z + s.w); + + return mix(mix(sample3, sample2, sx), mix(sample1, sample0, sx), sy); +} + +vec4 textureSS(sampler2D tex, vec2 tc, vec2 texStep) { + vec4 col = texture(tex, tc); + col += texture(tex, tc + vec2(1.5, 0.0) * texStep); + col += texture(tex, tc + vec2(-1.5, 0.0) * texStep); + col += texture(tex, tc + vec2(0.0, 1.5) * texStep); + col += texture(tex, tc + vec2(0.0, -1.5) * texStep); + col += texture(tex, tc + vec2(1.5, 1.5) * texStep); + col += texture(tex, tc + vec2(-1.5, -1.5) * texStep); + col += texture(tex, tc + vec2(1.5, -1.5) * texStep); + col += texture(tex, tc + vec2(-1.5, 1.5) * texStep); + return col / 9.0; +} diff --git a/compiled/Shaders/std/gbuffer.glsl b/compiled/Shaders/std/gbuffer.glsl new file mode 100644 index 00000000..4984f687 --- /dev/null +++ b/compiled/Shaders/std/gbuffer.glsl @@ -0,0 +1,130 @@ +#ifndef _GBUFFER_GLSL_ +#define _GBUFFER_GLSL_ + +vec2 octahedronWrap(const vec2 v) { + return (1.0 - abs(v.yx)) * (vec2(v.x >= 0.0 ? 1.0 : -1.0, v.y >= 0.0 ? 1.0 : -1.0)); +} + +vec3 getNor(const vec2 enc) { + vec3 n; + n.z = 1.0 - abs(enc.x) - abs(enc.y); + n.xy = n.z >= 0.0 ? enc.xy : octahedronWrap(enc.xy); + n = normalize(n); + return n; +} + +vec3 getPosView(const vec3 viewRay, const float depth, const vec2 cameraProj) { + float linearDepth = cameraProj.y / (cameraProj.x - depth); + // float linearDepth = cameraProj.y / ((depth * 0.5 + 0.5) - cameraProj.x); + return viewRay * linearDepth; +} + +vec3 getPos(const vec3 eye, const vec3 eyeLook, const vec3 viewRay, const float depth, const vec2 cameraProj) { + // eyeLook, viewRay should be normalized + float linearDepth = cameraProj.y / ((depth * 0.5 + 0.5) - cameraProj.x); + float viewZDist = dot(eyeLook, viewRay); + vec3 wposition = eye + viewRay * (linearDepth / viewZDist); + return wposition; +} + +vec3 getPosNoEye(const vec3 eyeLook, const vec3 viewRay, const float depth, const vec2 cameraProj) { + // eyeLook, viewRay should be normalized + float linearDepth = cameraProj.y / ((depth * 0.5 + 0.5) - cameraProj.x); + float viewZDist = dot(eyeLook, viewRay); + vec3 wposition = viewRay * (linearDepth / viewZDist); + return wposition; +} + +#ifdef HLSL +vec3 getPos2(const mat4 invVP, const float depth, vec2 coord) { + coord.y = 1.0 - coord.y; +#else +vec3 getPos2(const mat4 invVP, const float depth, const vec2 coord) { +#endif + vec4 pos = vec4(coord * 2.0 - 1.0, depth, 1.0); + pos = invVP * pos; + pos.xyz /= pos.w; + return pos.xyz; +} + +#ifdef HLSL +vec3 getPosView2(const mat4 invP, const float depth, vec2 coord) { + coord.y = 1.0 - coord.y; +#else +vec3 getPosView2(const mat4 invP, const float depth, const vec2 coord) { +#endif + vec4 pos = vec4(coord * 2.0 - 1.0, depth, 1.0); + pos = invP * pos; + pos.xyz /= pos.w; + return pos.xyz; +} + +#ifdef HLSL +vec3 getPos2NoEye(const vec3 eye, const mat4 invVP, const float depth, vec2 coord) { + coord.y = 1.0 - coord.y; +#else +vec3 getPos2NoEye(const vec3 eye, const mat4 invVP, const float depth, const vec2 coord) { +#endif + vec4 pos = vec4(coord * 2.0 - 1.0, depth, 1.0); + pos = invVP * pos; + pos.xyz /= pos.w; + return pos.xyz - eye; +} + +float packFloat(const float f1, const float f2) { + return floor(f1 * 100.0) + min(f2, 1.0 - 1.0 / 100.0); +} + +vec2 unpackFloat(const float f) { + return vec2(floor(f) / 100.0, fract(f)); +} + +float packFloat2(const float f1, const float f2) { + // Higher f1 = less precise f2 + return floor(f1 * 255.0) + min(f2, 1.0 - 1.0 / 100.0); +} + +vec2 unpackFloat2(const float f) { + return vec2(floor(f) / 255.0, fract(f)); +} + +vec4 encodeRGBM(const vec3 rgb) { + const float maxRange = 6.0; + float maxRGB = max(rgb.x, max(rgb.g, rgb.b)); + float m = maxRGB / maxRange; + m = ceil(m * 255.0) / 255.0; + return vec4(rgb / (m * maxRange), m); +} + +vec3 decodeRGBM(const vec4 rgbm) { + const float maxRange = 6.0; + return rgbm.rgb * rgbm.a * maxRange; +} + +uint encNor(vec3 n) { + ivec3 nor = ivec3(n * 255.0f); + uvec3 norSigns; + norSigns.x = (nor.x >> 5) & 0x04000000; + norSigns.y = (nor.y >> 14) & 0x00020000; + norSigns.z = (nor.z >> 23) & 0x00000100; + nor = abs(nor); + uint val = norSigns.x | (nor.x << 18) | norSigns.y | (nor.y << 9) | norSigns.z | nor.z; + return val; +} + +vec3 decNor(uint val) { + uvec3 nor; + nor.x = (val >> 18) & 0x000000ff; + nor.y = (val >> 9) & 0x000000ff; + nor.z = val & 0x000000ff; + uvec3 norSigns; + norSigns.x = (val >> 25) & 0x00000002; + norSigns.y = (val >> 16) & 0x00000002; + norSigns.z = (val >> 7) & 0x00000002; + norSigns = 1 - norSigns; + vec3 normal = vec3(nor) / 255.0f; + normal *= norSigns; + return normal; +} + +#endif diff --git a/compiled/Shaders/std/ies.glsl b/compiled/Shaders/std/ies.glsl new file mode 100644 index 00000000..a7e9f124 --- /dev/null +++ b/compiled/Shaders/std/ies.glsl @@ -0,0 +1,32 @@ + +uniform sampler2D texIES; + +float iesAttenuation(vec3 l) { + + const float PI = 3.1415926535; + // https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf + // Sample direction into light space + // vec3 iesSampleDirection = mul(light.worldToLight , -L); + // Cartesian to spherical + // Texture encoded with cos( phi ), scale from -1 - >1 to 0 - >1 + // float phiCoord = (iesSampleDirection.z * 0.5f) + 0.5f; + // float theta = atan2 (iesSampleDirection.y , iesSampleDirection .x); + // float thetaCoord = theta * (1.0 / (PI * 2.0)); + // float iesProfileScale = texture(texIES, vec2(thetaCoord, phiCoord)).r; + // return iesProfileScale; + + // 1D texture + // vec3 pl = normalize(p - lightPos); + // float f = asin(dot(pl, l)) / PI + 0.5; + // return texture(texIES, vec2(f, 0.0)).r; + + // 1D texture + // float cosTheta = dot(lightToPos, lightDir); + // float angle = acos(cosTheta) * (1.0 / PI); + // return texture(texIES, vec2(angle, 0.0), 0.0).r; + + // Based on https://github.com/tobspr/RenderPipeline + float hor = acos(l.z) / PI; + float vert = atan(l.x, l.y) * (1.0 / (PI * 2.0)) + 0.5; + return texture(texIES, vec2(hor, vert)).r; +} diff --git a/compiled/Shaders/std/light.glsl b/compiled/Shaders/std/light.glsl new file mode 100644 index 00000000..14502b52 --- /dev/null +++ b/compiled/Shaders/std/light.glsl @@ -0,0 +1,205 @@ +#ifndef _LIGHT_GLSL_ +#define _LIGHT_GLSL_ + +#include "compiled.inc" +#include "std/brdf.glsl" +#include "std/math.glsl" +#ifdef _ShadowMap +#include "std/shadows.glsl" +#endif +#ifdef _VoxelAOvar +#include "std/conetrace.glsl" +#endif +#ifdef _LTC +#include "std/ltc.glsl" +#endif +#ifdef _LightIES +#include "std/ies.glsl" +#endif + +#ifdef _ShadowMap +#ifdef _SinglePoint + #ifdef _Spot + uniform sampler2DShadow shadowMapSpot[1]; + uniform mat4 LWVPSpot0; + #else + uniform samplerCubeShadow shadowMapPoint[1]; + uniform vec2 lightProj; + #endif +#endif +#ifdef _Clusters + uniform samplerCubeShadow shadowMapPoint[4]; + uniform vec2 lightProj; + #ifdef _Spot + uniform sampler2DShadow shadowMapSpot[4]; + uniform mat4 LWVPSpot0; + uniform mat4 LWVPSpot1; + uniform mat4 LWVPSpot2; + uniform mat4 LWVPSpot3; + #endif +#endif +#endif + +#ifdef _LTC +uniform vec3 lightArea0; +uniform vec3 lightArea1; +uniform vec3 lightArea2; +uniform vec3 lightArea3; +uniform sampler2D sltcMat; +uniform sampler2D sltcMag; +#ifdef _ShadowMap + #ifndef _Spot + #ifdef _SinglePoint + uniform sampler2DShadow shadowMapSpot[1]; + uniform mat4 LWVPSpot0; + #endif + #ifdef _Clusters + uniform sampler2DShadow shadowMapSpot[4]; + uniform mat4 LWVPSpot0; + uniform mat4 LWVPSpot1; + uniform mat4 LWVPSpot2; + uniform mat4 LWVPSpot3; + #endif + #endif +#endif +#endif + +vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, const vec3 lp, const vec3 lightCol, + const vec3 albedo, const float rough, const float spec, const vec3 f0 + #ifdef _ShadowMap + , int index, float bias + #endif + #ifdef _Spot + , bool isSpot, float spotA, float spotB, vec3 spotDir + #endif + #ifdef _VoxelAOvar + #ifdef _VoxelShadow + , sampler3D voxels, vec3 voxpos + #endif + #endif + #ifdef _MicroShadowing + , float occ + #endif + ) { + vec3 ld = lp - p; + vec3 l = normalize(ld); + vec3 h = normalize(v + l); + float dotNH = dot(n, h); + float dotVH = dot(v, h); + float dotNL = dot(n, l); + + #ifdef _LTC + float theta = acos(dotNV); + vec2 tuv = vec2(rough, theta / (0.5 * PI)); + tuv = tuv * LUT_SCALE + LUT_BIAS; + vec4 t = textureLod(sltcMat, tuv, 0.0); + mat3 invM = mat3( + vec3(1.0, 0.0, t.y), + vec3(0.0, t.z, 0.0), + vec3(t.w, 0.0, t.x)); + float ltcspec = ltcEvaluate(n, v, dotNV, p, invM, lightArea0, lightArea1, lightArea2, lightArea3); + ltcspec *= textureLod(sltcMag, tuv, 0.0).a; + float ltcdiff = ltcEvaluate(n, v, dotNV, p, mat3(1.0), lightArea0, lightArea1, lightArea2, lightArea3); + vec3 direct = albedo * ltcdiff + ltcspec * spec * 0.05; + #else + vec3 direct = lambertDiffuseBRDF(albedo, dotNL) + + specularBRDF(f0, rough, dotNL, dotNH, dotNV, dotVH) * spec; + #endif + direct *= attenuate(distance(p, lp)); + direct *= lightCol; + + #ifdef _MicroShadowing + direct *= dotNL + 2.0 * occ * occ - 1.0; + #endif + + #ifdef _VoxelAOvar + #ifdef _VoxelShadow + direct *= 1.0 - traceShadow(voxels, voxpos, l); + #endif + #endif + + #ifdef _LTC + #ifdef _ShadowMap + #ifdef _SinglePoint + vec4 lPos = LWVPSpot0 * vec4(p + n * bias * 10, 1.0); + direct *= shadowTest(shadowMapSpot[0], lPos.xyz / lPos.w, bias); + #endif + #ifdef _Clusters + if (index == 0) { + vec4 lPos = LWVPSpot0 * vec4(p + n * bias * 10, 1.0); + direct *= shadowTest(shadowMapSpot[0], lPos.xyz / lPos.w, bias); + } + else if (index == 1) { + vec4 lPos = LWVPSpot1 * vec4(p + n * bias * 10, 1.0); + direct *= shadowTest(shadowMapSpot[1], lPos.xyz / lPos.w, bias); + } + else if (index == 2) { + vec4 lPos = LWVPSpot2 * vec4(p + n * bias * 10, 1.0); + direct *= shadowTest(shadowMapSpot[2], lPos.xyz / lPos.w, bias); + } + else if (index == 3) { + vec4 lPos = LWVPSpot3 * vec4(p + n * bias * 10, 1.0); + direct *= shadowTest(shadowMapSpot[3], lPos.xyz / lPos.w, bias); + } + #endif + #endif + return direct; + #endif + + #ifdef _Spot + if (isSpot) { + float spotEffect = dot(spotDir, l); // lightDir + // x - cutoff, y - cutoff - exponent + if (spotEffect < spotA) { + direct *= smoothstep(spotB, spotA, spotEffect); + } + #ifdef _ShadowMap + #ifdef _SinglePoint + vec4 lPos = LWVPSpot0 * vec4(p + n * bias * 10, 1.0); + direct *= shadowTest(shadowMapSpot[0], lPos.xyz / lPos.w, bias); + #endif + #ifdef _Clusters + if (index == 0) { + vec4 lPos = LWVPSpot0 * vec4(p + n * bias * 10, 1.0); + direct *= shadowTest(shadowMapSpot[0], lPos.xyz / lPos.w, bias); + } + else if (index == 1) { + vec4 lPos = LWVPSpot1 * vec4(p + n * bias * 10, 1.0); + direct *= shadowTest(shadowMapSpot[1], lPos.xyz / lPos.w, bias); + } + else if (index == 2) { + vec4 lPos = LWVPSpot2 * vec4(p + n * bias * 10, 1.0); + direct *= shadowTest(shadowMapSpot[2], lPos.xyz / lPos.w, bias); + } + else if (index == 3) { + vec4 lPos = LWVPSpot3 * vec4(p + n * bias * 10, 1.0); + direct *= shadowTest(shadowMapSpot[3], lPos.xyz / lPos.w, bias); + } + #endif + #endif + return direct; + } + #endif + + #ifdef _LightIES + direct *= iesAttenuation(-l); + #endif + + #ifdef _ShadowMap + #ifdef _SinglePoint + #ifndef _Spot + direct *= PCFCube(shadowMapPoint[0], ld, -l, bias, lightProj, n); + #endif + #endif + #ifdef _Clusters + if (index == 0) direct *= PCFCube(shadowMapPoint[0], ld, -l, bias, lightProj, n); + else if (index == 1) direct *= PCFCube(shadowMapPoint[1], ld, -l, bias, lightProj, n); + else if (index == 2) direct *= PCFCube(shadowMapPoint[2], ld, -l, bias, lightProj, n); + else if (index == 3) direct *= PCFCube(shadowMapPoint[3], ld, -l, bias, lightProj, n); + #endif + #endif + + return direct; +} + +#endif diff --git a/compiled/Shaders/std/light_mobile.glsl b/compiled/Shaders/std/light_mobile.glsl new file mode 100644 index 00000000..4b77b3c8 --- /dev/null +++ b/compiled/Shaders/std/light_mobile.glsl @@ -0,0 +1,107 @@ +#ifndef _LIGHT_MOBILE_GLSL_ +#define _LIGHT_MOBILE_GLSL_ + +#include "compiled.inc" +#include "std/brdf.glsl" +#ifdef _ShadowMap +#include "std/shadows.glsl" +#endif + +#ifdef _ShadowMap +#ifdef _SinglePoint + #ifdef _Spot + uniform sampler2DShadow shadowMapSpot[1]; + uniform mat4 LWVPSpot0; + #else + uniform samplerCubeShadow shadowMapPoint[1]; + uniform vec2 lightProj; + #endif +#endif +#ifdef _Clusters + uniform samplerCubeShadow shadowMapPoint[4]; + uniform vec2 lightProj; + #ifdef _Spot + uniform sampler2DShadow shadowMapSpot[4]; + uniform mat4 LWVPSpot0; + uniform mat4 LWVPSpot1; + uniform mat4 LWVPSpot2; + uniform mat4 LWVPSpot3; + #endif +#endif +#endif + +vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, const vec3 lp, const vec3 lightCol, + const vec3 albedo, const float rough, const float spec, const vec3 f0 + #ifdef _ShadowMap + , int index, float bias + #endif + #ifdef _Spot + , bool isSpot, float spotA, float spotB, vec3 spotDir + #endif + ) { + vec3 ld = lp - p; + vec3 l = normalize(ld); + vec3 h = normalize(v + l); + float dotNH = dot(n, h); + float dotVH = dot(v, h); + float dotNL = dot(n, l); + + vec3 direct = albedo * max(dotNL, 0.0) + + specularBRDF(f0, rough, dotNL, dotNH, dotNV, dotVH) * spec; + + direct *= lightCol; + direct *= attenuate(distance(p, lp)); + + #ifdef _Spot + if (isSpot) { + float spotEffect = dot(spotDir, l); // lightDir + // x - cutoff, y - cutoff - exponent + if (spotEffect < spotA) { + direct *= smoothstep(spotB, spotA, spotEffect); + } + #ifdef _ShadowMap + #ifdef _SinglePoint + vec4 lPos = LWVPSpot0 * vec4(p + n * bias * 10, 1.0); + direct *= shadowTest(shadowMapSpot[0], lPos.xyz / lPos.w, bias); + #endif + #ifdef _Clusters + if (index == 0) { + vec4 lPos = LWVPSpot0 * vec4(p + n * bias * 10, 1.0); + direct *= shadowTest(shadowMapSpot[0], lPos.xyz / lPos.w, bias); + } + else if (index == 1) { + vec4 lPos = LWVPSpot1 * vec4(p + n * bias * 10, 1.0); + direct *= shadowTest(shadowMapSpot[1], lPos.xyz / lPos.w, bias); + } + else if (index == 2) { + vec4 lPos = LWVPSpot2 * vec4(p + n * bias * 10, 1.0); + direct *= shadowTest(shadowMapSpot[2], lPos.xyz / lPos.w, bias); + } + else if (index == 3) { + vec4 lPos = LWVPSpot3 * vec4(p + n * bias * 10, 1.0); + direct *= shadowTest(shadowMapSpot[3], lPos.xyz / lPos.w, bias); + } + #endif + #endif + return direct; + } + #endif + + #ifdef _ShadowMap + #ifndef _Spot + #ifdef _SinglePoint + direct *= PCFCube(shadowMapPoint[0], ld, -l, bias, lightProj, n); + #endif + #ifdef _Clusters + if (index == 0) direct *= PCFCube(shadowMapPoint[0], ld, -l, bias, lightProj, n); + else if (index == 1) direct *= PCFCube(shadowMapPoint[1], ld, -l, bias, lightProj, n); + else if (index == 2) direct *= PCFCube(shadowMapPoint[2], ld, -l, bias, lightProj, n); + else if (index == 3) direct *= PCFCube(shadowMapPoint[3], ld, -l, bias, lightProj, n); + #endif + #endif + #endif + + return direct; +} + +#endif diff --git a/compiled/Shaders/std/ltc.glsl b/compiled/Shaders/std/ltc.glsl new file mode 100644 index 00000000..87eb0d93 --- /dev/null +++ b/compiled/Shaders/std/ltc.glsl @@ -0,0 +1,157 @@ +// Linearly Transformed Cosines +// https://eheitzresearch.wordpress.com/415-2/ + +const float LUT_SIZE = 64.0; +const float LUT_SCALE = (LUT_SIZE - 1.0) / LUT_SIZE; +const float LUT_BIAS = 0.5 / LUT_SIZE; + +vec3 L0; +vec3 L1; +vec3 L2; +vec3 L3; +vec3 L4; + +float integrateEdge(vec3 v1, vec3 v2) { + float cosTheta = dot(v1, v2); + float theta = acos(cosTheta); + float res = cross(v1, v2).z * ((theta > 0.001) ? theta / sin(theta) : 1.0); + return res; +} + +int clipQuadToHorizon(/*inout vec3 L[5], out int n*/) { + int n = 0; + // Detect clipping config + int config = 0; + if (L0.z > 0.0) config += 1; + if (L1.z > 0.0) config += 2; + if (L2.z > 0.0) config += 4; + if (L3.z > 0.0) config += 8; + + // Clip + if (config == 0) { + // Clip all + } + else if (config == 1) { // V1 clip V2 V3 V4 + n = 3; + L1 = -L1.z * L0 + L0.z * L1; + L2 = -L3.z * L0 + L0.z * L3; + } + else if (config == 2) { // V2 clip V1 V3 V4 + n = 3; + L0 = -L0.z * L1 + L1.z * L0; + L2 = -L2.z * L1 + L1.z * L2; + } + else if (config == 3) { // V1 V2 clip V3 V4 + n = 4; + L2 = -L2.z * L1 + L1.z * L2; + L3 = -L3.z * L0 + L0.z * L3; + } + else if (config == 4) { // V3 clip V1 V2 V4 + n = 3; + L0 = -L3.z * L2 + L2.z * L3; + L1 = -L1.z * L2 + L2.z * L1; + } + else if (config == 5) { // V1 V3 clip V2 V4) impossible + n = 0; + } + else if (config == 6) { // V2 V3 clip V1 V4 + n = 4; + L0 = -L0.z * L1 + L1.z * L0; + L3 = -L3.z * L2 + L2.z * L3; + } + else if (config == 7) { // V1 V2 V3 clip V4 + n = 5; + L4 = -L3.z * L0 + L0.z * L3; + L3 = -L3.z * L2 + L2.z * L3; + } + else if (config == 8) { // V4 clip V1 V2 V3 + n = 3; + L0 = -L0.z * L3 + L3.z * L0; + L1 = -L2.z * L3 + L3.z * L2; + L2 = L3; + } + else if (config == 9) { // V1 V4 clip V2 V3 + n = 4; + L1 = -L1.z * L0 + L0.z * L1; + L2 = -L2.z * L3 + L3.z * L2; + } + else if (config == 10) { // V2 V4 clip V1 V3) impossible + n = 0; + } + else if (config == 11) { // V1 V2 V4 clip V3 + n = 5; + L4 = L3; + L3 = -L2.z * L3 + L3.z * L2; + L2 = -L2.z * L1 + L1.z * L2; + } + else if (config == 12) { // V3 V4 clip V1 V2 + n = 4; + L1 = -L1.z * L2 + L2.z * L1; + L0 = -L0.z * L3 + L3.z * L0; + } + else if (config == 13) { // V1 V3 V4 clip V2 + n = 5; + L4 = L3; + L3 = L2; + L2 = -L1.z * L2 + L2.z * L1; + L1 = -L1.z * L0 + L0.z * L1; + } + else if (config == 14) { // V2 V3 V4 clip V1 + n = 5; + L4 = -L0.z * L3 + L3.z * L0; + L0 = -L0.z * L1 + L1.z * L0; + } + else if (config == 15) { // V1 V2 V3 V4 + n = 4; + } + + if (n == 3) L3 = L0; + if (n == 4) L4 = L0; + return n; +} + +float ltcEvaluate(vec3 N, vec3 V, float dotNV, vec3 P, mat3 Minv, vec3 points0, vec3 points1, vec3 points2, vec3 points3) { + // Construct orthonormal basis around N + vec3 T1, T2; + T1 = normalize(V - N * dotNV); + T2 = cross(N, T1); + + // Rotate area light in (T1, T2, R) basis + Minv = Minv * transpose(mat3(T1, T2, N)); + + // Polygon (allocate 5 vertices for clipping) + // vec3 L[5]; + L0 = Minv * (points0 - P); + L1 = Minv * (points1 - P); + L2 = Minv * (points2 - P); + L3 = Minv * (points3 - P); + L4 = vec3(0.0); + + // int n; + int n = clipQuadToHorizon(/*L, n*/); + + if (n == 0) return 0.0; + + // Project onto sphere + L0 = normalize(L0); + L1 = normalize(L1); + L2 = normalize(L2); + L3 = normalize(L3); + L4 = normalize(L4); + + // Integrate + float sum = 0.0; + + sum += integrateEdge(L0, L1); + sum += integrateEdge(L1, L2); + sum += integrateEdge(L2, L3); + + if (n >= 4) sum += integrateEdge(L3, L4); + if (n == 5) sum += integrateEdge(L4, L0); + +#ifdef _TwoSidedAreaLight + return abs(sum); +#else + return max(0.0, -sum); +#endif +} diff --git a/compiled/Shaders/std/math.glsl b/compiled/Shaders/std/math.glsl new file mode 100644 index 00000000..e052cb16 --- /dev/null +++ b/compiled/Shaders/std/math.glsl @@ -0,0 +1,43 @@ + +#ifndef _MATH_GLSL_ +#define _MATH_GLSL_ + +float hash(const vec2 p) { + float h = dot(p, vec2(127.1, 311.7)); + return fract(sin(h) * 43758.5453123); +} + +vec2 envMapEquirect(const vec3 normal) { + const float PI = 3.1415926535; + const float PI2 = PI * 2.0; + float phi = acos(normal.z); + float theta = atan(-normal.y, normal.x) + PI; + return vec2(theta / PI2, phi / PI); +} + +float rand(const vec2 co) { // Unreliable + return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453); +} + +vec2 rand2(const vec2 coord) { + const float width = 1100; + const float height = 500; + float noiseX = ((fract(1.0 - coord.s * (width / 2.0)) * 0.25) + (fract(coord.t * (height / 2.0)) * 0.75)) * 2.0 - 1.0; + float noiseY = ((fract(1.0 - coord.s * (width / 2.0)) * 0.75) + (fract(coord.t * (height / 2.0)) * 0.25)) * 2.0 - 1.0; + return vec2(noiseX, noiseY); +} + +float linearize(const float depth, vec2 cameraProj) { + // to viewz + return cameraProj.y / (depth - cameraProj.x); +} + +float attenuate(const float dist) { +// float attenuate(float dist, float constant, float linear, float quadratic) { + return 1.0 / (dist * dist); + // 1.0 / (constant * 1.0) + // 1.0 / (linear * dist) + // 1.0 / (quadratic * dist * dist); +} + +#endif diff --git a/compiled/Shaders/std/normals.glsl b/compiled/Shaders/std/normals.glsl new file mode 100644 index 00000000..3cd08094 --- /dev/null +++ b/compiled/Shaders/std/normals.glsl @@ -0,0 +1,31 @@ +// http://www.thetenthplanet.de/archives/1180 +mat3 cotangentFrame(const vec3 n, const vec3 p, const vec2 duv1, const vec2 duv2) { + // Get edge vectors of the pixel triangle + vec3 dp1 = dFdx(p); + vec3 dp2 = dFdy(p); + + // Solve the linear system + vec3 dp2perp = cross(dp2, n); + vec3 dp1perp = cross(n, dp1); + vec3 t = dp2perp * duv1.x + dp1perp * duv2.x; + vec3 b = dp2perp * duv1.y + dp1perp * duv2.y; + + // Construct a scale-invariant frame + float invmax = inversesqrt(max(dot(t, t), dot(b, b))); + return mat3(t * invmax, b * invmax, n); +} + +mat3 cotangentFrame(const vec3 n, const vec3 p, const vec2 texCoord) { + return cotangentFrame(n, p, dFdx(texCoord), dFdy(texCoord)); +} + +// vec3 perturbNormal(vec3 n, vec3 v, vec2 texCoord) { + // Assume N, the interpolated vertex normal and V, the view vector (vertex to eye) + // vec3 map = texture(snormal, texCoord).xyz * (255.0 / 127.0) - (128.0 / 127.0); +// WITH_NORMALMAP_2CHANNEL + // map.z = sqrt(1.0 - dot(map.xy, map.xy)); +// WITH_NORMALMAP_GREEN_UP + // map.y = -map.y; + // mat3 TBN = cotangentFrame(n, -v, texCoord); + // return normalize(TBN * map); +// } diff --git a/compiled/Shaders/std/shadows.glsl b/compiled/Shaders/std/shadows.glsl new file mode 100644 index 00000000..5a7769fb --- /dev/null +++ b/compiled/Shaders/std/shadows.glsl @@ -0,0 +1,147 @@ +#ifndef _SHADOWS_GLSL_ +#define _SHADOWS_GLSL_ + +#include "compiled.inc" + +#ifdef _CSM +uniform vec4 casData[shadowmapCascades * 4 + 4]; +#endif + +#ifdef _SMSizeUniform +uniform vec2 smSizeUniform; +#endif + +float PCF(sampler2DShadow shadowMap, const vec2 uv, const float compare, const vec2 smSize) { + float result = texture(shadowMap, vec3(uv + (vec2(-1.0, -1.0) / smSize), compare)); + result += texture(shadowMap, vec3(uv + (vec2(-1.0, 0.0) / smSize), compare)); + result += texture(shadowMap, vec3(uv + (vec2(-1.0, 1.0) / smSize), compare)); + result += texture(shadowMap, vec3(uv + (vec2(0.0, -1.0) / smSize), compare)); + result += texture(shadowMap, vec3(uv, compare)); + result += texture(shadowMap, vec3(uv + (vec2(0.0, 1.0) / smSize), compare)); + result += texture(shadowMap, vec3(uv + (vec2(1.0, -1.0) / smSize), compare)); + result += texture(shadowMap, vec3(uv + (vec2(1.0, 0.0) / smSize), compare)); + result += texture(shadowMap, vec3(uv + (vec2(1.0, 1.0) / smSize), compare)); + return result / 9.0; +} + +float lpToDepth(vec3 lp, const vec2 lightProj) { + lp = abs(lp); + float zcomp = max(lp.x, max(lp.y, lp.z)); + zcomp = lightProj.x - lightProj.y / zcomp; + return zcomp * 0.5 + 0.5; +} + +float PCFCube(samplerCubeShadow shadowMapCube, const vec3 lp, vec3 ml, const float bias, const vec2 lightProj, const vec3 n) { + const float s = shadowmapCubePcfSize; // TODO: incorrect... + float compare = lpToDepth(lp, lightProj) - bias * 1.5; + ml = ml + n * bias * 20; + #ifdef HLSL + ml.y = -ml.y; + #endif + float result = texture(shadowMapCube, vec4(ml, compare)); + result += texture(shadowMapCube, vec4(ml + vec3(s, s, s), compare)); + result += texture(shadowMapCube, vec4(ml + vec3(-s, s, s), compare)); + result += texture(shadowMapCube, vec4(ml + vec3(s, -s, s), compare)); + result += texture(shadowMapCube, vec4(ml + vec3(s, s, -s), compare)); + result += texture(shadowMapCube, vec4(ml + vec3(-s, -s, s), compare)); + result += texture(shadowMapCube, vec4(ml + vec3(s, -s, -s), compare)); + result += texture(shadowMapCube, vec4(ml + vec3(-s, s, -s), compare)); + result += texture(shadowMapCube, vec4(ml + vec3(-s, -s, -s), compare)); + return result / 9.0; +} + +float shadowTest(sampler2DShadow shadowMap, const vec3 lPos, const float shadowsBias) { + #ifdef _SMSizeUniform + vec2 smSize = smSizeUniform; + #else + const vec2 smSize = shadowmapSize; + #endif + if (lPos.x < 0.0 || lPos.y < 0.0 || lPos.x > 1.0 || lPos.y > 1.0) return 1.0; + return PCF(shadowMap, lPos.xy, lPos.z - shadowsBias, smSize); +} + +#ifdef _CSM +mat4 getCascadeMat(const float d, out int casi, out int casIndex) { + const int c = shadowmapCascades; + + // Get cascade index + // TODO: use bounding box slice selection instead of sphere + const vec4 ci = vec4(float(c > 0), float(c > 1), float(c > 2), float(c > 3)); + // int ci; + // if (d < casData[c * 4].x) ci = 0; + // else if (d < casData[c * 4].y) ci = 1 * 4; + // else if (d < casData[c * 4].z) ci = 2 * 4; + // else ci = 3 * 4; + // Splits + vec4 comp = vec4( + float(d > casData[c * 4].x), + float(d > casData[c * 4].y), + float(d > casData[c * 4].z), + float(d > casData[c * 4].w)); + casi = int(min(dot(ci, comp), c)); + + // Get cascade mat + casIndex = casi * 4; + + return mat4( + casData[casIndex ], + casData[casIndex + 1], + casData[casIndex + 2], + casData[casIndex + 3]); + + // if (casIndex == 0) return mat4(casData[0], casData[1], casData[2], casData[3]); + // .. +} + +float shadowTestCascade(sampler2DShadow shadowMap, const vec3 eye, const vec3 p, const float shadowsBias) { + #ifdef _SMSizeUniform + vec2 smSize = smSizeUniform * vec2(shadowmapCascades, 1.0); + #else + const vec2 smSize = shadowmapSize * vec2(shadowmapCascades, 1.0); + #endif + const int c = shadowmapCascades; + float d = distance(eye, p); + + int casi; + int casIndex; + mat4 LWVP = getCascadeMat(d, casi, casIndex); + + vec4 lPos = LWVP * vec4(p, 1.0); + lPos.xyz /= lPos.w; + + float visibility = 1.0; + if (lPos.w > 0.0) visibility = PCF(shadowMap, lPos.xy, lPos.z - shadowsBias, smSize); + + // Blend cascade + // https://github.com/TheRealMJP/Shadows + const float blendThres = 0.15; + float nextSplit = casData[c * 4][casi]; + float splitSize = casi == 0 ? nextSplit : nextSplit - casData[c * 4][casi - 1]; + float splitDist = (nextSplit - d) / splitSize; + if (splitDist <= blendThres && casi != c - 1) { + int casIndex2 = casIndex + 4; + mat4 LWVP2 = mat4( + casData[casIndex2 ], + casData[casIndex2 + 1], + casData[casIndex2 + 2], + casData[casIndex2 + 3]); + + vec4 lPos2 = LWVP2 * vec4(p, 1.0); + lPos2.xyz /= lPos2.w; + float visibility2 = 1.0; + if (lPos2.w > 0.0) visibility2 = PCF(shadowMap, lPos2.xy, lPos2.z - shadowsBias, smSize); + + float lerpAmt = smoothstep(0.0, blendThres, splitDist); + return mix(visibility2, visibility, lerpAmt); + } + return visibility; + + // Visualize cascades + // if (ci == 0) albedo.rgb = vec3(1.0, 0.0, 0.0); + // if (ci == 4) albedo.rgb = vec3(0.0, 1.0, 0.0); + // if (ci == 8) albedo.rgb = vec3(0.0, 0.0, 1.0); + // if (ci == 12) albedo.rgb = vec3(1.0, 1.0, 0.0); +} +#endif + +#endif diff --git a/compiled/Shaders/std/shirr.glsl b/compiled/Shaders/std/shirr.glsl new file mode 100644 index 00000000..39515beb --- /dev/null +++ b/compiled/Shaders/std/shirr.glsl @@ -0,0 +1,31 @@ +uniform vec4 shirr[7]; + +vec3 shIrradiance(const vec3 nor) { + const float c1 = 0.429043; + const float c2 = 0.511664; + const float c3 = 0.743125; + const float c4 = 0.886227; + const float c5 = 0.247708; + // TODO: Use padding for 4th component and pass shirr[].xyz directly + vec3 cl00 = vec3(shirr[0].x, shirr[0].y, shirr[0].z); + vec3 cl1m1 = vec3(shirr[0].w, shirr[1].x, shirr[1].y); + vec3 cl10 = vec3(shirr[1].z, shirr[1].w, shirr[2].x); + vec3 cl11 = vec3(shirr[2].y, shirr[2].z, shirr[2].w); + vec3 cl2m2 = vec3(shirr[3].x, shirr[3].y, shirr[3].z); + vec3 cl2m1 = vec3(shirr[3].w, shirr[4].x, shirr[4].y); + vec3 cl20 = vec3(shirr[4].z, shirr[4].w, shirr[5].x); + vec3 cl21 = vec3(shirr[5].y, shirr[5].z, shirr[5].w); + vec3 cl22 = vec3(shirr[6].x, shirr[6].y, shirr[6].z); + return ( + c1 * cl22 * (nor.y * nor.y - (-nor.z) * (-nor.z)) + + c3 * cl20 * nor.x * nor.x + + c4 * cl00 - + c5 * cl20 + + 2.0 * c1 * cl2m2 * nor.y * (-nor.z) + + 2.0 * c1 * cl21 * nor.y * nor.x + + 2.0 * c1 * cl2m1 * (-nor.z) * nor.x + + 2.0 * c2 * cl11 * nor.y + + 2.0 * c2 * cl1m1 * (-nor.z) + + 2.0 * c2 * cl10 * nor.x + ); +} diff --git a/compiled/Shaders/std/skinning.glsl b/compiled/Shaders/std/skinning.glsl new file mode 100644 index 00000000..0b9133a6 --- /dev/null +++ b/compiled/Shaders/std/skinning.glsl @@ -0,0 +1,28 @@ +// Geometric Skinning with Approximate Dual Quaternion Blending, Kavan +// Based on https://github.com/tcoppex/aer-engine/blob/master/demos/aura/data/shaders/Skinning.glsl +uniform vec4 skinBones[skinMaxBones * 2]; + +void getSkinningDualQuat(const ivec4 bone, vec4 weight, out vec4 A, inout vec4 B) { + // Retrieve the real and dual part of the dual-quaternions + ivec4 bonei = bone * 2; + mat4 matA = mat4( + skinBones[bonei.x], + skinBones[bonei.y], + skinBones[bonei.z], + skinBones[bonei.w]); + mat4 matB = mat4( + skinBones[bonei.x + 1], + skinBones[bonei.y + 1], + skinBones[bonei.z + 1], + skinBones[bonei.w + 1]); + // Handles antipodality by sticking joints in the same neighbourhood + // weight.xyz *= sign(matA[3] * mat3x4(matA)).xyz; + weight.xyz *= sign(matA[3] * matA).xyz; + // Apply weights + A = matA * weight; // Real part + B = matB * weight; // Dual part + // Normalize + float invNormA = 1.0 / length(A); + A *= invNormA; + B *= invNormA; +} diff --git a/compiled/Shaders/std/ssrs.glsl b/compiled/Shaders/std/ssrs.glsl new file mode 100644 index 00000000..d86a8ff2 --- /dev/null +++ b/compiled/Shaders/std/ssrs.glsl @@ -0,0 +1,37 @@ +#include "std/gbuffer.glsl" + +uniform mat4 VP; + +vec2 getProjectedCoord(vec3 hitCoord) { + vec4 projectedCoord = VP * vec4(hitCoord, 1.0); + projectedCoord.xy /= projectedCoord.w; + projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5; + #ifdef HLSL + projectedCoord.y = 1.0 - projectedCoord.y; + #endif + return projectedCoord.xy; +} + +float getDeltaDepth(vec3 hitCoord, sampler2D gbufferD, mat4 invVP, vec3 eye) { + vec2 texCoord = getProjectedCoord(hitCoord); + float depth = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0; + vec3 wpos = getPos2(invVP, depth, texCoord); + float d1 = length(eye - wpos); + float d2 = length(eye - hitCoord); + return d1 - d2; +} + +float traceShadowSS(vec3 dir, vec3 hitCoord, sampler2D gbufferD, mat4 invVP, vec3 eye) { + dir *= ssrsRayStep; + // for (int i = 0; i < maxSteps; i++) { + hitCoord += dir; + if (getDeltaDepth(hitCoord, gbufferD, invVP, eye) > 0.0) return 0.6; + hitCoord += dir; + if (getDeltaDepth(hitCoord, gbufferD, invVP, eye) > 0.0) return 0.7; + hitCoord += dir; + if (getDeltaDepth(hitCoord, gbufferD, invVP, eye) > 0.0) return 0.8; + hitCoord += dir; + if (getDeltaDepth(hitCoord, gbufferD, invVP, eye) > 0.0) return 0.9; + //} + return 1.0; +} diff --git a/compiled/Shaders/std/sss.glsl b/compiled/Shaders/std/sss.glsl new file mode 100644 index 00000000..7af08789 --- /dev/null +++ b/compiled/Shaders/std/sss.glsl @@ -0,0 +1,26 @@ + +// Separable SSS Transmittance Function, ref to sss_pass +vec3 SSSSTransmittance(mat4 LWVP, vec3 p, vec3 n, vec3 l, float lightFar, sampler2DShadow shadowMap) { + const float translucency = 1.0; + vec4 shrinkedPos = vec4(p - 0.005 * n, 1.0); + vec4 shadowPos = LWVP * shrinkedPos; + float scale = 8.25 * (1.0 - translucency) / (sssWidth / 10.0); + float d1 = texture(shadowMap, vec3(shadowPos.xy / shadowPos.w, shadowPos.z)).r; // 'd1' has a range of 0..1 + float d2 = shadowPos.z; // 'd2' has a range of 0..'lightFarPlane' + d1 *= lightFar; // So we scale 'd1' accordingly: + float d = scale * abs(d1 - d2); + + float dd = -d * d; + vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) + + vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) + + vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) + + vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) + + vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) + + vec3(0.078, 0.0, 0.0) * exp(dd / 7.41); + return profile * clamp(0.3 + dot(l, -n), 0.0, 1.0); +} + +vec3 SSSSTransmittanceCube(float translucency, vec4 shadowPos, vec3 n, vec3 l, float lightFar) { + // TODO + return vec3(0.0); +} diff --git a/compiled/Shaders/std/tonemap.glsl b/compiled/Shaders/std/tonemap.glsl new file mode 100644 index 00000000..a2ce7eb3 --- /dev/null +++ b/compiled/Shaders/std/tonemap.glsl @@ -0,0 +1,38 @@ + +vec3 uncharted2Tonemap(const vec3 x) { + const float A = 0.15; + const float B = 0.50; + const float C = 0.10; + const float D = 0.20; + const float E = 0.02; + const float F = 0.30; + return ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F; +} + +vec3 tonemapUncharted2(const vec3 color) { + const float W = 11.2; + const float exposureBias = 2.0; + vec3 curr = uncharted2Tonemap(exposureBias * color); + vec3 whiteScale = 1.0 / uncharted2Tonemap(vec3(W)); + return curr * whiteScale; +} + +// Based on Filmic Tonemapping Operators http://filmicgames.com/archives/75 +vec3 tonemapFilmic(const vec3 color) { + vec3 x = max(vec3(0.0), color - 0.004); + return (x * (6.2 * x + 0.5)) / (x * (6.2 * x + 1.7) + 0.06); +} + +// https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/ +vec3 acesFilm(const vec3 x) { + const float a = 2.51; + const float b = 0.03; + const float c = 2.43; + const float d = 0.59; + const float e = 0.14; + return clamp((x * (a * x + b)) / (x * (c * x + d ) + e), 0.0, 1.0); +} + +vec3 tonemapReinhard(const vec3 color) { + return color / (color + vec3(1.0)); +} diff --git a/compiled/Shaders/std/vr.glsl b/compiled/Shaders/std/vr.glsl new file mode 100644 index 00000000..d016e7bb --- /dev/null +++ b/compiled/Shaders/std/vr.glsl @@ -0,0 +1,26 @@ +uniform mat4 U; // Undistortion +uniform float maxRadSq; + +// GoogleVR Distortion using Vertex Displacement +float distortionFactor(const float rSquared) { + float ret = 0.0; + ret = rSquared * (ret + U[1][1]); + ret = rSquared * (ret + U[0][1]); + ret = rSquared * (ret + U[3][0]); + ret = rSquared * (ret + U[2][0]); + ret = rSquared * (ret + U[1][0]); + ret = rSquared * (ret + U[0][0]); + return ret + 1.0; +} +// Convert point from world space to undistorted camera space +vec4 undistort(const mat4 WV, vec4 pos) { + // Go to camera space + pos = WV * pos; + const float nearClip = 0.1; + if (pos.z <= -nearClip) { // Reminder: Forward is -Z + // Undistort the point's coordinates in XY + float r2 = clamp(dot(pos.xy, pos.xy) / (pos.z * pos.z), 0.0, maxRadSq); + pos.xy *= distortionFactor(r2); + } + return pos; +} diff --git a/compiled/Shaders/supersample_resolve.frag.glsl b/compiled/Shaders/supersample_resolve.frag.glsl new file mode 100644 index 00000000..16e61fc4 --- /dev/null +++ b/compiled/Shaders/supersample_resolve.frag.glsl @@ -0,0 +1,14 @@ +#version 450 + +#include "std/filters.glsl" + +uniform sampler2D tex; +uniform vec2 screenSizeInv; + +in vec2 texCoord; +out vec4 fragColor; + +void main() { + // 4X resolve + fragColor = textureSS(tex, texCoord, screenSizeInv / 4.0); +} diff --git a/compiled/Shaders/taa_pass.frag.glsl b/compiled/Shaders/taa_pass.frag.glsl new file mode 100644 index 00000000..57ec11af --- /dev/null +++ b/compiled/Shaders/taa_pass.frag.glsl @@ -0,0 +1,44 @@ +#version 450 + +#include "compiled.inc" + +uniform sampler2D tex; +uniform sampler2D tex2; +#ifdef _Veloc +uniform sampler2D sveloc; +#endif + +in vec2 texCoord; +out vec4 fragColor; + +const float SMAA_REPROJECTION_WEIGHT_SCALE = 30.0; + +void main() { + vec4 current = textureLod(tex, texCoord, 0.0); + +#ifdef _Veloc + // Velocity is assumed to be calculated for motion blur, so we need to inverse it for reprojection + vec2 velocity = -textureLod(sveloc, texCoord, 0.0).rg; + + #ifdef HLSL + velocity.y = -velocity.y; + #endif + + // Reproject current coordinates and fetch previous pixel + vec4 previous = textureLod(tex2, texCoord + velocity, 0.0); + + // Attenuate the previous pixel if the velocity is different + #ifdef _SMAA + float delta = abs(current.a * current.a - previous.a * previous.a) / 5.0; + #else + const float delta = 0.0; + #endif + float weight = 0.5 * clamp(1.0 - sqrt(delta) * SMAA_REPROJECTION_WEIGHT_SCALE, 0.0, 1.0); + + // Blend the pixels according to the calculated weight: + fragColor = vec4(mix(current.rgb, previous.rgb, weight), 1.0); +#else + vec4 previous = textureLod(tex2, texCoord, 0.0); + fragColor = vec4(mix(current.rgb, previous.rgb, 0.5), 1.0); +#endif +} diff --git a/compiled/Shaders/world_pass.frag.glsl b/compiled/Shaders/world_pass.frag.glsl new file mode 100644 index 00000000..dca8371e --- /dev/null +++ b/compiled/Shaders/world_pass.frag.glsl @@ -0,0 +1,172 @@ +#version 450 + +#include "compiled.inc" +#ifdef _EnvTex +#include "std/math.glsl" +#endif + +#ifdef _EnvCol + uniform vec3 backgroundCol; +#endif +#ifdef _EnvSky + uniform vec3 A; + uniform vec3 B; + uniform vec3 C; + uniform vec3 D; + uniform vec3 E; + uniform vec3 F; + uniform vec3 G; + uniform vec3 H; + uniform vec3 I; + uniform vec3 Z; + uniform vec3 hosekSunDirection; +#endif +#ifdef _EnvClouds + uniform sampler3D scloudsBase; + uniform sampler3D scloudsDetail; + uniform sampler2D scloudsMap; + uniform float time; +#endif +#ifdef _EnvTex + uniform sampler2D envmap; +#endif +#ifdef _EnvImg // Static background + uniform vec2 screenSize; + uniform sampler2D envmap; +#endif + +#ifdef _EnvStr +uniform float envmapStrength; +#endif + +in vec3 normal; +out vec4 fragColor; + +#ifdef _EnvSky +vec3 hosekWilkie(float cos_theta, float gamma, float cos_gamma) { + vec3 chi = (1 + cos_gamma * cos_gamma) / pow(1 + H * H - 2 * cos_gamma * H, vec3(1.5)); + return (1 + A * exp(B / (cos_theta + 0.01))) * (C + D * exp(E * gamma) + F * (cos_gamma * cos_gamma) + G * chi + I * sqrt(cos_theta)); +} +#endif + +#ifdef _EnvClouds +// GPU PRO 7 - Real-time Volumetric Cloudscapes +// https://www.guerrilla-games.com/read/the-real-time-volumetric-cloudscapes-of-horizon-zero-dawn +// https://github.com/sebh/TileableVolumeNoise +float remap(float old_val, float old_min, float old_max, float new_min, float new_max) { + return new_min + (((old_val - old_min) / (old_max - old_min)) * (new_max - new_min)); +} + +float getDensityHeightGradientForPoint(float height, float cloud_type) { + const vec4 stratusGrad = vec4(0.02f, 0.05f, 0.09f, 0.11f); + const vec4 stratocumulusGrad = vec4(0.02f, 0.2f, 0.48f, 0.625f); + const vec4 cumulusGrad = vec4(0.01f, 0.0625f, 0.78f, 1.0f); + float stratus = 1.0f - clamp(cloud_type * 2.0f, 0, 1); + float stratocumulus = 1.0f - abs(cloud_type - 0.5f) * 2.0f; + float cumulus = clamp(cloud_type - 0.5f, 0, 1) * 2.0f; + vec4 cloudGradient = stratusGrad * stratus + stratocumulusGrad * stratocumulus + cumulusGrad * cumulus; + return smoothstep(cloudGradient.x, cloudGradient.y, height) - smoothstep(cloudGradient.z, cloudGradient.w, height); +} + +float sampleCloudDensity(vec3 p) { + float cloud_base = textureLod(scloudsBase, p, 0).r * 40; // Base noise + vec3 weather_data = textureLod(scloudsMap, p.xy, 0).rgb; // Weather map + cloud_base *= getDensityHeightGradientForPoint(p.z, weather_data.b); // Cloud type + cloud_base = remap(cloud_base, weather_data.r, 1.0, 0.0, 1.0); // Coverage + cloud_base *= weather_data.r; + float cloud_detail = textureLod(scloudsDetail, p, 0).r * 2; // Detail noise + float cloud_detail_mod = mix(cloud_detail, 1.0 - cloud_detail, clamp(p.z * 10.0, 0, 1)); + cloud_base = remap(cloud_base, cloud_detail_mod * 0.2, 1.0, 0.0, 1.0); + return cloud_base; +} + +float cloudRadiance(vec3 p, vec3 dir){ + #ifdef _EnvSky + vec3 sun_dir = hosekSunDirection; + #else + vec3 sun_dir = vec3(0, 0, -1); + #endif + const int steps = 8; + float step_size = 0.5 / float(steps); + float d = 0.0; + p += sun_dir * step_size; + for(int i = 0; i < steps; ++i) { + d += sampleCloudDensity(p + sun_dir * float(i) * step_size); + } + return 1.0 - d; +} + +vec3 traceClouds(vec3 sky, vec3 dir) { + const float step_size = 0.5 / float(cloudsSteps); + float T = 1.0; + float C = 0.0; + vec2 uv = dir.xy / dir.z * 0.4 * cloudsLower + cloudsWind * time * 0.02; + + for (int i = 0; i < cloudsSteps; ++i) { + float h = float(i) / float(cloudsSteps); + vec3 p = vec3(uv * 0.04, h); + float d = sampleCloudDensity(p); + + if (d > 0) { + // float radiance = cloudRadiance(p, dir); + C += T * exp(h) * d * step_size * 0.6 * cloudsPrecipitation; + T *= exp(-d * step_size); + if (T < 0.01) break; + } + uv += (dir.xy / dir.z) * step_size * cloudsUpper; + } + + return vec3(C) + sky * T; +} +#endif // _EnvClouds + +void main() { + +#ifdef _EnvCol + fragColor.rgb = backgroundCol; +#ifdef _EnvTransp + return; +#endif +#ifdef _EnvClouds + vec3 n = normalize(normal); +#endif +#endif + +#ifndef _EnvSky // Prevent case when sky radiance is enabled +#ifdef _EnvTex + vec3 n = normalize(normal); + fragColor.rgb = texture(envmap, envMapEquirect(n)).rgb * envmapStrength; + #ifdef _EnvLDR + fragColor.rgb = pow(fragColor.rgb, vec3(2.2)); + #endif +#endif +#endif + +#ifdef _EnvImg // Static background + // Will have to get rid of gl_FragCoord, pass tc from VS + vec2 texco = gl_FragCoord.xy / screenSize; + fragColor.rgb = texture(envmap, vec2(texco.x, 1.0 - texco.y)).rgb * envmapStrength; +#endif + +#ifdef _EnvSky + vec3 n = normalize(normal); + float phi = acos(n.z); + float theta = atan(-n.y, n.x) + PI; + + float cos_theta = clamp(n.z, 0.0, 1.0); + float cos_gamma = dot(n, hosekSunDirection); + float gamma_val = acos(cos_gamma); + + fragColor.rgb = Z * hosekWilkie(cos_theta, gamma_val, cos_gamma) * envmapStrength; +#endif + +#ifdef _EnvClouds + if (n.z > 0.0) fragColor.rgb = mix(fragColor.rgb, traceClouds(fragColor.rgb, n), clamp(n.z * 5.0, 0, 1)); +#endif + +#ifdef _LDR + fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2)); +#endif + + fragColor.a = 0.0; // Mark as non-opaque +} diff --git a/compiled/Shaders/world_pass.vert.glsl b/compiled/Shaders/world_pass.vert.glsl new file mode 100644 index 00000000..bd27b1b3 --- /dev/null +++ b/compiled/Shaders/world_pass.vert.glsl @@ -0,0 +1,14 @@ +#version 450 + +in vec3 pos; +in vec3 nor; + +out vec3 normal; + +uniform mat4 SMVP; + +void main() { + normal = nor; + vec4 position = SMVP * vec4(pos, 1.0); + gl_Position = vec4(position); +} diff --git a/khafile.js b/khafile.js new file mode 100644 index 00000000..49ead612 --- /dev/null +++ b/khafile.js @@ -0,0 +1,50 @@ +let project = new Project('ArmorPaint'); + +project.addSources('Sources'); +project.addLibrary("armory"); +project.addLibrary("iron"); +project.addLibrary("zui"); +project.addLibrary("iron_format"); +project.addShaders("compiled/Shaders/*.glsl", { noembed: false}); +project.addShaders("compiled/Hlsl/*.glsl", { noprocessing: true, noembed: false }); +project.addAssets("compiled/Assets/**", { notinlist: true }); +project.addAssets("compiled/Shaders/*.arm", { notinlist: true }); +project.addAssets("Bundled/**", { notinlist: true }); +project.addAssets("Libraries/armory/Assets/brdf.png", { notinlist: true }); +project.addAssets("Libraries/armory/Assets/noise256.png", { notinlist: true }); +project.addAssets("Libraries/armory/Assets/smaa_area.png", { notinlist: true }); +project.addAssets("Libraries/armory/Assets/smaa_search.png", { notinlist: true }); +project.addAssets("Libraries/armory/Assets/font_default.ttf", { notinlist: false }); +project.addDefine('arm_deferred'); +project.addDefine('arm_voxelgi_revox'); +project.addDefine('arm_ltc'); +project.addDefine('rp_hdr'); +project.addDefine('rp_renderer=Deferred'); +project.addDefine('rp_background=World'); +project.addDefine('rp_render_to_texture'); +project.addDefine('rp_compositornodes'); +project.addDefine('rp_antialiasing=TAA'); +project.addDefine('arm_veloc'); +project.addDefine('arm_taa'); +project.addDefine('rp_supersampling=4'); +project.addDefine('rp_ssgi=RTAO'); +project.addDefine('rp_bloom'); +project.addDefine('rp_ssr'); +project.addDefine('rp_overlays'); +project.addDefine('rp_voxelao'); +project.addDefine('rp_voxelgi_resolution=256'); +project.addDefine('rp_voxelgi_resolution_z=1.0'); +project.addDefine('rp_gbuffer2'); +project.addDefine('arm_appwh'); +project.addDefine('arm_skip_envmap'); +project.addDefine('arm_no_audio'); +project.addDefine('kha_no_ogg'); +project.addDefine('arm_soundcompress'); +project.addDefine('arm_ui'); +project.addDefine('arm_skin'); +project.addDefine('arm_particles'); +project.addDefine('arm_config'); +project.addDefine('arm_resizable'); +project.addParameter('--macro include("arm.brushnode")'); + +resolve(project);