diff --git a/NEW_RELEASE_NOTES.md b/NEW_RELEASE_NOTES.md index 0c8949c7f20..4a1a9c7fa7e 100644 --- a/NEW_RELEASE_NOTES.md +++ b/NEW_RELEASE_NOTES.md @@ -7,5 +7,3 @@ for next branch cut* header. appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md). ## Release notes for next branch cut - -- utils: remove usages of `SpinLock`. Fixes b/321101014. diff --git a/README.md b/README.md index 8e93a38c314..9cd8235905f 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ repositories { } dependencies { - implementation 'com.google.android.filament:filament-android:1.50.0' + implementation 'com.google.android.filament:filament-android:1.50.1' } ``` @@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`: iOS projects can use CocoaPods to install the latest release: ```shell -pod 'Filament', '~> 1.50.0' +pod 'Filament', '~> 1.50.1' ``` ### Snapshots diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 9108461dbd4..c397c701ec3 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -7,6 +7,12 @@ A new header is inserted each time a *tag* is created. Instead, if you are authoring a PR for the main branch, add your release note to [NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md). +## v1.50.1 + +- Metal: fix some shader artifacts by disabling fast math optimizations. +- backend: remove `atan2` overload which had a typo and wasn't useful. Fixes b/320856413. +- utils: remove usages of `SpinLock`. Fixes b/321101014. + ## v1.50.0 - engine: TAA now supports 4x upscaling [BETA] [⚠️ **New Material Version**] diff --git a/android/filament-android/src/main/java/com/google/android/filament/View.java b/android/filament-android/src/main/java/com/google/android/filament/View.java index 81ecaddf3b9..28cb268c233 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/View.java +++ b/android/filament-android/src/main/java/com/google/android/filament/View.java @@ -1637,6 +1637,10 @@ public enum Filter { * circle of confusion scale factor (amount of blur) */ public float cocScale = 1.0f; + /** + * width/height aspect ratio of the circle of confusion (simulate anamorphic lenses) + */ + public float cocAspectRatio = 1.0f; /** * maximum aperture diameter in meters (zero to disable rotation) */ @@ -1921,6 +1925,7 @@ public enum JitterPattern { UNIFORM_HELIX_X4, HALTON_23_X8, HALTON_23_X16, + HALTON_23_X32, } /** @@ -1935,6 +1940,10 @@ public enum JitterPattern { * texturing lod bias (typically -1 or -2) */ public float lodBias = -1.0f; + /** + * post-TAA sharpen, especially useful when upscaling is true. + */ + public float sharpness = 0.0f; /** * enables or disables temporal anti-aliasing */ diff --git a/android/gradle.properties b/android/gradle.properties index 43efb083965..fd1dedad41d 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,5 +1,5 @@ GROUP=com.google.android.filament -VERSION_NAME=1.50.0 +VERSION_NAME=1.50.1 POM_DESCRIPTION=Real-time physically based rendering engine for Android. diff --git a/filament/backend/include/backend/Platform.h b/filament/backend/include/backend/Platform.h index dac1e37630c..ab7a4ee115d 100644 --- a/filament/backend/include/backend/Platform.h +++ b/filament/backend/include/backend/Platform.h @@ -41,18 +41,24 @@ class UTILS_PUBLIC Platform { struct Stream {}; struct DriverConfig { - /* - * size of handle arena in bytes. Setting to 0 indicates default value is to be used. + /** + * Size of handle arena in bytes. Setting to 0 indicates default value is to be used. * Driver clamps to valid values. */ size_t handleArenaSize = 0; - /* - * this number of most-recently destroyed textures will be tracked for use-after-free. + /** + * This number of most-recently destroyed textures will be tracked for use-after-free. * Throws an exception when a texture is freed but still bound to a SamplerGroup and used in * a draw call. 0 disables completely. Currently only respected by the Metal backend. */ size_t textureUseAfterFreePoolSize = 0; + + /** + * Set to `true` to forcibly disable parallel shader compilation in the backend. + * Currently only honored by the GL backend. + */ + bool disableParallelShaderCompile = false; }; Platform() noexcept; diff --git a/filament/backend/src/metal/MetalShaderCompiler.mm b/filament/backend/src/metal/MetalShaderCompiler.mm index 7f4280979ab..7bea1e21037 100644 --- a/filament/backend/src/metal/MetalShaderCompiler.mm +++ b/filament/backend/src/metal/MetalShaderCompiler.mm @@ -103,10 +103,19 @@ bool isReady() const noexcept { NSString* objcSource = [[NSString alloc] initWithBytes:source.data() length:source.size() - 1 encoding:NSUTF8StringEncoding]; + + // By default, Metal uses the most recent language version. + MTLCompileOptions* options = [MTLCompileOptions new]; + + // Disable Fast Math optimizations. + // This ensures that operations adhere to IEEE standards for floating-point arithmetic, + // which is crucial for half precision floats in scenarios where fast math optimizations + // lead to inaccuracies, such as in handling special values like NaN or Infinity. + options.fastMathEnabled = NO; + NSError* error = nil; - // When options is nil, Metal uses the most recent language version available. id library = [device newLibraryWithSource:objcSource - options:nil + options:options error:&error]; if (library == nil) { if (error) { diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp index 32494a9cf8d..1d3e06282c4 100644 --- a/filament/backend/src/opengl/OpenGLDriver.cpp +++ b/filament/backend/src/opengl/OpenGLDriver.cpp @@ -147,9 +147,9 @@ Driver* OpenGLDriver::create(OpenGLPlatform* const platform, #endif size_t const defaultSize = FILAMENT_OPENGL_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U; - Platform::DriverConfig validConfig {driverConfig}; + Platform::DriverConfig validConfig{ driverConfig }; validConfig.handleArenaSize = std::max(driverConfig.handleArenaSize, defaultSize); - OpenGLDriver* const driver = new OpenGLDriver(ec, validConfig); + OpenGLDriver* const driver = new(std::nothrow) OpenGLDriver(ec, validConfig); return driver; } @@ -171,7 +171,8 @@ OpenGLDriver::OpenGLDriver(OpenGLPlatform* platform, const Platform::DriverConfi mContext(), mShaderCompilerService(*this), mHandleAllocator("Handles", driverConfig.handleArenaSize), - mSamplerMap(32) { + mSamplerMap(32), + mDriverConfig(driverConfig) { std::fill(mSamplerBindings.begin(), mSamplerBindings.end(), nullptr); diff --git a/filament/backend/src/opengl/OpenGLDriver.h b/filament/backend/src/opengl/OpenGLDriver.h index 04e003fb3da..74f311a962e 100644 --- a/filament/backend/src/opengl/OpenGLDriver.h +++ b/filament/backend/src/opengl/OpenGLDriver.h @@ -400,6 +400,9 @@ class OpenGLDriver final : public DriverBase { // timer query implementation OpenGLTimerQueryInterface* mTimerQueryImpl = nullptr; + const Platform::DriverConfig mDriverConfig; + Platform::DriverConfig const& getDriverConfig() const noexcept { return mDriverConfig; } + // for ES2 sRGB support GLSwapChain* mCurrentDrawSwapChain = nullptr; bool mRec709OutputColorspace = false; diff --git a/filament/backend/src/opengl/ShaderCompilerService.cpp b/filament/backend/src/opengl/ShaderCompilerService.cpp index 64b9df2f49a..cf5c900c9d5 100644 --- a/filament/backend/src/opengl/ShaderCompilerService.cpp +++ b/filament/backend/src/opengl/ShaderCompilerService.cpp @@ -151,6 +151,12 @@ bool ShaderCompilerService::isParallelShaderCompileSupported() const noexcept { } void ShaderCompilerService::init() noexcept { + if (UTILS_UNLIKELY(mDriver.getDriverConfig().disableParallelShaderCompile)) { + // user disabled parallel shader compile + mMode = Mode::SYNCHRONOUS; + return; + } + // Here we decide which mode we'll be using. We always prefer our own thread-pool if // that mode is available because, we have no control on how the compilation queues are // handled if done by the driver (so at the very least we'd need to decode this per-driver). diff --git a/filament/backend/src/opengl/ShaderCompilerService.h b/filament/backend/src/opengl/ShaderCompilerService.h index 138a7773e4d..edd89aafdbb 100644 --- a/filament/backend/src/opengl/ShaderCompilerService.h +++ b/filament/backend/src/opengl/ShaderCompilerService.h @@ -109,7 +109,7 @@ class ShaderCompilerService { }; enum class Mode { - UNDEFINED, // init() has not beed called yet. + UNDEFINED, // init() has not been called yet. SYNCHRONOUS, // synchronous shader compilation THREAD_POOL, // asynchronous shader compilation using a thread-pool (most common) ASYNCHRONOUS // asynchronous shader compilation using KHR_parallel_shader_compile diff --git a/filament/include/filament/Options.h b/filament/include/filament/Options.h index 0ad6bb58645..450bbc10625 100644 --- a/filament/include/filament/Options.h +++ b/filament/include/filament/Options.h @@ -293,6 +293,7 @@ struct DepthOfFieldOptions { MEDIAN }; float cocScale = 1.0f; //!< circle of confusion scale factor (amount of blur) + float cocAspectRatio = 1.0f; //!< width/height aspect ratio of the circle of confusion (simulate anamorphic lenses) float maxApertureDiameter = 0.01f; //!< maximum aperture diameter in meters (zero to disable rotation) bool enabled = false; //!< enable or disable depth of field effect Filter filter = Filter::MEDIAN; //!< filter to use for filling gaps in the kernel @@ -437,6 +438,7 @@ struct TemporalAntiAliasingOptions { float filterWidth = 1.0f; //!< reconstruction filter width typically between 0.2 (sharper, aliased) and 1.5 (smoother) float feedback = 0.12f; //!< history feedback, between 0 (maximum temporal AA) and 1 (no temporal AA). float lodBias = -1.0f; //!< texturing lod bias (typically -1 or -2) + float sharpness = 0.0f; //!< post-TAA sharpen, especially useful when upscaling is true. bool enabled = false; //!< enables or disables temporal anti-aliasing bool upscaling = false; //!< 4x TAA upscaling. Disables Dynamic Resolution. [BETA] @@ -456,7 +458,8 @@ struct TemporalAntiAliasingOptions { RGSS_X4, //! 4-samples, rotated grid sampling UNIFORM_HELIX_X4, //! 4-samples, uniform grid in helix sequence HALTON_23_X8, //! 8-samples of halton 2,3 - HALTON_23_X16 //! 16-samples of halton 2,3 + HALTON_23_X16, //! 16-samples of halton 2,3 + HALTON_23_X32 //! 32-samples of halton 2,3 }; bool filterHistory = true; //!< whether to filter the history buffer diff --git a/filament/src/PostProcessManager.cpp b/filament/src/PostProcessManager.cpp index a61c155e694..9b29fe132d9 100644 --- a/filament/src/PostProcessManager.cpp +++ b/filament/src/PostProcessManager.cpp @@ -64,6 +64,7 @@ #include #include #include +#include #include #include @@ -74,6 +75,7 @@ #include #include +#include #include #include #include @@ -113,7 +115,7 @@ PostProcessManager::PostProcessMaterial::PostProcessMaterial() noexcept { } PostProcessManager::PostProcessMaterial::PostProcessMaterial(MaterialInfo const& info) noexcept - : PostProcessMaterial() { + : PostProcessMaterial() { mData = info.data; // aliased to mMaterial mSize = info.size; mConstants = info.constants; @@ -165,7 +167,7 @@ void PostProcessManager::PostProcessMaterial::loadMaterial(FEngine& engine) cons mHasMaterial = true; auto builder = Material::Builder(); builder.package(mData, mSize); - for (auto const& constant : mConstants) { + for (auto const& constant: mConstants) { std::visit([&](auto&& arg) { builder.constant(constant.name.data(), constant.name.size(), arg); }, constant.value); @@ -187,63 +189,60 @@ PipelineState PostProcessManager::PostProcessMaterial::getPipelineState( FMaterial* const material = getMaterial(engine); material->prepareProgram(Variant{ variantKey }); return { - .program = material->getProgram(Variant{variantKey}), + .program = material->getProgram(Variant{ variantKey }), .rasterState = material->getRasterState(), .scissor = material->getDefaultInstance()->getScissor() }; } UTILS_NOINLINE -FMaterialInstance* PostProcessManager::PostProcessMaterial::getMaterialInstance(FEngine& engine) const noexcept { +FMaterialInstance* PostProcessManager::PostProcessMaterial::getMaterialInstance( + FEngine& engine) const noexcept { FMaterial* const material = getMaterial(engine); return material->getDefaultInstance(); } // ------------------------------------------------------------------------------------------------ -const PostProcessManager::JitterSequence<4> PostProcessManager::sRGSS4 = {{ +const PostProcessManager::JitterSequence<4> PostProcessManager::sRGSS4 = {{{ { 0.625f, 0.125f }, { 0.125f, 0.375f }, { 0.875f, 0.625f }, { 0.375f, 0.875f } -}}; +}}}; -const PostProcessManager::JitterSequence<4> PostProcessManager::sUniformHelix4 = {{ +const PostProcessManager::JitterSequence<4> PostProcessManager::sUniformHelix4 = {{{ { 0.25f, 0.25f }, { 0.75f, 0.75f }, { 0.25f, 0.75f }, { 0.75f, 0.25f }, -}}; - -const PostProcessManager::JitterSequence<16> PostProcessManager::sHaltonSamples = {{ - { filament::halton( 0, 2), filament::halton( 0, 3) }, - { filament::halton( 1, 2), filament::halton( 1, 3) }, - { filament::halton( 2, 2), filament::halton( 2, 3) }, - { filament::halton( 3, 2), filament::halton( 3, 3) }, - { filament::halton( 4, 2), filament::halton( 4, 3) }, - { filament::halton( 5, 2), filament::halton( 5, 3) }, - { filament::halton( 6, 2), filament::halton( 6, 3) }, - { filament::halton( 7, 2), filament::halton( 7, 3) }, - { filament::halton( 8, 2), filament::halton( 8, 3) }, - { filament::halton( 9, 2), filament::halton( 9, 3) }, - { filament::halton(10, 2), filament::halton(10, 3) }, - { filament::halton(11, 2), filament::halton(11, 3) }, - { filament::halton(12, 2), filament::halton(12, 3) }, - { filament::halton(13, 2), filament::halton(13, 3) }, - { filament::halton(14, 2), filament::halton(14, 3) }, - { filament::halton(15, 2), filament::halton(15, 3) } -}}; +}}}; + +template +constexpr auto halton() { + std::array h; + for (size_t i = 0; i < COUNT; i++) { + h[i] = { + filament::halton(i, 2), + filament::halton(i, 3) }; + } + return h; +} + +const PostProcessManager::JitterSequence<32> + PostProcessManager::sHaltonSamples = { halton<32>() }; PostProcessManager::PostProcessManager(FEngine& engine) noexcept : mEngine(engine), - mWorkaroundSplitEasu(false), - mWorkaroundAllowReadOnlyAncillaryFeedbackLoop(false) { + mWorkaroundSplitEasu(false), + mWorkaroundAllowReadOnlyAncillaryFeedbackLoop(false) { } PostProcessManager::~PostProcessManager() noexcept = default; UTILS_NOINLINE -void PostProcessManager::registerPostProcessMaterial(std::string_view name, MaterialInfo const& info) { +void PostProcessManager::registerPostProcessMaterial(std::string_view name, + MaterialInfo const& info) { mMaterialRegistry.try_emplace(name, info); } @@ -326,13 +325,13 @@ void PostProcessManager::init() noexcept { driver.isWorkaroundNeeded(Workaround::ALLOW_READ_ONLY_ANCILLARY_FEEDBACK_LOOP); #pragma nounroll - for (auto const& info : sMaterialListFeatureLevel0) { + for (auto const& info: sMaterialListFeatureLevel0) { registerPostProcessMaterial(info.name, info); } if (mEngine.getActiveFeatureLevel() >= FeatureLevel::FEATURE_LEVEL_1) { #pragma nounroll - for (auto const& info : sMaterialList) { + for (auto const& info: sMaterialList) { registerPostProcessMaterial(info.name, info); } } @@ -1428,7 +1427,7 @@ FrameGraphId PostProcessManager::dof(FrameGraph& fg, FrameGraphId depth, const CameraInfo& cameraInfo, bool translucent, - float bokehAspectRatio, + float2 bokehScale, const DepthOfFieldOptions& dofOptions) noexcept { assert_invariant(depth); @@ -1683,8 +1682,8 @@ FrameGraphId PostProcessManager::dof(FrameGraph& fg, // we assume the width/height is already multiple of 16 assert_invariant(!(colorDesc.width & 0xF) && !(colorDesc.height & 0xF)); - const uint32_t tileBufferWidth = colorDesc.width / dofResolution; - const uint32_t tileBufferHeight = colorDesc.height / dofResolution; + const uint32_t tileBufferWidth = width; + const uint32_t tileBufferHeight = height; const size_t tileReductionCount = ctz(tileSize / dofResolution); struct PostProcessDofTiling1 { @@ -1818,8 +1817,8 @@ FrameGraphId PostProcessManager::dof(FrameGraph& fg, mi->setParameter("tiles", tilesCocMinMax, { .filterMin = SamplerMinFilter::NEAREST }); mi->setParameter("cocToTexelScale", float2{ - bokehAspectRatio / (inputDesc.width * dofResolution), - 1.0 / (inputDesc.height * dofResolution) + bokehScale.x / (inputDesc.width * dofResolution), + bokehScale.y / (inputDesc.height * dofResolution) }); mi->setParameter("cocToPixelScale", (1.0f / float(dofResolution))); mi->setParameter("ringCounts", float4{ @@ -2569,6 +2568,8 @@ void PostProcessManager::prepareTaa(FrameGraph& fg, case JitterPattern::HALTON_23_X8: return sHaltonSamples(frameIndex % 8); case JitterPattern::HALTON_23_X16: + return sHaltonSamples(frameIndex % 16); + case JitterPattern::HALTON_23_X32: return sHaltonSamples(frameIndex); } }; @@ -2618,6 +2619,7 @@ void PostProcessManager::configureTemporalAntiAliasingMaterial( } }; + setConstantParameter(ma, "upscaling", taaOptions.upscaling); setConstantParameter(ma, "historyReprojection", taaOptions.historyReprojection); setConstantParameter(ma, "filterHistory", taaOptions.filterHistory); setConstantParameter(ma, "filterInput", taaOptions.filterInput); @@ -2767,24 +2769,77 @@ FrameGraphId PostProcessManager::taa(FrameGraph& fg, }); input = colorGradingConfig.asSubpass ? taaPass->tonemappedOutput : taaPass->output; + auto history = input; + + // optional sharpen pass from FSR1 + if (taaOptions.sharpness > 0.0f) { + input = rcas(fg, taaOptions.sharpness, + input, fg.getDescriptor(input), colorGradingConfig.translucent); + } struct ExportColorHistoryData { FrameGraphId color; }; - auto& exportHistoryPass = fg.addPass("Export TAA history", + fg.addPass("Export TAA history", [&](FrameGraph::Builder& builder, auto& data) { // We need to use sideEffect here to ensure this pass won't be culled. // The "output" of this pass is going to be used during the next frame as // an "import". builder.sideEffect(); - data.color = builder.sample(input); // FIXME: an access must be declared for detach(), why? - }, [¤t](FrameGraphResources const& resources, auto const& data, - backend::DriverApi&) { - resources.detach(data.color, - ¤t.color, ¤t.desc); + data.color = builder.sample(history); // FIXME: an access must be declared for detach(), why? + }, [¤t](FrameGraphResources const& resources, auto const& data, auto&) { + resources.detach(data.color, ¤t.color, ¤t.desc); }); - return exportHistoryPass->color; + return input; +} + +FrameGraphId PostProcessManager::rcas( + FrameGraph& fg, + float sharpness, + FrameGraphId input, + FrameGraphTexture::Descriptor const& outDesc, + bool translucent) { + + struct QuadBlitData { + FrameGraphId input; + FrameGraphId output; + }; + + auto& ppFsrRcas = fg.addPass("FidelityFX FSR1 Rcas", + [&](FrameGraph::Builder& builder, auto& data) { + data.input = builder.sample(input); + data.input = builder.createTexture("FFX FSR1 Rcas output", outDesc); + data.input = builder.declareRenderPass(data.input); + }, + [=](FrameGraphResources const& resources, + auto const& data, DriverApi& driver) { + + auto input = resources.getTexture(data.input); + auto out = resources.getRenderPassInfo(); + auto const& outputDesc = resources.getDescriptor(data.input); + + auto& material = getPostProcessMaterial("fsr_rcas"); + FMaterialInstance* const mi = material.getMaterialInstance(mEngine); + + FSRUniforms uniforms; + FSR_SharpeningSetup(&uniforms, { .sharpness = 2.0f - 2.0f * sharpness }); + mi->setParameter("RcasCon", uniforms.RcasCon); + mi->setParameter("color", input, {}); // uses texelFetch + mi->setParameter("resolution", float4{ + outputDesc.width, outputDesc.height, + 1.0f / outputDesc.width, 1.0f / outputDesc.height }); + mi->commit(driver); + mi->use(driver); + + const uint8_t variant = uint8_t( + translucent ? PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE); + + PipelineState const pipeline(material.getPipelineState(mEngine, variant)); + render(out, pipeline, driver); + }); + + return ppFsrRcas->output; } FrameGraphId PostProcessManager::upscale(FrameGraph& fg, bool translucent, @@ -2947,41 +3002,9 @@ FrameGraphId PostProcessManager::upscale(FrameGraph& fg, bool auto output = ppQuadBlit->output; // if we had to take the low quality fallback, we still do the "sharpen pass" - if (dsrOptions.sharpness > 0.0f && (dsrOptions.quality != QualityLevel::LOW || lowQualityFallback)) { - auto& ppFsrRcas = fg.addPass("FidelityFX FSR1 Rcas", - [&](FrameGraph::Builder& builder, auto& data) { - data.input = builder.sample(output); - data.output = builder.createTexture("FFX FSR1 Rcas output", outDesc); - data.output = builder.declareRenderPass(data.output); - }, - [=](FrameGraphResources const& resources, - auto const& data, DriverApi& driver) { - - auto color = resources.getTexture(data.input); - auto out = resources.getRenderPassInfo(); - auto const& outputDesc = resources.getDescriptor(data.output); - - auto& material = getPostProcessMaterial("fsr_rcas"); - FMaterialInstance* const mi = material.getMaterialInstance(mEngine); - - FSRUniforms uniforms; - FSR_SharpeningSetup(&uniforms, { .sharpness = 2.0f - 2.0f * dsrOptions.sharpness }); - mi->setParameter("RcasCon", uniforms.RcasCon); - mi->setParameter("color", color, { }); // uses texelFetch - mi->setParameter("resolution", float4{ - outputDesc.width, outputDesc.height, - 1.0f / outputDesc.width, 1.0f / outputDesc.height }); - mi->commit(driver); - mi->use(driver); - - const uint8_t variant = uint8_t(translucent ? - PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE); - - PipelineState const pipeline(material.getPipelineState(mEngine, variant)); - render(out, pipeline, driver); - }); - - output = ppFsrRcas->output; + if (dsrOptions.sharpness > 0.0f && + (dsrOptions.quality != QualityLevel::LOW || lowQualityFallback)) { + output = rcas(fg, dsrOptions.sharpness, output, outDesc, translucent); } // we rely on automatic culling of unused render passes diff --git a/filament/src/PostProcessManager.h b/filament/src/PostProcessManager.h index df50e9b1843..bcffc50a017 100644 --- a/filament/src/PostProcessManager.h +++ b/filament/src/PostProcessManager.h @@ -36,6 +36,7 @@ #include +#include #include #include #include @@ -162,7 +163,7 @@ class PostProcessManager { FrameGraphId depth, const CameraInfo& cameraInfo, bool translucent, - float bokehAspectRatio, + math::float2 bokehScale, const DepthOfFieldOptions& dofOptions) noexcept; // Bloom @@ -241,6 +242,13 @@ class PostProcessManager { filament::Viewport const& vp, FrameGraphTexture::Descriptor const& outDesc, backend::SamplerMagFilter filter) noexcept; + FrameGraphId rcas( + FrameGraph& fg, + float sharpness, + FrameGraphId input, + FrameGraphTexture::Descriptor const& outDesc, + bool translucent); + // upscale/downscale blitter using shaders FrameGraphId blit(FrameGraph& fg, bool translucent, FrameGraphId input, @@ -362,12 +370,12 @@ class PostProcessManager { template struct JitterSequence { auto operator()(size_t i) const noexcept { return positions[i % SIZE] - 0.5f; } - const math::float2 positions[SIZE]; + const std::array positions; }; static const JitterSequence<4> sRGSS4; static const JitterSequence<4> sUniformHelix4; - static const JitterSequence<16> sHaltonSamples; + static const JitterSequence<32> sHaltonSamples; bool mWorkaroundSplitEasu : 1; bool mWorkaroundAllowReadOnlyAncillaryFeedbackLoop : 1; diff --git a/filament/src/details/Renderer.cpp b/filament/src/details/Renderer.cpp index db3a668992c..3c7567295b5 100644 --- a/filament/src/details/Renderer.cpp +++ b/filament/src/details/Renderer.cpp @@ -985,8 +985,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) { auto& history = view.getFrameHistory(); auto& current = history.getCurrent(); current.ssr.projection = projection; - resources.detach(data.history, - ¤t.ssr.color, ¤t.ssr.desc); + resources.detach(data.history, ¤t.ssr.color, ¤t.ssr.desc); }); } @@ -1043,9 +1042,13 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) { // The bokeh height is always correct regardless of the dynamic resolution scaling. // (because the CoC is calculated w.r.t. the height), so we only need to adjust // the width. - float const bokehAspectRatio = scale.x / scale.y; + float const aspect = (scale.x / scale.y) * dofOptions.cocAspectRatio; + float2 const bokehScale{ + aspect < 1.0f ? aspect : 1.0f, + aspect > 1.0f ? 1.0f / aspect : 1.0f + }; input = ppm.dof(fg, input, depth, cameraInfo, needsAlphaChannel, - bokehAspectRatio, dofOptions); + bokehScale, dofOptions); } FrameGraphId bloom, flare; diff --git a/filament/src/fg/details/Resource.h b/filament/src/fg/details/Resource.h index 966b4bc3388..6c3bffaf581 100644 --- a/filament/src/fg/details/Resource.h +++ b/filament/src/fg/details/Resource.h @@ -132,7 +132,7 @@ class Resource : public VirtualResource { Descriptor descriptor; SubResourceDescriptor subResourceDescriptor; - // weather the resource was detached + // whether the resource was detached bool detached = false; // An Edge with added data from this resource diff --git a/filament/src/materials/antiAliasing/taa.mat b/filament/src/materials/antiAliasing/taa.mat index efb089c29f1..b5430378c70 100644 --- a/filament/src/materials/antiAliasing/taa.mat +++ b/filament/src/materials/antiAliasing/taa.mat @@ -34,6 +34,11 @@ material { } ], constants : [ + { + type : bool, + name : upscaling, + default : false + }, { type : bool, name : historyReprojection, @@ -109,12 +114,41 @@ fragment { // no clipping (for debugging only) #define BOX_CLIPPING_NONE 2 -float luma(const vec3 color) { - if (materialConstants_useYCoCg) { - return color.x; - } else { - return luminance(color); - } +float rcp(float x) { + return 1.0 / x; +} + +float lumaRGB(const vec3 c) { + return luminance(c); +} + +float lumaYCoCg(const vec3 c) { + return c.x; +} + +float luma(const vec3 c) { + return materialConstants_useYCoCg ? lumaYCoCg(c) : lumaRGB(c); +} + +vec3 tonemap(const vec3 c) { + return c * rcp(1.0 + max3(c)); +} + +vec4 tonemap(const vec4 c) { + return vec4(c.rgb * rcp(1.0 + max3(c.rgb)), c.a); +} + +vec3 tonemap(const float w, const vec3 c) { + return c * (w * rcp(1.0 + max3(c))); +} + +vec4 tonemap(const float w, const vec4 c) { + return vec4(c.rgb * (w * rcp(1.0 + max3(c.rgb))), c.a); +} + +vec3 untonemap(const vec3 c) { + const float epsilon = 1.0 / 65504.0; + return c * rcp(max(epsilon, 1.0 - max3(c))); } vec3 RGB_YCoCg(const vec3 c) { @@ -159,15 +193,16 @@ vec4 clipToBox(const int quality, // Optimized to 5 taps by removing the corner samples // And modified for mediump support vec4 sampleTextureCatmullRom(const sampler2D tex, const highp vec2 uv, const highp vec2 texSize) { - // We're going to sample a a 4x4 grid of texels surrounding the target UV coordinate. We'll do this by rounding - // down the sample location to get the exact center of our "starting" texel. The starting texel will be at - // location [1, 1] in the grid, where [0, 0] is the top left corner. + // We're going to sample a a 4x4 grid of texels surrounding the target UV coordinate. + // We'll do this by rounding down the sample location to get the exact center of our "starting" + // texel. The starting texel will be at location [1, 1] in the grid, where [0, 0] is the + // top left corner. highp vec2 samplePos = uv * texSize; highp vec2 texPos1 = floor(samplePos - 0.5) + 0.5; - // Compute the fractional offset from our starting texel to our original sample location, which we'll - // feed into the Catmull-Rom spline function to get our filter weights. + // Compute the fractional offset from our starting texel to our original sample location, + // which we'll feed into the Catmull-Rom spline function to get our filter weights. highp vec2 f = samplePos - texPos1; highp vec2 f2 = f * f; highp vec2 f3 = f2 * f; @@ -200,13 +235,20 @@ vec4 sampleTextureCatmullRom(const sampler2D tex, const highp vec2 uv, const hig float k3 = w3.x * w12.y; float k4 = w12.x * w3.y; - vec4 result = textureLod(tex, vec2(texPos12.x, texPos0.y), 0.0) * k0 - + textureLod(tex, vec2(texPos0.x, texPos12.y), 0.0) * k1 - + textureLod(tex, vec2(texPos12.x, texPos12.y), 0.0) * k2 - + textureLod(tex, vec2(texPos3.x, texPos12.y), 0.0) * k3 - + textureLod(tex, vec2(texPos12.x, texPos3.y), 0.0) * k4; + vec4 s[5]; + s[0] = textureLod(tex, vec2(texPos12.x, texPos0.y), 0.0); + s[1] = textureLod(tex, vec2(texPos0.x, texPos12.y), 0.0); + s[2] = textureLod(tex, vec2(texPos12.x, texPos12.y), 0.0); + s[3] = textureLod(tex, vec2(texPos3.x, texPos12.y), 0.0); + s[4] = textureLod(tex, vec2(texPos12.x, texPos3.y), 0.0); - result *= 1.0 / (k0 + k1 + k2 + k3 + k4); + vec4 result = k0 * s[0] + + k1 * s[1] + + k2 * s[2] + + k3 * s[3] + + k4 * s[4]; + + result *= rcp(k0 + k1 + k2 + k3 + k4); // we could end-up with negative values result = max(vec4(0), result); @@ -242,7 +284,7 @@ void postProcess(inout PostProcessInputs postProcess) { highp vec2 size = vec2(textureSize(materialParams_color, 0)); highp vec2 p = (floor(uv.xy * size) + 0.5) / size; - vec4 color = textureLod(materialParams_color, p, 0.0); + vec4 filtered = textureLod(materialParams_color, p, 0.0); vec3 s[9]; if (materialConstants_filterInput || materialConstants_boxClipping != BOX_CLIPPING_NONE) { @@ -250,16 +292,12 @@ void postProcess(inout PostProcessInputs postProcess) { s[1] = textureLodOffset(materialParams_color, p, 0.0, ivec2( 0, -1)).rgb; s[2] = textureLodOffset(materialParams_color, p, 0.0, ivec2( 1, -1)).rgb; s[3] = textureLodOffset(materialParams_color, p, 0.0, ivec2(-1, 0)).rgb; - s[4] = color.rgb; + s[4] = filtered.rgb; s[5] = textureLodOffset(materialParams_color, p, 0.0, ivec2( 1, 0)).rgb; s[6] = textureLodOffset(materialParams_color, p, 0.0, ivec2(-1, 1)).rgb; s[7] = textureLodOffset(materialParams_color, p, 0.0, ivec2( 0, 1)).rgb; s[8] = textureLodOffset(materialParams_color, p, 0.0, ivec2( 1, 1)).rgb; - } - - if (materialConstants_useYCoCg) { - color.rgb = RGB_YCoCg(color.rgb); - if (materialConstants_filterInput || materialConstants_boxClipping != BOX_CLIPPING_NONE) { + if (materialConstants_useYCoCg) { for (int i = 0; i < 9; i++) { s[i] = RGB_YCoCg(s[i]); } @@ -267,24 +305,35 @@ void postProcess(inout PostProcessInputs postProcess) { } vec2 subPixelOffset = p - uv.xy; // +/- [0.25, 0.25] - float confidence = 0.0; + float confidence = materialConstants_upscaling ? 0.0 : 1.0; - vec4 filtered = color; if (materialConstants_filterInput) { // unjitter/filter input // figure out which set of coeficients to use - int jxp = subPixelOffset.y > 0.0 ? 3 : 0; - int jxn = subPixelOffset.y > 0.0 ? 2 : 1; - int j = subPixelOffset.x > 0.0 ? jxp : jxn; - filtered = vec4(0, 0, 0, color.a); - for (int i = 0; i < 9; i++) { - float w = materialParams.filterWeights[i][j]; - filtered.rgb += s[i] * w; - confidence = max(confidence, w); + filtered = vec4(0, 0, 0, filtered.a); + if (materialConstants_upscaling) { + int jxp = subPixelOffset.y > 0.0 ? 3 : 0; + int jxn = subPixelOffset.y > 0.0 ? 2 : 1; + int j = subPixelOffset.x > 0.0 ? jxp : jxn; + for (int i = 0; i < 9; i++) { + float w = materialParams.filterWeights[i][j]; + filtered.rgb += s[i] * w; + confidence = max(confidence, w); + } + } else { + for (int i = 0; i < 9; i++) { + float w = materialParams.filterWeights[i][0]; + filtered.rgb += s[i] * w; + } } } else { - confidence = float(materialParams.jitter.x * subPixelOffset.x > 0.0 && - materialParams.jitter.y * subPixelOffset.y > 0.0); + if (materialConstants_useYCoCg) { + filtered.rgb = RGB_YCoCg(filtered.rgb); + } + if (materialConstants_upscaling) { + confidence = float(materialParams.jitter.x * subPixelOffset.x > 0.0 && + materialParams.jitter.y * subPixelOffset.y > 0.0); + } } // build the history clamping box @@ -329,29 +378,30 @@ void postProcess(inout PostProcessInputs postProcess) { history = clipToBox(materialConstants_boxClipping, boxmin, boxmax, filtered, history); } - float lumaColor = luma(filtered.rgb); - float lumaHistory = luma(history.rgb); - float alpha = materialParams.alpha * confidence; if (materialConstants_preventFlickering) { // [Lottes] prevents flickering by modulating the blend weight by the difference in luma + float lumaColor = luma(filtered.rgb); + float lumaHistory = luma(history.rgb); float diff = 1.0 - abs(lumaColor - lumaHistory) / (0.001 + max(lumaColor, lumaHistory)); alpha *= diff * diff; } - // tonemapping for handling HDR - filtered.rgb *= 1.0 / (1.0 + lumaColor); - history.rgb *= 1.0 / (1.0 + lumaHistory); + // go back to RGB space before tonemapping + if (materialConstants_useYCoCg) { + filtered.rgb = YCoCg_RGB(filtered.rgb); + history.rgb = YCoCg_RGB(history.rgb); + } + + // tonemap before mixing + filtered.rgb = tonemap(filtered.rgb); + history.rgb = tonemap(history.rgb); // combine history and current frame vec4 result = mix(history, filtered, alpha); // untonemap result - result.rgb *= 1.0 / (1.0 - luma(result.rgb)); - - if (materialConstants_useYCoCg) { - result.rgb = YCoCg_RGB(result.rgb); - } + result.rgb = untonemap(result.rgb); #if POST_PROCESS_OPAQUE // kill the work performed above diff --git a/filament/src/materials/fsr/fsr_rcas.mat b/filament/src/materials/fsr/fsr_rcas.mat index 185e62d288c..cfdf0372042 100644 --- a/filament/src/materials/fsr/fsr_rcas.mat +++ b/filament/src/materials/fsr/fsr_rcas.mat @@ -43,6 +43,8 @@ fragment { #define FSR_RCAS_F 1 #if !POST_PROCESS_OPAQUE # define FSR_RCAS_PASSTHROUGH_ALPHA + // todo: make this a spec constant + # define FSR_RCAS_DENOISE #endif #include "ffx_fsr1.h" @@ -61,6 +63,9 @@ fragment { #endif p, materialParams.RcasCon); + // todo: make this an option + postProcess.color.rgb = max(vec3(0), postProcess.color.rgb); + #if POST_PROCESS_OPAQUE postProcess.color.a = 1.0; #endif diff --git a/ios/CocoaPods/Filament.podspec b/ios/CocoaPods/Filament.podspec index 5bc7c54c220..fc8d995577c 100644 --- a/ios/CocoaPods/Filament.podspec +++ b/ios/CocoaPods/Filament.podspec @@ -1,12 +1,12 @@ Pod::Spec.new do |spec| spec.name = "Filament" - spec.version = "1.50.0" + spec.version = "1.50.1" spec.license = { :type => "Apache 2.0", :file => "LICENSE" } spec.homepage = "https://google.github.io/filament" spec.authors = "Google LLC." spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL." spec.platform = :ios, "11.0" - spec.source = { :http => "https://github.com/google/filament/releases/download/v1.50.0/filament-v1.50.0-ios.tgz" } + spec.source = { :http => "https://github.com/google/filament/releases/download/v1.50.1/filament-v1.50.1-ios.tgz" } # Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon. spec.pod_target_xcconfig = { diff --git a/ios/samples/gltf-viewer/gltf-viewer/FILViewController.mm b/ios/samples/gltf-viewer/gltf-viewer/FILViewController.mm index 5366a7ef443..80898ec19e1 100644 --- a/ios/samples/gltf-viewer/gltf-viewer/FILViewController.mm +++ b/ios/samples/gltf-viewer/gltf-viewer/FILViewController.mm @@ -47,6 +47,9 @@ - (void)stopDisplayLink; - (void)createRenderables; - (void)createLights; +- (void)appWillResignActive:(NSNotification*)notification; +- (void)appDidBecomeActive:(NSNotification*)notification; + @end @implementation FILViewController { @@ -73,6 +76,16 @@ - (void)viewDidLoad { self.title = @"https://google.github.io/filament/remote"; + // Observe lifecycle notifications to prevent us from rendering in the background. + [NSNotificationCenter.defaultCenter addObserver:self + selector:@selector(appWillResignActive:) + name:UIApplicationWillResignActiveNotification + object:nil]; + [NSNotificationCenter.defaultCenter addObserver:self + selector:@selector(appDidBecomeActive:) + name:UIApplicationDidBecomeActiveNotification + object:nil]; + // Arguments: // --model // path to glb or gltf file to load from documents directory @@ -125,6 +138,14 @@ - (void)viewDidLoad { [self.view addSubview:_toastLabel]; } +- (void)appWillResignActive:(NSNotification*)notification { + [self stopDisplayLink]; +} + +- (void)appDidBecomeActive:(NSNotification*)notification { + [self startDisplayLink]; +} + - (void)viewWillAppear:(BOOL)animated { [self startDisplayLink]; } @@ -330,6 +351,7 @@ - (void)toastMessage:(NSString*)message { } - (void)dealloc { + [NSNotificationCenter.defaultCenter removeObserver:self]; delete _server; delete _automation; self.modelView.engine->destroy(_indirectLight); diff --git a/libs/iblprefilter/src/materials/equirectToCube.mat b/libs/iblprefilter/src/materials/equirectToCube.mat index b35a869b981..b3b9bee9fb0 100644 --- a/libs/iblprefilter/src/materials/equirectToCube.mat +++ b/libs/iblprefilter/src/materials/equirectToCube.mat @@ -48,7 +48,7 @@ fragment { void dummy() {} highp vec2 toEquirect(const highp vec3 s) { - highp float xf = atan2(s.x, s.z) * (1.0 / PI); // range [-1.0, 1.0] + highp float xf = atan(s.x, s.z) * (1.0 / PI); // range [-1.0, 1.0] highp float yf = asin(s.y) * (2.0 / PI); // range [-1.0, 1.0] xf = (xf + 1.0) * 0.5; // range [0, 1.0] yf = (1.0 - yf) * 0.5; // range [0, 1.0] @@ -62,17 +62,22 @@ mediump vec3 sampleEquirect(mediump sampler2D equirect, const highp vec3 r) { void postProcess(inout PostProcessInputs postProcess) { highp vec2 uv = variable_vertex.xy; // interpolated at pixel's center - highp vec2 p = uv * 2.0 - 1.0; + highp vec2 p = vec2( + uv.x * 2.0 - 1.0, + 1.0 - uv.y * 2.0); + float side = materialParams.side; + highp float l = inversesqrt(p.x * p.x + p.y * p.y + 1.0); // compute the view (and normal, since v = n) direction for each face - highp vec3 rx = normalize(vec3( side, -p.y, side * -p.x)); - highp vec3 ry = normalize(vec3( p.x, side, side * p.y)); - highp vec3 rz = normalize(vec3(side * p.x, -p.y, side)); + highp vec3 rx = vec3( side, p.y, side * -p.x); + highp vec3 ry = vec3( p.x, side, side * -p.y); + highp vec3 rz = vec3(side * p.x, p.y, side); + - postProcess.outx = sampleEquirect(materialParams_equirect, rx); - postProcess.outy = sampleEquirect(materialParams_equirect, ry); - postProcess.outz = sampleEquirect(materialParams_equirect, rz); + postProcess.outx = sampleEquirect(materialParams_equirect, rx * l); + postProcess.outy = sampleEquirect(materialParams_equirect, ry * l); + postProcess.outz = sampleEquirect(materialParams_equirect, rz * l); } } diff --git a/libs/viewer/src/Settings_generated.cpp b/libs/viewer/src/Settings_generated.cpp index b8af8f0fb25..3b7c5f6236e 100644 --- a/libs/viewer/src/Settings_generated.cpp +++ b/libs/viewer/src/Settings_generated.cpp @@ -391,6 +391,8 @@ int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, DepthOfFieldOpt CHECK_KEY(tok); if (compare(tok, jsonChunk, "cocScale") == 0) { i = parse(tokens, i + 1, jsonChunk, &out->cocScale); + } else if (compare(tok, jsonChunk, "cocAspectRatio") == 0) { + i = parse(tokens, i + 1, jsonChunk, &out->cocAspectRatio); } else if (compare(tok, jsonChunk, "maxApertureDiameter") == 0) { i = parse(tokens, i + 1, jsonChunk, &out->maxApertureDiameter); } else if (compare(tok, jsonChunk, "enabled") == 0) { @@ -424,6 +426,7 @@ int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, DepthOfFieldOpt std::ostream& operator<<(std::ostream& out, const DepthOfFieldOptions& in) { return out << "{\n" << "\"cocScale\": " << (in.cocScale) << ",\n" + << "\"cocAspectRatio\": " << (in.cocAspectRatio) << ",\n" << "\"maxApertureDiameter\": " << (in.maxApertureDiameter) << ",\n" << "\"enabled\": " << to_string(in.enabled) << ",\n" << "\"filter\": " << (in.filter) << ",\n" @@ -690,6 +693,7 @@ int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, TemporalAntiAli else if (0 == compare(tokens[i], jsonChunk, "UNIFORM_HELIX_X4")) { *out = TemporalAntiAliasingOptions::JitterPattern::UNIFORM_HELIX_X4; } else if (0 == compare(tokens[i], jsonChunk, "HALTON_23_X8")) { *out = TemporalAntiAliasingOptions::JitterPattern::HALTON_23_X8; } else if (0 == compare(tokens[i], jsonChunk, "HALTON_23_X16")) { *out = TemporalAntiAliasingOptions::JitterPattern::HALTON_23_X16; } + else if (0 == compare(tokens[i], jsonChunk, "HALTON_23_X32")) { *out = TemporalAntiAliasingOptions::JitterPattern::HALTON_23_X32; } else { slog.w << "Invalid TemporalAntiAliasingOptions::JitterPattern: '" << STR(tokens[i], jsonChunk) << "'" << io::endl; } @@ -702,6 +706,7 @@ std::ostream& operator<<(std::ostream& out, TemporalAntiAliasingOptions::JitterP case TemporalAntiAliasingOptions::JitterPattern::UNIFORM_HELIX_X4: return out << "\"UNIFORM_HELIX_X4\""; case TemporalAntiAliasingOptions::JitterPattern::HALTON_23_X8: return out << "\"HALTON_23_X8\""; case TemporalAntiAliasingOptions::JitterPattern::HALTON_23_X16: return out << "\"HALTON_23_X16\""; + case TemporalAntiAliasingOptions::JitterPattern::HALTON_23_X32: return out << "\"HALTON_23_X32\""; } return out << "\"INVALID\""; } @@ -718,6 +723,8 @@ int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, TemporalAntiAli i = parse(tokens, i + 1, jsonChunk, &out->feedback); } else if (compare(tok, jsonChunk, "lodBias") == 0) { i = parse(tokens, i + 1, jsonChunk, &out->lodBias); + } else if (compare(tok, jsonChunk, "sharpness") == 0) { + i = parse(tokens, i + 1, jsonChunk, &out->sharpness); } else if (compare(tok, jsonChunk, "enabled") == 0) { i = parse(tokens, i + 1, jsonChunk, &out->enabled); } else if (compare(tok, jsonChunk, "upscaling") == 0) { @@ -757,6 +764,7 @@ std::ostream& operator<<(std::ostream& out, const TemporalAntiAliasingOptions& i << "\"filterWidth\": " << (in.filterWidth) << ",\n" << "\"feedback\": " << (in.feedback) << ",\n" << "\"lodBias\": " << (in.lodBias) << ",\n" + << "\"sharpness\": " << (in.sharpness) << ",\n" << "\"enabled\": " << to_string(in.enabled) << ",\n" << "\"upscaling\": " << to_string(in.upscaling) << ",\n" << "\"filterHistory\": " << to_string(in.filterHistory) << ",\n" diff --git a/libs/viewer/src/ViewerGui.cpp b/libs/viewer/src/ViewerGui.cpp index 387134f3275..9d352e36007 100644 --- a/libs/viewer/src/ViewerGui.cpp +++ b/libs/viewer/src/ViewerGui.cpp @@ -805,10 +805,11 @@ void ViewerGui::updateUserInterface() { int jitterSequence = (int)mSettings.view.taa.jitterPattern; int boxClipping = (int)mSettings.view.taa.boxClipping; int boxType = (int)mSettings.view.taa.boxType; - ImGui::Combo("Jitter Pattern", &jitterSequence, "RGSS x4\0Uniform Helix x4\0Halton x8\0Halton x16\0\0"); + ImGui::Combo("Jitter Pattern", &jitterSequence, "RGSS x4\0Uniform Helix x4\0Halton x8\0Halton x16\0Halton x32\0\0"); ImGui::Combo("Box Clipping", &boxClipping, "Accurate\0Clamp\0None\0\0"); ImGui::Combo("Box Type", &boxType, "AABB\0Variance\0Both\0\0"); ImGui::SliderFloat("Variance Gamma", &mSettings.view.taa.varianceGamma, 0.75f, 1.25f); + ImGui::SliderFloat("RCAS", &mSettings.view.taa.sharpness, 0.0f, 1.0f); mSettings.view.taa.boxClipping = (TemporalAntiAliasingOptions::BoxClipping)boxClipping; mSettings.view.taa.boxType = (TemporalAntiAliasingOptions::BoxType)boxType; mSettings.view.taa.jitterPattern = (TemporalAntiAliasingOptions::JitterPattern)jitterSequence; @@ -1036,6 +1037,7 @@ void ViewerGui::updateUserInterface() { ImGui::Checkbox("Enabled##dofEnabled", &mSettings.view.dof.enabled); ImGui::SliderFloat("Focus distance", &mSettings.viewer.cameraFocusDistance, 0.0f, 30.0f); ImGui::SliderFloat("Blur scale", &mSettings.view.dof.cocScale, 0.1f, 10.0f); + ImGui::SliderFloat("CoC aspect-ratio", &mSettings.view.dof.cocAspectRatio, 0.25f, 4.0f); ImGui::SliderInt("Ring count", &dofRingCount, 1, 17); ImGui::SliderInt("Max CoC", &dofMaxCoC, 1, 32); ImGui::Checkbox("Native Resolution", &mSettings.view.dof.nativeResolution); diff --git a/shaders/src/common_math.glsl b/shaders/src/common_math.glsl index 98b205f65dc..28d04685d16 100644 --- a/shaders/src/common_math.glsl +++ b/shaders/src/common_math.glsl @@ -19,7 +19,6 @@ #endif #define saturate(x) clamp(x, 0.0, 1.0) -#define atan2(x, y) atan(y, x) //------------------------------------------------------------------------------ // Scalar operations diff --git a/tools/matc/src/matc/JsonishLexer.cpp b/tools/matc/src/matc/JsonishLexer.cpp index 3cca02e560f..2173693c0a2 100644 --- a/tools/matc/src/matc/JsonishLexer.cpp +++ b/tools/matc/src/matc/JsonishLexer.cpp @@ -27,9 +27,7 @@ JsonType JsonishLexer::readIdentifier() noexcept { consume(); } - const char* lexemeEnd = mCursor - 1; - - size_t lexemeSize = lexemeEnd - lexemeStart; + size_t lexemeSize = mCursor - lexemeStart; // Check what kind of keyword we got here. if (strncmp("true", lexemeStart, lexemeSize) == 0) { diff --git a/web/filament-js/extensions_generated.js b/web/filament-js/extensions_generated.js index 99801d163c8..a0d69778c46 100644 --- a/web/filament-js/extensions_generated.js +++ b/web/filament-js/extensions_generated.js @@ -60,6 +60,7 @@ Filament.loadGeneratedExtensions = function() { Filament.View.prototype.setDepthOfFieldOptionsDefaults = function(overrides) { const options = { cocScale: 1.0, + cocAspectRatio: 1.0, maxApertureDiameter: 0.01, enabled: false, filter: Filament.View$DepthOfFieldOptions$Filter.MEDIAN, @@ -140,6 +141,7 @@ Filament.loadGeneratedExtensions = function() { filterWidth: 1.0, feedback: 0.12, lodBias: -1.0, + sharpness: 0.0, enabled: false, upscaling: false, filterHistory: true, diff --git a/web/filament-js/filament.d.ts b/web/filament-js/filament.d.ts index 49e404f81a5..17d874c3528 100644 --- a/web/filament-js/filament.d.ts +++ b/web/filament-js/filament.d.ts @@ -1409,6 +1409,10 @@ export interface View$DepthOfFieldOptions { * circle of confusion scale factor (amount of blur) */ cocScale?: number; + /** + * width/height aspect ratio of the circle of confusion (simulate anamorphic lenses) + */ + cocAspectRatio?: number; /** * maximum aperture diameter in meters (zero to disable rotation) */ @@ -1653,6 +1657,7 @@ export enum View$TemporalAntiAliasingOptions$JitterPattern { UNIFORM_HELIX_X4, HALTON_23_X8, HALTON_23_X16, + HALTON_23_X32, } /** @@ -1679,6 +1684,10 @@ export interface View$TemporalAntiAliasingOptions { * texturing lod bias (typically -1 or -2) */ lodBias?: number; + /** + * post-TAA sharpen, especially useful when upscaling is true. + */ + sharpness?: number; /** * enables or disables temporal anti-aliasing */ diff --git a/web/filament-js/jsbindings_generated.cpp b/web/filament-js/jsbindings_generated.cpp index 250840744ac..07fd54e786b 100644 --- a/web/filament-js/jsbindings_generated.cpp +++ b/web/filament-js/jsbindings_generated.cpp @@ -58,6 +58,7 @@ value_object("View$FogOptions") value_object("View$DepthOfFieldOptions") .field("cocScale", &View::DepthOfFieldOptions::cocScale) + .field("cocAspectRatio", &View::DepthOfFieldOptions::cocAspectRatio) .field("maxApertureDiameter", &View::DepthOfFieldOptions::maxApertureDiameter) .field("enabled", &View::DepthOfFieldOptions::enabled) .field("filter", &View::DepthOfFieldOptions::filter) @@ -120,6 +121,7 @@ value_object("View$TemporalAntiAliasingOption .field("filterWidth", &View::TemporalAntiAliasingOptions::filterWidth) .field("feedback", &View::TemporalAntiAliasingOptions::feedback) .field("lodBias", &View::TemporalAntiAliasingOptions::lodBias) + .field("sharpness", &View::TemporalAntiAliasingOptions::sharpness) .field("enabled", &View::TemporalAntiAliasingOptions::enabled) .field("upscaling", &View::TemporalAntiAliasingOptions::upscaling) .field("filterHistory", &View::TemporalAntiAliasingOptions::filterHistory) diff --git a/web/filament-js/jsenums_generated.cpp b/web/filament-js/jsenums_generated.cpp index 9a9d23618ae..d729b59c3cc 100644 --- a/web/filament-js/jsenums_generated.cpp +++ b/web/filament-js/jsenums_generated.cpp @@ -50,6 +50,7 @@ enum_("View$TemporalAntiAliasi .value("UNIFORM_HELIX_X4", View::TemporalAntiAliasingOptions::JitterPattern::UNIFORM_HELIX_X4) .value("HALTON_23_X8", View::TemporalAntiAliasingOptions::JitterPattern::HALTON_23_X8) .value("HALTON_23_X16", View::TemporalAntiAliasingOptions::JitterPattern::HALTON_23_X16) + .value("HALTON_23_X32", View::TemporalAntiAliasingOptions::JitterPattern::HALTON_23_X32) ; enum_("View$AntiAliasing") diff --git a/web/filament-js/package.json b/web/filament-js/package.json index d4ea454a999..916c1178cd3 100644 --- a/web/filament-js/package.json +++ b/web/filament-js/package.json @@ -1,6 +1,6 @@ { "name": "filament", - "version": "1.50.0", + "version": "1.50.1", "description": "Real-time physically based rendering engine", "main": "filament.js", "module": "filament.js",