diff --git a/projects/indirect_dispatch/resources/shaders/motionBlur.comp b/projects/indirect_dispatch/resources/shaders/motionBlur.comp index 58f95854a86f347a022c2f988d7ed6e163bd5248..43981689e9a5f8ed79f7e62ea8641a69609f16f6 100644 --- a/projects/indirect_dispatch/resources/shaders/motionBlur.comp +++ b/projects/indirect_dispatch/resources/shaders/motionBlur.comp @@ -12,8 +12,8 @@ layout(set=0, binding=5, r11f_g11f_b10f) uniform image2D outImage; layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; layout( push_constant ) uniform constants{ - float motionScaleFactor; // computed from delta time and shutter speed - float minVelocity; + // computed from delta time and shutter speed + float motionScaleFactor; // camera planes are needed to linearize depth float cameraNearPlane; float cameraFarPlane; @@ -76,12 +76,14 @@ vec2 processMotionVector(vec2 motion){ vec2 motionHalf = motion * 0.5; vec2 motionScaled = motionHalf * motionScaleFactor; // scale factor contains shutter speed and delta time - // pixels are anisotropic so the smaller dimension is used, so the clamping is conservative - float pixelSize = 1.f / max(imageSize(outImage).x, imageSize(outImage).y); - float velocity = length(motionScaled); - float epsilon = 0.0001; + float velocityPixels = length(motionScaled * imageSize(outImage)); + float epsilon = 0.0001; + + // pixels are anisotropic, so the ratio for clamping the velocity is computed in pixels instead of uv coordinates + vec2 motionPixel = motionScaled * imageSize(outImage); + // this clamps the motion to not exceed the radius given by the motion tile size - return motionScaled * max(0.5 * pixelSize, min(velocity, motionTileSize * pixelSize)) / (velocity + epsilon); + return motionScaled * max(0.5, min(velocityPixels, motionTileSize)) / (velocityPixels + epsilon); } SampleData loadSampleData(vec2 uv){ @@ -122,8 +124,8 @@ void main(){ SampleData mainPixel = loadSampleData(uv); - // early out on little movement - if(length(motionNeighbourhoodMax) <= minVelocity){ + // early out on movement less than half a pixel + if(length(motionNeighbourhoodMax * imageSize(outImage)) <= 0.5){ imageStore(outImage, coord, vec4(mainPixel.color, 0.f)); return; } diff --git a/projects/indirect_dispatch/src/App.cpp b/projects/indirect_dispatch/src/App.cpp index 60c3a075c85c33bd81876f12b1f7c268f130afb2..b27798b6573b24ecfdfc9b1087e070f5dd92d67c 100644 --- a/projects/indirect_dispatch/src/App.cpp +++ b/projects/indirect_dispatch/src/App.cpp @@ -94,7 +94,6 @@ void App::run() { float objectVerticalSpeed = 5; float objectAmplitude = 1; float objectMeanHeight = 1; - float motionBlurMinVelocity = 0.001; int cameraShutterSpeedInverse = 24; float motionVectorVisualisationRange = 0.008; @@ -114,7 +113,7 @@ void App::run() { sceneObjects.push_back(ground); Object sphere; - sphere.meshResources = m_sphereMesh; + sphere.meshResources = m_cubeMesh; sphere.modelMatrixUpdate = [&](float time, Object& obj) { const float currentHeight = objectMeanHeight + objectAmplitude * glm::sin(time * objectVerticalSpeed); obj.modelMatrix = glm::translate(glm::mat4(1), glm::vec3(0, currentHeight, 0)); @@ -249,8 +248,7 @@ void App::run() { cameraNear, cameraFar, fDeltaTimeSeconds, - cameraShutterSpeedInverse, - motionBlurMinVelocity); + cameraShutterSpeedInverse); } else { eMotionVectorMode debugViewMode; @@ -320,7 +318,6 @@ void App::run() { static_cast<int>(eMotionVectorMode::OptionCount)); ImGui::InputInt("Camera shutter speed inverse", &cameraShutterSpeedInverse); - ImGui::DragFloat("Motion blur min velocity", &motionBlurMinVelocity, 0.01, 0, 1); ImGui::InputFloat("Object movement speed", &objectVerticalSpeed); ImGui::InputFloat("Object movement amplitude", &objectAmplitude); diff --git a/projects/indirect_dispatch/src/MotionBlur.cpp b/projects/indirect_dispatch/src/MotionBlur.cpp index cc1bbc82a21b7bf19c6147d297230b8289c0d892..a731b8b91819057c6e39e9138efdec0c2ea7ad91 100644 --- a/projects/indirect_dispatch/src/MotionBlur.cpp +++ b/projects/indirect_dispatch/src/MotionBlur.cpp @@ -58,8 +58,7 @@ vkcv::ImageHandle MotionBlur::render( const float cameraNear, const float cameraFar, const float deltaTimeSeconds, - const float cameraShutterSpeedInverse, - const float motionBlurMinVelocity) { + const float cameraShutterSpeedInverse) { computeMotionTiles(cmdStream, motionBufferFullRes); @@ -92,16 +91,14 @@ vkcv::ImageHandle MotionBlur::render( // must match layout in "motionBlur.comp" struct MotionBlurConstantData { float motionFactor; - float minVelocity; float cameraNearPlane; float cameraFarPlane; }; MotionBlurConstantData motionBlurConstantData; - const float deltaTimeMotionBlur = std::max(deltaTimeSeconds, MotionBlurConfig::timeScaleMax); + const float deltaTimeMotionBlur = deltaTimeSeconds; motionBlurConstantData.motionFactor = 1 / (deltaTimeMotionBlur * cameraShutterSpeedInverse); - motionBlurConstantData.minVelocity = motionBlurMinVelocity; motionBlurConstantData.cameraNearPlane = cameraNear; motionBlurConstantData.cameraFarPlane = cameraFar; diff --git a/projects/indirect_dispatch/src/MotionBlur.hpp b/projects/indirect_dispatch/src/MotionBlur.hpp index ba72ea649a2bd0bd7643656e0a581be7c020f91c..a6232125d19e6c548796f62ae50b908a638585b5 100644 --- a/projects/indirect_dispatch/src/MotionBlur.hpp +++ b/projects/indirect_dispatch/src/MotionBlur.hpp @@ -31,8 +31,7 @@ public: const float cameraNear, const float cameraFar, const float deltaTimeSeconds, - const float cameraShutterSpeedInverse, - const float motionBlurMinVelocity); + const float cameraShutterSpeedInverse); vkcv::ImageHandle renderMotionVectorVisualisation( const vkcv::CommandStreamHandle cmdStream, diff --git a/projects/indirect_dispatch/src/MotionBlurConfig.hpp b/projects/indirect_dispatch/src/MotionBlurConfig.hpp index ecd7f8f8f4d65c0705e5fedd8ed37165261f87c3..bdeb8acf988118fbc084595cc880f281594c62b1 100644 --- a/projects/indirect_dispatch/src/MotionBlurConfig.hpp +++ b/projects/indirect_dispatch/src/MotionBlurConfig.hpp @@ -4,11 +4,5 @@ namespace MotionBlurConfig { const vk::Format motionVectorTileFormat = vk::Format::eR16G16Sfloat; const vk::Format outputColorFormat = vk::Format::eB10G11R11UfloatPack32; - const uint32_t maxMotionTileSize = 20; // must match "motionTileSize" in motionVectorMax.comp - - // small mouse movements are restricted to pixel level and therefore quite unprecise - // therefore extrapolating movement at high framerates results in big jerky movements - // this results in wide sudden motion blur, which looks quite bad - // as a workaround the time scale is limited to a maximum value - const float timeScaleMax = 1.f / 60; + const uint32_t maxMotionTileSize = 20; // must match "motionTileSize" in motionBlurConfig.inc } \ No newline at end of file