#extension GL_EXT_samplerless_texture_functions : require #extension GL_EXT_nonuniform_qualifier : enable #define DEFERRED 1 #define MAX_TEXTURES TEXTURES //#define TEXTURE_WORKAROUND 0 #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 (input_attachment_index = 0, binding = 0) uniform usubpassInput samplerId; layout (input_attachment_index = 1, binding = 1) uniform subpassInput samplerNormal; #if DEFERRED_SAMPLING layout (input_attachment_index = 2, binding = 2) uniform subpassInput samplerUv; #else layout (input_attachment_index = 2, binding = 2) uniform subpassInput samplerAlbedo; #endif layout (input_attachment_index = 3, binding = 3) uniform subpassInput samplerDepth; #if DEFERRED_SAMPLING layout (input_attachment_index = 4, binding = 4) uniform subpassInput samplerMips; #endif #else layout (input_attachment_index = 0, binding = 0) uniform usubpassInputMS samplerId; layout (input_attachment_index = 1, binding = 1) uniform subpassInputMS samplerNormal; #if DEFERRED_SAMPLING layout (input_attachment_index = 2, binding = 2) uniform subpassInputMS samplerUv; #else layout (input_attachment_index = 2, binding = 2) uniform subpassInputMS samplerAlbedo; #endif layout (input_attachment_index = 3, binding = 3) uniform subpassInputMS samplerDepth; #if DEFERRED_SAMPLING layout (input_attachment_index = 4, binding = 4) uniform subpassInputMS samplerMips; #endif #endif #include "../common/structs.h" layout (binding = 4) uniform UBO { EyeMatrices eyes[2]; Mode mode; Fog fog; Vxgi vxgi; uint lights; uint materials; uint textures; uint drawCommands; vec3 ambient; float gamma; float exposure; float brightnessThreshold; uint msaa; uint shadowSamples; uint indexSkybox; uint padding1; uint padding2; uint padding3; } ubo; /* layout (std140, binding = 5) readonly buffer DrawCommands { DrawCommand drawCommands[]; }; */ layout (std140, binding = 5) readonly buffer Instances { Instance instances[]; }; layout (std140, binding = 6) readonly buffer Materials { Material materials[]; }; layout (std140, binding = 7) readonly buffer Textures { Texture textures[]; }; layout (std140, binding = 8) readonly buffer Lights { Light lights[]; }; layout (binding = 9) uniform sampler2D samplerTextures[TEXTURES]; layout (binding = 10) uniform samplerCube samplerCubemaps[CUBEMAPS]; layout (binding = 11) uniform sampler3D samplerNoise; #if VXGI layout (binding = 12) uniform usampler3D voxelId[CASCADES]; layout (binding = 13) uniform sampler3D voxelNormal[CASCADES]; layout (binding = 14) uniform sampler3D voxelRadiance[CASCADES]; #endif layout (location = 0) in vec2 inUv; layout (location = 1) in flat uvec2 inPushConstantPass; layout (location = 0) out vec4 outFragColor; layout (location = 1) out vec4 outFragBright; #include "../common/functions.h" #include "../common/fog.h" #include "../common/pbr.h" #include "../common/shadows.h" #if VXGI #include "../common/vxgi.h" #endif void postProcess() { float brightness = dot(surface.fragment.rgb, vec3(0.2126, 0.7152, 0.0722)); outFragBright = brightness > ubo.brightnessThreshold ? vec4(surface.fragment.rgb, 1.0) : vec4(0, 0, 0, 1); #if FOG fog( surface.ray, surface.fragment.rgb, surface.fragment.a ); #endif #if TONE_MAP surface.fragment.rgb = vec3(1.0) - exp(-surface.fragment.rgb * ubo.exposure); #endif #if GAMMA_CORRECT surface.fragment.rgb = pow(surface.fragment.rgb, vec3(1.0 / ubo.gamma)); #endif #if WHITENOISE if ( enabled(ubo.mode.type, 1) ) whitenoise(surface.fragment.rgb, ubo.mode.parameters); #endif outFragColor = vec4(surface.fragment.rgb, 1.0); } void populateSurface() { surface.fragment = vec4(0); surface.pass = inPushConstantPass.x; { #if !MULTISAMPLING const float depth = subpassLoad(samplerDepth).r; #else const float depth = subpassLoad(samplerDepth, msaa.currentID).r; // resolve(samplerDepth, ubo.msaa).r; #endif vec4 positionEye = ubo.eyes[surface.pass].iProjection * vec4(inUv * 2.0 - 1.0, depth, 1.0); positionEye /= positionEye.w; surface.position.eye = positionEye.xyz; surface.position.world = vec3( ubo.eyes[surface.pass].iView * positionEye ); } #if 0 { const vec4 near4 = ubo.eyes[surface.pass].iProjectionView * (vec4(2.0 * inUv - 1.0, -1.0, 1.0)); const vec4 far4 = ubo.eyes[surface.pass].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; surface.ray.origin = near3; surface.ray.direction = normalize( far3 - near3 ); } // separate our ray direction due to floating point precision problems { const mat4 iProjectionView = inverse( ubo.eyes[surface.pass].projection * mat4(mat3(ubo.eyes[surface.pass].view)) ); 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; surface.ray.direction = normalize( far3 - near3 ); } #else { const mat4 iProjectionView = inverse( ubo.eyes[surface.pass].projection * mat4(mat3(ubo.eyes[surface.pass].view)) ); 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; surface.ray.direction = normalize( far3 - near3 ); surface.ray.origin = ubo.eyes[surface.pass].eyePos.xyz; } #endif #if !MULTISAMPLING surface.normal.world = decodeNormals( subpassLoad(samplerNormal).xy ); const uvec2 ID = subpassLoad(samplerId).xy; #else surface.normal.world = decodeNormals( subpassLoad(samplerNormal, msaa.currentID).xy ); // decodeNormals( resolve(samplerNormal, ubo.msaa).xy ); const uvec2 ID = msaa.IDs[msaa.currentID]; // subpassLoad(samplerId, msaa.currentID).xy; //resolve(samplerId, ubo.msaa).xy; #endif surface.normal.eye = vec3( ubo.eyes[surface.pass].view * vec4(surface.normal.world, 0.0) ); const uint drawID = ID.x - 1; const uint instanceID = ID.y - 1; if ( ID.x == 0 || ID.y == 0 ) { surface.fragment.rgb = texture( samplerCubemaps[ubo.indexSkybox], surface.ray.direction ).rgb; surface.fragment.a = 0.0; postProcess(); return; } // const DrawCommand drawCommand = drawCommands[drawID]; const Instance instance = instances[instanceID]; surface.instance = instance; // surface.instance.materialID = instance.materialID; // surface.instance.lightmapID = instance.lightmapID; const Material material = materials[surface.instance.materialID]; surface.material.albedo = material.colorBase; surface.material.metallic = material.factorMetallic; surface.material.roughness = material.factorRoughness; surface.material.occlusion = material.factorOcclusion; surface.fragment = material.colorEmissive; #if DEFERRED_SAMPLING { #if !MULTISAMPLING const vec4 uv = subpassLoad(samplerUv); const vec2 mips = vec2(0); // subpassLoad(samplerMips).xy; #else const vec4 uv = subpassLoad(samplerUv, msaa.currentID); // resolve(samplerUv, ubo.msaa); const vec2 mips = vec2(0); // subpassLoad(samplerMips, msaa.currentID).xy; // resolve(samplerUv, ubo.msaa); #endif surface.uv.xy = uv.xy; surface.uv.z = mips.x; surface.st.xy = uv.zw; surface.st.z = mips.y; } if ( validTextureIndex( material.indexAlbedo ) ) { surface.material.albedo = sampleTexture( material.indexAlbedo ); } // OPAQUE if ( material.modeAlpha == 0 ) { surface.material.albedo.a = 1; // BLEND } else if ( material.modeAlpha == 1 ) { // MASK } else if ( material.modeAlpha == 2 ) { } // Lightmap if ( validTextureIndex( surface.instance.lightmapID ) ) { surface.material.albedo.rgb *= sampleTexture( surface.instance.lightmapID, surface.st ).rgb; } // Emissive textures if ( validTextureIndex( material.indexEmissive ) ) { surface.material.albedo += sampleTexture( material.indexEmissive ); } // Occlusion map if ( validTextureIndex( material.indexOcclusion ) ) { surface.material.occlusion = sampleTexture( material.indexOcclusion ).r; } // Metallic/Roughness map if ( validTextureIndex( material.indexMetallicRoughness ) ) { vec4 samp = sampleTexture( material.indexMetallicRoughness ); surface.material.metallic = samp.r; surface.material.roughness = samp.g; } #else #if !MULTISAMPLING surface.material.albedo = subpassLoad(samplerAlbedo); #else surface.material.albedo = subpassLoad(samplerAlbedo, msaa.currentID); // resolve(samplerAlbedo, ubo.msaa); #endif #endif } void directLighting() { const vec3 ambient = ubo.ambient.rgb * surface.material.occlusion + surface.material.indirect.rgb; // surface.fragment.rgb += surface.material.albedo.rgb * ambient; if ( validTextureIndex( surface.instance.lightmapID ) ) { surface.fragment.rgb += surface.material.albedo.rgb + ambient; } else { surface.fragment.rgb += surface.material.albedo.rgb * ambient; } // if ( ubo.lights == 0 ) { surface.fragment.rgb = surface.material.albedo.rgb; return; } #if PBR pbr(); #elif LAMBERT lambert(); #elif PHONG phong(); #endif } #if MULTISAMPLING void resolveSurfaceFragment() { for ( int i = 0; i < ubo.msaa; ++i ) { msaa.currentID = i; msaa.IDs[i] = subpassLoad(samplerId, msaa.currentID).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 indirectLighting(); #endif directLighting(); } msaa.fragment += surface.fragment; msaa.fragments[msaa.currentID] = surface.fragment; } surface.fragment = msaa.fragment / ubo.msaa; } #endif