diff --git a/projects/voxelization/resources/shaders/brdf.inc b/projects/voxelization/resources/shaders/brdf.inc index fc97b6013c8c69ecc9f529151dd661ca5f18a328..4cf334eaceedd18815ab928aed38d5f8d3f51c1e 100644 --- a/projects/voxelization/resources/shaders/brdf.inc +++ b/projects/voxelization/resources/shaders/brdf.inc @@ -14,14 +14,14 @@ vec3 fresnelSchlick(float cosTheta, vec3 f0){ 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); + return r2 / max(denom, 0.00001); } 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); + return nom / max(denom, 0.00001); } float GGXSmithShadowing(float r, float NoV, float NoL){ diff --git a/projects/voxelization/resources/shaders/shader.frag b/projects/voxelization/resources/shaders/shader.frag index 2b3566912727bc5f48617252bc9240d3993962a4..13a9fa3d03a6d9ffac9d9ce541073378d3cd66c1 100644 --- a/projects/voxelization/resources/shaders/shader.frag +++ b/projects/voxelization/resources/shaders/shader.frag @@ -38,12 +38,13 @@ vec3 cookTorrance(vec3 f0, float r, vec3 N, vec3 V, vec3 L){ float NoH = clamp(dot(N, H), 0, 1); float NoL = clamp(dot(N, L), 0, 1); - float NoV = clamp(dot(N, V), 0, 1); + float NoV = clamp(abs(dot(N, V)), 0, 1); // abs to account for wrong visibility caused by normal mapping - vec3 F = fresnelSchlick(NoH, f0); - float D = GGXDistribution(r, NoH); - float G = GGXSmithShadowing(r, NoV, NoL); - return (F * D * G) / max(4 * NoV * NoL, 0.000001); + vec3 F = fresnelSchlick(NoH, f0); + float D = GGXDistribution(r, NoH); + float G = GGXSmithShadowing(r, NoV, NoL); + + return (F * D * G) / max(4 * NoV * NoL, 0.00001); } float roughnessToConeAngleDegree(float r){ @@ -56,6 +57,17 @@ float interleavedGradientNoise(vec2 uv){ return fract(magic.z * fract(dot(uv, magic.xy))); } +// from: https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile +vec3 EnvBRDFApprox(vec3 SpecularColor, float Roughness, float NoV ) +{ + const vec4 c0 = { -1, -0.0275, -0.572, 0.022 }; + const vec4 c1 = { 1, 0.0425, 1.04, -0.04 }; + vec4 r = Roughness * c0 + c1; + float a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y; + vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw; + return SpecularColor * AB.x + AB.y; +} + void main() { vec3 albedoTexel = texture(sampler2D(albedoTexture, textureSampler), passUV).rgb; @@ -74,17 +86,16 @@ void main() { vec3 B = cross(N_geo, T) * passTangent.w; mat3 TBN = mat3(T, B, N_geo); normalTexel = normalTexel * 2 - 1; - - vec3 N = TBN * normalTexel; + + vec3 N = normalize(TBN * normalTexel); vec3 L = lightInfo.L; vec3 V = normalize(cameraPos - passPos); float NoL = clamp(dot(N, L), 0, 1); - float NoV = clamp(dot(N, V), 0, 1); - - vec3 sunSpecular = cookTorrance(f0, r, N, V, L); + float NoV = clamp(abs(dot(N, V)), 0, 1); - vec3 sun = lightInfo.sunStrength * lightInfo.sunColor * NoL; + vec3 sunSpecular = cookTorrance(f0, r, N, V, L); + vec3 sun = lightInfo.sunStrength * lightInfo.sunColor * NoL; float noise = 2 * pi * interleavedGradientNoise(gl_FragCoord.xy); vec2 shadowOffset = 0.05f * vec2(sin(noise), cos(noise)) / textureSize(sampler2D(shadowMap, shadowMapSampler), 0); @@ -108,7 +119,7 @@ void main() { offsetTraceStart += R * interleavedGradientNoise(gl_FragCoord.xy) * 0.5; vec3 specularTrace = voxelConeTrace(R, offsetTraceStart, reflectionConeAngle, voxelTexture, voxelSampler, voxelInfo); specularTrace *= clamp(dot(N, R), 0, 1); - vec3 reflectionBRDF = cookTorrance(f0, r, N, V, R); + vec3 reflectionBRDF = EnvBRDFApprox(f0, r, NoV); outColor = (diffuse + sunSpecular) * sun + diff --git a/projects/voxelization/resources/shaders/shadowMapping.inc b/projects/voxelization/resources/shaders/shadowMapping.inc index 4755e7ec9183a8bd7184de8409c1edc959d993ea..c4bcd94e70766dfb4d403076f63007a37d3e868a 100644 --- a/projects/voxelization/resources/shaders/shadowMapping.inc +++ b/projects/voxelization/resources/shaders/shadowMapping.inc @@ -70,10 +70,10 @@ float reduceLightBleeding(float shadow, float amount) } float shadowTest(vec3 worldPos, LightInfo lightInfo, texture2D shadowMap, sampler shadowMapSampler, vec2 offset){ - vec4 lightPos = lightInfo.lightMatrix * vec4(worldPos, 1); - lightPos /= lightPos.w; - lightPos.xy = lightPos.xy * 0.5 + 0.5; - lightPos.xy += offset; + vec4 lightPos = lightInfo.lightMatrix * vec4(worldPos, 1); + lightPos /= lightPos.w; + lightPos.xy = lightPos.xy * 0.5 + 0.5; + lightPos.xy += offset; if(any(lessThan(lightPos.xy, vec2(0))) || any(greaterThan(lightPos.xy, vec2(1)))){ return 1; diff --git a/projects/voxelization/resources/shaders/sky.frag b/projects/voxelization/resources/shaders/sky.frag new file mode 100644 index 0000000000000000000000000000000000000000..2a3b2ad03e1936641a565b2f3fbd1f19f186ff7a --- /dev/null +++ b/projects/voxelization/resources/shaders/sky.frag @@ -0,0 +1,13 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) out vec3 outColor; + +layout( push_constant ) uniform constants{ + vec3 skyColor; + float skyStrength; +}; + +void main() { + outColor = skyColor * skyStrength; +} \ No newline at end of file diff --git a/projects/voxelization/resources/shaders/sky.vert b/projects/voxelization/resources/shaders/sky.vert new file mode 100644 index 0000000000000000000000000000000000000000..686e6f352e9bb1054656f58340a9cfc9b55fcff4 --- /dev/null +++ b/projects/voxelization/resources/shaders/sky.vert @@ -0,0 +1,12 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +const vec2 positions[3] = { + vec2(-1, -1), + vec2(-1, 4), + vec2(4, -1) +}; + +void main() { + gl_Position = vec4(positions[gl_VertexIndex], 1, 1); +} \ No newline at end of file diff --git a/projects/voxelization/resources/shaders/voxel.inc b/projects/voxelization/resources/shaders/voxel.inc index a22ea032ccd371f9f131aa007a2b793b2e6091c0..6133ca7cfc52ca77cb70fb8c2cc0e83ef6da4016 100644 --- a/projects/voxelization/resources/shaders/voxel.inc +++ b/projects/voxelization/resources/shaders/voxel.inc @@ -149,10 +149,8 @@ vec3 voxelConeTrace(vec3 direction, vec3 startPosition, float coneAngleRadian, t color += (1 - a) * voxelSample.rgb; a += (1 - a) * voxelSample.a; - float minStepSize = 1.5f; + float minStepSize = 1.f; d += max(coneDiameter, minStepSize); - samplePos = startPosition + d * direction; - sampleUV = worldToVoxelCoordinates(samplePos, voxelInfo); } return color; } diff --git a/projects/voxelization/src/main.cpp b/projects/voxelization/src/main.cpp index fa2b921d9eb88a6f526617e95ec5e5f66bbe808b..daf1211f4d728e7dd180fba06c7164cbd70de30b 100644 --- a/projects/voxelization/src/main.cpp +++ b/projects/voxelization/src/main.cpp @@ -286,6 +286,52 @@ int main(int argc, const char** argv) { return EXIT_FAILURE; } + // sky + struct SkySettings { + glm::vec3 color; + float strength; + }; + SkySettings skySettings; + skySettings.color = glm::vec3(0.15, 0.65, 1); + skySettings.strength = 5; + + const vkcv::AttachmentDescription skyColorAttachment( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::LOAD, + colorBufferFormat); + + const vkcv::AttachmentDescription skyDepthAttachments( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::LOAD, + depthBufferFormat); + + vkcv::PassConfig skyPassConfig({ skyColorAttachment, skyDepthAttachments }, msaa); + vkcv::PassHandle skyPass = core.createPass(skyPassConfig); + + vkcv::ShaderProgram skyShader; + compiler.compile(vkcv::ShaderStage::VERTEX, std::filesystem::path("resources/shaders/sky.vert"), + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + skyShader.addShader(shaderStage, path); + }); + compiler.compile(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/sky.frag"), + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + skyShader.addShader(shaderStage, path); + }); + + vkcv::PipelineConfig skyPipeConfig; + skyPipeConfig.m_ShaderProgram = skyShader; + skyPipeConfig.m_Width = windowWidth; + skyPipeConfig.m_Height = windowHeight; + skyPipeConfig.m_PassHandle = skyPass; + skyPipeConfig.m_VertexLayout = vkcv::VertexLayout({}); + skyPipeConfig.m_DescriptorLayouts = {}; + skyPipeConfig.m_UseDynamicViewport = true; + skyPipeConfig.m_multisampling = msaa; + skyPipeConfig.m_depthWrite = false; + + vkcv::PipelineHandle skyPipe = core.createGraphicsPipeline(skyPipeConfig); + + // render targets vkcv::ImageHandle depthBuffer = core.createImage(depthBufferFormat, windowWidth, windowHeight, 1, false, false, false, msaa).getHandle(); const bool colorBufferRequiresStorage = !usingMsaa; @@ -526,6 +572,15 @@ int main(int argc, const char** argv) { voxelization.renderVoxelVisualisation(cmdStream, viewProjectionCamera, renderTargets, voxelVisualisationMip); } + // sky + core.recordDrawcallsToCmdStream( + cmdStream, + skyPass, + skyPipe, + vkcv::PushConstantData((void*)&skySettings, sizeof(skySettings)), + { vkcv::DrawcallInfo(vkcv::Mesh({}, nullptr, 3), {}) }, + renderTargets); + const uint32_t fullscreenLocalGroupSize = 8; const uint32_t fulsscreenDispatchCount[3] = { static_cast<uint32_t>(glm::ceil(windowWidth / static_cast<float>(fullscreenLocalGroupSize))), @@ -581,6 +636,9 @@ int main(int argc, const char** argv) { ImGui::DragFloat("Max shadow distance", &maxShadowDistance); maxShadowDistance = std::max(maxShadowDistance, 1.f); + ImGui::ColorEdit3("Sky color", &skySettings.color.x); + ImGui::DragFloat("Sky strength", &skySettings.strength, 0.1); + ImGui::Checkbox("Draw voxel visualisation", &renderVoxelVis); ImGui::SliderInt("Visualisation mip", &voxelVisualisationMip, 0, 7); ImGui::DragFloat("Voxelization extent", &voxelizationExtent, 1.f, 0.f); diff --git a/src/vkcv/DrawcallRecording.cpp b/src/vkcv/DrawcallRecording.cpp index df7b7bbcb3fe278622cd160593eb750db00ec7b1..d28ea36c6108306fe603185e9848a72af6455606 100644 --- a/src/vkcv/DrawcallRecording.cpp +++ b/src/vkcv/DrawcallRecording.cpp @@ -27,12 +27,14 @@ namespace vkcv { // char* cast because void* does not support pointer arithmetic const void* drawcallPushConstantData = drawcallPushConstantOffset + (char*)pushConstantData.data; - cmdBuffer.pushConstants( - pipelineLayout, - vk::ShaderStageFlagBits::eAll, - 0, - pushConstantData.sizePerDrawcall, - drawcallPushConstantData); + if (pushConstantData.data && pushConstantData.sizePerDrawcall > 0) { + cmdBuffer.pushConstants( + pipelineLayout, + vk::ShaderStageFlagBits::eAll, + 0, + pushConstantData.sizePerDrawcall, + drawcallPushConstantData); + } if (drawcall.mesh.indexBuffer) { cmdBuffer.bindIndexBuffer(drawcall.mesh.indexBuffer, 0, vk::IndexType::eUint16); //FIXME: choose proper size diff --git a/src/vkcv/PipelineManager.cpp b/src/vkcv/PipelineManager.cpp index 1b05269a34f90d2df0f218dd6155c2ba85164db7..ca0f9225759cc7f4e16b1ba9596f2b9fd6275464 100644 --- a/src/vkcv/PipelineManager.cpp +++ b/src/vkcv/PipelineManager.cpp @@ -221,14 +221,18 @@ namespace vkcv { 1.f,1.f,1.f,1.f } ); - const size_t matrixPushConstantSize = config.m_ShaderProgram.getPushConstantSize(); - const vk::PushConstantRange pushConstantRange(vk::ShaderStageFlagBits::eAll, 0, matrixPushConstantSize); + const size_t pushConstantSize = config.m_ShaderProgram.getPushConstantSize(); + const vk::PushConstantRange pushConstantRange(vk::ShaderStageFlagBits::eAll, 0, pushConstantSize); // pipeline layout vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo( {}, (config.m_DescriptorLayouts), (pushConstantRange)); + if (pushConstantSize == 0) { + pipelineLayoutCreateInfo.pushConstantRangeCount = 0; + } + vk::PipelineLayout vkPipelineLayout{}; if (m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &vkPipelineLayout) != vk::Result::eSuccess)