From fe3e5650674b963d8fbe6bd518f9c2378a3ab9f7 Mon Sep 17 00:00:00 2001 From: Vladimir Guguiev <1524432+vovacodes@users.noreply.github.com> Date: Sun, 5 Jan 2025 22:56:54 +0100 Subject: [PATCH] WIP: add bloomOptions to FilamentScene --- package/cpp/core/RNFViewWrapper.cpp | 1 + package/src/react/Configurator.tsx | 9 ++ package/src/types/Options.ts | 138 +++++++++++++++++++ package/src/types/View.ts | 5 +- package/src/utilities/makeBloomHostObject.ts | 59 ++++++++ 5 files changed, 211 insertions(+), 1 deletion(-) create mode 100644 package/src/utilities/makeBloomHostObject.ts diff --git a/package/cpp/core/RNFViewWrapper.cpp b/package/cpp/core/RNFViewWrapper.cpp index c49131ed..5b37f67d 100644 --- a/package/cpp/core/RNFViewWrapper.cpp +++ b/package/cpp/core/RNFViewWrapper.cpp @@ -5,6 +5,7 @@ namespace margelo { void ViewWrapper::loadHybridMethods() { registerHybridMethod("getAspectRatio", &ViewWrapper::getAspectRatio, this); registerHybridMethod("createAmbientOcclusionOptions", &ViewWrapper::createAmbientOcclusionOptions, this); + //FIXME: registerHybridMethod("createBloomOptions", &ViewWrapper::createBloomOptions, this); registerHybridMethod("setAmbientOcclusionOptions", &ViewWrapper::setAmbientOcclusionOptions, this); registerHybridMethod("getAmbientOcclusionOptions", &ViewWrapper::getAmbientOcclusionOptions, this); registerHybridMethod("createDynamicResolutionOptions", &ViewWrapper::createDynamicResolutionOptions, this); diff --git a/package/src/react/Configurator.tsx b/package/src/react/Configurator.tsx index b1d5c02c..ceb219e9 100644 --- a/package/src/react/Configurator.tsx +++ b/package/src/react/Configurator.tsx @@ -1,6 +1,7 @@ import { PropsWithChildren, useEffect } from 'react' import { AmbientOcclusionOptions, + BloomOptions, DynamicResolutionOptions, FrameRateOptions, TemporalAntiAliasingOptions, @@ -10,11 +11,13 @@ import { import { useFilamentContext } from '../hooks/useFilamentContext' import { makeAmbientOcclusionHostObject } from '../utilities/makeAmbientOcclusionHostObject' import { makeDynamicResolutionHostObject } from '../utilities/makeDynamicResolutionHostObject' +import { makeBloomHostObject } from '../utilities/makeBloomHostObject' export type ViewConfigProps = Partial< Pick > & { ambientOcclusionOptions?: AmbientOcclusionOptions + bloomOptions?: BloomOptions dynamicResolutionOptions?: DynamicResolutionOptions temporalAntiAliasingOptions?: TemporalAntiAliasingOptions } @@ -40,6 +43,7 @@ export function Configurator({ rendererProps, viewProps, children }: Configurato // Apply view configs const { ambientOcclusionOptions, + bloomOptions, antiAliasing, dithering, dynamicResolutionOptions, @@ -53,6 +57,10 @@ export function Configurator({ rendererProps, viewProps, children }: Configurato const options = makeAmbientOcclusionHostObject(view, ambientOcclusionOptions) view.setAmbientOcclusionOptions(options) } + if (bloomOptions != null) { + const options = makeBloomHostObject(view, bloomOptions) + view.setBloomOptions(options) + } if (dynamicResolutionOptions != null) { const options = makeDynamicResolutionHostObject(view, dynamicResolutionOptions) view.setDynamicResolutionOptions(options) @@ -66,6 +74,7 @@ export function Configurator({ rendererProps, viewProps, children }: Configurato }, [ view, ambientOcclusionOptions, + bloomOptions, antiAliasing, dithering, dynamicResolutionOptions, diff --git a/package/src/types/Options.ts b/package/src/types/Options.ts index 9c807b5d..960c1ffd 100644 --- a/package/src/types/Options.ts +++ b/package/src/types/Options.ts @@ -77,6 +77,144 @@ export interface AmbientOcclusionOptions { export type QualityLevel = 'LOW' | 'MEDIUM' | 'HIGH' | 'ULTRA' +/** + * Options to control the bloom effect + */ +export interface BloomOptions { + /** + * Enable or disable the bloom post-processing effect. + * @default false + */ + enabled?: boolean + + /** + * Number of successive blurs to achieve the blur effect, the minimum is 3 and the + * maximum is 12. This value together with resolution influences the spread of the + * blur effect. This value can be silently reduced to accommodate the original + * image size. + * @default 6 + */ + levels?: number + + /** + * Resolution of bloom's minor axis. The minimum value is 2^levels and + * the maximum is lower of the original resolution and 4096. This parameter is + * silently clamped to the minimum and maximum. + * It is highly recommended that this value be smaller than the target resolution + * after dynamic resolution is applied (horizontally and vertically). + * @default 384 + */ + resolution?: number + + /** + * how much of the bloom is added to the original image. Between 0 and 1. + * @default 0.1 + */ + strength?: number + + /** + * Whether the bloom effect is purely additive ('ADD') or mixed with the original + * image ('INTERPOLATE'). + * @default 'ADD' + */ + blendMode?: BloomBlendMode + + /** + * When enabled, a threshold at 1.0 is applied on the source image, this is + * useful for artistic reasons and is usually needed when a dirt texture is used. + * @default true + */ + threshold?: boolean + + /** + * Limit highlights to this value before bloom [10, +inf] + * @default 1000 + */ + highlight?: number + + /** + * Bloom quality level. + * LOW (default): use a more optimized down-sampling filter, however there can be artifacts + * with dynamic resolution, this can be alleviated by using the homogenous mode. + * MEDIUM: Good balance between quality and performance. + * HIGH: In this mode the bloom resolution is automatically increased to avoid artifacts. + * This mode can be significantly slower on mobile, especially at high resolution. + * This mode greatly improves the anamorphic bloom. + * @default 'LOW' + */ + quality?: QualityLevel + + /** + * enable screen-space lens flare + * @default false + */ + lensFlare?: boolean + + /** + * enable starburst effect on lens flare + * @default true + */ + starburst?: boolean + + /** + * amount of chromatic aberration + * @default 0.005 + */ + chromaticAberration?: number + + /** + * number of flare "ghosts" + * @default 4 + */ + ghostCount?: number + + /** + * spacing of the ghost in screen units [0, 1] + * @default 0.6 + */ + ghostSpacing?: number + + /** + * hdr threshold for the ghosts + * @default 10 + */ + ghostThreshold?: number + + /** + * thickness of halo in vertical screen units, 0 to disable + * @default 0.1 + */ + haloThickness?: number + + /** + * radius of halo in vertical screen units [0, 0.5] + * @default 0.4 + */ + haloRadius?: number + + /** + * hdr threshold for the halo + * @default 10 + */ + haloThreshold?: number + + // /** + // * A dirt/scratch/smudges texture (that can be RGB), which gets added to the + // * bloom effect. Smudges are visible where bloom occurs. Threshold must be + // * enabled for the dirt effect to work properly. + // * @default undefined + // */ + // dirt?: Texture + + // /** + // * Strength of the dirt texture. + // * @default 0.2 + // */ + // dirtStrength?: number +} + +export type BloomBlendMode = 'ADD' | 'INTERPOLATE' + /** * Dynamic resolution can be used to either reach a desired target frame rate * by lowering the resolution of a View, or to increase the quality when the diff --git a/package/src/types/View.ts b/package/src/types/View.ts index 57be54db..9881d641 100644 --- a/package/src/types/View.ts +++ b/package/src/types/View.ts @@ -1,6 +1,6 @@ import { RNFCamera } from './Camera' import { Entity } from './Entity' -import { AmbientOcclusionOptions, DynamicResolutionOptions } from './Options' +import { AmbientOcclusionOptions, BloomOptions, DynamicResolutionOptions } from './Options' import { PointerHolder } from './PointerHolder' import { Scene } from './Scene' import { Float3 } from './Math' @@ -38,6 +38,8 @@ export interface View extends PointerHolder { getViewport(): Viewport setAmbientOcclusionOptions(options: AmbientOcclusionOptions): void getAmbientOcclusionOptions(): AmbientOcclusionOptions + setBloomOptions(options: BloomOptions): void + getBloomOptions(): BloomOptions setDynamicResolutionOptions(options: DynamicResolutionOptions): void getDynamicResolutionOptions(): DynamicResolutionOptions @@ -103,6 +105,7 @@ export interface View extends PointerHolder { // Internal helper to create HostObject options object createAmbientOcclusionOptions(): AmbientOcclusionOptions + createBloomOptions(): BloomOptions createDynamicResolutionOptions(): DynamicResolutionOptions /** diff --git a/package/src/utilities/makeBloomHostObject.ts b/package/src/utilities/makeBloomHostObject.ts new file mode 100644 index 00000000..e0bf616b --- /dev/null +++ b/package/src/utilities/makeBloomHostObject.ts @@ -0,0 +1,59 @@ +import { BloomOptions } from '../types/Options' +import { View } from '../types/View' + +// We need to wrap our options in a host object to be able to pass them to the view +export function makeBloomHostObject(view: View, options: BloomOptions): BloomOptions { + const optionsWrapper = view.createBloomOptions() + if (options.enabled != null) { + optionsWrapper.enabled = options.enabled + } + if (options.levels != null) { + optionsWrapper.levels = options.levels + } + if (options.resolution != null) { + optionsWrapper.resolution = options.resolution + } + if (options.strength != null) { + optionsWrapper.strength = options.strength + } + if (options.blendMode != null) { + optionsWrapper.blendMode = options.blendMode + } + if (options.threshold != null) { + optionsWrapper.threshold = options.threshold + } + if (options.highlight != null) { + optionsWrapper.highlight = options.highlight + } + if (options.quality != null) { + optionsWrapper.quality = options.quality + } + if (options.lensFlare != null) { + optionsWrapper.lensFlare = options.lensFlare + } + if (options.starburst != null) { + optionsWrapper.starburst = options.starburst + } + if (options.chromaticAberration != null) { + optionsWrapper.chromaticAberration = options.chromaticAberration + } + if (options.ghostCount != null) { + optionsWrapper.ghostCount = options.ghostCount + } + if (options.ghostSpacing != null) { + optionsWrapper.ghostSpacing = options.ghostSpacing + } + if (options.ghostThreshold != null) { + optionsWrapper.ghostThreshold = options.ghostThreshold + } + if (options.haloThickness != null) { + optionsWrapper.haloThickness = options.haloThickness + } + if (options.haloRadius != null) { + optionsWrapper.haloRadius = options.haloRadius + } + if (options.haloThreshold != null) { + optionsWrapper.haloThreshold = options.haloThreshold + } + return optionsWrapper +}