#extension GL_EXT_samplerless_texture_functions : require #extension GL_EXT_nonuniform_qualifier : enable #if RT #extension GL_EXT_ray_tracing : enable #extension GL_EXT_ray_query : enable #endif layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in; #define COMPUTE 1 #define DEFERRED 1 #define DEFERRED_SAMPLING 1 #define PBR 1 #define LAMBERT 0 #define FOG 1 #define FOG_RAY_MARCH 1 #include "../../../common/macros.h" layout (constant_id = 0) const uint TEXTURES = 512; layout (constant_id = 1) const uint CUBEMAPS = 128; #if VXGI layout (constant_id = 2) const uint CASCADES = 16; #endif #if !MULTISAMPLING layout(binding = 0) uniform utexture2D samplerId; #if BARYCENTRIC #if !BARYCENTRIC_CALCULATE layout(binding = 1) uniform texture2D samplerBary; #endif #else layout(binding = 1) uniform texture2D samplerUv; layout(binding = 2) uniform texture2D samplerNormal; #endif layout(binding = 3) uniform texture2D samplerDepth; #else layout(binding = 0) uniform utexture2DMS samplerId; #if BARYCENTRIC #if !BARYCENTRIC_CALCULATE layout(binding = 1) uniform texture2DMS samplerBary; #endif #else layout(binding = 1) uniform texture2DMS samplerUv; layout(binding = 2) uniform texture2DMS samplerNormal; #endif layout(binding = 3) uniform texture2DMS samplerDepth; #endif layout(binding = 7, rgba16f) uniform volatile coherent image2D imageColor; layout(binding = 8, rgba16f) uniform volatile coherent image2D imageBright; layout(binding = 9, rg16f) uniform volatile coherent image2D imageMotion; layout( push_constant ) uniform PushBlock { uint pass; uint draw; } PushConstant; #include "../../../common/structs.h" layout (binding = 10) uniform UBO { EyeMatrices eyes[2]; Settings settings; } ubo; /* */ layout (std140, binding = 11) readonly buffer DrawCommands { DrawCommand drawCommands[]; }; layout (std140, binding = 12) readonly buffer Instances { Instance instances[]; }; layout (std140, binding = 13) readonly buffer InstanceAddresseses { InstanceAddresses instanceAddresses[]; }; layout (std140, binding = 14) readonly buffer Objects { Object objects[]; }; layout (std140, binding = 15) readonly buffer Materials { Material materials[]; }; layout (std140, binding = 16) readonly buffer Textures { Texture textures[]; }; layout (std140, binding = 17) readonly buffer Lights { Light lights[]; }; layout (binding = 18) uniform sampler2D samplerTextures[TEXTURES]; layout (binding = 19) uniform samplerCube samplerCubemaps[CUBEMAPS]; layout (binding = 20) uniform sampler3D samplerNoise; #if VXGI layout (binding = 21) uniform usampler3D voxelDrawId[CASCADES]; layout (binding = 22) uniform usampler3D voxelInstanceId[CASCADES]; layout (binding = 23) uniform sampler3D voxelNormalX[CASCADES]; layout (binding = 24) uniform sampler3D voxelNormalY[CASCADES]; layout (binding = 25) uniform sampler3D voxelRadianceR[CASCADES]; layout (binding = 26) uniform sampler3D voxelRadianceG[CASCADES]; layout (binding = 27) uniform sampler3D voxelRadianceB[CASCADES]; layout (binding = 28) uniform sampler3D voxelRadianceA[CASCADES]; layout (binding = 29) uniform sampler3D voxelCount[CASCADES]; layout (binding = 30) uniform sampler3D voxelOutput[CASCADES]; #endif #if RT layout (binding = 31) uniform accelerationStructureEXT tlas; #endif #if BUFFER_REFERENCE //layout(buffer_reference, scalar) buffer Vertices { Vertex v[]; }; layout(buffer_reference, scalar) buffer Indices { uint i[]; }; //layout(buffer_reference, scalar) buffer Indices { uvec3 i[]; }; layout(buffer_reference, scalar) buffer Indirects { DrawCommand dc[]; }; //layout(buffer_reference, scalar) buffer VPos { vec3 v[]; }; layout(buffer_reference, scalar) buffer VPos { float v[]; }; layout(buffer_reference, scalar) buffer VUv { vec2 v[]; }; //layout(buffer_reference, scalar) buffer VUv { float v[]; }; layout(buffer_reference, scalar) buffer VColor { uint v[]; }; layout(buffer_reference, scalar) buffer VSt { vec2 v[]; }; //layout(buffer_reference, scalar) buffer VSt { float v[]; }; //layout(buffer_reference, scalar) buffer VNormal { vec3 v[]; }; layout(buffer_reference, scalar) buffer VNormal { float v[]; }; //layout(buffer_reference, scalar) buffer VTangent { vec3 v[]; }; layout(buffer_reference, scalar) buffer VTangent { float v[]; }; layout(buffer_reference, scalar) buffer VID { uint v[]; }; #endif #include "../../../common/functions.h" #include "../../../common/fog.h" #include "../../../common/light.h" #include "../../../common/shadows.h" #if VXGI #include "../../../common/vxgi.h" #endif #if RT #include "../../../common/rt.h" #endif #if MULTISAMPLING #define IMAGE_LOAD(X) texelFetch( X, ivec2(gl_GlobalInvocationID.xy), msaa.currentID ) #else #define IMAGE_LOAD(X) texelFetch( X, ivec2(gl_GlobalInvocationID.xy), 0 ) #endif #define IMAGE_STORE(X, Y) imageStore( X, ivec2(gl_GlobalInvocationID.xy), Y ) bool USE_SKYBOX_ON_DIVERGENCE = false; void postProcess() { if ( USE_SKYBOX_ON_DIVERGENCE ) { if ( 0 <= ubo.settings.lighting.indexSkybox && ubo.settings.lighting.indexSkybox < CUBEMAPS ) { surface.fragment.rgb = texture( samplerCubemaps[ubo.settings.lighting.indexSkybox], surface.ray.direction ).rgb; } } #if FOG fog( surface.ray, surface.fragment.rgb, surface.fragment.a ); #endif float brightness = dot(surface.fragment.rgb, vec3(0.2126, 0.7152, 0.0722)); bool bloom = brightness > ubo.settings.bloom.threshold; //if ( bloom ) toneMap( surface.fragment.rgb, brightness ); vec4 outFragColor = vec4(surface.fragment.rgb, 1.0); vec4 outFragBright = bloom ? vec4(surface.fragment.rgb, 1.0) : vec4(0, 0, 0, 1); vec2 outFragMotion = surface.motion; if ( ubo.settings.mode.type > 0x0000 ) { uvec2 renderSize = imageSize(imageColor); vec2 inUv = (vec2(gl_GlobalInvocationID.xy) / vec2(renderSize)) * 2.0f - 1.0f; if ( true ) { // if ( ubo.settings.mode.type == 0x0001 ) outFragColor = vec4(surface.barycentric.rgb, 1); if ( ubo.settings.mode.type == 0x0001 ) outFragColor = vec4(surface.material.albedo.rgb, 1); else if ( ubo.settings.mode.type == 0x0002 ) outFragColor = vec4(surface.light.rgb, 1); else if ( ubo.settings.mode.type == 0x0003 ) outFragColor = vec4(vec3(surface.light.a), 1); else if ( ubo.settings.mode.type == 0x0004 ) outFragColor = vec4(surface.normal.eye.rgb, 1); else if ( ubo.settings.mode.type == 0x0005 ) outFragColor = vec4(surface.uv.xy, 0, 1); else if ( ubo.settings.mode.type == 0x0006 ) outFragColor = vec4(surface.st.xy, 0, 1); else if ( ubo.settings.mode.type == 0x0007 ) outFragColor = vec4(vec3(surface.material.metallic), 1); else if ( ubo.settings.mode.type == 0x0008 ) outFragColor = vec4(vec3(surface.material.roughness * 4), 1); else if ( ubo.settings.mode.type == 0x0009 ) outFragColor = vec4(vec3(surface.material.occlusion), 1); } } IMAGE_STORE( imageColor, outFragColor ); IMAGE_STORE( imageBright, outFragBright ); IMAGE_STORE( imageMotion, vec4(outFragMotion, 0, 0) ); } void populateSurface() { const uvec2 renderSize = imageSize(imageColor); if ( gl_GlobalInvocationID.x >= renderSize.x || gl_GlobalInvocationID.y >= renderSize.y || gl_GlobalInvocationID.z > PushConstant.pass ) return; surface.pass = PushConstant.pass; surface.fragment = vec4(0); surface.light = vec4(0); surface.motion = vec2(0); surface.material.indirect = vec4(0); surface.material.metallic = 1; surface.material.roughness = 0; surface.material.occlusion = 0; float depth = 0.0; { vec2 inUv = (vec2(gl_GlobalInvocationID.xy) / vec2(renderSize)) * 2.0f - 1.0f; const mat4 iProjectionView = inverse( ubo.eyes[surface.pass].projection * mat4(mat3(ubo.eyes[surface.pass].view)) ); const vec4 near4 = iProjectionView * (vec4(inUv, -1.0, 1.0)); const vec4 far4 = iProjectionView * (vec4(inUv, 1.0, 1.0)); const vec3 near3 = near4.xyz / near4.w; const vec3 far3 = far4.xyz / far4.w; surface.ray.direction = normalize( far3 - near3 ); // surface.ray.origin = near3.xyz; surface.ray.origin = ubo.eyes[surface.pass].eyePos.xyz; // surface.ray.origin = vec3( -ubo.eyes[surface.pass].view[0][3], -ubo.eyes[surface.pass].view[1][3], -ubo.eyes[surface.pass].view[2][3] ); depth = IMAGE_LOAD(samplerDepth).r; vec4 eye = ubo.eyes[surface.pass].iProjection * vec4(inUv, depth, 1.0); eye /= eye.w; surface.position.eye = eye.xyz; surface.position.world = vec3( ubo.eyes[surface.pass].iView * eye ); } #if !MULTISAMPLING const uvec2 ID = uvec2(IMAGE_LOAD(samplerId).xy); #else const uvec2 ID = msaa.IDs[msaa.currentID]; #endif if ( ID.x == 0 || ID.y == 0 || depth <= 0.0 ) { USE_SKYBOX_ON_DIVERGENCE = true; } /* if ( ID.x == 0 || ID.y == 0 || depth <= 0.0 ) { if ( 0 <= ubo.settings.lighting.indexSkybox && ubo.settings.lighting.indexSkybox < CUBEMAPS ) { surface.fragment.rgb = texture( samplerCubemaps[ubo.settings.lighting.indexSkybox], surface.ray.direction ).rgb; } return; } */ { const uint triangleID = ID.x == 0 ? 0 : ID.x - 1; const uint instanceID = ID.y == 0 ? 0 : ID.y - 1; surface.subID = 1; #if BARYCENTRIC #if !BARYCENTRIC_CALCULATE surface.barycentric = decodeBarycentrics(IMAGE_LOAD(samplerBary).xy).xyz; #endif populateSurface( instanceID, triangleID ); #else vec4 uvst = IMAGE_LOAD(samplerUv); vec4 normaltangent = IMAGE_LOAD(samplerNormal); surface.uv.xy = uvst.xy; surface.uv.z = 0; surface.st.xy = uvst.zw; surface.st.z = 0; surface.normal.world = decodeNormals(normaltangent.xy); // surface.tangent.world = decodeNormals(normaltangent.zw); surface.instance = instances[instanceID >= instances.length() ? 0 : instanceID]; surface.object = objects[surface.instance.objectID]; populateSurfaceMaterial(); #endif } { vec4 pNDC = ubo.eyes[surface.pass].previous * surface.object.previous * vec4(surface.position.world, 1); vec4 cNDC = ubo.eyes[surface.pass].model * surface.object.model * vec4(surface.position.world, 1); pNDC /= pNDC.w; cNDC /= cNDC.w; surface.motion = cNDC.xy - pNDC.xy; } } void directLighting() { #if VXGI // to-do: proper "visual" of the VXGI maps (directly pick the pixel instead of just rawdog tracing for it) if ( ubo.settings.mode.type == 0x000A ) { Ray ray; ray.direction = surface.ray.direction; ray.origin = surface.ray.origin; ray.origin -= ray.direction; vec4 radiance = voxelConeTrace( ray, 0 ); surface.material.albedo.rgb = radiance.rgb; surface.material.indirect.rgb = vec3(0); surface.fragment.rgb = radiance.rgb; surface.fragment.a = radiance.a; //return; } #endif surface.light.rgb += surface.material.albedo.rgb * ubo.settings.lighting.ambient.rgb * surface.material.occlusion; // add ambient lighting surface.light.rgb += surface.material.indirect.rgb; // add indirect lighting #if PBR pbr(); #elif LAMBERT lambert(); #elif PHONG phong(); #endif surface.fragment.rgb += surface.light.rgb; } void indirectLighting() { uint scale = 0; #if RT ++scale; indirectLightingRT(); #endif #if VXGI ++scale; indirectLightingVXGI(); #endif // if ( scale > 1 ) surface.material.indirect.rgb /= scale; } #if MULTISAMPLING void resolveSurfaceFragment() { for ( int i = 0; i < ubo.settings.mode.msaa; ++i ) { msaa.currentID = i; msaa.IDs[i] = uvec3(IMAGE_LOAD(samplerId)).xy; // check if ID is already used bool unique = true; for ( int j = msaa.currentID - 1; j >= 0; --j ) { if ( msaa.IDs[j] == msaa.IDs[i] ) { surface.fragment = msaa.fragments[j]; unique = false; break; } } if ( unique ) { populateSurface(); #if VXGI || RT indirectLighting(); #endif directLighting(); } msaa.fragment += surface.fragment; msaa.fragments[msaa.currentID] = surface.fragment; } surface.fragment = msaa.fragment / ubo.settings.mode.msaa; } #endif