diff --git a/examples/ssgi/main.cpp b/examples/ssgi/main.cpp index 8699604..537c269 100644 --- a/examples/ssgi/main.cpp +++ b/examples/ssgi/main.cpp @@ -105,7 +105,7 @@ Pipeline CreateViewPipeline(VulkanAPI& vk, LvkIm3dState& im3dState, ShaderProgra gbuffer->Build(vk); auto* lightPassImage = p.AddFramebuffer(vk); - lightPassImage->AddColourAttachment(vk, ResolutionScale::Full, 1, VK_SAMPLE_COUNT_1_BIT, VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + lightPassImage->AddColourAttachment(vk, ResolutionScale::Full, 1, VK_SAMPLE_COUNT_1_BIT, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, VK_IMAGE_ASPECT_COLOR_BIT); lightPassImage->Build(vk); @@ -128,10 +128,7 @@ Pipeline CreateViewPipeline(VulkanAPI& vk, LvkIm3dState& im3dState, ShaderProgra // A channel is depth auto* ssgiMat = p.AddMaterial(vk, ssgiProg); - ssgiMat->SetDepthAttachment(vk, "depthImageSampler", *gbuffer); - ssgiMat->SetColourAttachment(vk, "positionBufferSampler", *gbuffer, 1); - ssgiMat->SetColourAttachment(vk, "normalBufferSampler", *gbuffer, 2); - ssgiMat->SetColourAttachment(vk, "lightPassImageSampler", *lightPassImage, 0); + ssgiMat->SetColourAttachment(vk, "lightPassBuffer", *lightPassImage, 0); p.SetOutputFramebuffer(finalImage); @@ -310,6 +307,7 @@ Pipeline CreateViewPipeline(VulkanAPI& vk, LvkIm3dState& im3dState, ShaderProgra glm::mat4 proj; glm::vec4 resolutionFov; glm::vec4 eyePos; + glm::vec4 eyeAngles; uint32_t frameIndex; }; @@ -318,6 +316,7 @@ Pipeline CreateViewPipeline(VulkanAPI& vk, LvkIm3dState& im3dState, ShaderProgra data.proj = view.m_Camera.Proj; data.resolutionFov = glm::vec4{ static_cast(view.m_CurrentResolution.width), static_cast(view.m_CurrentResolution.height), view.m_Camera.FOV, 0.0f }; data.eyePos = glm::vec4(view.m_Camera.Position, 0.0); + data.eyeAngles = glm::vec4(view.m_Camera.Rotation, 0.0); data.frameIndex = frameCount++; Array clearValues{}; diff --git a/examples/ssgi/shaders/SSGI.frag b/examples/ssgi/shaders/SSGI.frag index 86097f4..8001ebe 100644 --- a/examples/ssgi/shaders/SSGI.frag +++ b/examples/ssgi/shaders/SSGI.frag @@ -5,7 +5,6 @@ // which is an implementation of this paper: https://arxiv.org/pdf/2301.11376.pdf #include "SSGI.utils.glsl" - layout(location = 0) in vec2 UV; layout(location = 0) out vec4 outColor; @@ -15,13 +14,14 @@ layout(push_constant, std430) uniform pc { mat4 proj; vec4 resolutionFov; vec4 eyePos; + vec4 eyeAngles; int FrameIndex; }; -layout(binding = 0) uniform sampler2D positionBufferSampler; -layout(binding = 1) uniform sampler2D normalBufferSampler; -layout(binding = 2) uniform sampler2D lightPassImageSampler; -layout(binding = 3) uniform sampler2D depthImageSampler; +#define fragCoord gl_FragCoord.xy +#define IRES 1.0 / resolutionFov.xy + +layout(binding = 0) uniform sampler2D lightPassBuffer; // this counts the number of 1s in the binary representation of val int CountBits(int val) @@ -35,82 +35,71 @@ int CountBits(int val) } void main() { - vec4 result = vec4(0.0); - result.w = 1.0; - - float CurrentFrame = FrameIndex; - vec2 SSOffset = vec2(0.); - vec2 fragCoord = gl_FragCoord.xy; - // send these in push constant buffer - vec2 IRES = 1.0 / resolutionFov.xy; - float fov = resolutionFov[2]; - float CFOV = tan(fov); - vec2 ASPECT = vec2(resolutionFov.x/resolutionFov.y,1.0); - - - // sample gbuffer - vec3 colour = (texture(lightPassImageSampler, UV) * proj * view).xyz; - // vec3 position = texture(positionBufferSampler, UV).xyz; - vec3 position = (texture(positionBufferSampler, UV) * proj * view).xyz; - // vec3 normal = texture(normalBufferSampler, UV).xyz; - vec3 normal = (texture(normalBufferSampler, UV) * proj * view).xyz; - vec3 Tan = vec3(0.0); - vec3 Bit = TBN(eyePos.xyz, Tan); - mat3 EyeMat = TBN(eyePos.xyz); - - if(length(colour) > -0.5) + vec4 Output = vec4(0.0); + Output.w = 1.0; + vec2 ASPECT = vec2(resolutionFov.x / resolutionFov.y, 1.0); + float CFOV = tan(resolutionFov.z); + if (FrameIndex > 1 && DFBox(fragCoord - 1.0,resolutionFov.xy) < 0.0) { - // Horizons (AKA wtf is happening) - // vec3 VNormal = vec3(dot(normal, Tan), dot(normal, Bit), dot(normal, eyePos.xyz)); - vec3 VNormal = normal; - // vec3 VPPos = vec3(dot(position, Tan), dot(position, Bit), dot(position, eyePos.xyz)); - vec3 VPPos = position; - // vec2 ModFC = mod(fragCoord, 4.0); - vec2 ModFC = fragCoord; - float RandPhiOffset = ARand21(vec2(1.234)+mod(CurrentFrame*3.26346,7.2634)); - float RandPhiMultiplier = 2 * PI * I64; - float RandPhi = (mod(floor(ModFC.x)+floor(ModFC.y)*4.0+CurrentFrame*5.0, 16.0) + RandPhiOffset) * RandPhiMultiplier; - - for(int i = 0; i < 4; i++) + float CurrentFrame = float(FrameIndex); + vec2 SSOffset = vec2(0.); + vec3 Tan; + vec3 Bit = TBN(eyePos.xyz,Tan); + mat3 EyeMat = TBN(eyePos.xyz); + vec3 Dir = normalize(vec3(((fragCoord+SSOffset)*IRES*2.-1.)*(ASPECT*CFOV),1.)*EyeMat); + vec4 Attr = texture(lightPassBuffer, UV); + + if(Attr.y > -0.5) { - RandPhi += PI * 0.5; - vec2 SSDir = vec2(cos(RandPhi), sin(RandPhi)); - float StepDist = 1.0; - float StepCoeff = 0.15+0.15*ARand21(fragCoord*IRES*(1.4+mod(CurrentFrame *3.26346,6.2634))); - int BitMask = 0; + vec3 PPos = eyePos.xyz+Dir*Attr.w; + vec3 Normal = FloatToVec3(Attr.z)*2.-1.; + Output.xyz = vec3(0.); + vec3 VNormal = vec3(dot(Normal,Tan),dot(Normal,Bit),dot(Normal,eyeAngles.xyz)); + vec3 VPPos = vec3(dot(PPos-eyePos.xyz,Tan),dot(PPos-eyePos.xyz,Bit),dot(PPos-eyePos.xyz,eyeAngles.xyz)); + + vec2 ModFC = mod(fragCoord,4.); + float RandPhiOffset = ARand21(vec2(1.234)+mod(CurrentFrame*3.26346,7.2634)); + float RandPhi = (mod(floor(ModFC.x)+floor(ModFC.y)*4.+CurrentFrame*5.,16.)+RandPhiOffset)*2.*PI*I64; - for (int s= 1; s < 32; s++) { - vec2 SUV = fragCoord+SSDir*StepDist; - float CurrentStep = max(1.,StepDist*StepCoeff); - StepDist += CurrentStep; - if (DFBox(SUV-1.,resolutionFov.xy-1.)>0.) break; - vec2 SAttrUV = SUV * IRES; - vec3 SAttrY = texture(lightPassImageSampler, SAttrUV * resolutionFov.xy).xyz; - if (length(SAttrY) <-1.5) continue; - vec3 SAttrZ = texture(normalBufferSampler, SAttrUV).xyz; - vec3 SVPPos = texture(positionBufferSampler, SAttrUV).xyz; - float NorDot = dot(VNormal, SVPPos - VPPos) - EPSILON; - float TanDist = length(SVPPos-VPPos-NorDot*VNormal); - float Angle1f = atan(NorDot,TanDist); - float Angle2f = atan(NorDot-0.03*max(1.,StepDist*0.07),TanDist); - float Angle1 = max(0.,ceil(Angle1f/(PI*0.5)*32.)); - float Angle2 = max(0.,floor(Angle2f/(PI*0.5)*32.)); - int SBitMask = (int(pow(2.,Angle1-Angle2))-1) << int(Angle2); - vec3 SNormal = SAttrZ *2.-1.; - SNormal = vec3(dot(SNormal,Tan),dot(SNormal,Bit),dot(SNormal,eyePos.xyz)); + for (float i=0.; i<3.5; i++) { + RandPhi += PI*0.5; + vec2 SSDir = vec2(cos(RandPhi),sin(RandPhi)); + float StepDist = 1.; + float StepCoeff = 0.15+0.15*ARand21(fragCoord*IRES*(1.4+mod(float(FrameIndex)*3.26346,6.2634))); + int BitMask = int(0); - result.xyz += float(CountBits(SBitMask & (~BitMask)))/max(1.,Angle1-Angle2)*SAttrY *LightCoeff - *(pow(cos(Angle2*I64*PI),2.)-pow(cos(Angle1*I64*PI),2.)) - *sqrt(max(0.,dot(SNormal,-normalize(SVPPos-VPPos)))); + for (float s=1.; s<32.5; s++) { + //32 steps + vec2 SUV = fragCoord+SSDir*StepDist; + float CurrentStep = max(1.,StepDist*StepCoeff); + StepDist += CurrentStep; + if (DFBox(SUV-1.,resolutionFov.xy-1.)>0.) break; + vec4 SAttr = texture(lightPassBuffer,SUV*IRES); - //Update bitmask - BitMask = BitMask | SBitMask; + vec3 SVPPos = normalize(vec3((SUV*IRES*2.-1.)*(ASPECT*CFOV),1.))*SAttr.w; + float NorDot = dot(VNormal,SVPPos-VPPos)-0.001; + float TanDist = length(SVPPos-VPPos-NorDot*VNormal); + float Angle1f = atan(NorDot,TanDist); + float Angle2f = atan(NorDot-0.03*max(1.,StepDist*0.07),TanDist); + float Angle1 = max(0.,ceil(Angle1f/(PI*0.5)*32.)); + float Angle2 = max(0.,floor(Angle2f/(PI*0.5)*32.)); + int SBitMask = (int(pow(2.,Angle1-Angle2))-1) << int(Angle2); + vec3 SNormal = FloatToVec3(SAttr.z)*2.-1.; + SNormal = vec3(dot(SNormal,Tan),dot(SNormal,Bit),dot(SNormal,eyeAngles.xyz)); + Output.xyz += float(CountBits(SBitMask & (~BitMask)))/max(1.,Angle1-Angle2)*FloatToVec3(SAttr.x)*LightCoeff + *(pow(cos(Angle2*I64*PI),2.)-pow(cos(Angle1*I64*PI),2.)) + *sqrt(max(0.,dot(SNormal,-normalize(SVPPos-VPPos)))); + //Update bitmask + BitMask = BitMask | SBitMask; + } } } - } - - vec3 final = (result.xyz * 0.5) + (colour * 0.5); + else + { + Output.xyz = FloatToVec3(Attr.x) * LightCoeff; + } - outColor = result; + } + outColor = Output; } \ No newline at end of file diff --git a/examples/ssgi/shaders/SSGIold.frag b/examples/ssgi/shaders/SSGIold.frag new file mode 100644 index 0000000..86097f4 --- /dev/null +++ b/examples/ssgi/shaders/SSGIold.frag @@ -0,0 +1,116 @@ +#version 450 + +// Screen Space Horizon GI +// Adapted from https://www.shadertoy.com/view/dsGBzW +// which is an implementation of this paper: https://arxiv.org/pdf/2301.11376.pdf + +#include "SSGI.utils.glsl" + +layout(location = 0) in vec2 UV; + +layout(location = 0) out vec4 outColor; + +layout(push_constant, std430) uniform pc { + mat4 view; + mat4 proj; + vec4 resolutionFov; + vec4 eyePos; + int FrameIndex; +}; + +layout(binding = 0) uniform sampler2D positionBufferSampler; +layout(binding = 1) uniform sampler2D normalBufferSampler; +layout(binding = 2) uniform sampler2D lightPassImageSampler; +layout(binding = 3) uniform sampler2D depthImageSampler; + +// this counts the number of 1s in the binary representation of val +int CountBits(int val) +{ + val = (val&0x55555555)+((val>>1)&0x55555555); + val = (val&0x33333333)+((val>>2)&0x33333333); + val = (val&0x0F0F0F0F)+((val>>4)&0x0F0F0F0F); + val = (val&0x00FF00FF)+((val>>8)&0x00FF00FF); + val = (val&0x0000FFFF)+((val>>16)&0x0000FFFF); + return val; +} + +void main() { + vec4 result = vec4(0.0); + result.w = 1.0; + + float CurrentFrame = FrameIndex; + vec2 SSOffset = vec2(0.); + vec2 fragCoord = gl_FragCoord.xy; + // send these in push constant buffer + vec2 IRES = 1.0 / resolutionFov.xy; + float fov = resolutionFov[2]; + float CFOV = tan(fov); + vec2 ASPECT = vec2(resolutionFov.x/resolutionFov.y,1.0); + + + // sample gbuffer + vec3 colour = (texture(lightPassImageSampler, UV) * proj * view).xyz; + // vec3 position = texture(positionBufferSampler, UV).xyz; + vec3 position = (texture(positionBufferSampler, UV) * proj * view).xyz; + // vec3 normal = texture(normalBufferSampler, UV).xyz; + vec3 normal = (texture(normalBufferSampler, UV) * proj * view).xyz; + vec3 Tan = vec3(0.0); + vec3 Bit = TBN(eyePos.xyz, Tan); + mat3 EyeMat = TBN(eyePos.xyz); + + if(length(colour) > -0.5) + { + // Horizons (AKA wtf is happening) + // vec3 VNormal = vec3(dot(normal, Tan), dot(normal, Bit), dot(normal, eyePos.xyz)); + vec3 VNormal = normal; + // vec3 VPPos = vec3(dot(position, Tan), dot(position, Bit), dot(position, eyePos.xyz)); + vec3 VPPos = position; + // vec2 ModFC = mod(fragCoord, 4.0); + vec2 ModFC = fragCoord; + float RandPhiOffset = ARand21(vec2(1.234)+mod(CurrentFrame*3.26346,7.2634)); + float RandPhiMultiplier = 2 * PI * I64; + float RandPhi = (mod(floor(ModFC.x)+floor(ModFC.y)*4.0+CurrentFrame*5.0, 16.0) + RandPhiOffset) * RandPhiMultiplier; + + for(int i = 0; i < 4; i++) + { + RandPhi += PI * 0.5; + vec2 SSDir = vec2(cos(RandPhi), sin(RandPhi)); + float StepDist = 1.0; + float StepCoeff = 0.15+0.15*ARand21(fragCoord*IRES*(1.4+mod(CurrentFrame *3.26346,6.2634))); + int BitMask = 0; + + for (int s= 1; s < 32; s++) { + vec2 SUV = fragCoord+SSDir*StepDist; + float CurrentStep = max(1.,StepDist*StepCoeff); + StepDist += CurrentStep; + if (DFBox(SUV-1.,resolutionFov.xy-1.)>0.) break; + vec2 SAttrUV = SUV * IRES; + vec3 SAttrY = texture(lightPassImageSampler, SAttrUV * resolutionFov.xy).xyz; + if (length(SAttrY) <-1.5) continue; + vec3 SAttrZ = texture(normalBufferSampler, SAttrUV).xyz; + vec3 SVPPos = texture(positionBufferSampler, SAttrUV).xyz; + float NorDot = dot(VNormal, SVPPos - VPPos) - EPSILON; + float TanDist = length(SVPPos-VPPos-NorDot*VNormal); + float Angle1f = atan(NorDot,TanDist); + float Angle2f = atan(NorDot-0.03*max(1.,StepDist*0.07),TanDist); + float Angle1 = max(0.,ceil(Angle1f/(PI*0.5)*32.)); + float Angle2 = max(0.,floor(Angle2f/(PI*0.5)*32.)); + int SBitMask = (int(pow(2.,Angle1-Angle2))-1) << int(Angle2); + vec3 SNormal = SAttrZ *2.-1.; + SNormal = vec3(dot(SNormal,Tan),dot(SNormal,Bit),dot(SNormal,eyePos.xyz)); + + result.xyz += float(CountBits(SBitMask & (~BitMask)))/max(1.,Angle1-Angle2)*SAttrY *LightCoeff + *(pow(cos(Angle2*I64*PI),2.)-pow(cos(Angle1*I64*PI),2.)) + *sqrt(max(0.,dot(SNormal,-normalize(SVPPos-VPPos)))); + + //Update bitmask + BitMask = BitMask | SBitMask; + + } + } + } + + vec3 final = (result.xyz * 0.5) + (colour * 0.5); + + outColor = result; +} \ No newline at end of file diff --git a/examples/ssgi/shaders/lights.frag b/examples/ssgi/shaders/lights.frag index 7dac5b8..f820d87 100644 --- a/examples/ssgi/shaders/lights.frag +++ b/examples/ssgi/shaders/lights.frag @@ -156,6 +156,23 @@ void main() { //lightColour lightColour += BlinnPhong_Spot(i, position, normal, vec3(0.0f), textureColour.xyz, vec3(0.0f), 0.0f); } - - outColor = vec4(lightColour, 1.0); + vec3 emissiveness = vec3(0.0); + if(length(lightColour) > length(vec3(LightCoeff))) + { + emissiveness = lightColour; + } + else + { + emissiveness = vec3(1.0); + } + // emissiveness + float gbx = Vec3ToFloat(emissiveness); + // out colour as float + float gby = Vec3ToFloat(lightColour); + // pack normal to z + float gbz = Vec3ToFloat(normal); + // depth as w + float gbw = gl_FragCoord.z; + + outColor = vec4(gbx, gby, gbz, gbw); } \ No newline at end of file diff --git a/examples/ssgi/shaders/lights.frag.spv b/examples/ssgi/shaders/lights.frag.spv index 317ea78..4245d63 100644 Binary files a/examples/ssgi/shaders/lights.frag.spv and b/examples/ssgi/shaders/lights.frag.spv differ diff --git a/examples/ssgi/shaders/ssgi.frag.spv b/examples/ssgi/shaders/ssgi.frag.spv index 9c7f84b..a2f2dc5 100644 Binary files a/examples/ssgi/shaders/ssgi.frag.spv and b/examples/ssgi/shaders/ssgi.frag.spv differ diff --git a/lvk/src/lvk/Material.cpp b/lvk/src/lvk/Material.cpp index 79625d5..e33b752 100644 --- a/lvk/src/lvk/Material.cpp +++ b/lvk/src/lvk/Material.cpp @@ -123,7 +123,7 @@ lvk::Material lvk::Material::Create(VulkanAPI& vk, ShaderProgram& shader) VkWriteDescriptorSet write{}; write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; write.dstSet = mat.m_DescriptorSets.front().m_Sets[i]; - write.dstBinding = 1; + write.dstBinding = bindings[j]; write.dstArrayElement = 0; write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; write.descriptorCount = 1;