From 1fbf98155fac17e6dcd53aa90634e60867ba6e71 Mon Sep 17 00:00:00 2001 From: mrq Date: Tue, 20 Apr 2021 00:00:00 -0500 Subject: [PATCH] Commit for 2021.04.20.7z --- bin/data/shaders/display/subpass.frag.glsl | 710 +++++------------- ...svogi.frag.glsl => subpass.vxgi.frag.glsl} | 543 +++++++------- .../{svogi.comp.glsl => vxgi.comp.glsl} | 292 ++++--- bin/data/shaders/gltf/baked.frag.glsl | 23 +- bin/data/shaders/gltf/baking/bake.frag.glsl | 300 ++++---- bin/data/shaders/gltf/base.frag.glsl | 60 +- bin/data/shaders/gltf/voxelize.frag.glsl | 73 +- engine/inc/uf/engine/object/behavior.h | 6 +- engine/src/engine/object/behavior.cpp | 24 +- engine/src/engine/object/behaviors/gltf.cpp | 4 +- engine/src/engine/object/object.cpp | 34 +- engine/src/engine/scene/scene.cpp | 4 +- engine/src/ext/gltf/graph.cpp | 18 +- .../src/ext/vulkan/rendermodes/deferred.cpp | 4 +- .../ext/vulkan/rendermodes/rendertarget.cpp | 10 +- ext/behaviors/light/behavior.cpp | 7 +- ext/behaviors/light/behavior.h | 2 +- ext/behaviors/scene/behavior.cpp | 31 +- ext/behaviors/scene/behavior.h | 2 + ext/behaviors/voxelizer/behavior.cpp | 33 +- ext/behaviors/voxelizer/behavior.h | 6 +- 21 files changed, 971 insertions(+), 1215 deletions(-) rename bin/data/shaders/display/{subpass.svogi.frag.glsl => subpass.vxgi.frag.glsl} (50%) rename bin/data/shaders/display/{svogi.comp.glsl => vxgi.comp.glsl} (53%) diff --git a/bin/data/shaders/display/subpass.frag.glsl b/bin/data/shaders/display/subpass.frag.glsl index 0286d1c6..bf2dec1f 100644 --- a/bin/data/shaders/display/subpass.frag.glsl +++ b/bin/data/shaders/display/subpass.frag.glsl @@ -2,8 +2,32 @@ #extension GL_EXT_samplerless_texture_functions : require #define MULTISAMPLING 1 +#define DEFERRED_SAMPLING 0 #define RAY_MARCH_FOG 1 -#define UF_DEFERRED_SAMPLING 0 + +const float PI = 3.14159265359; +const float EPSILON = 0.00001; + +const float LIGHT_POWER_CUTOFF = 0.005; + +const vec2 poissonDisk[16] = vec2[]( + vec2( -0.94201624, -0.39906216 ), + vec2( 0.94558609, -0.76890725 ), + vec2( -0.094184101, -0.92938870 ), + vec2( 0.34495938, 0.29387760 ), + vec2( -0.91588581, 0.45771432 ), + vec2( -0.81544232, -0.87912464 ), + vec2( -0.38277543, 0.27676845 ), + vec2( 0.97484398, 0.75648379 ), + vec2( 0.44323325, -0.97511554 ), + vec2( 0.53742981, -0.47373420 ), + vec2( -0.26496911, -0.41893023 ), + vec2( 0.79197514, 0.19090188 ), + vec2( -0.24188840, 0.99706507 ), + vec2( -0.81409955, 0.91437590 ), + vec2( 0.19984126, 0.78641367 ), + vec2( 0.14383161, -0.14100790 ) +); layout (constant_id = 0) const uint TEXTURES = 256; @@ -98,7 +122,7 @@ struct DrawCall { #if !MULTISAMPLING layout (input_attachment_index = 0, binding = 0) uniform usubpassInput samplerId; layout (input_attachment_index = 1, binding = 1) uniform subpassInput samplerNormal; - #if UF_DEFERRED_SAMPLING + #if DEFERRED_SAMPLING layout (input_attachment_index = 2, binding = 2) uniform subpassInput samplerUv; #else layout (input_attachment_index = 2, binding = 2) uniform subpassInput samplerAlbedo; @@ -107,7 +131,7 @@ struct DrawCall { #else layout (input_attachment_index = 0, binding = 0) uniform usubpassInputMS samplerId; layout (input_attachment_index = 1, binding = 1) uniform subpassInputMS samplerNormal; - #if UF_DEFERRED_SAMPLING + #if DEFERRED_SAMPLING layout (input_attachment_index = 2, binding = 2) uniform subpassInputMS samplerUv; #else layout (input_attachment_index = 2, binding = 2) uniform subpassInputMS samplerAlbedo; @@ -131,8 +155,8 @@ layout (binding = 4) uniform UBO { uint msaa; uint poissonSamples; - uint padding1; - uint padding2; + float gamma; + float exposure; } ubo; layout (std140, binding = 5) readonly buffer Lights { @@ -158,321 +182,40 @@ layout (location = 1) in flat uint inPushConstantPass; layout (location = 0) out vec4 outFragColor; -vec2 poissonDisk[16] = vec2[]( - vec2( -0.94201624, -0.39906216 ), - vec2( 0.94558609, -0.76890725 ), - vec2( -0.094184101, -0.92938870 ), - vec2( 0.34495938, 0.29387760 ), - vec2( -0.91588581, 0.45771432 ), - vec2( -0.81544232, -0.87912464 ), - vec2( -0.38277543, 0.27676845 ), - vec2( 0.97484398, 0.75648379 ), - vec2( 0.44323325, -0.97511554 ), - vec2( 0.53742981, -0.47373420 ), - vec2( -0.26496911, -0.41893023 ), - vec2( 0.79197514, 0.19090188 ), - vec2( -0.24188840, 0.99706507 ), - vec2( -0.81409955, 0.91437590 ), - vec2( 0.19984126, 0.78641367 ), - vec2( 0.14383161, -0.14100790 ) -); - -void phong( Light light, vec4 albedoSpecular, inout vec3 i ) { - vec3 Ls = vec3(1.0, 1.0, 1.0); // light specular - vec3 Ld = light.color; // light color - vec3 La = vec3(1.0, 1.0, 1.0); - - vec3 Ks = vec3(albedoSpecular.a); // material specular - vec3 Kd = albedoSpecular.rgb; // material diffuse - vec3 Ka = vec3(1.0, 1.0, 1.0); - - float Kexp = ubo.kexp; - - vec3 V = position.eye; - vec3 N = normal.eye; - vec3 L = light.position.xyz - V; - float dist = length(L); -// if ( light.radius > 0.001 && light.radius < dist ) return; - - vec3 D = normalize(L); - float d_dot = max(dot( D, N ), 0.0); - - vec3 R = reflect( -D, N ); - vec3 S = normalize(-V); - float s_factor = pow( max(dot( R, S ), 0.0), Kexp ); - if ( Kexp < 0.0001 ) s_factor = 0; - - float radiance = light.power / (dist * dist); - - vec3 Ia = La * Ka; - vec3 Id = Ld * Kd * d_dot * radiance; - vec3 Is = Ls * Ks * s_factor * radiance; - - i += Id + Is; -} -void phongSpecular( Light light, vec4 albedoSpecular, inout vec3 i ) { - vec3 Ls = vec3(1.0, 1.0, 1.0); // light specular - vec3 Ld = light.color; // light color - vec3 La = vec3(1.0, 1.0, 1.0); - - vec3 Ks = vec3(albedoSpecular.a); // material specular - vec3 Kd = albedoSpecular.rgb; // material diffuse - vec3 Ka = vec3(1.0, 1.0, 1.0); - - float Kexp = ubo.kexp; - - vec3 V = position.eye; - vec3 N = normal.eye; - vec3 L = light.position.xyz - V; - float dist = length(L); - - vec3 D = normalize(L); - vec3 R = reflect( -D, N ); - vec3 S = normalize(-V); - float s_factor = pow( max(dot( R, S ), 0.0), Kexp ); - if ( Kexp < 0.0001 ) s_factor = 0; - - float radiance = light.power / (dist * dist); - - vec3 Ia = La * Ka; - vec3 Is = Ls * Ks * s_factor * radiance; - - i += Is; -} -const float PI = 3.14159265359; -float DistributionGGX(vec3 N, vec3 H, float roughness) { - float a = roughness*roughness; - float a2 = a*a; - float NdotH = max(dot(N, H), 0.0); - float NdotH2 = NdotH*NdotH; - - float num = a2; - float denom = (NdotH2 * (a2 - 1.0) + 1.0); - denom = PI * denom * denom; - - return num / denom; +// GGX/Towbridge-Reitz normal distribution function. +// Uses Disney's reparametrization of alpha = roughness^2. +float ndfGGX(float cosLh, float roughness) { + const float alpha = roughness * roughness; + const float alphaSq = alpha * alpha; + const float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0; + return alphaSq / (PI * denom * denom); } -float GeometrySchlickGGX(float NdotV, float roughness) { - float r = (roughness + 1.0); - float k = (r*r) / 8.0; +// Single term for separable Schlick-GGX below. +float gaSchlickG1(float cosTheta, float k) { + return cosTheta / (cosTheta * (1.0 - k) + k); +} - float num = NdotV; - float denom = NdotV * (1.0 - k) + k; - - return num / denom; +// Schlick-GGX approximation of geometric attenuation function using Smith's method. +float gaSchlickGGX(float cosLi, float cosLo, float roughness) { + const float r = roughness + 1.0; + const float k = (r * r) / 8.0; // Epic suggests using this roughness remapping for analytic lights. + return gaSchlickG1(cosLi, k) * gaSchlickG1(cosLo, k); } -float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) { - float NdotV = max(dot(N, V), 0.0); - float NdotL = max(dot(N, L), 0.0); - float ggx2 = GeometrySchlickGGX(NdotV, roughness); - float ggx1 = GeometrySchlickGGX(NdotL, roughness); - - return ggx1 * ggx2; -} -vec3 fresnelSchlick(float cosTheta, vec3 F0) { +vec3 fresnelSchlick(vec3 F0, float cosTheta) { return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); } float random(vec3 seed, int i){ - vec4 seed4 = vec4(seed,i); - float dot_product = dot(seed4, vec4(12.9898,78.233,45.164,94.673)); - return fract(sin(dot_product) * 43758.5453); + return fract(sin(dot(vec4(seed,i), vec4(12.9898,78.233,45.164,94.673))) * 43758.5453); } -float shadowFactor( Light light, uint shadowMap, float def ) { - vec4 positionClip = light.projection * light.view * vec4(position.world, 1.0); - positionClip.xyz /= positionClip.w; - - if ( positionClip.x < -1 || positionClip.x >= 1 ) return def; //0.0; - if ( positionClip.y < -1 || positionClip.y >= 1 ) return def; //0.0; - if ( positionClip.z <= 0 || positionClip.z >= 1 ) return def; //0.0; - - float factor = 1.0; - - // spot light - if ( light.type == 1 || light.type == 2 ) { - float dist = length( positionClip.xy ); - if ( dist > 0.5 ) return def; //0.0; - - // spot light with attenuation - if ( light.type == 2 ) { - factor = 1.0 - (pow(dist * 2,2.0)); - } - } - - vec2 uv = positionClip.xy * 0.5 + 0.5; - float bias = light.depthBias; -/* - if ( true ) { - float cosTheta = clamp(dot(normal.eye, normalize(light.position.xyz - position.eye)), 0, 1); - bias = clamp(bias * tan(acos(cosTheta)), 0, 0.01); - } else if ( true ) { - bias = max(bias * 10 * (1.0 - dot(normal.eye, normalize(light.position.xyz - position.eye))), bias); - } -*/ - - float eyeDepth = positionClip.z; - - int samples = int(ubo.poissonSamples); - if ( samples <= 1 ) { - return eyeDepth < texture(samplerTextures[shadowMap], uv).r - bias ? 0.0 : factor; - } - for ( int i = 0; i < samples; ++i ) { - // int index = i; - // int index = int( float(samples) * random(gl_FragCoord.xyy, i) ) % samples; - int index = int( float(samples) * random(floor(position.world.xyz * 1000.0), i)) % samples; - float lightDepth = texture(samplerTextures[shadowMap], uv + poissonDisk[index] / 700.0 ).r; - if ( eyeDepth < lightDepth - bias ) factor -= 1.0 / samples; - } - return factor; +// Returns a vector that is orthogonal to u. +vec3 orthogonal(vec3 u){ + u = normalize(u); + const vec3 v = vec3(0.99146, 0.11664, 0.05832); // Pick any normalized vector. + return abs(dot(u, v)) > 0.99999f ? cross(u, vec3(0, 1, 0)) : cross(u, v); } -vec3 hslToRgb(vec3 HSL) { - vec3 RGB; { - float H = HSL.x; - float R = abs(H * 6 - 3) - 1; - float G = 2 - abs(H * 6 - 2); - float B = 2 - abs(H * 6 - 4); - RGB = clamp(vec3(R,G,B), 0, 1); - } - float C = (1 - abs(2 * HSL.z - 1)) * HSL.y; - return (RGB - 0.5) * C + HSL.z; -} -vec3 rgbToHsl(vec3 RGB) { - float Epsilon = 1e-10; - vec3 HCV; { - vec4 P = (RGB.g < RGB.b) ? vec4(RGB.bg, -1.0, 2.0/3.0) : vec4(RGB.gb, 0.0, -1.0/3.0); - vec4 Q = (RGB.r < P.x) ? vec4(P.xyw, RGB.r) : vec4(RGB.r, P.yzx); - float C = Q.x - min(Q.w, Q.y); - float H = abs((Q.w - Q.y) / (6 * C + Epsilon) + Q.z); - HCV = vec3(H, C, Q.x); - } - float L = HCV.z - HCV.y * 0.5; - float S = HCV.y / (1 - abs(L * 2 - 1) + Epsilon); - return vec3(HCV.x, S, L); -} - -float hueDistance(float h1, float h2) { - float diff = abs((h1 - h2)); - return min(abs((1.0 - diff)), diff); -} -const float lightnessSteps = 4.0; -float lightnessStep(float l) { - return floor((0.5 + l * lightnessSteps)) / lightnessSteps; -} -const int indexMatrix16x16[256] = int[](0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255, - 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127, - 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223, - 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95, - 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247, - 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119, - 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215, - 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87, - 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253, - 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125, - 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221, - 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93, - 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245, - 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117, - 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213, - 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85); -float indexValue16x16( float scale ) { - int x = int(mod(gl_FragCoord.x * scale, 16)); - int y = int(mod(gl_FragCoord.y * scale, 16)); - return indexMatrix16x16[(x + y * 16)] / 256.0; -} -const int indexMatrix8x8[64] = int[](0, 32, 8, 40, 2, 34, 10, 42, - 48, 16, 56, 24, 50, 18, 58, 26, - 12, 44, 4, 36, 14, 46, 6, 38, - 60, 28, 52, 20, 62, 30, 54, 22, - 3, 35, 11, 43, 1, 33, 9, 41, - 51, 19, 59, 27, 49, 17, 57, 25, - 15, 47, 7, 39, 13, 45, 5, 37, - 63, 31, 55, 23, 61, 29, 53, 21); -float indexValue8x8( float scale ) { - int x = int(mod(gl_FragCoord.x * scale, 8)); - int y = int(mod(gl_FragCoord.y * scale, 8)); - return indexMatrix8x8[(x + y * 8)] / 64.0; -} -const int indexMatrix4x4[16] = int[](0, 8, 2, 10, - 12, 4, 14, 6, - 3, 11, 1, 9, - 15, 7, 13, 5); -float indexValue4x4( float scale ) { - int x = int(mod(gl_FragCoord.x * scale, 4)); - int y = int(mod(gl_FragCoord.y * scale, 4)); - return indexMatrix4x4[(x + y * 4)] / 16.0; -} -vec3[2] closestColors(float hue) { - vec3 ret[2]; - vec3 closest = vec3(-2, 0, 0); - vec3 secondClosest = vec3(-2, 0, 0); - vec3 temp; -/* - for (int i = 0; i < palette.length(); ++i) { - temp = rgbToHsl(palette[i].rgb); - float tempDistance = hueDistance(temp.x, hue); - if (tempDistance < hueDistance(closest.x, hue)) { - secondClosest = closest; - closest = temp; - } else { - if (tempDistance < hueDistance(secondClosest.x, hue)) { - secondClosest = temp; - } - } - } -*/ - ret[0] = closest; - ret[1] = secondClosest; - return ret; -} -float dither(float color) { - float closestColor = (color < 0.5) ? 0 : 1; - float secondClosestColor = 1 - closestColor; - float d = 1; // -0.5 - fract(ubo.mode.parameters.w / 8.0); - if ( ubo.mode.scalar == 16 ) { - d = indexValue16x16(1); - } else if ( ubo.mode.scalar == 8 ) { - d = indexValue8x8(1); - } else if ( ubo.mode.scalar == 4 ) { - d = indexValue4x4(1); - } - float distance = abs(closestColor - color); - return (distance < d) ? closestColor : secondClosestColor; -} -void dither(inout vec3 color) { - vec3 hsl = rgbToHsl(color); - hsl.x = dither(hsl.x); - color = hslToRgb(hsl); -} -void dither1(inout vec3 color) { - vec3 hsl = rgbToHsl(color); - - float d = 0; - vec3 cs[2] = { hsl, hsl }; // closestColors(hsl.x); - float scale = 1; - if ( ubo.mode.scalar == 16 ) { - d = indexValue16x16(scale); - } else if ( ubo.mode.scalar == 8 ) { - d = indexValue8x8(scale); - } else if ( ubo.mode.scalar == 4 ) { - d = indexValue4x4(scale); - } - float hueDiff = hueDistance(hsl.x, cs[0].x) / hueDistance(cs[1].x, cs[0].x); - float l1 = lightnessStep(max((hsl.z - 0.125), 0.0)); - float l2 = lightnessStep(min((hsl.z + 0.124), 1.0)); - float lightnessDiff = (hsl.z - l1) / (l2 - l1); - - vec3 resultColor = (hueDiff < d) ? cs[0] : cs[1]; - resultColor.z = (lightnessDiff < d) ? l1 : l2; - color = hslToRgb(resultColor); -} -vec3 dither2() { - vec3 vDither = dot( vec2( 171.0, 231.0 ), inUv.xy + ubo.mode.parameters.w ).xxx; - vDither.rgb = fract( vDither.rgb / vec3( 103.0, 71.0, 97.0 ) ) - vec3( 0.5, 0.5, 0.5 ); - return ( vDither.rgb / 255.0 ) * 0.375; -} - float rand2(vec2 co){ return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 143758.5453); } @@ -480,95 +223,31 @@ float rand3(vec3 co){ return fract(sin(dot(co.xyz ,vec3(12.9898,78.233, 37.719))) * 143758.5453); } void whitenoise(inout vec3 color) { - float flicker = ubo.mode.parameters.x; - float pieces = ubo.mode.parameters.y; - float blend = ubo.mode.parameters.z; - float time = ubo.mode.parameters.w; + const float flicker = ubo.mode.parameters.x; + const float pieces = ubo.mode.parameters.y; + const float blend = ubo.mode.parameters.z; + const float time = ubo.mode.parameters.w; if ( blend < 0.0001 ) return; - float freq = sin(pow(mod(time, flicker) + flicker, 1.9)); -// float whiteNoise = rand3( floor(position.world / pieces) + floor(time * 2) ); - float whiteNoise = rand2( floor(gl_FragCoord.xy / pieces) + mod(time, freq) ); + const float freq = sin(pow(mod(time, flicker) + flicker, 1.9)); + const float whiteNoise = rand2( floor(gl_FragCoord.xy / pieces) + mod(time, freq) ); color = mix( color, vec3(whiteNoise), blend ); } - -void pbr( Light light, vec3 albedo, float metallic, float roughness, vec3 lightPositionWorld, inout vec3 i ) { - vec3 F0 = vec3(0.04); - F0 = mix(F0, albedo, metallic); - - vec3 N = normalize(normal.eye); - vec3 L = light.position.xyz - position.eye; - float dist = length(L); - - L = normalize(L); - vec3 V = normalize(-position.eye); - vec3 H = normalize(V + L); - - float NdotL = max(dot(N, L), 0.0); - float NdotV = max(dot(N, V), 0.0); - float attenuation = light.power / (dist * dist); - vec3 radiance = light.color.rgb * attenuation; - - // cook-torrance brdf - float NDF = DistributionGGX(N, H, roughness); - float G = GeometrySmith(N, V, L, roughness); - vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0); - - vec3 kD = vec3(1.0) - F; - kD *= 1.0 - metallic; - - vec3 numerator = NDF * G * F; - float denominator = 4.0 * NdotV * NdotL; - vec3 specular = numerator / max(denominator, 0.001); - - // add to outgoing radiance Lo - i += (kD * albedo / PI + specular) * radiance * NdotL; +vec3 gamma( vec3 i ) { + return pow(i.rgb, vec3(1.0 / 2.2)); } -void pbrSpecular( Light light, vec3 albedo, float metallic, float roughness, inout vec3 i ) { - vec3 F0 = vec3(0.04); - F0 = mix(F0, albedo, metallic); - vec3 N = normalize(normal.eye); - vec3 L = light.position.xyz - position.eye; - float dist = length(L); - - L = normalize(L); - vec3 V = normalize(-position.eye); - vec3 H = normalize(V + L); - - float NdotL = max(dot(N, L), 0.0); - float NdotV = max(dot(N, V), 0.0); - float attenuation = light.power / (dist * dist); - vec3 radiance = light.color.rgb * attenuation; - - // cook-torrance brdf - float NDF = DistributionGGX(N, H, roughness); - float G = GeometrySmith(N, V, L, roughness); - vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0); - - vec3 kD = vec3(1.0) - F; - kD *= 1.0 - metallic; - - vec3 numerator = NDF * G * F; - float denominator = 4.0 * NdotV * NdotL; - vec3 specular = numerator / max(denominator, 0.001); - - // add to outgoing radiance Lo - i += specular * radiance * NdotL; -} vec2 rayBoxDst( vec3 boundsMin, vec3 boundsMax, vec3 rayO, vec3 rayD ) { - vec3 t0 = (boundsMin - rayO) / rayD; - vec3 t1 = (boundsMax - rayO) / rayD; - vec3 tmin = min(t0, t1); - vec3 tmax = max(t0, t1); - float dstA = max( max(tmin.x, tmin.y), tmin.z ); - float dstB = min( tmax.x, min(tmax.y, tmax.z) ); - float dstToBox = max(0, dstA); - float dstInsideBox = max(0, dstB - dstToBox); - return vec2(dstToBox, dstInsideBox); + const vec3 t0 = (boundsMin - rayO) / rayD; + const vec3 t1 = (boundsMax - rayO) / rayD; + const vec3 tmin = min(t0, t1); + const vec3 tmax = max(t0, t1); + const float tStart = max(0, max( max(tmin.x, tmin.y), tmin.z )); + const float tEnd = max(0, min( tmax.x, min(tmax.y, tmax.z) ) - tStart); + return vec2(tStart, tEnd); } float sampleDensity( vec3 position ) { - vec3 uvw = position * ubo.fog.densityScale * 0.001 + ubo.fog.offset * 0.01; + const vec3 uvw = position * ubo.fog.densityScale * 0.001 + ubo.fog.offset * 0.01; return max(0, texture(samplerNoise, uvw).r - ubo.fog.densityThreshold) * ubo.fog.densityMultiplier; } @@ -577,15 +256,15 @@ void fog( vec3 rayO, vec3 rayD, inout vec3 i, float scale ) { if ( ubo.fog.range.x == 0 || ubo.fog.range.y == 0 ) return; #if RAY_MARCH_FOG - float range = ubo.fog.range.y; - vec3 boundsMin = vec3(-range,-range,-range) + rayO; - vec3 boundsMax = vec3(range,range,range) + rayO; - int numSteps = int(length(boundsMax - boundsMin) * ubo.fog.stepScale ); + const float range = ubo.fog.range.y; + const vec3 boundsMin = vec3(-range,-range,-range) + rayO; + const vec3 boundsMax = vec3(range,range,range) + rayO; + const int numSteps = int(length(boundsMax - boundsMin) * ubo.fog.stepScale ); - vec2 rayBoxInfo = rayBoxDst( boundsMin, boundsMax, rayO, rayD ); - float dstToBox = rayBoxInfo.x; - float dstInsideBox = rayBoxInfo.y; - float depth = position.eye.z; + const vec2 rayBoxInfo = rayBoxDst( boundsMin, boundsMax, rayO, rayD ); + const float dstToBox = rayBoxInfo.x; + const float dstInsideBox = rayBoxInfo.y; + const float depth = position.eye.z; float lightEnergy = 0; // march @@ -608,22 +287,20 @@ void fog( vec3 rayO, vec3 rayD, inout vec3 i, float scale ) { } #endif - vec3 color = ubo.fog.color.rgb; - float inner = ubo.fog.range.x; - float outer = ubo.fog.range.y * scale; - float distance = length(-position.eye); - float factor = (distance - inner) / (outer - inner); - factor = clamp( factor, 0.0, 1.0 ); + const vec3 color = ubo.fog.color.rgb; + const float inner = ubo.fog.range.x; + const float outer = ubo.fog.range.y * scale; + const float distance = length(-position.eye); + const float factor = clamp( (distance - inner) / (outer - inner), 0.0, 1.0 ); i.rgb = mix(i.rgb, color, factor); } vec3 decodeNormals( vec2 enc ) { -#define kPI 3.1415926536f - vec2 ang = enc*2-1; - vec2 scth = vec2( sin(ang.x * kPI), cos(ang.x * kPI) ); - vec2 scphi = vec2(sqrt(1.0 - ang.y*ang.y), ang.y); - return vec3(scth.y*scphi.x, scth.x*scphi.x, scphi.y); + const vec2 ang = enc*2-1; + const vec2 scth = vec2( sin(ang.x * PI), cos(ang.x * PI) ); + const vec2 scphi = vec2(sqrt(1.0 - ang.y*ang.y), ang.y); + return normalize( vec3(scth.y*scphi.x, scth.x*scphi.x, scphi.y) ); /* vec2 fenc = enc*4-2; float f = dot(fenc,fenc); @@ -638,15 +315,15 @@ vec2 wrap( vec2 uv ) { return vec2( wrap( uv.x ), wrap( uv.y ) ); } float mipLevel( in vec2 uv ) { - vec2 dx_vtc = dFdx(uv); - vec2 dy_vtc = dFdy(uv); + const vec2 dx_vtc = dFdx(uv); + const vec2 dy_vtc = dFdy(uv); return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc))); } bool validTextureIndex( int textureIndex ) { return 0 <= textureIndex; // && textureIndex < ubo.textures; } vec4 resolve( subpassInputMS t ) { - int samples = int(ubo.msaa); + const int samples = int(ubo.msaa); vec4 resolved = vec4(0); for ( int i = 0; i < samples; ++i ) { resolved += subpassLoad(t, i); @@ -655,7 +332,7 @@ vec4 resolve( subpassInputMS t ) { return resolved; } uvec4 resolve( usubpassInputMS t ) { - int samples = int(ubo.msaa); + const int samples = int(ubo.msaa); uvec4 resolved = uvec4(0); for ( int i = 0; i < samples; ++i ) { resolved += subpassLoad(t, i); @@ -664,6 +341,42 @@ uvec4 resolve( usubpassInputMS t ) { return resolved; } +float shadowFactor( const Light light, float def ) { + if ( !validTextureIndex(light.mapIndex) ) return 1.0; + + vec4 positionClip = light.projection * light.view * vec4(position.world, 1.0); + positionClip.xyz /= positionClip.w; + + if ( positionClip.x < -1 || positionClip.x >= 1 ) return def; //0.0; + if ( positionClip.y < -1 || positionClip.y >= 1 ) return def; //0.0; + if ( positionClip.z <= 0 || positionClip.z >= 1 ) return def; //0.0; + + float factor = 1.0; + + // spot light + if ( abs(light.type) == 2 || abs(light.type) == 3 ) { + const float dist = length( positionClip.xy ); + if ( dist > 0.5 ) return def; //0.0; + + // spot light with attenuation + if ( abs(light.type) == 3 ) { + factor = 1.0 - (pow(dist * 2,2.0)); + } + } + + const vec2 uv = positionClip.xy * 0.5 + 0.5; + const float bias = light.depthBias; + const float eyeDepth = positionClip.z; + const int samples = int(ubo.poissonSamples); + if ( samples <= 1 ) return eyeDepth < texture(samplerTextures[light.mapIndex], uv).r - bias ? 0.0 : factor; + for ( int i = 0; i < samples; ++i ) { + const int index = int( float(samples) * random(floor(position.world.xyz * 1000.0), i)) % samples; + const float lightDepth = texture(samplerTextures[light.mapIndex], uv + poissonDisk[index] / 700.0 ).r; + if ( eyeDepth < lightDepth - bias ) factor -= 1.0 / samples; + } + return factor; +} + void main() { vec3 rayO = vec3(0); vec3 rayD = vec3(0); @@ -671,77 +384,72 @@ void main() { { #if !MULTISAMPLING - float depth = subpassLoad(samplerDepth).r; + const float depth = subpassLoad(samplerDepth).r; #else - float depth = resolve( samplerDepth ).r; + const float depth = resolve( samplerDepth ).r; #endif - vec4 positionClip = vec4(inUv * 2.0 - 1.0, depth, 1.0); - vec4 positionEye = ubo.matrices.iProjection[inPushConstantPass] * positionClip; + vec4 positionEye = ubo.matrices.iProjection[inPushConstantPass] * vec4(inUv * 2.0 - 1.0, depth, 1.0); positionEye /= positionEye.w; position.eye = positionEye.xyz; - - vec4 positionWorld = ubo.matrices.iView[inPushConstantPass] * positionEye; - position.world = positionWorld.xyz; + position.world = vec3( ubo.matrices.iView[inPushConstantPass] * positionEye ); } { - vec4 near4 = ubo.matrices.iProjectionView[inPushConstantPass] * (vec4(2.0 * inUv - 1.0, -1.0, 1.0)); - vec4 far4 = ubo.matrices.iProjectionView[inPushConstantPass] * (vec4(2.0 * inUv - 1.0, 1.0, 1.0)); - vec3 near3 = near4.xyz / near4.w; - vec3 far3 = far4.xyz / far4.w; + const vec4 near4 = ubo.matrices.iProjectionView[inPushConstantPass] * (vec4(2.0 * inUv - 1.0, -1.0, 1.0)); + const vec4 far4 = ubo.matrices.iProjectionView[inPushConstantPass] * (vec4(2.0 * inUv - 1.0, 1.0, 1.0)); + const vec3 near3 = near4.xyz / near4.w; + const vec3 far3 = far4.xyz / far4.w; rayO = near3; + rayD = normalize( far3 - near3 ); } - { - mat4 iProjectionView = inverse( ubo.matrices.projection[inPushConstantPass] * mat4(mat3(ubo.matrices.view[inPushConstantPass])) ); - vec4 near4 = iProjectionView * (vec4(2.0 * inUv - 1.0, -1.0, 1.0)); - vec4 far4 = iProjectionView * (vec4(2.0 * inUv - 1.0, 1.0, 1.0)); - vec3 near3 = near4.xyz / near4.w; - vec3 far3 = far4.xyz / far4.w; + // separate our ray direction due to floating point precision problems + if ( false ) { + const mat4 iProjectionView = inverse( ubo.matrices.projection[inPushConstantPass] * mat4(mat3(ubo.matrices.view[inPushConstantPass])) ); + const vec4 near4 = iProjectionView * (vec4(2.0 * inUv - 1.0, -1.0, 1.0)); + const vec4 far4 = iProjectionView * (vec4(2.0 * inUv - 1.0, 1.0, 1.0)); + const vec3 near3 = near4.xyz / near4.w; + const vec3 far3 = far4.xyz / far4.w; rayD = normalize( far3 - near3 ); } #if !MULTISAMPLING normal.world = decodeNormals( subpassLoad(samplerNormal).xy ); - uvec2 ID = subpassLoad(samplerId).xy; + const uvec2 ID = subpassLoad(samplerId).xy; #else normal.world = decodeNormals( resolve(samplerNormal).xy ); - uvec2 ID = resolve(samplerId).xy; + const uvec2 ID = resolve(samplerId).xy; #endif normal.eye = vec3( ubo.matrices.view[inPushConstantPass] * vec4(normal.world, 0.0) ); - uint drawId = ID.x; - uint materialId = ID.y; - if ( drawId == 0 || materialId == 0 ) { + if ( ID.x == 0 || ID.y == 0 ) { fragColor.rgb = texture( samplerSkybox, rayD ).rgb; fog(rayO, rayD, fragColor, 0.0); outFragColor = vec4(fragColor,1); return; } - --drawId; - --materialId; - - DrawCall drawCall = drawCalls[drawId]; - materialId += drawCall.materialIndex; - - Material material = materials[materialId]; - vec4 C = material.colorBase; -#if UF_DEFERRED_SAMPLING + const uint drawId = ID.x - 1; + const DrawCall drawCall = drawCalls[drawId]; + const uint materialId = ID.y + drawCall.materialIndex - 1; + const Material material = materials[materialId]; + vec4 A = material.colorBase; +#if DEFERRED_SAMPLING #if !MULTISAMPLING - vec2 uv = subpassLoad(samplerUv).xy; + const vec2 uv = subpassLoad(samplerUv).xy; #else - vec2 uv = resolve(samplerUv).xy; + const vec2 uv = resolve(samplerUv).xy; #endif - bool useAtlas = validTextureIndex( drawCall.textureIndex + material.indexAtlas ); + const float mip = mipLevel(inUv.xy); + const bool useAtlas = validTextureIndex( drawCall.textureIndex + material.indexAtlas ); Texture textureAtlas; if ( useAtlas ) textureAtlas = textures[drawCall.textureIndex + material.indexAtlas]; if ( validTextureIndex( drawCall.textureIndex + material.indexAtlas ) ) { Texture t = textures[drawCall.textureIndex + material.indexAlbedo]; - C = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip ); + A = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip ); } // OPAQUE if ( material.modeAlpha == 0 ) { - C.a = 1; + A.a = 1; // BLEND } else if ( material.modeAlpha == 1 ) { @@ -751,78 +459,65 @@ void main() { } #else #if !MULTISAMPLING - C = subpassLoad(samplerAlbedo); + A = subpassLoad(samplerAlbedo); #else - C = resolve(samplerAlbedo); + A = resolve(samplerAlbedo); #endif #endif - float M = material.factorMetallic; - float R = material.factorRoughness * 4.0; - float AO = material.factorOcclusion; + const float M = material.factorMetallic; + const float R = material.factorRoughness; + const float AO = 1.0f - material.factorOcclusion; - bool usePbr = true; - bool gammaCorrect = false; float litFactor = 1.0; - bool useLightmap = 0 <= material.indexLightmap; - if ( useLightmap ) { - fragColor = C.rgb + ubo.ambient.rgb; - for ( uint i = 0; i < ubo.lights; ++i ) { - Light light = lights[i]; - - if ( light.power <= 0.001 ) continue; - - light.position.xyz = vec3(ubo.matrices.view[inPushConstantPass] * vec4(light.position.xyz, 1)); - if ( validTextureIndex(light.mapIndex) ) { - float factor = shadowFactor( light, light.mapIndex, 0.0 ); - light.power *= factor; - litFactor += light.power; - } - if ( light.power <= 0.0001 ) continue; - if ( usePbr ) pbrSpecular( light, C.rgb, M, R, fragColor ); else phongSpecular( light, C, fragColor ); - } - /* - float totalShadows = 0.0; - float totalLights = 0.0; + if ( 0 <= material.indexLightmap ) { + fragColor = A.rgb + ubo.ambient.rgb * (1 - AO); + } else { + fragColor = A.rgb * ubo.ambient.rgb * (1 - AO); + } + { + const vec3 N = normal.eye; + const vec3 F0 = mix(vec3(0.04), A.rgb, M); + const vec3 Lo = normalize( -position.eye ); + const float cosLo = max(0.0, dot(N, Lo)); for ( uint i = 0; i < ubo.lights; ++i ) { - Light light = lights[i]; + const Light light = lights[i]; + if ( light.power <= LIGHT_POWER_CUTOFF ) continue; + const vec3 Lp = light.position; + const vec3 Liu = vec3(ubo.matrices.view[inPushConstantPass] * vec4(light.position, 1)) - position.eye; + const vec3 Li = normalize(Liu); + const float Ls = shadowFactor( light, 0.0 ); + const float La = 1.0 / (PI * pow(length(Liu), 2.0)); + if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue; + + const float cosLi = max(0.0, dot(N, Li)); + + const vec3 Lh = normalize(Li + Lo); + const float cosLh = max(0.0, dot(N, Lh)); - if ( light.power <= 0.001 ) continue; - - vec3 lightPositionWorld = light.position.xyz; - light.position.xyz = vec3(ubo.matrices.view[inPushConstantPass] * vec4(light.position.xyz, 1)); - ++totalLights; - if ( !validTextureIndex(light.mapIndex) ) continue; - totalShadows += shadowFactor( light, light.mapIndex, 1.0 ); - } - fragColor = vec3(totalShadows / totalLights); - */ - } else { - fragColor = C.rgb * ubo.ambient.rgb * AO; - for ( uint i = 0; i < ubo.lights; ++i ) { - Light light = lights[i]; - - if ( light.power <= 0.001 ) continue; - - vec3 lightPositionWorld = light.position.xyz; - light.position.xyz = vec3(ubo.matrices.view[inPushConstantPass] * vec4(light.position.xyz, 1)); - - if ( validTextureIndex(light.mapIndex) ) { - float factor = shadowFactor( light, light.mapIndex, 0.0 ); - light.power *= factor; - litFactor += light.power; - } - if ( light.power <= 0.0001 ) continue; - if ( usePbr ) pbr( light, C.rgb, M, R, lightPositionWorld, fragColor ); else phong( light, C, fragColor ); + const vec3 Lr = light.color.rgb * light.power * La * Ls; + const vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) ); + const float D = ndfGGX( cosLh, R ); + const float G = gaSchlickGGX(cosLi, cosLo, R); + const vec3 diffuseBRDF = mix( vec3(1.0) - F, vec3(0.0), M ) * A.rgb; + const vec3 specularBRDF = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo); + if ( light.type >= 0 && 0 <= material.indexLightmap ) fragColor.rgb += (specularBRDF) * Lr * cosLi; + // else if ( light.type == 0 ) fragColor.rgb += (diffuseBRDF) * Lr * cosLi; + else fragColor.rgb += (diffuseBRDF + specularBRDF) * Lr * cosLi; + litFactor += light.power * La * Ls; } } - if ( gammaCorrect ) { - fragColor = fragColor / (fragColor + vec3(1.0)); - fragColor = pow(fragColor, vec3(1.0/2.2)); - } fog(rayO, rayD, fragColor, litFactor); +#if TONE_MAP +// fragColor = fragColor / (fragColor + 1.0f); + fragColor = vec3(1.0) - exp(-fragColor * ubo.exposure); +#endif +#if GAMMA_CORRECT + fragColor = pow(fragColor, vec3(1.0 / ubo.gama)); +#endif + /* if ( (ubo.mode.type & (0x1 << 0)) == (0x1 << 0) ) { @@ -833,5 +528,6 @@ void main() { if ( (ubo.mode.type & (0x1 << 1)) == (0x1 << 1) ) { whitenoise(fragColor); } + outFragColor = vec4(fragColor,1); } \ No newline at end of file diff --git a/bin/data/shaders/display/subpass.svogi.frag.glsl b/bin/data/shaders/display/subpass.vxgi.frag.glsl similarity index 50% rename from bin/data/shaders/display/subpass.svogi.frag.glsl rename to bin/data/shaders/display/subpass.vxgi.frag.glsl index 110d1466..7292ecb2 100644 --- a/bin/data/shaders/display/subpass.svogi.frag.glsl +++ b/bin/data/shaders/display/subpass.vxgi.frag.glsl @@ -3,7 +3,36 @@ #define MULTISAMPLING 1 #define RAY_MARCH_FOG 1 -#define UF_DEFERRED_SAMPLING 0 +#define DEFERRED_SAMPLING 0 +#define SHADOW_CONE_TRACED 0 +#define VOXEL_TRACE_IN_NDC 0 + +#define GAMMA_CORRECT 1 +#define TONE_MAP 1 + +const float PI = 3.14159265359; +const float EPSILON = 0.00001; + +const float LIGHT_POWER_CUTOFF = 0.005; + +const vec2 poissonDisk[16] = vec2[]( + vec2( -0.94201624, -0.39906216 ), + vec2( 0.94558609, -0.76890725 ), + vec2( -0.094184101, -0.92938870 ), + vec2( 0.34495938, 0.29387760 ), + vec2( -0.91588581, 0.45771432 ), + vec2( -0.81544232, -0.87912464 ), + vec2( -0.38277543, 0.27676845 ), + vec2( 0.97484398, 0.75648379 ), + vec2( 0.44323325, -0.97511554 ), + vec2( 0.53742981, -0.47373420 ), + vec2( -0.26496911, -0.41893023 ), + vec2( 0.79197514, 0.19090188 ), + vec2( -0.24188840, 0.99706507 ), + vec2( -0.81409955, 0.91437590 ), + vec2( 0.19984126, 0.78641367 ), + vec2( 0.14383161, -0.14100790 ) +); layout (constant_id = 0) const uint TEXTURES = 256; @@ -105,7 +134,7 @@ struct Voxel { #if !MULTISAMPLING layout (input_attachment_index = 0, binding = 0) uniform usubpassInput samplerId; layout (input_attachment_index = 1, binding = 1) uniform subpassInput samplerNormal; - #if UF_DEFERRED_SAMPLING + #if DEFERRED_SAMPLING layout (input_attachment_index = 2, binding = 2) uniform subpassInput samplerUv; #else layout (input_attachment_index = 2, binding = 2) uniform subpassInput samplerAlbedo; @@ -114,7 +143,7 @@ struct Voxel { #else layout (input_attachment_index = 0, binding = 0) uniform usubpassInputMS samplerId; layout (input_attachment_index = 1, binding = 1) uniform subpassInputMS samplerNormal; - #if UF_DEFERRED_SAMPLING + #if DEFERRED_SAMPLING layout (input_attachment_index = 2, binding = 2) uniform subpassInputMS samplerUv; #else layout (input_attachment_index = 2, binding = 2) uniform subpassInputMS samplerAlbedo; @@ -138,8 +167,8 @@ layout (binding = 4) uniform UBO { uint msaa; uint poissonSamples; - uint padding1; - uint padding2; + float gamma; + float exposure; } ubo; layout (std140, binding = 5) readonly buffer Lights { @@ -170,35 +199,12 @@ layout (location = 1) in flat uint inPushConstantPass; layout (location = 0) out vec4 outFragColor; layout (location = 1) out vec4 outDebugValue; -vec2 poissonDisk[16] = vec2[]( - vec2( -0.94201624, -0.39906216 ), - vec2( 0.94558609, -0.76890725 ), - vec2( -0.094184101, -0.92938870 ), - vec2( 0.34495938, 0.29387760 ), - vec2( -0.91588581, 0.45771432 ), - vec2( -0.81544232, -0.87912464 ), - vec2( -0.38277543, 0.27676845 ), - vec2( 0.97484398, 0.75648379 ), - vec2( 0.44323325, -0.97511554 ), - vec2( 0.53742981, -0.47373420 ), - vec2( -0.26496911, -0.41893023 ), - vec2( 0.79197514, 0.19090188 ), - vec2( -0.24188840, 0.99706507 ), - vec2( -0.81409955, 0.91437590 ), - vec2( 0.19984126, 0.78641367 ), - vec2( 0.14383161, -0.14100790 ) -); - -const float PI = 3.14159265359; -const float EPSILON = 0.00001; - // GGX/Towbridge-Reitz normal distribution function. // Uses Disney's reparametrization of alpha = roughness^2. float ndfGGX(float cosLh, float roughness) { - float alpha = roughness * roughness; - float alphaSq = alpha * alpha; - - float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0; + const float alpha = roughness * roughness; + const float alphaSq = alpha * alpha; + const float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0; return alphaSq / (PI * denom * denom); } @@ -209,8 +215,8 @@ float gaSchlickG1(float cosTheta, float k) { // Schlick-GGX approximation of geometric attenuation function using Smith's method. float gaSchlickGGX(float cosLi, float cosLo, float roughness) { - float r = roughness + 1.0; - float k = (r * r) / 8.0; // Epic suggests using this roughness remapping for analytic lights. + const float r = roughness + 1.0; + const float k = (r * r) / 8.0; // Epic suggests using this roughness remapping for analytic lights. return gaSchlickG1(cosLi, k) * gaSchlickG1(cosLo, k); } vec3 fresnelSchlick(vec3 F0, float cosTheta) { @@ -218,54 +224,13 @@ vec3 fresnelSchlick(vec3 F0, float cosTheta) { } float random(vec3 seed, int i){ - vec4 seed4 = vec4(seed,i); - float dot_product = dot(seed4, vec4(12.9898,78.233,45.164,94.673)); - return fract(sin(dot_product) * 43758.5453); + return fract(sin(dot(vec4(seed,i), vec4(12.9898,78.233,45.164,94.673))) * 43758.5453); } -float shadowFactor( Light light, uint shadowMap, float def ) { - vec4 positionClip = light.projection * light.view * vec4(position.world, 1.0); - positionClip.xyz /= positionClip.w; - - if ( positionClip.x < -1 || positionClip.x >= 1 ) return def; //0.0; - if ( positionClip.y < -1 || positionClip.y >= 1 ) return def; //0.0; - if ( positionClip.z <= 0 || positionClip.z >= 1 ) return def; //0.0; - - float factor = 1.0; - - // spot light - if ( light.type == 1 || light.type == 2 ) { - float dist = length( positionClip.xy ); - if ( dist > 0.5 ) return def; //0.0; - - // spot light with attenuation - if ( light.type == 2 ) { - factor = 1.0 - (pow(dist * 2,2.0)); - } - } - - vec2 uv = positionClip.xy * 0.5 + 0.5; - float bias = light.depthBias; - - float eyeDepth = positionClip.z; - - int samples = int(ubo.poissonSamples); - if ( samples <= 1 ) { - return eyeDepth < texture(samplerTextures[shadowMap], uv).r - bias ? 0.0 : factor; - } - for ( int i = 0; i < samples; ++i ) { - // int index = i; - // int index = int( float(samples) * random(gl_FragCoord.xyy, i) ) % samples; - int index = int( float(samples) * random(floor(position.world.xyz * 1000.0), i)) % samples; - float lightDepth = texture(samplerTextures[shadowMap], uv + poissonDisk[index] / 700.0 ).r; - if ( eyeDepth < lightDepth - bias ) factor -= 1.0 / samples; - } - return factor; -} // Returns a vector that is orthogonal to u. vec3 orthogonal(vec3 u){ u = normalize(u); - vec3 v = vec3(0.99146, 0.11664, 0.05832); // Pick any normalized vector. + const vec3 v = vec3(0.99146, 0.11664, 0.05832); // Pick any normalized vector. return abs(dot(u, v)) > 0.99999f ? cross(u, vec3(0, 1, 0)) : cross(u, v); } float rand2(vec2 co){ @@ -275,14 +240,13 @@ float rand3(vec3 co){ return fract(sin(dot(co.xyz ,vec3(12.9898,78.233, 37.719))) * 143758.5453); } void whitenoise(inout vec3 color) { - float flicker = ubo.mode.parameters.x; - float pieces = ubo.mode.parameters.y; - float blend = ubo.mode.parameters.z; - float time = ubo.mode.parameters.w; + const float flicker = ubo.mode.parameters.x; + const float pieces = ubo.mode.parameters.y; + const float blend = ubo.mode.parameters.z; + const float time = ubo.mode.parameters.w; if ( blend < 0.0001 ) return; - float freq = sin(pow(mod(time, flicker) + flicker, 1.9)); -// float whiteNoise = rand3( floor(position.world / pieces) + floor(time * 2) ); - float whiteNoise = rand2( floor(gl_FragCoord.xy / pieces) + mod(time, freq) ); + const float freq = sin(pow(mod(time, flicker) + flicker, 1.9)); + const float whiteNoise = rand2( floor(gl_FragCoord.xy / pieces) + mod(time, freq) ); color = mix( color, vec3(whiteNoise), blend ); } vec3 gamma( vec3 i ) { @@ -290,19 +254,17 @@ vec3 gamma( vec3 i ) { } vec2 rayBoxDst( vec3 boundsMin, vec3 boundsMax, vec3 rayO, vec3 rayD ) { - vec3 t0 = (boundsMin - rayO) / rayD; - vec3 t1 = (boundsMax - rayO) / rayD; - vec3 tmin = min(t0, t1); - vec3 tmax = max(t0, t1); - float dstA = max( max(tmin.x, tmin.y), tmin.z ); - float dstB = min( tmax.x, min(tmax.y, tmax.z) ); - float tStart = max(0, dstA); - float tEnd = max(0, dstB - tStart); + const vec3 t0 = (boundsMin - rayO) / rayD; + const vec3 t1 = (boundsMax - rayO) / rayD; + const vec3 tmin = min(t0, t1); + const vec3 tmax = max(t0, t1); + const float tStart = max(0, max( max(tmin.x, tmin.y), tmin.z )); + const float tEnd = max(0, min( tmax.x, min(tmax.y, tmax.z) ) - tStart); return vec2(tStart, tEnd); } float sampleDensity( vec3 position ) { - vec3 uvw = position * ubo.fog.densityScale * 0.001 + ubo.fog.offset * 0.01; + const vec3 uvw = position * ubo.fog.densityScale * 0.001 + ubo.fog.offset * 0.01; return max(0, texture(samplerNoise, uvw).r - ubo.fog.densityThreshold) * ubo.fog.densityMultiplier; } @@ -311,15 +273,15 @@ void fog( vec3 rayO, vec3 rayD, inout vec3 i, float scale ) { if ( ubo.fog.range.x == 0 || ubo.fog.range.y == 0 ) return; #if RAY_MARCH_FOG - float range = ubo.fog.range.y; - vec3 boundsMin = vec3(-range,-range,-range) + rayO; - vec3 boundsMax = vec3(range,range,range) + rayO; - int numSteps = int(length(boundsMax - boundsMin) * ubo.fog.stepScale ); + const float range = ubo.fog.range.y; + const vec3 boundsMin = vec3(-range,-range,-range) + rayO; + const vec3 boundsMax = vec3(range,range,range) + rayO; + const int numSteps = int(length(boundsMax - boundsMin) * ubo.fog.stepScale ); - vec2 rayBoxInfo = rayBoxDst( boundsMin, boundsMax, rayO, rayD ); - float dstToBox = rayBoxInfo.x; - float dstInsideBox = rayBoxInfo.y; - float depth = position.eye.z; + const vec2 rayBoxInfo = rayBoxDst( boundsMin, boundsMax, rayO, rayD ); + const float dstToBox = rayBoxInfo.x; + const float dstInsideBox = rayBoxInfo.y; + const float depth = position.eye.z; float lightEnergy = 0; // march @@ -342,21 +304,19 @@ void fog( vec3 rayO, vec3 rayD, inout vec3 i, float scale ) { } #endif - vec3 color = ubo.fog.color.rgb; - float inner = ubo.fog.range.x; - float outer = ubo.fog.range.y * scale; - float distance = length(-position.eye); - float factor = (distance - inner) / (outer - inner); - factor = clamp( factor, 0.0, 1.0 ); + const vec3 color = ubo.fog.color.rgb; + const float inner = ubo.fog.range.x; + const float outer = ubo.fog.range.y * scale; + const float distance = length(-position.eye); + const float factor = clamp( (distance - inner) / (outer - inner), 0.0, 1.0 ); i.rgb = mix(i.rgb, color, factor); } vec3 decodeNormals( vec2 enc ) { -#define kPI 3.1415926536f - vec2 ang = enc*2-1; - vec2 scth = vec2( sin(ang.x * kPI), cos(ang.x * kPI) ); - vec2 scphi = vec2(sqrt(1.0 - ang.y*ang.y), ang.y); + const vec2 ang = enc*2-1; + const vec2 scth = vec2( sin(ang.x * PI), cos(ang.x * PI) ); + const vec2 scphi = vec2(sqrt(1.0 - ang.y*ang.y), ang.y); return normalize( vec3(scth.y*scphi.x, scth.x*scphi.x, scphi.y) ); /* vec2 fenc = enc*4-2; @@ -372,15 +332,15 @@ vec2 wrap( vec2 uv ) { return vec2( wrap( uv.x ), wrap( uv.y ) ); } float mipLevel( in vec2 uv ) { - vec2 dx_vtc = dFdx(uv); - vec2 dy_vtc = dFdy(uv); + const vec2 dx_vtc = dFdx(uv); + const vec2 dy_vtc = dFdy(uv); return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc))); } bool validTextureIndex( int textureIndex ) { return 0 <= textureIndex; // && textureIndex < ubo.textures; } vec4 resolve( subpassInputMS t ) { - int samples = int(ubo.msaa); + const int samples = int(ubo.msaa); vec4 resolved = vec4(0); for ( int i = 0; i < samples; ++i ) { resolved += subpassLoad(t, i); @@ -389,7 +349,7 @@ vec4 resolve( subpassInputMS t ) { return resolved; } uvec4 resolve( usubpassInputMS t ) { - int samples = int(ubo.msaa); + const int samples = int(ubo.msaa); uvec4 resolved = uvec4(0); for ( int i = 0; i < samples; ++i ) { resolved += subpassLoad(t, i); @@ -398,8 +358,44 @@ uvec4 resolve( usubpassInputMS t ) { return resolved; } +float shadowFactor( const Light light, float def ) { + if ( !validTextureIndex(light.mapIndex) ) return 1.0; + + vec4 positionClip = light.projection * light.view * vec4(position.world, 1.0); + positionClip.xyz /= positionClip.w; + + if ( positionClip.x < -1 || positionClip.x >= 1 ) return def; //0.0; + if ( positionClip.y < -1 || positionClip.y >= 1 ) return def; //0.0; + if ( positionClip.z <= 0 || positionClip.z >= 1 ) return def; //0.0; + + float factor = 1.0; + + // spot light + if ( abs(light.type) == 2 || abs(light.type) == 3 ) { + const float dist = length( positionClip.xy ); + if ( dist > 0.5 ) return def; //0.0; + + // spot light with attenuation + if ( abs(light.type) == 3 ) { + factor = 1.0 - (pow(dist * 2,2.0)); + } + } + + const vec2 uv = positionClip.xy * 0.5 + 0.5; + const float bias = light.depthBias; + const float eyeDepth = positionClip.z; + const int samples = int(ubo.poissonSamples); + if ( samples <= 1 ) return eyeDepth < texture(samplerTextures[light.mapIndex], uv).r - bias ? 0.0 : factor; + for ( int i = 0; i < samples; ++i ) { + const int index = int( float(samples) * random(floor(position.world.xyz * 1000.0), i)) % samples; + const float lightDepth = texture(samplerTextures[light.mapIndex], uv + poissonDisk[index] / 700.0 ).r; + if ( eyeDepth < lightDepth - bias ) factor -= 1.0 / samples; + } + return factor; +} + Voxel getVoxel( vec3 P ) { - vec3 uvw = vec3( ubo.matrices.voxel * vec4( P, 1.0f ) ) * 0.5f + 0.5f; + const vec3 uvw = vec3( ubo.matrices.voxel * vec4( P, 1.0f ) ) * 0.5f + 0.5f; Voxel voxel; voxel.id = uvec2(texture(voxelId, uvw).xy); @@ -411,64 +407,65 @@ Voxel getVoxel( vec3 P ) { return voxel; } -#define VOXEL_TRACE_IN_NDC 0 -vec4 voxelConeTrace( vec3 rayO, vec3 rayD, float aperture ) { - // bounds - float albedoSize = textureSize( voxelAlbedo, 0 ).x; - float mipmapLevels = textureQueryLod( voxelAlbedo, vec3(0) ).x; +struct VoxelInfo { + vec3 min; + vec3 max; + + float mipmapLevels; + float albedoSize; + float voxelSize; +}; +VoxelInfo voxelInfo; + +vec4 voxelConeTrace( vec3 rayO, vec3 rayD, float aperture, float maxDistance ) { #if VOXEL_TRACE_IN_NDC rayO = vec3( ubo.matrices.voxel * vec4( rayO, 1.0 ) ); rayD = vec3( ubo.matrices.voxel * vec4( rayD, 0.0 ) ); - - vec3 boundsMin = vec3( -1 ); - vec3 boundsMax = vec3( 1 ); - float voxelSize = 1.0 / albedoSize; -#else - mat4 inverseOrtho = inverse( ubo.matrices.voxel ); - vec3 boundsMin = vec3( inverseOrtho * vec4( -1, -1, -1, 1 ) ); - vec3 boundsMax = vec3( inverseOrtho * vec4( 1, 1, 1, 1 ) ); - float voxelSize = 1; #endif - float granularity = 1.0 / 6.0; // (2.0 * sqrt(2.0) ); + const float granularity = 1.0 / 6.0; // (2.0 * sqrt(2.0) ); // box - vec2 rayBoxInfo = rayBoxDst( boundsMin, boundsMax, rayO, rayD ); - float tStart = rayBoxInfo.x; - float tEnd = rayBoxInfo.y; + const vec2 rayBoxInfo = rayBoxDst( voxelInfo.min, voxelInfo.max, rayO, rayD ); + const float tStart = rayBoxInfo.x; + const float tEnd = maxDistance > 0 ? min(maxDistance, rayBoxInfo.y) : rayBoxInfo.y; // steps - float tDelta = voxelSize * granularity; - uint maxSteps = uint(albedoSize / granularity); + const float tDelta = voxelInfo.voxelSize * granularity; + const uint maxSteps = uint(voxelInfo.albedoSize / granularity); // marcher float t = tStart + tDelta * 2.0; vec3 rayPos = vec3(0); vec4 radiance = vec4(0); vec3 uvw = vec3(0); // cone mipmap shit - float coneCoefficient = 2.0 * tan(aperture * 0.5); + const float coneCoefficient = 2.0 * tan(aperture * 0.5); float coneDiameter = coneCoefficient * t; - float level = aperture > 0 ? log2( coneDiameter / albedoSize ) : 0; + float level = aperture > 0 ? log2( coneDiameter / voxelInfo.albedoSize ) : 0; // results vec4 color = vec4(0); float occlusion = 0.0; - // do uint stepCounter = 0; - while ( t < tEnd && occlusion < 1.0 && stepCounter++ < maxSteps ) { - t += tDelta; + const float falloff = 256.0f; + const vec3 voxelBoundsRecip = 1.0f / (voxelInfo.max - voxelInfo.min); + while ( t < tEnd && color.a < 1.0 && occlusion < 1.0 && stepCounter++ < maxSteps ) { + t += tDelta * pow(2, coneDiameter / voxelInfo.albedoSize); rayPos = rayO + rayD * t; #if VOXEL_TRACE_IN_NDC uvw = rayPos * 0.5 + 0.5; #else - uvw = (rayPos - boundsMin) / (boundsMax - boundsMin); // vec3( ubo.matrices.voxel * vec4( rayPos, 1 ) ) * 0.5 + 0.5; + uvw = (rayPos - voxelInfo.min) * voxelBoundsRecip; #endif if ( abs(uvw.x) > 1.0 || abs(uvw.y) > 1.0 || abs(uvw.z) > 1.0 ) break; coneDiameter = coneCoefficient * t; - level = log2( coneDiameter / albedoSize ); + level = log2( coneDiameter / voxelInfo.albedoSize ); radiance = texture(voxelAlbedo, uvw, level) * granularity; - occlusion += radiance.a; - color.rgb += (1.0 - occlusion) * radiance.rgb; + color += (1.0 - color.a) * radiance; + occlusion += ((1.0f - occlusion) * radiance.a) / (1.0f + falloff * coneDiameter); } return vec4(color.rgb, occlusion); } +vec4 voxelConeTrace( vec3 rayO, vec3 rayD, float aperture ) { + return voxelConeTrace( rayO, rayD, aperture, 0 ); +} void main() { vec3 rayO = vec3(0); @@ -477,77 +474,72 @@ void main() { { #if !MULTISAMPLING - float depth = subpassLoad(samplerDepth).r; + const float depth = subpassLoad(samplerDepth).r; #else - float depth = resolve( samplerDepth ).r; + const float depth = resolve( samplerDepth ).r; #endif - vec4 positionClip = vec4(inUv * 2.0 - 1.0, depth, 1.0); - vec4 positionEye = ubo.matrices.iProjection[inPushConstantPass] * positionClip; + vec4 positionEye = ubo.matrices.iProjection[inPushConstantPass] * vec4(inUv * 2.0 - 1.0, depth, 1.0); positionEye /= positionEye.w; position.eye = positionEye.xyz; - - vec4 positionWorld = ubo.matrices.iView[inPushConstantPass] * positionEye; - position.world = positionWorld.xyz; + position.world = vec3( ubo.matrices.iView[inPushConstantPass] * positionEye ); } { - vec4 near4 = ubo.matrices.iProjectionView[inPushConstantPass] * (vec4(2.0 * inUv - 1.0, -1.0, 1.0)); - vec4 far4 = ubo.matrices.iProjectionView[inPushConstantPass] * (vec4(2.0 * inUv - 1.0, 1.0, 1.0)); - vec3 near3 = near4.xyz / near4.w; - vec3 far3 = far4.xyz / far4.w; + const vec4 near4 = ubo.matrices.iProjectionView[inPushConstantPass] * (vec4(2.0 * inUv - 1.0, -1.0, 1.0)); + const vec4 far4 = ubo.matrices.iProjectionView[inPushConstantPass] * (vec4(2.0 * inUv - 1.0, 1.0, 1.0)); + const vec3 near3 = near4.xyz / near4.w; + const vec3 far3 = far4.xyz / far4.w; rayO = near3; + rayD = normalize( far3 - near3 ); } - { - mat4 iProjectionView = inverse( ubo.matrices.projection[inPushConstantPass] * mat4(mat3(ubo.matrices.view[inPushConstantPass])) ); - vec4 near4 = iProjectionView * (vec4(2.0 * inUv - 1.0, -1.0, 1.0)); - vec4 far4 = iProjectionView * (vec4(2.0 * inUv - 1.0, 1.0, 1.0)); - vec3 near3 = near4.xyz / near4.w; - vec3 far3 = far4.xyz / far4.w; + // separate our ray direction due to floating point precision problems + if ( true ) { + const mat4 iProjectionView = inverse( ubo.matrices.projection[inPushConstantPass] * mat4(mat3(ubo.matrices.view[inPushConstantPass])) ); + const vec4 near4 = iProjectionView * (vec4(2.0 * inUv - 1.0, -1.0, 1.0)); + const vec4 far4 = iProjectionView * (vec4(2.0 * inUv - 1.0, 1.0, 1.0)); + const vec3 near3 = near4.xyz / near4.w; + const vec3 far3 = far4.xyz / far4.w; rayD = normalize( far3 - near3 ); } #if !MULTISAMPLING normal.world = decodeNormals( subpassLoad(samplerNormal).xy ); - uvec2 ID = subpassLoad(samplerId).xy; + const uvec2 ID = subpassLoad(samplerId).xy; #else normal.world = decodeNormals( resolve(samplerNormal).xy ); - uvec2 ID = resolve(samplerId).xy; + const uvec2 ID = resolve(samplerId).xy; #endif normal.eye = vec3( ubo.matrices.view[inPushConstantPass] * vec4(normal.world, 0.0) ); - uint drawId = ID.x; - uint materialId = ID.y; - if ( drawId == 0 || materialId == 0 ) { + if ( ID.x == 0 || ID.y == 0 ) { fragColor.rgb = texture( samplerSkybox, rayD ).rgb; - fog(rayO, rayD, fragColor, 0.0); + fog(rayO, rayD, fragColor, 0.5); outFragColor = vec4(fragColor,1); return; } - --drawId; - --materialId; - - DrawCall drawCall = drawCalls[drawId]; - materialId += drawCall.materialIndex; - - Material material = materials[materialId]; - vec4 C = material.colorBase; -#if UF_DEFERRED_SAMPLING + const uint drawId = ID.x - 1; + const DrawCall drawCall = drawCalls[drawId]; + const uint materialId = ID.y + drawCall.materialIndex - 1; + const Material material = materials[materialId]; + vec4 A = material.colorBase; +#if DEFERRED_SAMPLING #if !MULTISAMPLING - vec2 uv = subpassLoad(samplerUv).xy; + const vec2 uv = subpassLoad(samplerUv).xy; #else - vec2 uv = resolve(samplerUv).xy; + const vec2 uv = resolve(samplerUv).xy; #endif - bool useAtlas = validTextureIndex( drawCall.textureIndex + material.indexAtlas ); + const float mip = mipLevel(inUv.xy); + const bool useAtlas = validTextureIndex( drawCall.textureIndex + material.indexAtlas ); Texture textureAtlas; if ( useAtlas ) textureAtlas = textures[drawCall.textureIndex + material.indexAtlas]; if ( validTextureIndex( drawCall.textureIndex + material.indexAtlas ) ) { Texture t = textures[drawCall.textureIndex + material.indexAlbedo]; - C = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip ); + A = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip ); } // OPAQUE if ( material.modeAlpha == 0 ) { - C.a = 1; + A.a = 1; // BLEND } else if ( material.modeAlpha == 1 ) { @@ -557,131 +549,128 @@ void main() { } #else #if !MULTISAMPLING - C = subpassLoad(samplerAlbedo); + A = subpassLoad(samplerAlbedo); #else - C = resolve(samplerAlbedo); + A = resolve(samplerAlbedo); #endif #endif - float M = material.factorMetallic; - float R = material.factorRoughness; + const float M = material.factorMetallic; + const float R = material.factorRoughness; float AO = material.factorOcclusion; vec4 indirectLighting = vec4(0); // GI { - vec3 P = position.world; - vec3 N = normal.world; - - // outFragColor = voxelConeTrace(rayO, rayD, 0 ); - // return; - - const float ROUGHNESS_SCALE = clamp(sqrt( 0.111111f / ( R * R + 0.111111f ) ), 0.0, 1.0); - const float ANGLE_MIX = 0.5f; - const float DIFFUSE_CONE_APERTURE = 0.325; - const float DIFFUSE_INDIRECT_FACTOR = ROUGHNESS_SCALE; //0.11111f * 0.111111f; - - const vec3 ortho = normalize(orthogonal(N)); - const vec3 ortho2 = normalize(cross(ortho, N)); - const vec3 corner = 0.5f * (ortho + ortho2); - const vec3 corner2 = 0.5f * (ortho - ortho2); - - const vec3 CONES[9] = { - N, - - mix(N, ortho, ANGLE_MIX), - mix(N, -ortho, ANGLE_MIX), - mix(N, ortho2, ANGLE_MIX), - mix(N, -ortho2, ANGLE_MIX), - - mix(N, corner, ANGLE_MIX), - mix(N, -corner, ANGLE_MIX), - mix(N, corner2, ANGLE_MIX), - mix(N, -corner2, ANGLE_MIX), - }; - vec4 indirectDiffuse = vec4(0); vec4 indirectSpecular = vec4(0); - // indirectDiffuse += voxelConeTrace( P, N, 0.325 ); - for ( uint i = 0; i < 1; ++i ) { - indirectDiffuse += voxelConeTrace(P, CONES[i], DIFFUSE_CONE_APERTURE ); + const vec3 P = position.world; + const vec3 N = normal.world; + + const float DIFFUSE_CONE_APERTURE = 0.57735f; + const float DIFFUSE_INDIRECT_FACTOR = 1.0f; + + const float SPECULAR_CONE_APERTURE = clamp(tan(PI * 0.5f * R), 0.0174533f, PI); + const float SPECULAR_INDIRECT_FACTOR = 1.0f; + + const vec4 CONES[] = { + vec4(0.0f, 1.0f, 0.0f, PI / 4.0f), + vec4(0.0f, 0.5f, 0.866025f, 3.0f * PI / 20.0f), + vec4(0.823639f, 0.5f, 0.267617f, 3.0f * PI / 20.0f), + vec4(0.509037f, 0.5f, -0.7006629f, 3.0f * PI / 20.0f), + vec4(-0.50937f, 0.5f, -0.7006629f, 3.0f * PI / 20.0f), + vec4(-0.823639f, 0.5f, 0.267617f, 3.0f * PI / 20.0f) + }; + if ( DIFFUSE_INDIRECT_FACTOR > 0.0f ) { + voxelInfo.albedoSize = textureSize( voxelAlbedo, 0 ).x; + voxelInfo.mipmapLevels = textureQueryLod( voxelAlbedo, vec3(0) ).x; + #if VOXEL_TRACE_IN_NDC + voxelInfo.min = vec3( -1 ); + voxelInfo.max = vec3( 1 ); + voxelInfo.voxelSize = 1.0 / voxelInfo.albedoSize; + #else + const mat4 inverseOrtho = inverse( ubo.matrices.voxel ); + voxelInfo.min = vec3( inverseOrtho * vec4( -1, -1, -1, 1 ) ); + voxelInfo.max = vec3( inverseOrtho * vec4( 1, 1, 1, 1 ) ); + voxelInfo.voxelSize = 1; + #endif } + if ( SPECULAR_INDIRECT_FACTOR > 0.0f ) { + vec3 guide = vec3(0.0f, 1.0f, 0.0f); + if (abs(dot(N,guide)) == 1.0f) guide = vec3(0.0f, 0.0f, 1.0f); - const float SPECULAR_CONE_APERTURE = acos( ROUGHNESS_SCALE ); - const float SPECULAR_INDIRECT_FACTOR = ROUGHNESS_SCALE; // 0.1; - - vec3 R = reflect( normalize(P - rayO), N ); - indirectSpecular = voxelConeTrace( P, R, SPECULAR_CONE_APERTURE ); - indirectLighting = indirectDiffuse * DIFFUSE_INDIRECT_FACTOR + indirectSpecular * SPECULAR_INDIRECT_FACTOR; - // AO = 1.0 - clamp(indirectDiffuse.a, 0.0, 1.0); - // outFragColor.rgb = vec3(AO); - // return; - - // outFragColor.rgb = indirectLighting.rgb; - // outFragColor.rgb = indirectDiffuse.rgb; - // outFragColor.rgb = indirectSpecular.rgb; - // return; + const vec3 right = normalize(guide - dot(N, guide) * N); + const vec3 up = cross(right, N); + for ( uint i = 0; i < 6; ++i ) { + const vec3 coneDirection = normalize(N + CONES[i].x * right + CONES[i].z * up); + indirectDiffuse += voxelConeTrace(P, coneDirection, DIFFUSE_CONE_APERTURE ) * CONES[i].w; + } + indirectDiffuse.rgb *= A.rgb; + AO = indirectDiffuse.a; + // outFragColor.rgb = indirectDiffuse.rgb; return; + } + { + const vec3 R = reflect( normalize(P - rayO), N ); + indirectSpecular = voxelConeTrace( P, R, SPECULAR_CONE_APERTURE ); + indirectLighting = indirectDiffuse * DIFFUSE_INDIRECT_FACTOR + indirectSpecular * SPECULAR_INDIRECT_FACTOR; + // outFragColor.rgb = indirectSpecular.rgb; return; + } + // outFragColor.rgb = indirectLighting.rgb; return; } - R *= 2.0f; - bool usePbr = true; - bool gammaCorrect = false; float litFactor = 1.0; - bool useLightmap = 0 <= material.indexLightmap; - if ( useLightmap ) { - fragColor = C.rgb + ubo.ambient.rgb + indirectLighting.rgb; + if ( 0 <= material.indexLightmap ) { + fragColor = A.rgb + ubo.ambient.rgb * (1 - AO) + indirectLighting.rgb; } else { - fragColor = C.rgb * ubo.ambient.rgb * (1 - AO) + indirectLighting.rgb; + fragColor = A.rgb * ubo.ambient.rgb * (1 - AO) + indirectLighting.rgb; } { - const float LIGHT_POWER_CUTOFF = 0.0001; - vec3 N = normal.eye; - vec3 F0 = mix(vec3(0.04), C.rgb, M); + const vec3 N = normal.eye; + const vec3 F0 = mix(vec3(0.04), A.rgb, M); + const vec3 Lo = normalize( -position.eye ); + const float cosLo = max(0.0, dot(N, Lo)); + #if 0 for ( uint i = 0; i < ubo.lights; ++i ) { - Light light = lights[i]; - if ( light.power <= LIGHT_POWER_CUTOFF ) continue; - light.position = vec3(ubo.matrices.view[inPushConstantPass] * vec4(light.position.xyz, 1)); - if ( validTextureIndex(light.mapIndex) ) { - float factor = shadowFactor( light, light.mapIndex, 0.0 ); - light.power *= factor; - litFactor += light.power; - } - vec3 Li = light.position - position.eye; - light.power *= 1.0 / (PI * pow(length(Li), 2.0)); + const Light light = lights[i]; if ( light.power <= LIGHT_POWER_CUTOFF ) continue; + const vec3 Lp = light.position; + const vec3 Liu = vec3(ubo.matrices.view[inPushConstantPass] * vec4(light.position, 1)) - position.eye; + const vec3 Li = normalize(Liu); + const float Ls = shadowFactor( light, 0.0 ); + const float La = 1.0 / (PI * pow(length(Liu), 2.0)); + if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue; - Li = normalize(Li); - vec3 Lo = normalize( -position.eye ); - vec3 Lh = normalize(Li + Lo); + const float cosLi = max(0.0, dot(N, Li)); + + const vec3 Lh = normalize(Li + Lo); + const float cosLh = max(0.0, dot(N, Lh)); - vec3 Lradiance = light.color.rgb * light.power; - vec3 albedo = C.rgb; - - float cosLi = max(0.0, dot(N, Li)); - float cosLo = max(0.0, dot(N, Lo)); - float cosLh = max(0.0, dot(N, Lh)); - - vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) ); - float D = ndfGGX( cosLh, R ); - float G = gaSchlickGGX(cosLi, cosLo, R); - - vec3 Kd = mix( vec3(1.0) - F, vec3(0.0), M ); - vec3 diffuseBRDF = Kd * albedo; - vec3 specularBRDF = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo); - if ( useLightmap ) { - fragColor.rgb += (specularBRDF) * Lradiance * cosLi; - } else { - fragColor.rgb += (diffuseBRDF + specularBRDF) * Lradiance * cosLi; - } + const vec3 Lr = light.color.rgb * light.power * La * Ls; + const vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) ); + const float D = ndfGGX( cosLh, R ); + const float G = gaSchlickGGX(cosLi, cosLo, R); + const vec3 diffuseBRDF = mix( vec3(1.0) - F, vec3(0.0), M ) * A.rgb; + const vec3 specularBRDF = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo); + if ( light.type >= 0 && 0 <= material.indexLightmap ) fragColor.rgb += (specularBRDF) * Lr * cosLi; + // else if ( abs(light.type) == 1 ) fragColor.rgb += (diffuseBRDF) * Lr * cosLi; + else fragColor.rgb += (diffuseBRDF + specularBRDF) * Lr * cosLi; + litFactor += light.power * La * Ls; } + #endif } - if ( gammaCorrect ) fragColor = gamma( fragColor ); - fog(rayO, rayD, fragColor, litFactor); + fog(rayO, rayD, fragColor, 1.0 ); //litFactor); + +#if TONE_MAP + fragColor = vec3(1.0) - exp(-fragColor * ubo.exposure); +#endif +#if GAMMA_CORRECT + fragColor = pow(fragColor, vec3(1.0 / ubo.gamma)); +#endif if ( (ubo.mode.type & (0x1 << 1)) == (0x1 << 1) ) { whitenoise(fragColor); } - outFragColor = vec4(fragColor,1); + outFragColor = vec4(fragColor,1); } \ No newline at end of file diff --git a/bin/data/shaders/display/svogi.comp.glsl b/bin/data/shaders/display/vxgi.comp.glsl similarity index 53% rename from bin/data/shaders/display/svogi.comp.glsl rename to bin/data/shaders/display/vxgi.comp.glsl index a57f83fa..59d8621f 100644 --- a/bin/data/shaders/display/svogi.comp.glsl +++ b/bin/data/shaders/display/vxgi.comp.glsl @@ -5,7 +5,31 @@ layout (local_size_x = 8, local_size_y = 8, local_size_z = 8) in; #define MULTISAMPLING 1 #define RAY_MARCH_FOG 1 -#define UF_DEFERRED_SAMPLING 0 +#define DEFERRED_SAMPLING 0 + +const float PI = 3.14159265359; +const float EPSILON = 0.00001; + +const float LIGHT_POWER_CUTOFF = 0.005; + +const vec2 poissonDisk[16] = vec2[]( + vec2( -0.94201624, -0.39906216 ), + vec2( 0.94558609, -0.76890725 ), + vec2( -0.094184101, -0.92938870 ), + vec2( 0.34495938, 0.29387760 ), + vec2( -0.91588581, 0.45771432 ), + vec2( -0.81544232, -0.87912464 ), + vec2( -0.38277543, 0.27676845 ), + vec2( 0.97484398, 0.75648379 ), + vec2( 0.44323325, -0.97511554 ), + vec2( 0.53742981, -0.47373420 ), + vec2( -0.26496911, -0.41893023 ), + vec2( 0.79197514, 0.19090188 ), + vec2( -0.24188840, 0.99706507 ), + vec2( -0.81409955, 0.91437590 ), + vec2( 0.19984126, 0.78641367 ), + vec2( 0.14383161, -0.14100790 ) +); layout (constant_id = 0) const uint TEXTURES = 256; @@ -113,8 +137,8 @@ layout (binding = 4) uniform UBO { uint msaa; uint poissonSamples; - uint padding1; - uint padding2; + float gamma; + float exposure; } ubo; layout (std140, binding = 5) readonly buffer Lights { @@ -139,16 +163,12 @@ layout (binding = 13) uniform sampler3D samplerNoise; layout (binding = 14) uniform samplerCube samplerSkybox; layout (binding = 15) uniform sampler2D samplerTextures[TEXTURES]; -const float PI = 3.14159265359; -const float EPSILON = 0.00001; - // GGX/Towbridge-Reitz normal distribution function. // Uses Disney's reparametrization of alpha = roughness^2. float ndfGGX(float cosLh, float roughness) { - float alpha = roughness * roughness; - float alphaSq = alpha * alpha; - - float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0; + const float alpha = roughness * roughness; + const float alphaSq = alpha * alpha; + const float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0; return alphaSq / (PI * denom * denom); } @@ -159,8 +179,8 @@ float gaSchlickG1(float cosTheta, float k) { // Schlick-GGX approximation of geometric attenuation function using Smith's method. float gaSchlickGGX(float cosLi, float cosLo, float roughness) { - float r = roughness + 1.0; - float k = (r * r) / 8.0; // Epic suggests using this roughness remapping for analytic lights. + const float r = roughness + 1.0; + const float k = (r * r) / 8.0; // Epic suggests using this roughness remapping for analytic lights. return gaSchlickG1(cosLi, k) * gaSchlickG1(cosLo, k); } vec3 fresnelSchlick(vec3 F0, float cosTheta) { @@ -168,31 +188,45 @@ vec3 fresnelSchlick(vec3 F0, float cosTheta) { } float random(vec3 seed, int i){ - vec4 seed4 = vec4(seed,i); - float dot_product = dot(seed4, vec4(12.9898,78.233,45.164,94.673)); - return fract(sin(dot_product) * 43758.5453); + return fract(sin(dot(vec4(seed,i), vec4(12.9898,78.233,45.164,94.673))) * 43758.5453); } -vec2 poissonDisk[16] = vec2[]( - vec2( -0.94201624, -0.39906216 ), - vec2( 0.94558609, -0.76890725 ), - vec2( -0.094184101, -0.92938870 ), - vec2( 0.34495938, 0.29387760 ), - vec2( -0.91588581, 0.45771432 ), - vec2( -0.81544232, -0.87912464 ), - vec2( -0.38277543, 0.27676845 ), - vec2( 0.97484398, 0.75648379 ), - vec2( 0.44323325, -0.97511554 ), - vec2( 0.53742981, -0.47373420 ), - vec2( -0.26496911, -0.41893023 ), - vec2( 0.79197514, 0.19090188 ), - vec2( -0.24188840, 0.99706507 ), - vec2( -0.81409955, 0.91437590 ), - vec2( 0.19984126, 0.78641367 ), - vec2( 0.14383161, -0.14100790 ) -); +// Returns a vector that is orthogonal to u. +vec3 orthogonal(vec3 u){ + u = normalize(u); + const vec3 v = vec3(0.99146, 0.11664, 0.05832); // Pick any normalized vector. + return abs(dot(u, v)) > 0.99999f ? cross(u, vec3(0, 1, 0)) : cross(u, v); +} +float rand2(vec2 co){ + return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 143758.5453); +} +float rand3(vec3 co){ + return fract(sin(dot(co.xyz ,vec3(12.9898,78.233, 37.719))) * 143758.5453); +} + +vec3 gamma( vec3 i ) { + return pow(i.rgb, vec3(1.0 / 2.2)); +} + +vec3 decodeNormals( vec2 enc ) { + const vec2 ang = enc*2-1; + const vec2 scth = vec2( sin(ang.x * PI), cos(ang.x * PI) ); + const vec2 scphi = vec2(sqrt(1.0 - ang.y*ang.y), ang.y); + return normalize( vec3(scth.y*scphi.x, scth.x*scphi.x, scphi.y) ); +} +float wrap( float i ) { + return fract(i); +} +vec2 wrap( vec2 uv ) { + return vec2( wrap( uv.x ), wrap( uv.y ) ); +} +bool validTextureIndex( int textureIndex ) { + return 0 <= textureIndex; // && textureIndex < ubo.textures; +} + +float shadowFactor( const Light light, float def ) { + if ( !validTextureIndex(light.mapIndex) ) return 1.0; -float shadowFactor( Light light, uint shadowMap, float def ) { vec4 positionClip = light.projection * light.view * vec4(position.world, 1.0); positionClip.xyz /= positionClip.w; @@ -203,107 +237,66 @@ float shadowFactor( Light light, uint shadowMap, float def ) { float factor = 1.0; // spot light - if ( light.type == 1 || light.type == 2 ) { - float dist = length( positionClip.xy ); + if ( abs(light.type) == 2 || abs(light.type) == 3 ) { + const float dist = length( positionClip.xy ); if ( dist > 0.5 ) return def; //0.0; // spot light with attenuation - if ( light.type == 2 ) { + if ( abs(light.type) == 3 ) { factor = 1.0 - (pow(dist * 2,2.0)); } } - vec2 uv = positionClip.xy * 0.5 + 0.5; - float bias = light.depthBias; -/* - if ( true ) { - float cosTheta = clamp(dot(normal.eye, normalize(light.position.xyz - position.eye)), 0, 1); - bias = clamp(bias * tan(acos(cosTheta)), 0, 0.01); - } else if ( true ) { - bias = max(bias * 10 * (1.0 - dot(normal.eye, normalize(light.position.xyz - position.eye))), bias); - } -*/ - - float eyeDepth = positionClip.z; - - int samples = int(ubo.poissonSamples); - if ( samples <= 1 ) { - return eyeDepth < texture(samplerTextures[shadowMap], uv).r - bias ? 0.0 : factor; - } + const vec2 uv = positionClip.xy * 0.5 + 0.5; + const float bias = light.depthBias; + const float eyeDepth = positionClip.z; + const int samples = int(ubo.poissonSamples); + if ( samples <= 1 ) return eyeDepth < texture(samplerTextures[light.mapIndex], uv).r - bias ? 0.0 : factor; for ( int i = 0; i < samples; ++i ) { - // int index = i; - // int index = int( float(samples) * random(gl_FragCoord.xyy, i) ) % samples; - int index = int( float(samples) * random(floor(position.world.xyz * 1000.0), i)) % samples; - float lightDepth = texture(samplerTextures[shadowMap], uv + poissonDisk[index] / 700.0 ).r; + const int index = int( float(samples) * random(floor(position.world.xyz * 1000.0), i)) % samples; + const float lightDepth = texture(samplerTextures[light.mapIndex], uv + poissonDisk[index] / 700.0 ).r; if ( eyeDepth < lightDepth - bias ) factor -= 1.0 / samples; } return factor; } -vec3 decodeNormals( vec2 enc ) { -#define kPI 3.1415926536f - vec2 ang = enc*2-1; - vec2 scth = vec2( sin(ang.x * kPI), cos(ang.x * kPI) ); - vec2 scphi = vec2(sqrt(1.0 - ang.y*ang.y), ang.y); - return normalize( vec3(scth.y*scphi.x, scth.x*scphi.x, scphi.y) ); -/* - vec2 fenc = enc*4-2; - float f = dot(fenc,fenc); - float g = sqrt(1-f/4); - return normalize( vec3(fenc * g, 1 - f / 2) ); -*/ -} -float wrap( float i ) { - return fract(i); -} -vec2 wrap( vec2 uv ) { - return vec2( wrap( uv.x ), wrap( uv.y ) ); -} +void main() { + vec3 fragColor = vec3(0); + + const vec3 tUvw = gl_GlobalInvocationID.xyz; + { + const vec2 N = vec2(imageLoad(voxelNormal, ivec3(tUvw) ).xy); + normal.world = decodeNormals( N ); + normal.eye = vec3( ubo.matrices.voxel * vec4( normal.world, 0.0f ) ); + + position.eye = vec3(gl_GlobalInvocationID.xyz) / vec3(imageSize(voxelAlbedo)) * 2.0f - 1.0f; + position.world = vec3( inverse(ubo.matrices.voxel) * vec4( position.eye, 1.0f ) ); + } -bool validTextureIndex( int textureIndex ) { - return 0 <= textureIndex; // && textureIndex < ubo.textures; -} - -void main() { - vec3 tUvw = gl_GlobalInvocationID.xyz; - - uvec2 ID = uvec2(imageLoad(voxelID, ivec3(tUvw) ).xy); - vec2 N = vec2(imageLoad(voxelNormal, ivec3(tUvw) ).xy); - - normal.world = decodeNormals( N ); - normal.eye = vec3( ubo.matrices.voxel * vec4( normal.world, 0.0f ) ); - - position.eye = vec3(gl_GlobalInvocationID.xyz) / vec3(imageSize(voxelAlbedo)) * 2.0f - 1.0f; - position.world = vec3( inverse(ubo.matrices.voxel) * vec4( position.eye, 1.0f ) ); - - vec2 uv = imageLoad(voxelUv, ivec3(tUvw) ).xy; - - uint drawId = ID.x; - uint materialId = ID.y; - if ( drawId == 0 || materialId == 0 ) { + const uvec2 ID = uvec2(imageLoad(voxelID, ivec3(tUvw) ).xy); + if ( ID.x == 0 || ID.y == 0 ) { imageStore(voxelAlbedo, ivec3(tUvw), vec4(0)); return; } - --drawId; - --materialId; + const uint drawId = ID.x - 1; + const DrawCall drawCall = drawCalls[drawId]; + const uint materialId = ID.y + drawCall.materialIndex - 1; + const Material material = materials[materialId]; + vec4 A = material.colorBase; - DrawCall drawCall = drawCalls[drawId]; - materialId += drawCall.materialIndex; - - Material material = materials[materialId]; - vec4 C = material.colorBase; - - bool useAtlas = validTextureIndex( drawCall.textureIndex + material.indexAtlas ); +#if DEFERRED_SAMPLING + const vec2 uv = imageLoad(voxelUv, ivec3(tUvw) ).xy; + const bool useAtlas = validTextureIndex( drawCall.textureIndex + material.indexAtlas ); Texture textureAtlas; if ( useAtlas ) textureAtlas = textures[drawCall.textureIndex + material.indexAtlas]; if ( validTextureIndex( drawCall.textureIndex + material.indexAtlas ) ) { Texture t = textures[drawCall.textureIndex + material.indexAlbedo]; - C = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv ); + A = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv ); } // OPAQUE if ( material.modeAlpha == 0 ) { - C.a = 1; + A.a = 1; // BLEND } else if ( material.modeAlpha == 1 ) { @@ -311,61 +304,52 @@ void main() { } else if ( material.modeAlpha == 2 ) { } +#else + A = imageLoad(voxelAlbedo, ivec3(tUvw) ); +#endif + const float M = material.factorMetallic; + const float R = material.factorRoughness; + const float AO = material.factorOcclusion; - float M = material.factorMetallic; - float R = material.factorRoughness * 4.0; - float AO = material.factorOcclusion; - - bool usePbr = true; - bool gammaCorrect = false; float litFactor = 1.0; - bool useLightmap = 0 <= material.indexLightmap; - vec3 fragColor = vec3(0.0); - if ( useLightmap ) { - fragColor = C.rgb + ubo.ambient.rgb; + if ( 0 <= material.indexLightmap ) { + fragColor = A.rgb + ubo.ambient.rgb * (1 - AO); } else { - fragColor = C.rgb * ubo.ambient.rgb * (1 - AO); + fragColor = A.rgb * ubo.ambient.rgb * (1 - AO); } { - const float LIGHT_POWER_CUTOFF = 0.005; - vec3 N = normal.world; - vec3 F0 = mix(vec3(0.04), C.rgb, M); + const vec3 N = normal.world; + const vec3 F0 = mix(vec3(0.04), A.rgb, M); + const vec3 Lo = normalize( -position.world ); + const float cosLo = max(0.0, dot(N, Lo)); + for ( uint i = 0; i < ubo.lights; ++i ) { - Light light = lights[i]; - if ( light.power <= LIGHT_POWER_CUTOFF ) continue; - if ( validTextureIndex(light.mapIndex) ) { - float factor = shadowFactor( light, light.mapIndex, 0.0 ); - light.power *= factor; - litFactor += light.power; - } - vec3 Li = light.position - position.world; - light.power *= 1.0 / (PI * pow(length(Li), 2.0)); + const Light light = lights[i]; if ( light.power <= LIGHT_POWER_CUTOFF ) continue; + const vec3 Lp = light.position; + const vec3 Liu = light.position - position.world; + const vec3 Li = normalize(Liu); + const float Ls = shadowFactor( light, 0.0 ); + const float La = 1.0 / (PI * pow(length(Liu), 2.0)); + if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue; - Li = normalize(Li); - vec3 Lo = normalize( -position.world ); - vec3 Lh = normalize(Li + Lo); + const float cosLi = max(0.0, dot(N, Li)); + + const vec3 Lh = normalize(Li + Lo); + const float cosLh = max(0.0, dot(N, Lh)); - vec3 Lradiance = light.color.rgb * light.power; - vec3 albedo = C.rgb; - - float cosLi = max(0.0, dot(N, Li)); - float cosLo = max(0.0, dot(N, Lo)); - float cosLh = max(0.0, dot(N, Lh)); - - vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) ); - float D = ndfGGX( cosLh, R ); - float G = gaSchlickGGX(cosLi, cosLo, R); - - vec3 Kd = mix( vec3(1.0) - F, vec3(0.0), M ); - vec3 diffuseBRDF = Kd * albedo; - vec3 specularBRDF = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo); - if ( useLightmap ) { - fragColor.rgb += (specularBRDF) * Lradiance * cosLi; - } else { - fragColor.rgb += (diffuseBRDF + specularBRDF) * Lradiance * cosLi; - } + const vec3 Lr = light.color.rgb * light.power * La * Ls; + const vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) ); + const float D = ndfGGX( cosLh, R ); + const float G = gaSchlickGGX(cosLi, cosLo, R); + const vec3 diffuseBRDF = mix( vec3(1.0) - F, vec3(0.0), M ) * A.rgb; + const vec3 specularBRDF = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo); + if ( light.type >= 0 && 0 <= material.indexLightmap ) fragColor.rgb += (specularBRDF) * Lr * cosLi; + // else if ( light.type == 0 ) fragColor.rgb += (diffuseBRDF) * Lr * cosLi; + else fragColor.rgb += (diffuseBRDF + specularBRDF) * Lr * cosLi; + litFactor += light.power * La * Ls; } } + imageStore(voxelAlbedo, ivec3(tUvw), vec4(fragColor.rgb, 1)); } \ No newline at end of file diff --git a/bin/data/shaders/gltf/baked.frag.glsl b/bin/data/shaders/gltf/baked.frag.glsl index 08dee772..6eef61e2 100644 --- a/bin/data/shaders/gltf/baked.frag.glsl +++ b/bin/data/shaders/gltf/baked.frag.glsl @@ -3,6 +3,8 @@ #define UF_DEFERRED_SAMPLING 0 #define UF_CAN_DISCARD 1 +#define PI 3.1415926536f + layout (constant_id = 0) const uint TEXTURES = 1; layout (binding = 0) uniform sampler2D samplerTextures[TEXTURES]; @@ -58,8 +60,7 @@ layout (location = 1) out vec2 outNormals; vec2 encodeNormals( vec3 n ) { // return n.xy / sqrt(n.z*8+8) + 0.5; -#define kPI 3.1415926536f - return (vec2(atan(n.y,n.x)/kPI, n.z)+1.0)*0.5; + return (vec2(atan(n.y,n.x)/PI, n.z)+1.0)*0.5; } float wrap( float i ) { @@ -69,25 +70,25 @@ vec2 wrap( vec2 uv ) { return vec2( wrap( uv.x ), wrap( uv.y ) ); } float mipLevel( in vec2 uv ) { - vec2 dx_vtc = dFdx(uv); - vec2 dy_vtc = dFdy(uv); + const vec2 dx_vtc = dFdx(uv); + const vec2 dy_vtc = dFdy(uv); return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc))); } bool validTextureIndex( int textureIndex ) { return 0 <= textureIndex && textureIndex < TEXTURES; } void main() { - float mip = mipLevel(inUv.xy); - vec2 uv = wrap(inUv.xy); - vec4 C = vec4(0, 0, 0, 0); - vec3 P = inPosition; - vec3 N = inNormal; + const float mip = mipLevel(inUv.xy); + const vec2 uv = wrap(inUv.xy); + vec4 A = vec4(0, 0, 0, 0); + const vec3 P = inPosition; + const vec3 N = inNormal; #if UF_DEFERRED_SAMPLING outUvs = wrap(inUv.xy); - vec4 outAlbedo = vec4(0,0,0,0); + const vec4 outAlbedo = vec4(0,0,0,0); #endif #if !UF_DEFERRED_SAMPLING - C = textureLod( samplerTextures[0], inSt, mip ); + A = textureLod( samplerTextures[0], inSt, mip ); #endif outNormals = encodeNormals( N ); outId = ivec2(inId.w+1, inId.y+1); diff --git a/bin/data/shaders/gltf/baking/bake.frag.glsl b/bin/data/shaders/gltf/baking/bake.frag.glsl index 86b9ffd8..e3b91a40 100644 --- a/bin/data/shaders/gltf/baking/bake.frag.glsl +++ b/bin/data/shaders/gltf/baking/bake.frag.glsl @@ -1,5 +1,29 @@ #version 450 +const float PI = 3.14159265359; +const float EPSILON = 0.00001; + +const float LIGHT_POWER_CUTOFF = 0.005; + +const vec2 poissonDisk[16] = vec2[]( + vec2( -0.94201624, -0.39906216 ), + vec2( 0.94558609, -0.76890725 ), + vec2( -0.094184101, -0.92938870 ), + vec2( 0.34495938, 0.29387760 ), + vec2( -0.91588581, 0.45771432 ), + vec2( -0.81544232, -0.87912464 ), + vec2( -0.38277543, 0.27676845 ), + vec2( 0.97484398, 0.75648379 ), + vec2( 0.44323325, -0.97511554 ), + vec2( 0.53742981, -0.47373420 ), + vec2( -0.26496911, -0.41893023 ), + vec2( 0.79197514, 0.19090188 ), + vec2( -0.24188840, 0.99706507 ), + vec2( -0.81409955, 0.91437590 ), + vec2( 0.19984126, 0.78641367 ), + vec2( 0.14383161, -0.14100790 ) +); + layout (constant_id = 0) const uint TEXTURES = 1; layout (binding = 0) uniform sampler2D samplerTextures[TEXTURES]; @@ -64,65 +88,58 @@ layout (location = 7) flat in ivec4 inId; layout (location = 0) out vec4 outAlbedo; -vec2 poissonDisk[16] = vec2[]( - vec2( -0.94201624, -0.39906216 ), - vec2( 0.94558609, -0.76890725 ), - vec2( -0.094184101, -0.92938870 ), - vec2( 0.34495938, 0.29387760 ), - vec2( -0.91588581, 0.45771432 ), - vec2( -0.81544232, -0.87912464 ), - vec2( -0.38277543, 0.27676845 ), - vec2( 0.97484398, 0.75648379 ), - vec2( 0.44323325, -0.97511554 ), - vec2( 0.53742981, -0.47373420 ), - vec2( -0.26496911, -0.41893023 ), - vec2( 0.79197514, 0.19090188 ), - vec2( -0.24188840, 0.99706507 ), - vec2( -0.81409955, 0.91437590 ), - vec2( 0.19984126, 0.78641367 ), - vec2( 0.14383161, -0.14100790 ) -); -float random(vec3 seed, int i){ - vec4 seed4 = vec4(seed,i); - float dot_product = dot(seed4, vec4(12.9898,78.233,45.164,94.673)); - return fract(sin(dot_product) * 43758.5453); +// GGX/Towbridge-Reitz normal distribution function. +// Uses Disney's reparametrization of alpha = roughness^2. +float ndfGGX(float cosLh, float roughness) { + const float alpha = roughness * roughness; + const float alphaSq = alpha * alpha; + const float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0; + return alphaSq / (PI * denom * denom); } -float shadowFactor( vec3 position, Light light, uint shadowMap, float def ) { - vec4 positionClip = light.projection * light.view * vec4(position, 1.0); - positionClip.xyz /= positionClip.w; - if ( positionClip.x < -1 || positionClip.x >= 1 ) return def; - if ( positionClip.y < -1 || positionClip.y >= 1 ) return def; - if ( positionClip.z <= 0 || positionClip.z >= 1 ) return def; +// Single term for separable Schlick-GGX below. +float gaSchlickG1(float cosTheta, float k) { + return cosTheta / (cosTheta * (1.0 - k) + k); +} - float factor = 1.0; +// Schlick-GGX approximation of geometric attenuation function using Smith's method. +float gaSchlickGGX(float cosLi, float cosLo, float roughness) { + const float r = roughness + 1.0; + const float k = (r * r) / 8.0; // Epic suggests using this roughness remapping for analytic lights. + return gaSchlickG1(cosLi, k) * gaSchlickG1(cosLo, k); +} +vec3 fresnelSchlick(vec3 F0, float cosTheta) { + return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); +} - // spot light - if ( light.type == 2 || light.type == 3 ) { - float dist = length( positionClip.xy ); - if ( dist > 0.5 ) return def; - - // spot light with attenuation - if ( light.type == 3 ) { - factor = 1.0 - (pow(dist * 2,2.0)); - } - } - - vec2 uv = positionClip.xy * 0.5 + 0.5; - float bias = light.depthBias; +float random(vec3 seed, int i){ + return fract(sin(dot(vec4(seed,i), vec4(12.9898,78.233,45.164,94.673))) * 43758.5453); +} - float eyeDepth = positionClip.z; +// Returns a vector that is orthogonal to u. +vec3 orthogonal(vec3 u){ + u = normalize(u); + const vec3 v = vec3(0.99146, 0.11664, 0.05832); // Pick any normalized vector. + return abs(dot(u, v)) > 0.99999f ? cross(u, vec3(0, 1, 0)) : cross(u, v); +} +float rand2(vec2 co){ + return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 143758.5453); +} +float rand3(vec3 co){ + return fract(sin(dot(co.xyz ,vec3(12.9898,78.233, 37.719))) * 143758.5453); +} - int samples = 16; - if ( samples <= 1 ) { - return eyeDepth < texture(samplerTextures[shadowMap], uv).r - bias ? 0.0 : factor; - } - for ( int i = 0; i < samples; ++i ) { - int index = int( float(samples) * random(floor(position * 1000.0), i)) % samples; - float lightDepth = texture(samplerTextures[shadowMap], uv + poissonDisk[index] / 700.0 ).r; - if ( eyeDepth < lightDepth - bias ) factor -= 1.0 / samples; - } - return factor; +vec3 decodeNormals( vec2 enc ) { + const vec2 ang = enc*2-1; + const vec2 scth = vec2( sin(ang.x * PI), cos(ang.x * PI) ); + const vec2 scphi = vec2(sqrt(1.0 - ang.y*ang.y), ang.y); + return normalize( vec3(scth.y*scphi.x, scth.x*scphi.x, scphi.y) ); +/* + vec2 fenc = enc*4-2; + float f = dot(fenc,fenc); + float g = sqrt(1-f/4); + return normalize( vec3(fenc * g, 1 - f / 2) ); +*/ } float wrap( float i ) { return fract(i); @@ -131,116 +148,83 @@ vec2 wrap( vec2 uv ) { return vec2( wrap( uv.x ), wrap( uv.y ) ); } float mipLevel( in vec2 uv ) { - vec2 dx_vtc = dFdx(uv); - vec2 dy_vtc = dFdy(uv); + const vec2 dx_vtc = dFdx(uv); + const vec2 dy_vtc = dFdy(uv); return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc))); } bool validTextureIndex( int textureIndex ) { - return 0 <= textureIndex && textureIndex < textures.length(); + return 0 <= textureIndex; // && textureIndex < ubo.textures; } -const float PI = 3.14159265359; -float DistributionGGX(vec3 N, vec3 H, float roughness) { - float a = roughness*roughness; - float a2 = a*a; - float NdotH = max(dot(N, H), 0.0); - float NdotH2 = NdotH*NdotH; + +float shadowFactor( const Light light, const vec3 P, float def ) { + if ( !validTextureIndex(light.mapIndex) ) return 1.0; + + vec4 positionClip = light.projection * light.view * vec4(P, 1.0); + positionClip.xyz /= positionClip.w; + + if ( positionClip.x < -1 || positionClip.x >= 1 ) return def; //0.0; + if ( positionClip.y < -1 || positionClip.y >= 1 ) return def; //0.0; + if ( positionClip.z <= 0 || positionClip.z >= 1 ) return def; //0.0; + + float factor = 1.0; + + // spot light + if ( abs(light.type) == 2 || abs(light.type) == 3 ) { + const float dist = length( positionClip.xy ); + if ( dist > 0.5 ) return def; //0.0; + + // spot light with attenuation + if ( abs(light.type) == 3 ) { + factor = 1.0 - (pow(dist * 2,2.0)); + } + } - float num = a2; - float denom = (NdotH2 * (a2 - 1.0) + 1.0); - denom = PI * denom * denom; - - return num / denom; -} - -float GeometrySchlickGGX(float NdotV, float roughness) { - float r = (roughness + 1.0); - float k = (r*r) / 8.0; - - float num = NdotV; - float denom = NdotV * (1.0 - k) + k; - - return num / denom; -} -float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) { - float NdotV = max(dot(N, V), 0.0); - float NdotL = max(dot(N, L), 0.0); - float ggx2 = GeometrySchlickGGX(NdotV, roughness); - float ggx1 = GeometrySchlickGGX(NdotL, roughness); - - return ggx1 * ggx2; -} -vec3 fresnelSchlick(float cosTheta, vec3 F0) { - return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); -} -void pbr( Light light, vec3 albedo, float metallic, float roughness, vec3 normal, vec3 position, inout vec3 i ) { - vec3 F0 = vec3(0.04); - F0 = mix(F0, albedo, metallic); - - vec3 N = normalize(normal); - vec3 L = light.position.xyz - position; - float dist = length(L); - - L = normalize(L); - vec3 V = normalize(-position); - vec3 H = normalize(V + L); - - float NdotL = max(dot(N, L), 0.0); - float NdotV = max(dot(N, V), 0.0); - float attenuation = light.power / (dist * dist); - vec3 radiance = light.color.rgb * attenuation; - - // cook-torrance brdf - float NDF = DistributionGGX(N, H, roughness); - float G = GeometrySmith(N, V, L, roughness); - vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0); - - vec3 kD = vec3(1.0) - F; - kD *= 1.0 - metallic; - - vec3 numerator = NDF * G * F; - float denominator = 4.0 * NdotV * NdotL; - vec3 specular = numerator / max(denominator, 0.001); - - // add to outgoing radiance Lo - // ignore specular - i += (kD * albedo / PI ) * radiance * NdotL; + const vec2 uv = positionClip.xy * 0.5 + 0.5; + const float bias = light.depthBias; + const float eyeDepth = positionClip.z; + const int samples = 16; //int(ubo.poissonSamples); + if ( samples <= 1 ) return eyeDepth < texture(samplerTextures[light.mapIndex], uv).r - bias ? 0.0 : factor; + for ( int i = 0; i < samples; ++i ) { + const int index = int( float(samples) * random(floor(P * 1000.0), i)) % samples; + const float lightDepth = texture(samplerTextures[light.mapIndex], uv + poissonDisk[index] / 700.0 ).r; + if ( eyeDepth < lightDepth - bias ) factor -= 1.0 / samples; + } + return factor; } void main() { - float mip = mipLevel(inUv.xy); - vec2 uv = wrap(inUv.xy); - vec4 C = vec4(1, 1, 1, 1); - vec3 P = inPosition; + vec4 A = vec4(1, 1, 1, 1); vec3 N = normalize( inNormal ); - - int materialId = int(inId.y); - Material material = materials[materialId]; + const float mip = mipLevel(inUv.xy); + const vec2 uv = wrap(inUv.xy); + const vec3 P = inPosition; + const int materialId = int(inId.y); + const Material material = materials[materialId]; - float M = material.factorMetallic; - float R = material.factorRoughness; - float AO = material.factorOcclusion; - + const float M = material.factorMetallic; + const float R = material.factorRoughness; + const float AO = 1.0f - material.factorOcclusion; #if 0 // sample albedo - bool useAtlas = validTextureIndex( material.indexAtlas ); + const bool useAtlas = validTextureIndex( material.indexAtlas ); Texture textureAtlas; if ( useAtlas ) textureAtlas = textures[material.indexAtlas]; if ( !validTextureIndex( material.indexAlbedo ) ) discard; { Texture t = textures[material.indexAlbedo]; - C = textureLod( samplerTextures[(useAtlas) ? textureAtlas.index : t.index], (useAtlas) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip ); + A = textureLod( samplerTextures[(useAtlas) ? textureAtlas.index : t.index], (useAtlas) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip ); // alpha mode OPAQUE if ( material.modeAlpha == 0 ) { - C.a = 1; + A.a = 1; // alpha mode BLEND } else if ( material.modeAlpha == 1 ) { // alpha mode MASK } else if ( material.modeAlpha == 2 ) { - if ( C.a < abs(material.factorAlphaCutoff) ) discard; - C.a = 1; + if ( A.a < abs(material.factorAlphaCutoff) ) discard; + A.a = 1; } - if ( C.a == 0 ) discard; + if ( A.a == 0 ) discard; } // sample normal @@ -248,20 +232,40 @@ void main() { Texture t = textures[material.indexNormal]; N = inTBN * normalize( textureLod( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip ).xyz * 2.0 - vec3(1.0)); } +#else + A = vec4(1); #endif - C = vec4(1); - bool lit = false; + float litFactor = 1.0; vec3 fragColor = vec3(0); - for ( uint i = 0; i < lights.length(); ++i ) { - Light light = lights[i]; - if ( light.power <= 0.001 ) continue; - if ( 0 <= light.mapIndex ) { - float factor = shadowFactor( P, light, light.mapIndex, 0.0 ); - light.power *= factor; + { + const vec3 F0 = mix(vec3(0.04), A.rgb, M); + const vec3 Lo = normalize( -P ); + const float cosLo = max(0.0, dot(N, Lo)); + + for ( uint i = 0; i < lights.length(); ++i ) { + const Light light = lights[i]; + if ( light.power <= LIGHT_POWER_CUTOFF ) continue; + const vec3 Lp = light.position; + const vec3 Liu = light.position - P; + const float La = 1.0 / (PI * pow(length(Liu), 2.0)); + const float Ls = shadowFactor( light, P, 0.0 ); + if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue; + + const vec3 Li = normalize(Liu); + const vec3 Lh = normalize(Li + Lo); + const float cosLi = max(0.0, dot(N, Li)); + const float cosLh = max(0.0, dot(N, Lh)); + + const vec3 Lr = light.color.rgb * light.power * La * Ls; + const vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) ); + const float D = ndfGGX( cosLh, R ); + const float G = gaSchlickGGX(cosLi, cosLo, R); + const vec3 diffuseBRDF = mix( vec3(1.0) - F, vec3(0.0), M ) * A.rgb; + fragColor.rgb += (diffuseBRDF) * Lr * cosLi; + litFactor += light.power * La * Ls; } - if ( light.power <= 0.0001 ) continue; - pbr( light, C.rgb, M, R, N, P, fragColor ); } + outAlbedo = vec4(fragColor, 1); } \ No newline at end of file diff --git a/bin/data/shaders/gltf/base.frag.glsl b/bin/data/shaders/gltf/base.frag.glsl index 41df8a87..77a214e0 100644 --- a/bin/data/shaders/gltf/base.frag.glsl +++ b/bin/data/shaders/gltf/base.frag.glsl @@ -1,7 +1,8 @@ #version 450 -#define UF_DEFERRED_SAMPLING 0 -#define UF_CAN_DISCARD 1 +#define DEFERRED_SAMPLING 0 +#define CAN_DISCARD 1 +#define USE_LIGHTMAP 1 layout (constant_id = 0) const uint TEXTURES = 1; layout (binding = 0) uniform sampler2D samplerTextures[TEXTURES]; @@ -50,16 +51,17 @@ layout (location = 8) flat in ivec4 inId; layout (location = 0) out uvec2 outId; layout (location = 1) out vec2 outNormals; -#if UF_DEFERRED_SAMPLING +#if DEFERRED_SAMPLING layout (location = 2) out vec2 outUvs; #else layout (location = 2) out vec4 outAlbedo; #endif +#define PI 3.1415926536f + vec2 encodeNormals( vec3 n ) { // return n.xy / sqrt(n.z*8+8) + 0.5; -#define kPI 3.1415926536f - return (vec2(atan(n.y,n.x)/kPI, n.z)+1.0)*0.5; + return (vec2(atan(n.y,n.x)/PI, n.z)+1.0)*0.5; } float wrap( float i ) { return fract(i); @@ -68,24 +70,24 @@ vec2 wrap( vec2 uv ) { return vec2( wrap( uv.x ), wrap( uv.y ) ); } float mipLevel( in vec2 uv ) { - vec2 dx_vtc = dFdx(uv); - vec2 dy_vtc = dFdy(uv); + const vec2 dx_vtc = dFdx(uv); + const vec2 dy_vtc = dFdy(uv); return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc))); } bool validTextureIndex( int textureIndex ) { return 0 <= textureIndex && textureIndex < textures.length(); } void main() { - float mip = mipLevel(inUv.xy); - vec2 uv = wrap(inUv.xy); - vec4 C = vec4(0, 0, 0, 0); - vec3 P = inPosition; + const float mip = mipLevel(inUv.xy); + const vec2 uv = wrap(inUv.xy); + const vec3 P = inPosition; vec3 N = inNormal; -#if UF_DEFERRED_SAMPLING + vec4 A = vec4(0, 0, 0, 0); +#if DEFERRED_SAMPLING vec4 outAlbedo = vec4(0,0,0,0); #endif -#if !UF_DEFERRED_SAMPLING || UF_CAN_DISCARD - int materialId = int(inId.y); +#if !DEFERRED_SAMPLING || CAN_DISCARD + const int materialId = int(inId.y); Material material = materials[materialId]; float M = material.factorMetallic; @@ -93,37 +95,39 @@ void main() { float AO = material.factorOcclusion; // sample albedo - bool useAtlas = validTextureIndex( material.indexAtlas ); + const bool useAtlas = validTextureIndex( material.indexAtlas ); Texture textureAtlas; if ( useAtlas ) textureAtlas = textures[material.indexAtlas]; if ( !validTextureIndex( material.indexAlbedo ) ) discard; { Texture t = textures[material.indexAlbedo]; - C = textureLod( samplerTextures[(useAtlas) ? textureAtlas.index : t.index], (useAtlas) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip ); + A = textureLod( samplerTextures[(useAtlas) ? textureAtlas.index : t.index], (useAtlas) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip ); // alpha mode OPAQUE if ( material.modeAlpha == 0 ) { - C.a = 1; + A.a = 1; // alpha mode BLEND } else if ( material.modeAlpha == 1 ) { // alpha mode MASK } else if ( material.modeAlpha == 2 ) { - if ( C.a < abs(material.factorAlphaCutoff) ) discard; - C.a = 1; + if ( A.a < abs(material.factorAlphaCutoff) ) discard; + A.a = 1; } - if ( C.a == 0 ) discard; + if ( A.a == 0 ) discard; } -#if 1 +#if USE_LIGHTMAP if ( validTextureIndex( material.indexLightmap ) ) { - #if UF_DEFERRED_SAMPLING + #if DEFERRED_SAMPLING outUvs = inSt; #else Texture t = textures[material.indexLightmap]; - C *= textureLod( samplerTextures[t.index], inSt, mip ); + const float gamma = 1.6; + const vec4 L = pow(textureLod( samplerTextures[t.index], inSt, mip ), vec4(1.0 / gamma)); + A *= L; #endif } #endif #endif -#if !UF_DEFERRED_SAMPLING +#if !DEFERRED_SAMPLING // sample normal if ( validTextureIndex( material.indexNormal ) ) { Texture t = textures[material.indexNormal]; @@ -131,9 +135,9 @@ void main() { } #if 0 // sample metallic/roughness - if ( validTextureIndex( material.indexNormal ) ) { - Texture t = textures[material.indexNormal]; - vec4 sampled = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip ); + if ( validTextureIndex( material.indexMetallicRoughness ) ) { + Texture t = textures[material.indexMetallicRoughness]; + const vec4 sampled = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip ); M = sampled.b; R = sampled.g; } @@ -144,7 +148,7 @@ void main() { AO = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv ).r; } #endif - outAlbedo = C * inColor; + outAlbedo = A * inColor; #else outUvs = wrap(inUv.xy); #endif diff --git a/bin/data/shaders/gltf/voxelize.frag.glsl b/bin/data/shaders/gltf/voxelize.frag.glsl index 7bae0b9a..1d135f36 100644 --- a/bin/data/shaders/gltf/voxelize.frag.glsl +++ b/bin/data/shaders/gltf/voxelize.frag.glsl @@ -1,7 +1,9 @@ #version 450 -#define UF_DEFERRED_SAMPLING 0 -#define UF_CAN_DISCARD 1 +#define DEFERRED_SAMPLING 0 +#define USE_LIGHTMAP 1 + +#define PI 3.1415926536f layout (constant_id = 0) const uint TEXTURES = 1; @@ -56,7 +58,7 @@ layout (binding = 11, rgba8) uniform volatile coherent image3D voxelAlbedo; layout (location = 0) out uvec2 outId; layout (location = 1) out vec2 outNormals; -#if UF_DEFERRED_SAMPLING +#if DEFERRED_SAMPLING layout (location = 2) out vec2 outUvs; #else layout (location = 2) out vec4 outAlbedo; @@ -64,8 +66,7 @@ layout (location = 1) out vec2 outNormals; vec2 encodeNormals( vec3 n ) { // return n.xy / sqrt(n.z*8+8) + 0.5; -#define kPI 3.1415926536f - return (vec2(atan(n.y,n.x)/kPI, n.z)+1.0)*0.5; + return (vec2(atan(n.y,n.x)/PI, n.z)+1.0)*0.5; } float wrap( float i ) { return fract(i); @@ -74,8 +75,8 @@ vec2 wrap( vec2 uv ) { return vec2( wrap( uv.x ), wrap( uv.y ) ); } float mipLevel( in vec2 uv ) { - vec2 dx_vtc = dFdx(uv); - vec2 dy_vtc = dFdy(uv); + const vec2 dx_vtc = dFdx(uv); + const vec2 dy_vtc = dFdy(uv); return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc))); } bool validTextureIndex( int textureIndex ) { @@ -83,51 +84,57 @@ bool validTextureIndex( int textureIndex ) { } void main() { - vec3 P = inPosition; + const vec3 P = inPosition; if ( !(abs(P.x) < 1.0 && abs(P.y) < 1 && abs(P.z) < 1) ) discard; - vec4 C = vec4(0, 0, 0, 0); - vec3 N = inNormal; - vec2 uv = wrap(inUv.xy); - float mip = mipLevel(inUv.xy); + vec4 A = vec4(0, 0, 0, 0); + const vec3 N = inNormal; + const vec2 uv = wrap(inUv.xy); + const float mip = mipLevel(inUv.xy); + const int materialId = int(inId.y); + const Material material = materials[materialId]; - int materialId = int(inId.y); - Material material = materials[materialId]; - - float M = material.factorMetallic; - float R = material.factorRoughness; - float AO = material.factorOcclusion; + const float M = material.factorMetallic; + const float R = material.factorRoughness; + const float AO = material.factorOcclusion; // sample albedo - bool useAtlas = validTextureIndex( material.indexAtlas ); + const bool useAtlas = validTextureIndex( material.indexAtlas ); Texture textureAtlas; if ( useAtlas ) textureAtlas = textures[material.indexAtlas]; if ( !validTextureIndex( material.indexAlbedo ) ) discard; { Texture t = textures[material.indexAlbedo]; - C = textureLod( samplerTextures[(useAtlas) ? textureAtlas.index : t.index], (useAtlas) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip ); + A = textureLod( samplerTextures[(useAtlas) ? textureAtlas.index : t.index], (useAtlas) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip ); // alpha mode OPAQUE if ( material.modeAlpha == 0 ) { - C.a = 1; + A.a = 1; // alpha mode BLEND } else if ( material.modeAlpha == 1 ) { // alpha mode MASK } else if ( material.modeAlpha == 2 ) { - if ( C.a < abs(material.factorAlphaCutoff) ) discard; - C.a = 1; + if ( A.a < abs(material.factorAlphaCutoff) ) discard; + A.a = 1; } - if ( C.a == 0 ) discard; + if ( A.a == 0 ) discard; + } +#if USE_LIGHTMAP + if ( validTextureIndex( material.indexLightmap ) ) { + #if DEFERRED_SAMPLING + outUvs = inSt; + #else + Texture t = textures[material.indexLightmap]; + const float gamma = 1.6; + const vec4 L = pow(textureLod( samplerTextures[t.index], inSt, mip ), vec4(1.0 / gamma)); + A *= L; + #endif } - -#if UF_DEFERRED_SAMPLING - vec4 outAlbedo; -#else - vec2 outUvs; #endif - /*vec4*/ outAlbedo = C * inColor; - /*uvec2*/ outId = uvec2(inId.w+1, inId.y+1); - /*vec2*/ outNormals = encodeNormals( normalize( N ) ); - /*vec2*/ outUvs = wrap(inUv.xy); + + const vec4 outAlbedo = A * inColor; + const uvec2 outId = uvec2(inId.w+1, inId.y+1); + const vec2 outNormals = encodeNormals( normalize( N ) ); + const vec2 outUvs = wrap(inUv.xy); imageStore(voxelID, ivec3(P * imageSize(voxelID)), uvec4(outId, 0, 0)); imageStore(voxelNormal, ivec3(P * imageSize(voxelNormal)), vec4(outNormals, 0, 0)); diff --git a/engine/inc/uf/engine/object/behavior.h b/engine/inc/uf/engine/object/behavior.h index 7c3bfef9..82f9934a 100644 --- a/engine/inc/uf/engine/object/behavior.h +++ b/engine/inc/uf/engine/object/behavior.h @@ -22,7 +22,11 @@ namespace uf { ext::json::Value payload; double timeout; }; - + struct { + size_t mtime = 0; + bool enabled = false; + std::string source = ""; + } hotReload; struct { std::unordered_map> bound; std::vector queue; diff --git a/engine/src/engine/object/behavior.cpp b/engine/src/engine/object/behavior.cpp index a94c1e2e..b16241fb 100644 --- a/engine/src/engine/object/behavior.cpp +++ b/engine/src/engine/object/behavior.cpp @@ -175,20 +175,19 @@ void uf::ObjectBehavior::destroy( uf::Object& self ) { void uf::ObjectBehavior::tick( uf::Object& self ) { // listen for metadata file changes #if UF_ENTITY_METADATA_USE_JSON - auto& metadata = this->getComponent(); + auto& metadataJson = this->getComponent(); #if !UF_ENV_DREAMCAST - if ( metadata["system"]["hot reload"]["enabled"].as() ) { - size_t mtime = uf::io::mtime( metadata["system"]["source"].as() ); - if ( metadata["system"]["hot reload"]["mtime"].as() < mtime ) { - std::cout << "File reload detected: " << ": " << metadata["system"]["source"].as() << ", " << metadata["system"]["hot reload"]["mtime"] << " -> " << mtime << std::endl; - metadata["system"]["hot reload"]["mtime"] = mtime; + if ( metadataJson["system"]["hot reload"]["enabled"].as() ) { + size_t mtime = uf::io::mtime( metadataJson["system"]["source"].as() ); + if ( metadataJson["system"]["hot reload"]["mtime"].as() < mtime ) { + metadataJson["system"]["hot reload"]["mtime"] = mtime; this->reload(); } } #endif // Call queued hooks { - auto& queue = metadata["system"]["hooks"]["queue"]; + auto& queue = metadataJson["system"]["hooks"]["queue"]; if ( !uf::Object::timer.running() ) uf::Object::timer.start(); float curTime = uf::Object::timer.elapsed().asDouble(); uf::Serializer newQueue = ext::json::array(); @@ -202,11 +201,18 @@ void uf::ObjectBehavior::tick( uf::Object& self ) { else newQueue.emplace_back(member); }); } - if ( ext::json::isObject( metadata ) ) queue = newQueue; + if ( ext::json::isObject( metadataJson ) ) queue = newQueue; } #else - auto& metadata = this->getComponent(); + if ( metadata.hotReload.enabled ) { + size_t mtime = uf::io::mtime( metadata.hotReload.source ); + if ( metadata.hotReload.mtime < mtime ) { + metadata.hotReload.mtime = mtime; + this->reload(); + } + } + auto& queue = metadata.hooks.queue; if ( !uf::Object::timer.running() ) uf::Object::timer.start(); float curTime = uf::Object::timer.elapsed().asDouble(); diff --git a/engine/src/engine/object/behaviors/gltf.cpp b/engine/src/engine/object/behaviors/gltf.cpp index 345042c5..858f6857 100644 --- a/engine/src/engine/object/behaviors/gltf.cpp +++ b/engine/src/engine/object/behaviors/gltf.cpp @@ -129,8 +129,8 @@ void uf::GltfBehavior::tick( uf::Object& self ) { auto& storageBuffer = *graphic.getStorageBuffer("Models"); graphic.updateBuffer( (void*) instances.data(), instances.size() * sizeof(pod::Matrix4f), graph.instanceBufferIndex /*storageBuffer*/ ); } - if ( graphic.material.hasShader("geometry", "svogi") ) { - auto& shader = graphic.material.getShader("geometry", "svogi"); + if ( graphic.material.hasShader("geometry", "vxgi") ) { + auto& shader = graphic.material.getShader("geometry", "vxgi"); pod::Vector3f min = uf::vector::decode( graph.metadata["extents"]["min"], pod::Vector3f{} ); pod::Vector3f max = uf::vector::decode( graph.metadata["extents"]["max"], pod::Vector3f{} ); diff --git a/engine/src/engine/object/object.cpp b/engine/src/engine/object/object.cpp index c027b5f5..1e434f31 100644 --- a/engine/src/engine/object/object.cpp +++ b/engine/src/engine/object/object.cpp @@ -93,7 +93,13 @@ bool uf::Object::load( const std::string& f, bool inheritRoot ) { json["root"] = uf::io::directory(filename); json["source"] = filename; +#if UF_ENTITY_METADATA_USE_JSON json["hot reload"]["mtime"] = uf::io::mtime(filename) + 10; +#else + auto& metadata = this->getComponent(); + metadata.hotReload.source = filename; + metadata.hotReload.mtime = uf::io::mtime(filename) + 10; +#endif return this->load(json); } @@ -118,7 +124,7 @@ bool uf::Object::reload( bool hard ) { transform.reference = reference; } payload["new"] = metadata; - UF_DEBUG_MSG("Updated metadata for " << uf::string::toString( this )); +// UF_DEBUG_MSG("Updated metadata for " << uf::string::toString( this )); this->queueHook("object:Reload.%UID%", payload); return true; } @@ -160,7 +166,14 @@ bool uf::Object::load( const uf::Serializer& _json ) { if ( ext::json::isNull( json[key] ) ) json[key] = value; }); +#if UF_ENTITY_METADATA_USE_JSON json["hot reload"]["enabled"] = json["system"]["hot reload"]["enabled"]; +#else + { + auto& metadata = this->getComponent(); + metadata.hotReload.enabled = json["system"]["hot reload"]["enabled"].as(); + } +#endif // Basic entity information // Set name this->m_name = json["name"].is() ? json["name"].as() : json["type"].as(); @@ -325,7 +338,14 @@ bool uf::Object::load( const uf::Serializer& _json ) { json["root"] = uf::io::directory(filename); json["source"] = filename; - json["hot reload"]["mtime"] = uf::io::mtime( filename ) + 10; + #if UF_ENTITY_METADATA_USE_JSON + json["hot reload"]["mtime"] = uf::io::mtime(filename) + 10; + #else + { + auto& metadata = this->getComponent(); + metadata.hotReload.mtime = uf::io::mtime(filename) + 10; + } + #endif if ( this->loadChildUid(json) == -1 ) continue; } @@ -363,7 +383,15 @@ uf::Object& uf::Object::loadChild( const std::string& f, bool initialize ) { json["root"] = uf::io::directory(filename); json["source"] = filename; - json["hot reload"]["mtime"] = uf::io::mtime( filename ) + 10; +#if UF_ENTITY_METADATA_USE_JSON + json["hot reload"]["mtime"] = uf::io::mtime(filename) + 10; +#else + { + auto& metadata = this->getComponent(); + metadata.hotReload.mtime = uf::io::mtime(filename) + 10; + } +#endif + return this->loadChild(json, initialize); } uf::Object& uf::Object::loadChild( const uf::Serializer& _json, bool initialize ) { diff --git a/engine/src/engine/scene/scene.cpp b/engine/src/engine/scene/scene.cpp index 1b462433..2eda26ba 100644 --- a/engine/src/engine/scene/scene.cpp +++ b/engine/src/engine/scene/scene.cpp @@ -54,7 +54,7 @@ uf::Scene& uf::scene::loadScene( const std::string& name, const std::string& fil */ target = uf::string::lowercase( target ); scene->load(filename != "" ? filename : "./scenes/" + target + "/scene.json"); - if ( uf::renderer::settings::experimental::deferredMode == "svogi" ) { + if ( uf::renderer::settings::experimental::deferredMode == "vxgi" ) { uf::instantiator::bind( "VoxelizerBehavior", *scene ); } scene->initialize(); @@ -64,7 +64,7 @@ uf::Scene& uf::scene::loadScene( const std::string& name, const uf::Serializer& uf::Scene* scene = uf::instantiator::objects->has( name ) ? (uf::Scene*) &uf::instantiator::instantiate( name ) : new uf::Scene; uf::scene::scenes.emplace_back( scene ); if ( data != "" ) scene->load(data); - if ( uf::renderer::settings::experimental::deferredMode == "svogi" ) { + if ( uf::renderer::settings::experimental::deferredMode == "vxgi" ) { uf::instantiator::bind( "VoxelizerBehavior", *scene ); } scene->initialize(); diff --git a/engine/src/ext/gltf/graph.cpp b/engine/src/ext/gltf/graph.cpp index d9b82ad7..3c3ed8f1 100644 --- a/engine/src/ext/gltf/graph.cpp +++ b/engine/src/ext/gltf/graph.cpp @@ -68,8 +68,8 @@ namespace { } #endif } - // svogi pipeline - if ( uf::renderer::settings::experimental::deferredMode == "svogi" ) { + // vxgi pipeline + if ( uf::renderer::settings::experimental::deferredMode == "vxgi" ) { std::string vertexShaderFilename = graph.metadata["shaders"]["vertex"].as("/gltf/base.vert.spv"); std::string geometryShaderFilename = graph.metadata["shaders"]["geometry"].as("/gltf/voxelize.geom.spv"); std::string fragmentShaderFilename = graph.metadata["shaders"]["fragment"].as("/gltf/voxelize.frag.spv"); @@ -79,21 +79,21 @@ namespace { vertexShaderFilename = graph.metadata["flags"]["SKINNED"].as() ? "/gltf/skinned.instanced.vert.spv" : "/gltf/instanced.vert.spv"; } else if ( graph.metadata["flags"]["SKINNED"].as() ) vertexShaderFilename = "/gltf/skinned.vert.spv"; vertexShaderFilename = entity.grabURI( vertexShaderFilename, root ); - graphic.material.attachShader(vertexShaderFilename, uf::renderer::enums::Shader::VERTEX, "svogi"); + graphic.material.attachShader(vertexShaderFilename, uf::renderer::enums::Shader::VERTEX, "vxgi"); } */ if ( geometryShaderFilename != "" && uf::renderer::device.enabledFeatures.geometryShader ) { geometryShaderFilename = entity.grabURI( geometryShaderFilename, root ); - graphic.material.attachShader(geometryShaderFilename, uf::renderer::enums::Shader::GEOMETRY, "svogi"); + graphic.material.attachShader(geometryShaderFilename, uf::renderer::enums::Shader::GEOMETRY, "vxgi"); } { fragmentShaderFilename = entity.grabURI( fragmentShaderFilename, root ); - graphic.material.attachShader(fragmentShaderFilename, uf::renderer::enums::Shader::FRAGMENT, "svogi"); + graphic.material.attachShader(fragmentShaderFilename, uf::renderer::enums::Shader::FRAGMENT, "vxgi"); } #if UF_USE_VULKAN /* { - auto& shader = graphic.material.getShader("vertex", "svogi"); + auto& shader = graphic.material.getShader("vertex", "vxgi"); struct SpecializationConstant { uint32_t passes = 6; }; @@ -106,7 +106,7 @@ namespace { */ /* if ( geometryShaderFilename != "" && uf::renderer::device.enabledFeatures.geometryShader ) { - auto& shader = graphic.material.getShader("geometry", "svogi"); + auto& shader = graphic.material.getShader("geometry", "vxgi"); pod::Vector3f min = uf::vector::decode( graph.metadata["extents"]["min"], pod::Vector3f{} ); pod::Vector3f max = uf::vector::decode( graph.metadata["extents"]["max"], pod::Vector3f{} ); @@ -121,7 +121,7 @@ namespace { } */ { - auto& shader = graphic.material.getShader("fragment", "svogi"); + auto& shader = graphic.material.getShader("fragment", "vxgi"); struct SpecializationConstant { uint32_t textures = 1; }; @@ -164,7 +164,7 @@ namespace { graphic.material.samplers.emplace_back( sampler ); } // bind scene's voxel texture - if ( uf::renderer::settings::experimental::deferredMode == "svogi" ) { + if ( uf::renderer::settings::experimental::deferredMode == "vxgi" ) { auto& scene = uf::scene::getCurrentScene(); auto& sceneTextures = scene.getComponent(); graphic.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.id); diff --git a/engine/src/ext/vulkan/rendermodes/deferred.cpp b/engine/src/ext/vulkan/rendermodes/deferred.cpp index b98032b7..34df59bb 100644 --- a/engine/src/ext/vulkan/rendermodes/deferred.cpp +++ b/engine/src/ext/vulkan/rendermodes/deferred.cpp @@ -198,10 +198,10 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { blitter.initialize( this->getName() ); blitter.initializeMesh( mesh ); - if ( ext::vulkan::settings::experimental::deferredMode == "svogi" ) { + if ( ext::vulkan::settings::experimental::deferredMode == "vxgi" ) { blitter.material.initializeShaders({ {uf::io::root+"/shaders/display/subpass.vert.spv", VK_SHADER_STAGE_VERTEX_BIT}, - {uf::io::root+"/shaders/display/subpass.svogi.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT} + {uf::io::root+"/shaders/display/subpass.vxgi.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT} }); } else { blitter.material.initializeShaders({ diff --git a/engine/src/ext/vulkan/rendermodes/rendertarget.cpp b/engine/src/ext/vulkan/rendermodes/rendertarget.cpp index bb07e5f8..3821e54b 100644 --- a/engine/src/ext/vulkan/rendermodes/rendertarget.cpp +++ b/engine/src/ext/vulkan/rendermodes/rendertarget.cpp @@ -37,10 +37,10 @@ ext::vulkan::GraphicDescriptor ext::vulkan::RenderTargetRenderMode::bindGraphicD descriptor.parse(metadata["descriptor"]); std::string type = metadata["type"].as(); std::string target = metadata["target"].as(); - if ( pass == 0 && type == "svogi" ) { + if ( pass == 0 && type == "vxgi" ) { descriptor.cullMode = VK_CULL_MODE_NONE; descriptor.depth.test = false; - descriptor.pipeline = "svogi"; + descriptor.pipeline = "vxgi"; } else if ( type == "depth" ) { descriptor.cullMode = VK_CULL_MODE_NONE; } @@ -63,7 +63,7 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { if ( subpasses == 0 ) subpasses = 1; renderTarget.device = &device; for ( size_t currentPass = 0; currentPass < subpasses; ++currentPass ) { - if ( type == "depth" /*|| type == "svogi"*/ ) { + if ( type == "depth" || type == "vxgi" ) { struct { size_t depth; } attachments; @@ -341,7 +341,7 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { {uf::io::root+"/shaders/display/renderTarget.frag.spv", ext::vulkan::enums::Shader::FRAGMENT} }); } - if ( metadata["type"].as() == "svogi" ) { + if ( metadata["type"].as() == "vxgi" ) { auto& scene = uf::scene::getCurrentScene(); auto& shader = blitter.material.getShader("compute"); @@ -409,7 +409,7 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { void ext::vulkan::RenderTargetRenderMode::tick() { ext::vulkan::RenderMode::tick(); - if ( metadata["type"].as() == "svogi" ) { + if ( metadata["type"].as() == "vxgi" ) { if ( ext::vulkan::states::resized ) { renderTarget.initialize( *renderTarget.device ); if ( blitter.process ) blitter.getPipeline().update( blitter ); diff --git a/ext/behaviors/light/behavior.cpp b/ext/behaviors/light/behavior.cpp index ff5fa8c2..7ca4add6 100644 --- a/ext/behaviors/light/behavior.cpp +++ b/ext/behaviors/light/behavior.cpp @@ -154,9 +154,10 @@ void ext::LightBehavior::tick( uf::Object& self ) { metadata.type = metadataJson["light"]["type"].as(); } else if ( metadataJson["light"]["type"].is() ) { std::string lightType = metadataJson["light"]["type"].as(); - if ( lightType == "point" ) metadata.type = 0; - else if ( lightType == "spot" ) metadata.type = 1; + if ( lightType == "point" ) metadata.type = 1; + else if ( lightType == "spot" ) metadata.type = 2; } + if ( metadataJson["light"]["dynamic"].as() ) metadata.type = -metadata.type; } #endif #if 0 @@ -223,7 +224,7 @@ void ext::LightBehavior::tick( uf::Object& self ) { if ( !metadata.renderer.external ) { auto& camera = this->getComponent(); // omni light - if ( metadata.shadows && metadata.type == 0 ) { + if ( metadata.shadows && std::abs(metadata.type) == 1 ) { auto transform = camera.getTransform(); std::vector> rotations = { uf::quaternion::axisAngle( { 0, 1, 0 }, 0 * 1.57079633 ), diff --git a/ext/behaviors/light/behavior.h b/ext/behaviors/light/behavior.h index 9b3575f4..fceca95f 100644 --- a/ext/behaviors/light/behavior.h +++ b/ext/behaviors/light/behavior.h @@ -19,7 +19,7 @@ namespace ext { float power = 0.0f; float bias = 0.0f; bool shadows = false; - size_t type = 0; + int32_t type = 1; struct { std::string mode = "in-range"; float limiter = 0.0f; diff --git a/ext/behaviors/scene/behavior.cpp b/ext/behaviors/scene/behavior.cpp index 0eec2fd1..e2e9597d 100644 --- a/ext/behaviors/scene/behavior.cpp +++ b/ext/behaviors/scene/behavior.cpp @@ -210,6 +210,8 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { metadataJson["light"]["should"] = metadata.light.enabled; metadataJson["light"]["ambient"] = uf::vector::encode( metadata.light.ambient ); metadataJson["light"]["specular"] = uf::vector::encode( metadata.light.specular ); + metadataJson["light"]["exposure"] = metadata.light.exposure; + metadataJson["light"]["gamma"] = metadata.light.gamma; metadataJson["light"]["fog"]["color"] = uf::vector::encode( metadata.fog.color ); metadataJson["light"]["fog"]["step scale"] = metadata.fog.stepScale; metadataJson["light"]["fog"]["absorbtion"] = metadata.fog.absorbtion; @@ -229,6 +231,8 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { metadata.light.updateThreshold = metadataJson["system"]["config"]["engine"]["scenes"]["lights"]["update threshold"].as(); metadata.light.ambient = uf::vector::decode( metadataJson["light"]["ambient"], pod::Vector4f{ 1, 1, 1, 1 } ); metadata.light.specular = uf::vector::decode( metadataJson["light"]["specular"], pod::Vector4f{ 1, 1, 1, 1 } ); + metadata.light.exposure = metadataJson["light"]["exposure"].as(1.0f); + metadata.light.gamma = metadataJson["light"]["gamma"].as(2.2f); metadata.fog.color = uf::vector::decode( metadataJson["light"]["fog"]["color"], pod::Vector3f{ 1, 1, 1 } ); metadata.fog.stepScale = metadataJson["light"]["fog"]["step scale"].as(); metadata.fog.absorbtion = metadataJson["light"]["fog"]["absorbtion"].as(); @@ -238,11 +242,14 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { metadata.fog.density.threshold = metadataJson["light"]["fog"]["density"]["threshold"].as(); metadata.fog.density.multiplier = metadataJson["light"]["fog"]["density"]["multiplier"].as(); metadata.fog.density.scale = metadataJson["light"]["fog"]["density"]["scale"].as(); + + UF_DEBUG_MSG( metadata.light.exposure << " | " << metadata.light.gamma ); #if UF_USE_OPENGL_FIXED_FUNCTION uf::renderer::states::rebuild = true; #endif }; this->addHook( "object:UpdateMetadata.%UID%", metadata.deserialize); + this->addHook( "object:Reload.%UID%", metadata.deserialize); metadata.deserialize(); } void ext::ExtSceneBehavior::tick( uf::Object& self ) { @@ -361,6 +368,8 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { if ( !metadata.light.shadowSamples ) metadata.light.shadowSamples = metadataJson["system"]["config"]["engine"]["scenes"]["lights"]["shadow samples"].as(); if ( !metadata.light.shadowThreshold ) metadata.light.shadowThreshold = metadataJson["system"]["config"]["engine"]["scenes"]["lights"]["shadow threshold"].as(); if ( !metadata.light.updateThreshold ) metadata.light.updateThreshold = metadataJson["system"]["config"]["engine"]["scenes"]["lights"]["update threshold"].as(); + if ( !metadata.light.exposure ) metadata.light.exposure = metadataJson["light"]["exposure"].as(1.0f); + if ( !metadata.light.gamma ) metadata.light.gamma = metadataJson["light"]["gamma"].as(2.2f); #endif /* Update lights */ if ( metadata.light.enabled ) { ext::ExtSceneBehavior::bindBuffers( *this ); @@ -477,8 +486,8 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re alignas(4) uint32_t msaa; alignas(4) uint32_t poissonSamples; - alignas(4) uint32_t padding1; - alignas(4) uint32_t padding2; + alignas(4) float gamma; + alignas(4) float exposure; }; struct SpecializationConstant { uint32_t maxTextures = 512; @@ -493,7 +502,7 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re float distance = 0; float bias = 0; bool shadows = false; - size_t type = 0; + int32_t type = 0; }; std::vector entities; std::vector graphs; @@ -561,6 +570,8 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re uniforms->ambient = metadata.light.ambient; uniforms->msaa = ext::vulkan::settings::msaa; uniforms->poissonSamples = shadowSamples; + uniforms->exposure = metadata.light.exposure; + uniforms->gamma = metadata.light.gamma; uniforms->fog.color = metadata.fog.color; uniforms->fog.color.w = metadata.fog.stepScale; @@ -586,7 +597,7 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re for ( auto& texture : graphic.material.textures ) previousTextures.emplace_back(texture.image); graphic.material.textures.clear(); - if ( uf::renderer::settings::experimental::deferredMode == "svogi" ) { + if ( uf::renderer::settings::experimental::deferredMode == "vxgi" ) { graphic.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.id); //this->getComponent()); graphic.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.normal); //this->getComponent()); graphic.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.uv); //this->getComponent()); @@ -647,13 +658,13 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re max.z = std::max( max.z, graphMax.z ); } - min.x += floor(controllerTransform.position.x); - min.y -= floor(controllerTransform.position.y); - min.z -= floor(controllerTransform.position.z); + min.x += floor(controllerTransform.position.x ); + min.y -= floor(controllerTransform.position.y ); + min.z -= floor(controllerTransform.position.z ); - max.x += floor(controllerTransform.position.x); - max.y -= floor(controllerTransform.position.y); - max.z -= floor(controllerTransform.position.z); + max.x += floor(controllerTransform.position.x ); + max.y -= floor(controllerTransform.position.y ); + max.z -= floor(controllerTransform.position.z ); uniforms->matrices.ortho = /*uf::matrix::translate( uf::matrix::identity(), controllerTransform.position ) **/ uf::matrix::ortho( min.x, max.x, min.y, max.y, min.z, max.z ); diff --git a/ext/behaviors/scene/behavior.h b/ext/behaviors/scene/behavior.h index 467f410b..483629e4 100644 --- a/ext/behaviors/scene/behavior.h +++ b/ext/behaviors/scene/behavior.h @@ -27,6 +27,8 @@ namespace ext { size_t updateThreshold = 4; pod::Vector4f ambient = {0,0,0,1}; pod::Vector4f specular = {1,1,1,1}; + float exposure = 1.0f; + float gamma = 1.0f; } light; struct { pod::Vector3f color = {1,1,1}; diff --git a/ext/behaviors/voxelizer/behavior.cpp b/ext/behaviors/voxelizer/behavior.cpp index 468d18bd..218d8078 100644 --- a/ext/behaviors/voxelizer/behavior.cpp +++ b/ext/behaviors/voxelizer/behavior.cpp @@ -20,12 +20,18 @@ UF_BEHAVIOR_REGISTER_CPP(ext::VoxelizerBehavior) void ext::VoxelizerBehavior::initialize( uf::Object& self ) { #if UF_USE_VULKAN auto& metadata = this->getComponent(); + auto& scene = uf::scene::getCurrentScene(); + auto& sceneMetadataJson = scene.getComponent(); auto& sceneTextures = this->getComponent(); // initialize voxel map { - if ( metadata.voxelSize.x == 0 ) metadata.voxelSize.x = 256; - if ( metadata.voxelSize.y == 0 ) metadata.voxelSize.y = 256; - if ( metadata.voxelSize.z == 0 ) metadata.voxelSize.z = 256; + const uint32_t DEFAULT_VOXEL_SIZE = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["vxgi"]["size"].as(); + const float DEFAULT_VOXELIZE_LIMITER = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["vxgi"]["limiter"].as(); + + if ( metadata.voxelSize.x == 0 ) metadata.voxelSize.x = DEFAULT_VOXEL_SIZE; + if ( metadata.voxelSize.y == 0 ) metadata.voxelSize.y = DEFAULT_VOXEL_SIZE; + if ( metadata.voxelSize.z == 0 ) metadata.voxelSize.z = DEFAULT_VOXEL_SIZE; + if ( metadata.renderer.limiter == 0 ) metadata.renderer.limiter = DEFAULT_VOXELIZE_LIMITER; std::vector empty(metadata.voxelSize.x * metadata.voxelSize.y * metadata.voxelSize.z * sizeof(uint8_t) * 4); @@ -43,16 +49,16 @@ void ext::VoxelizerBehavior::initialize( uf::Object& self ) { // if ( metadata.fragmentSize.y == 0 ) metadata.fragmentSize.y = metadata.voxelSize.y * 2; auto& renderMode = this->getComponent(); - metadata.renderModeName = "SVOGI:" + std::to_string((int) this->getUid()); + metadata.renderModeName = "VXGI:" + std::to_string((int) this->getUid()); uf::renderer::addRenderMode( &renderMode, metadata.renderModeName ); - renderMode.metadata["type"] = "svogi"; + renderMode.metadata["type"] = "vxgi"; renderMode.metadata["samples"] = 1; renderMode.blitter.device = &ext::vulkan::device; renderMode.width = metadata.fragmentSize.x; renderMode.height = metadata.fragmentSize.y; #if COMP_SHADER_USED - renderMode.metadata["shaders"]["compute"] = "/shaders/display/svogi.comp.spv"; + renderMode.metadata["shaders"]["compute"] = "/shaders/display/vxgi.comp.spv"; renderMode.blitter.descriptor.renderMode = metadata.renderModeName; renderMode.blitter.descriptor.subpass = -1; renderMode.blitter.process = true; @@ -126,9 +132,18 @@ void ext::VoxelizerBehavior::tick( uf::Object& self ) { auto& metadata = this->getComponent(); auto& renderMode = this->getComponent(); renderMode.setTarget(""); - if ( renderMode.executed && !metadata.initialized ) { - // renderMode.execute = false; - metadata.initialized = true; + if ( renderMode.executed ) { + if ( !metadata.initialized ) metadata.initialized = true; + + if ( metadata.renderer.limiter > 0 ) { + if ( metadata.renderer.timer > metadata.renderer.limiter ) { + metadata.renderer.timer = 0; + renderMode.execute = true; + } else { + metadata.renderer.timer = metadata.renderer.timer + uf::physics::time::delta; + renderMode.execute = false; + } + } } #if COMP_SHADER_USED auto& scene = uf::scene::getCurrentScene(); diff --git a/ext/behaviors/voxelizer/behavior.h b/ext/behaviors/voxelizer/behavior.h index 169068ac..2e31bb3a 100644 --- a/ext/behaviors/voxelizer/behavior.h +++ b/ext/behaviors/voxelizer/behavior.h @@ -19,12 +19,16 @@ namespace ext { pod::Vector3ui fragmentSize = { 0, 0 }; pod::Vector3ui voxelSize = { 256, 256, 256 }; pod::Vector3ui dispatchSize = { 8, 8, 8 }; - std::string renderModeName = "SVOGI"; + std::string renderModeName = "VXGI"; struct { pod::Vector3f min = {}; pod::Vector3f max = {}; pod::Matrix4f matrix = uf::matrix::identity(); } extents; + struct { + float limiter = 0.0f; + float timer = 0.0f; + } renderer; bool initialized = false; }; }