diff --git a/projects/voxelization/resources/shaders/brdf.inc b/projects/voxelization/resources/shaders/brdf.inc new file mode 100644 index 0000000000000000000000000000000000000000..f8f1388bbda7bb5f6e90176bb503bf9209065147 --- /dev/null +++ b/projects/voxelization/resources/shaders/brdf.inc @@ -0,0 +1,26 @@ +const float pi = 3.1415; + +vec3 lambertBRDF(vec3 albedo){ + return albedo / pi; +} + +vec3 fresnelSchlick(float cosTheta, vec3 f0){ + return f0 + (vec3(1) - f0) * pow(1 - cosTheta, 5); +} + +float GGXDistribution(float r, float NoH){ + float r2 = r * r; + float denom = pi * pow(NoH * NoH * (r2 - 1) + 1, 2); + return r2 / max(denom, 0.000001); +} + +float GGXSmithShadowingPart(float r, float cosTheta){ + float nom = cosTheta * 2; + float r2 = r * r; + float denom = cosTheta + sqrt(r2 + (1 - r2) * cosTheta * cosTheta); + return nom / max(denom, 0.000001); +} + +float GGXSmithShadowing(float r, float NoV, float NoL){ + return GGXSmithShadowingPart(r, NoV) * GGXSmithShadowingPart(r, NoL); +} \ No newline at end of file diff --git a/projects/voxelization/resources/shaders/shader.frag b/projects/voxelization/resources/shaders/shader.frag index 445caea832331b510e33df21f9787a3be2d5099f..aba54a23963c02ef8ae08a7409e0ff83318f2039 100644 --- a/projects/voxelization/resources/shaders/shader.frag +++ b/projects/voxelization/resources/shaders/shader.frag @@ -5,6 +5,8 @@ #include "perMeshResources.inc" #include "lightInfo.inc" #include "shadowMapping.inc" +#include "brdf.inc" +#include "voxel.inc" layout(location = 0) in vec3 passNormal; layout(location = 1) in vec2 passUV; @@ -23,31 +25,51 @@ layout(set=0, binding=3) uniform cameraBuffer { vec3 cameraPos; }; -const float pi = 3.1415; +layout(set=0, binding=4) uniform texture3D voxelTexture; +layout(set=0, binding=5) uniform sampler voxelSampler; -vec3 lambertBRDF(vec3 albedo){ - return albedo / pi; -} - -vec3 fresnelSchlick(float cosTheta, vec3 f0){ - return f0 + (vec3(1) - f0) * pow(1 - cosTheta, 5); -} - -float GGXDistribution(float r, float NoH){ - float r2 = r * r; - float denom = pi * pow(NoH * NoH * (r2 - 1) + 1, 2); - return r2 / max(denom, 0.000001); -} +layout(set=0, binding=6) uniform VoxelInfoBuffer{ + VoxelInfo voxelInfo; +}; -float GGXSmithShadowingPart(float r, float cosTheta){ - float nom = cosTheta * 2; - float r2 = r * r; - float denom = cosTheta + sqrt(r2 + (1 - r2) * cosTheta * cosTheta); - return nom / max(denom, 0.000001); -} +vec3 voxelConeTrace(texture3D voxelTexture, sampler voxelSampler, vec3 direction, vec3 startPosition, float coneAngleRadian){ -float GGXSmithShadowing(float r, float NoV, float NoL){ - return GGXSmithShadowingPart(r, NoV) * GGXSmithShadowingPart(r, NoL); + int voxelResolution = textureSize(sampler3D(voxelTexture, voxelSampler), 0).x; + float voxelSize = voxelInfo.extent / voxelResolution; + float maxMip = float(log2(voxelResolution)); + float maxStableMip = 4; // must be the same as in Voxelization::voxelizeMeshes + maxMip = min(maxMip, maxStableMip); + float d = sqrt(3 * pow(voxelSize, 2)); + vec3 color = vec3(0); + float a = 0; + + float coneAngleHalf = coneAngleRadian * 0.5f; + + int maxSamples = 16; + for(int i = 0; i < maxSamples; i++){ + + vec3 samplePos = startPosition + d * direction; + vec3 sampleUV = worldToVoxelCoordinates(samplePos, voxelInfo); + + if(a >= 0.95 || any(lessThan(sampleUV, vec3(0))) || any(greaterThan(sampleUV, vec3(1)))){ + break; + } + + float coneDiameter = 2 * tan(coneAngleHalf) * d; + float mip = log2(coneDiameter / voxelSize); + mip = min(mip, maxMip); + + vec4 voxelSample = textureLod(sampler3D(voxelTexture, voxelSampler), sampleUV , mip); + + color += (1 - a) * voxelSample.rgb; + voxelSample.a = pow(voxelSample.a, 0.6); + a += (1 - a) * voxelSample.a; + + d += coneDiameter; + samplePos = startPosition + d * direction; + sampleUV = worldToVoxelCoordinates(samplePos, voxelInfo); + } + return color; } void main() { @@ -86,11 +108,31 @@ void main() { vec3 sun = lightInfo.sunStrength * lightInfo.sunColor * NoL; sun *= shadowTest(passPos, lightInfo, shadowMap, shadowMapSampler); - vec3 ambient = vec3(0.05); vec3 F_in = fresnelSchlick(NoL, f0); vec3 F_out = fresnelSchlick(NoV, f0); vec3 diffuse = lambertBRDF(albedo) * (1 - F_in) * (1 - F_out); - outColor = (diffuse + specular) * sun + lambertBRDF(albedo) * ambient; + vec3 up = N_geo.y >= 0.99 ? vec3(1, 0, 0) : vec3(0, 1, 0); + vec3 right = normalize(cross(up, N)); + up = cross(N, right); + mat3 toSurface = mat3(right, up, N); + + float coneAngle = 60.f / 180.f * pi; + vec3 diffuseTrace = vec3(0); + { + vec3 sampleDirection = toSurface * vec3(0, 0, 1); + float weight = pi / 4.f; + diffuseTrace += weight * voxelConeTrace(voxelTexture, voxelSampler, sampleDirection, passPos, coneAngle); + } + for(int i = 0; i < 6;i++){ + float theta = 2 * pi / i; + float phi = pi / 3; // 60 degrees + vec3 sampleDirection = toSurface * vec3(cos(theta) * sin(phi), sin(theta) * sin(phi), cos(phi)); + float weight = pi * (3.f / 4.f) / i; + diffuseTrace += voxelConeTrace(voxelTexture, voxelSampler, sampleDirection, passPos, coneAngle); + } + + outColor = (diffuse + specular) * sun + diffuse * diffuseTrace; + //outColor = diffuseTrace; } \ No newline at end of file diff --git a/projects/voxelization/resources/shaders/voxel.inc b/projects/voxelization/resources/shaders/voxel.inc index 25c0a82bbc887913a4d69ccdeee2b0d8934828c8..6a2441135754984fe05db42c8828bc98bf1570c2 100644 --- a/projects/voxelization/resources/shaders/voxel.inc +++ b/projects/voxelization/resources/shaders/voxel.inc @@ -7,6 +7,14 @@ uint flattenVoxelUVToIndex(ivec3 UV, ivec3 voxelImageSize){ return UV.x + UV.y * voxelImageSize.x + UV.z * voxelImageSize.x* voxelImageSize.y; } +vec3 worldToVoxelCoordinates(vec3 world, VoxelInfo info){ + return (world - info.offset) / info.extent + 0.5f; +} + +ivec3 voxelCoordinatesToUV(vec3 voxelCoordinates, ivec3 voxelImageResolution){ + return ivec3(voxelCoordinates * voxelImageResolution); +} + // packed voxel data: // 1 bit opacity // 7 bit exposure diff --git a/projects/voxelization/resources/shaders/voxelization.frag b/projects/voxelization/resources/shaders/voxelization.frag index a49b13185ec26b069661141cfdbbfbbe45d14fd3..59cd07e11a2d8e01ae6ddf3cced77b52b0eca17e 100644 --- a/projects/voxelization/resources/shaders/voxelization.frag +++ b/projects/voxelization/resources/shaders/voxelization.frag @@ -6,6 +6,7 @@ #include "perMeshResources.inc" #include "lightInfo.inc" #include "shadowMapping.inc" +#include "brdf.inc" layout(location = 0) in vec3 passPos; layout(location = 1) in vec2 passUV; @@ -28,14 +29,6 @@ layout(set=0, binding=3) uniform sunBuffer { layout(set=0, binding=4) uniform texture2D shadowMap; layout(set=0, binding=5) uniform sampler shadowMapSampler; -vec3 worldToVoxelCoordinates(vec3 world, VoxelInfo info){ - return (world - info.offset) / info.extent + 0.5f; -} - -ivec3 voxelCoordinatesToUV(vec3 voxelCoordinates, ivec3 voxelImageResolution){ - return ivec3(voxelCoordinates * voxelImageResolution); -} - void main() { vec3 voxelCoordinates = worldToVoxelCoordinates(passPos, voxelInfo); ivec3 voxelImageSize = imageSize(voxelImage); @@ -51,7 +44,7 @@ void main() { float NoL = clamp(dot(N, lightInfo.L), 0, 1); vec3 sun = lightInfo.sunStrength * lightInfo.sunColor * NoL * shadowTest(passPos, lightInfo, shadowMap, shadowMapSampler); vec3 color = albedo * sun; - color = albedo * sun; + color = lambertBRDF(albedo) * sun; atomicMax(packedVoxelData[flatIndex], packVoxelInfo(color)); } \ No newline at end of file diff --git a/projects/voxelization/src/Voxelization.cpp b/projects/voxelization/src/Voxelization.cpp index a04131cedfdc508e14a3dbd97da642e1af48f8da..15a6a8f5e3dfd4c0b78594cb8cf7f37c05ff1119 100644 --- a/projects/voxelization/src/Voxelization.cpp +++ b/projects/voxelization/src/Voxelization.cpp @@ -182,8 +182,9 @@ Voxelization::Voxelization( } void Voxelization::voxelizeMeshes( - vkcv::CommandStreamHandle cmdStream, - const glm::vec3& cameraPosition, + vkcv::CommandStreamHandle cmdStream, + const glm::vec3& cameraPosition, + const glm::vec3& cameraLookDirection, const std::vector<vkcv::Mesh>& meshes, const std::vector<glm::mat4>& modelMatrices, const std::vector<vkcv::DescriptorSetHandle>& perMeshDescriptorSets) { @@ -192,8 +193,12 @@ void Voxelization::voxelizeMeshes( voxelizationInfo.extent = m_voxelExtent; // move voxel offset with camera in voxel sized steps - const float voxelSize = m_voxelExtent / voxelResolution; - voxelizationInfo.offset = glm::floor(cameraPosition / voxelSize) * voxelSize; + const float voxelSize = m_voxelExtent / voxelResolution; + const int maxStableMip = 4; // must be the same as in voxelConeTrace shader function + const float snapSize = voxelSize * exp2(maxStableMip); + + const glm::vec3 voxelVolumeCenter = cameraPosition + (1.f / 3.f) * m_voxelExtent * cameraLookDirection; + voxelizationInfo.offset = glm::floor(voxelVolumeCenter / snapSize) * snapSize; m_voxelInfoBuffer.fill({ voxelizationInfo }); @@ -268,6 +273,7 @@ void Voxelization::voxelizeMeshes( m_corePtr->recordImageMemoryBarrier(cmdStream, m_voxelImage.getHandle()); m_voxelImage.recordMipChainGeneration(cmdStream); + m_corePtr->prepareImageForSampling(cmdStream, m_voxelImage.getHandle()); } void Voxelization::renderVoxelVisualisation( @@ -294,6 +300,7 @@ void Voxelization::renderVoxelVisualisation( vkcv::Mesh({}, nullptr, drawVoxelCount), { vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_visualisationDescriptorSet).vulkanHandle) }); + m_corePtr->prepareImageForStorage(cmdStream, m_voxelImage.getHandle()); m_corePtr->recordDrawcallsToCmdStream( cmdStream, m_visualisationPass, @@ -305,4 +312,12 @@ void Voxelization::renderVoxelVisualisation( void Voxelization::setVoxelExtent(float extent) { m_voxelExtent = extent; +} + +vkcv::ImageHandle Voxelization::getVoxelImageHandle() const { + return m_voxelImage.getHandle(); +} + +vkcv::BufferHandle Voxelization::getVoxelInfoBufferHandle() const { + return m_voxelInfoBuffer.getHandle(); } \ No newline at end of file diff --git a/projects/voxelization/src/Voxelization.hpp b/projects/voxelization/src/Voxelization.hpp index 25830b171edb9154e37b2d597c2bbbf2daea6b2e..bb0b5c5a91f59080d278a752e9637f32e194f620 100644 --- a/projects/voxelization/src/Voxelization.hpp +++ b/projects/voxelization/src/Voxelization.hpp @@ -17,8 +17,9 @@ public: vkcv::SamplerHandle shadowSampler); void voxelizeMeshes( - vkcv::CommandStreamHandle cmdStream, - const glm::vec3& cameraPosition, + vkcv::CommandStreamHandle cmdStream, + const glm::vec3& cameraPosition, + const glm::vec3& cameraLookDirection, const std::vector<vkcv::Mesh>& meshes, const std::vector<glm::mat4>& modelMatrices, const std::vector<vkcv::DescriptorSetHandle>& perMeshDescriptorSets); @@ -31,6 +32,9 @@ public: void setVoxelExtent(float extent); + vkcv::ImageHandle getVoxelImageHandle() const; + vkcv::BufferHandle getVoxelInfoBufferHandle() const; + private: vkcv::Core* m_corePtr; @@ -63,5 +67,5 @@ private: }; vkcv::Buffer<VoxelizationInfo> m_voxelInfoBuffer; - float m_voxelExtent = 20.f; + float m_voxelExtent = 30.f; }; \ No newline at end of file diff --git a/projects/voxelization/src/main.cpp b/projects/voxelization/src/main.cpp index 281faaf1d234aa0bf5e2b8fed6de56921904a9b4..57e25066c23119e3ed54054c7e0206e59c0496d8 100644 --- a/projects/voxelization/src/main.cpp +++ b/projects/voxelization/src/main.cpp @@ -168,16 +168,6 @@ int main(int argc, const char** argv) { vkcv::DescriptorSetHandle forwardShadingDescriptorSet = core.createDescriptorSet({ forwardProgram.getReflectedDescriptors()[0] }); - vkcv::Buffer<glm::vec3> cameraPosBuffer = core.createBuffer<glm::vec3>(vkcv::BufferType::UNIFORM, 1); - - vkcv::DescriptorWrites forwardDescriptorWrites; - forwardDescriptorWrites.uniformBufferWrites = { - vkcv::UniformBufferDescriptorWrite(0, lightBuffer.getHandle()), - vkcv::UniformBufferDescriptorWrite(3, cameraPosBuffer.getHandle()) }; - forwardDescriptorWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(1, shadowMap.getHandle()) }; - forwardDescriptorWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(2, shadowSampler) }; - core.writeDescriptorSet(forwardShadingDescriptorSet, forwardDescriptorWrites); - vkcv::SamplerHandle colorSampler = core.createSampler( vkcv::SamplerFilterType::LINEAR, vkcv::SamplerFilterType::LINEAR, @@ -251,7 +241,7 @@ int main(int argc, const char** argv) { perMeshDescriptorSets.push_back(materialDescriptorSets[vertexGroup.materialIndex]); } - const vkcv::PipelineConfig forwardPipelineConfig { + vkcv::PipelineConfig forwardPipelineConfig { forwardProgram, windowWidth, windowHeight, @@ -361,11 +351,33 @@ int main(int argc, const char** argv) { shadowMap.getHandle(), shadowSampler); + vkcv::Buffer<glm::vec3> cameraPosBuffer = core.createBuffer<glm::vec3>(vkcv::BufferType::UNIFORM, 1); + + vkcv::SamplerHandle voxelSampler = core.createSampler( + vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerMipmapMode::LINEAR, + vkcv::SamplerAddressMode::CLAMP_TO_EDGE); + + // write forward pass descriptor set + vkcv::DescriptorWrites forwardDescriptorWrites; + forwardDescriptorWrites.uniformBufferWrites = { + vkcv::UniformBufferDescriptorWrite(0, lightBuffer.getHandle()), + vkcv::UniformBufferDescriptorWrite(3, cameraPosBuffer.getHandle()), + vkcv::UniformBufferDescriptorWrite(6, voxelization.getVoxelInfoBufferHandle()) }; + forwardDescriptorWrites.sampledImageWrites = { + vkcv::SampledImageDescriptorWrite(1, shadowMap.getHandle()), + vkcv::SampledImageDescriptorWrite(4, voxelization.getVoxelImageHandle()) }; + forwardDescriptorWrites.samplerWrites = { + vkcv::SamplerDescriptorWrite(2, shadowSampler), + vkcv::SamplerDescriptorWrite(5, voxelSampler) }; + core.writeDescriptorSet(forwardShadingDescriptorSet, forwardDescriptorWrites); + vkcv::gui::GUI gui(core, window); glm::vec2 lightAngles(90.f, 0.f); int voxelVisualisationMip = 0; - float voxelizationExtent = 20.f; + float voxelizationExtent = 30.f; auto start = std::chrono::system_clock::now(); const auto appStartTime = start; @@ -454,6 +466,7 @@ int main(int argc, const char** argv) { voxelization.voxelizeMeshes( cmdStream, cameraManager.getActiveCamera().getPosition(), + cameraManager.getActiveCamera().getFront(), meshes, modelMatrices, perMeshDescriptorSets); @@ -501,7 +514,28 @@ int main(int argc, const char** argv) { ImGui::Checkbox("Draw voxel visualisation", &renderVoxelVis); ImGui::SliderInt("Visualisation mip", &voxelVisualisationMip, 0, 7); ImGui::DragFloat("Voxelization extent", &voxelizationExtent, 1.f, 0.f); + voxelizationExtent = std::max(voxelizationExtent, 1.f); voxelVisualisationMip = std::max(voxelVisualisationMip, 0); + + if (ImGui::Button("Reload forward pass")) { + + vkcv::ShaderProgram newForwardProgram; + compiler.compile(vkcv::ShaderStage::VERTEX, std::filesystem::path("resources/shaders/shader.vert"), + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + newForwardProgram.addShader(shaderStage, path); + }); + compiler.compile(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/shader.frag"), + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + newForwardProgram.addShader(shaderStage, path); + }); + forwardPipelineConfig.m_ShaderProgram = newForwardProgram; + vkcv::PipelineHandle newPipeline = core.createGraphicsPipeline(forwardPipelineConfig); + + if (newPipeline) { + forwardPipeline = newPipeline; + } + } + ImGui::End(); gui.endGUI();