diff --git a/com.unity.postprocessing/.signature b/com.unity.postprocessing/.signature
new file mode 100644
index 0000000..89ef440
--- /dev/null
+++ b/com.unity.postprocessing/.signature
@@ -0,0 +1,5 @@
+{
+ "timestamp": 1649276899,
+ "signature": "Uz3yekLHtnWL7w25ej6xvIKNRTSenmg5xgFVCW/d13pvms7Gv/OvUgVrm6FkjXVGQ+jf42aX7CK3w9lk70098i7QvvIchXRRiVE3gsdPJ33GJFqwbBJHhtc9mG3Y0DAwjbEWOYPlf55IgtXUmKyvaa4+jD+hBs4T0NqNhleIinDVOvSVZBLIBhnmQAMMOqhMqV4f8MnfbYxE1V2bq6D1bTyJ0toVLdEzteCrlIMc/Wudo2MUV3/ewvRWsVmPJuNPSzriRgZ/bArBz/uMX1TZgIzYPPif5y++cAa2higr7kcCS6WZwrq5wS+h/zeQpstDB8gv/GtS+GI+WiG1qqeOubKe30Ug4zlG9pL0wniTpJ6ZYAOTSvcOYqstKpDBM/EoCOn7y+ZxkKOVbAt2b6faRTJGrtTs+fnRQwj14ybInBXRWthTuiTXAbu3MN5N0eR/JFWB3C1+1siBTkJoWAD13jHK33fBtKctzCxED3DGMmjFQiUUVEo8XetLspKJCpHD",
+ "publicKey": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQm9qQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FZOEFNSUlCaWdLQ0FZRUFzdUhXYUhsZ0I1cVF4ZEJjTlJKSAordHR4SmoxcVY1NTdvMlZaRE1XaXhYRVBkRTBEMVFkT1JIRXNSS1RscmplUXlERU83ZlNQS0ZwZ1A3MU5TTnJCCkFHM2NFSU45aHNQVDhOVmllZmdWem5QTkVMenFkVmdEbFhpb2VpUnV6OERKWFgvblpmU1JWKytwbk9ySTRibG4KS0twelJlNW14OTc1SjhxZ1FvRktKT0NNRlpHdkJMR2MxSzZZaEIzOHJFODZCZzgzbUovWjBEYkVmQjBxZm13cgo2ZDVFUXFsd0E5Y3JZT1YyV1VpWXprSnBLNmJZNzRZNmM1TmpBcEFKeGNiaTFOaDlRVEhUcU44N0ZtMDF0R1ZwCjVNd1pXSWZuYVRUemEvTGZLelR5U0pka0tldEZMVGdkYXpMYlpzUEE2aHBSK0FJRTJhc0tLTi84UUk1N3UzU2cKL2xyMnZKS1IvU2l5eEN1Q20vQWJkYnJMbXk0WjlSdm1jMGdpclA4T0lLQWxBRWZ2TzV5Z2hSKy8vd1RpTFlzUQp1SllDM0V2UE16ZGdKUzdGR2FscnFLZzlPTCsxVzROY05yNWdveVdSUUJ0cktKaWlTZEJVWmVxb0RvSUY5NHpCCndGbzJJT1JFdXFqcU51M3diMWZIM3p1dGdtalFra3IxVjJhd3hmcExLWlROQWdNQkFBRT0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg"
+}
\ No newline at end of file
diff --git a/com.unity.postprocessing/CHANGELOG.md b/com.unity.postprocessing/CHANGELOG.md
new file mode 100644
index 0000000..12023f3
--- /dev/null
+++ b/com.unity.postprocessing/CHANGELOG.md
@@ -0,0 +1,337 @@
+# Changelog
+All notable changes to this package will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
+and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+
+## [3.3.1] - 2023-06-02
+
+### Fixed
+- Fixed obsolete FormatUsage bug
+
+## [3.3.0] - 2023-05-11
+
+### Fixed
+- Fixed some post effects not scaling correctly when dynamic resolution is enabled on a camera's target texture (case 1166603)
+- Fixed obsolete API call GetScriptingDefineSymbolsForGroup
+- Remove support for OpenGL ES 2.0 in Unity 2023.1 or newer
+
+## [3.2.2] - 2022-04-05
+
+### Fixed
+- Fixed FXAA artefact when trying to preserve alpha channel output.
+- Fixed MSVO aliasing artifact by using a z-Bias parameter. (case 1375337)
+
+## [3.2.1] - 2022-01-12
+
+### Fixed
+- Fixed missing XR warnings for XR non-friendly effects when using XR plugins (case 1328062)
+- Fixed rendering artifacts when depth buffer is used after screen space reflections pass on iOS and M1 (case 1341052)
+- Fixed compilation error when built-in VR module is disabled (case 1389160)
+- Fixed bug where alpha could not be used with HDR on mobile (case 1387848). HDR texture format is now set from Graphics Tier Settings when using Unity 2019.3 or newer.
+- Fixed incorrect Screen-space Reflections rendering on OpenGL platforms (case 1368370)
+
+## [3.2.0] - 2021-11-15
+
+### Fixed
+- Catch thrown errors in `PostProcessEffectRenderer`, preventing resources allocation leaks and crash (case 1221972)
+- Fixed error thrown when changing post process layer right after creation or before destruction.
+- Fix FXAA when render-target has no alpha channel (case 1344618) (case 1351502)
+
+## [3.1.1] - 2021-03-08
+
+### Fixed
+- Fix for broken MSVO on desktop platforms.
+- Fix for compilation issue with BuildTarget error on XboxOne platform.
+
+## [3.1.0] - 2021-03-02
+
+### Added
+- Support for the PlayStation 5 platform has been added.
+- Support for the XboxSeries platform has been added.
+
+### Fixed
+- Fix for issue thrown upon unloading a scene from an AssetBundle (case 1262826)
+- Fix for MSVO when used with dynamic resolution reallocating temporary render targets whenever the dynamic resolution scale was changed which could cause a higher peak VRAM usage and fragmentation (Case 1285605). Temporary targets will now use dynamic scaling as well to solve this. Please note there is a bug in Unity that breaks this fix (case 1285577) To make use of dynamic resolution and MSVO please use Unity 2019.4.19f1, 2020.2.2f1, 2021.1.0a9 or later.
+- Fix for compilation error in the FinalPass shader with GLES2/WebGL1 (case 1311160)
+- Fix for MSVO errors on unsupported Android platforms (case 1316915)
+
+## [3.0.3] - 2021-02-19
+
+- bump version to 3.0.3 to not conflict with unrelease 3.0.2
+
+## [3.0.2] - 2020-12-08
+
+### Fixed
+- Fix FXAA when running on render-targets without alpha channel: force using green channel as luminance
+
+### Changed
+- ResetProjection isn't being called anymore if Temporal Anti-aliasing isn't enabled, allowing the use of custom projection matrices.
+
+## [3.0.1] - 2020-10-15
+
+### Fixed
+- Fix for a compilation error in the Depth of Field shader on Linux.
+
+## [3.0.0] - 2020-10-13
+
+### Fixed
+- Fix for VR Single Pass Instancing (SPI) not working with the built-in renderers. Only effects that currently support SPI for use with SRP will work correctly (so AO for example will not work with SPI even with this fix) (case 1187257)
+- Fix for shader compilation errors when importing the 3D+Extras template (case 1234411)
+- Fix Duplicated RenderTextures when using MultiScaleVO on Xbox (case 1235888)
+- Fix for the rendering being broken when an SRP is in use and its asset comes from quality settings instead of graphics settings.
+- Fix for burger buttons on volume components being misaligned on 2019.3+ (case 1238461)
+- Fix for depth buffer being discarded when using deferred fog with Vulkan (case 1271512)
+- Fix for compilation errors when the built-in VR package is disabled (case 1266931)
+- Fix for Temporal Anti-Aliasing produces artifacts on the edges of objects when using VR (case 1167219)
+- Fix for blurry image when using the Post Process Layer in single-pass VR (case 1173697)
+- Fix for ambient occlusion is misaligned when using single pass rendering VR mode (case 1217583)
+
+### Changed
+- Motion Blur and Lens Distortion are disabled only when rendering with stereo cameras instead of having VR enabled in the project.
+- Minimum Unity version for this version has been bumped to 2018.4.
+
+## [2.3.0] - 2020-01-10
+
+### Fixed
+- Fix for XR multipass and legacy built-in renderer (case 1197855, 1152584)
+- Optimized type lookup on domain reload in the editor (case 1203325)
+- Fixed a serialization issue causing an assertion on resources (case 1202441)
+
+## [2.2.2] - 2019-11-18
+
+### Fixed
+- Fixed deprecated XR API usage.
+
+## [2.2.1] - 2019-11-07
+
+### Fixed
+- Fixed a compilation warning with Unity 2019.3 and 2020.1.
+
+### Changed
+- Following a change in the compilation pipeline, this version is only compatible with Unity 2017.2 and up.
+
+## [2.1.9] - 2019-10-24
+
+### Fixed
+- Shader compilation error on PS4 with Unity 2019.3.
+
+## [2.1.8] - 2019-10-11
+
+### Added
+- Support for dynamic resolution.
+
+### Fixed
+- Potential fp16 overflow in Depth of Field that could cause NaN on some platforms.
+- Error with Screen-space Reflections when HDR is disabled.
+- Internal "copy" materials were recreated on every frame after the asset bundle-related fix from 2.1.7.
+
+## [2.1.7] - 2019-06-12
+
+### Added
+- Initial Stadia platform support.
+
+### Fixed
+- Viewport handling wasn't working correctly when FXAA or SMAA were used with builtin pipelines.
+- Depth of Field could end up fully blurry depending on the project setup.
+- Reloading an asset bundle that has references to post-processing was broken.
+
+### Changed
+- Warning for mobiles about using post-processing with non-fullscreen cameras.
+- Directly to Camera Target on the PostProcessLayer component is now disabled by default.
+- The framework now uses its own random number generator instead of the default Unity one.
+
+## [2.1.6] - 2019-04-11
+
+### Fixed
+- Post-processing would crash if "Managed Stripping Level" was set to Medium or High.
+- Serialization warnings on build.
+- Removed unwanted garbage collection.
+
+## [2.1.5] - 2019-03-25
+
+### Fixed
+- LDR Color grading in gamma mode no longer produces banding artifacts on Mali GPUs on OpenGL ES2.
+- Gamma mode no longer darken the screen with LWRP.
+
+## [2.1.4] - 2019-02-27
+
+### Fixed
+- Shader compilation errors with OpenGL ES2 and other platforms.
+- Proper viewport support on Builtin render pipelines.
+
+## [2.1.3] - 2019-01-30
+
+### Fixed
+- Color grading would output negative values in some cases and break rendering on some platforms.
+- Custom effects with `allowInSceneView` set to `false` could make the scene view flicker to black.
+- R8_SRGB error in 2019.1 when Depth of Field and Temporal Anti-aliasing are enabled at the same time.
+- Auto-exposure compute shader on Metal/iOS.
+
+## [2.1.2] - 2018-12-05
+
+### Fixed
+- Made the package manager happy.
+
+## [2.1.1] - 2018-11-30
+
+### Fixed
+- Optimized volume texture blending.
+- Compilation issues with 2019.1+ on some platforms.
+
+### Changed
+- Chromatic aberration is now forced to "fast mode" when running on GLES2.0 platforms due to compatibility issues.
+
+## [2.1.0] - 2018-11-26
+
+### Changed
+- Minor version bump following the release of 2018.3 and verified compatibility with 2019.1.
+
+## [2.0.20] - 2018-11-22
+
+### Fixed
+- Camera viewport wasn't working properly when outputting directly to the backbuffer.
+- More improvements to VR support.
+- Compatibility fixes for 2017.1 to 2017.4.
+- Post-processing wouldn't work when loaded from an asset bundle.
+- Compilation issue when Cinemachine is used with Post-processing.
+
+### Changed
+- Scriptable Render Pipelines should now call `PostProcessLayer.UpdateVolumeSystem(Camera, CommandBuffer)` at the beginning of the frame.
+
+## [2.0.17-preview] - 2018-11-06
+
+### Fixed
+- First pass at improving VR support.
+- Assert on Invalid LDR Lookup Texture size; added a check in the inspector for the user.
+- Improved performance on Unity 2019.1+ by avoiding unnecessary blits if no other image effect is active.
+- Use new ASTC enums on unity 2019.1+.
+
+## [2.0.16-preview] - 2018-10-23
+
+### Fixed
+- Grain shader compilation errors on some mobile GPUs.
+- Compilation issue with Unity 2019.1+ due to an internal API change.
+
+## [2.0.15-preview] - 2018-10-12
+
+### Fixed
+- Warning on `[ShaderIncludePath]` in 2018.3+.
+
+## [2.0.14-preview] - 2018-10-05
+
+### Fixed
+- Bloom flicker in single-pass double-wide stereo rendering.
+- Right eye bloom offset in single-pass double-wide stereo rendering.
+- If any parent of PostProcessingVolume has non-identity scale the Gizmo is rendered incorrectly.
+- Cleanup error when going back'n'forth between Builtins & Scriptable pipelines.
+
+### Changed
+- Use `ExecuteAlways` in 2018.3+ for better compatibility with "Prefab Mode".
+
+## [2.0.13-preview] - 2018-09-14
+
+### Fixed
+- Compilation issue with Unity 2019.1.
+- Screen-space reflection memory leak.
+
+## [2.0.12-preview] - 2018-09-07
+
+### Fixed
+- Ambient Occlusion could distort the screen on Android/Vulkan.
+- Warning about SettingsProvider in 2018.3.
+- Fixed issue with physical camera mode not working with post-processing.
+- Fixed thread group warning message on Metal and Intel Iris.
+- Fixed compatibility with versions pre-2018.2.
+
+## [2.0.10-preview] - 2018-07-24
+
+### Fixed
+- Better handling of volumes in nested-prefabs.
+- The Multi-scale volumetric obscurance effect wasn't properly releasing some of its temporary targets.
+- N3DS deprecation warnings in 2018.3.
+
+## [2.0.9-preview] - 2018-07-16
+
+### Changed
+- Update assembly definitions to output assemblies that match Unity naming convention (Unity.*).
+
+## [2.0.8-preview] - 2018-07-06
+
+### Fixed
+- Post-processing is now working with VR SRP in PC.
+- Crash on Vulkan when blending 3D textures.
+- `RuntimeUtilities.DestroyVolume()` works as expected now.
+- Excessive CPU usage on PS4 due to a badly initialized render texture.
+
+### Changed
+- Improved volume texture blending.
+
+### Added
+- `Depth` debug mode can now display linear depth instead of the raw platform depth.
+
+## [2.0.7-preview] - 2018-05-31
+
+### Fixed
+- Post-processing wasn't working on Unity 2018.3.
+
+### Added
+- Bloom now comes with a `Clamp` parameter to limit the amount of bloom that comes with ultra-bright pixels.
+
+## [2.0.6-preview] - 2018-05-24
+
+### Fixed
+- On large scenes, the first object you'd add to a profile could throw a `NullReferenceException`. ([#530](https://github.com/Unity-Technologies/PostProcessing/pull/530))
+- Dithering now works correctly in dark areas when working in Gamma mode.
+- Colored grain wasn't colored when `POSTFX_DEBUG_STATIC_GRAIN` was set.
+- No more warning in the console when `POSTFX_DEBUG_STATIC_GRAIN` is set.
+
+### Changed
+- Minor scripting API improvements. ([#530](https://github.com/Unity-Technologies/PostProcessing/pull/530))
+- More implicit casts for `VectorXParameter` and `ColorParameter` to `Vector2`, `Vector3` and `Vector4`.
+- Script-instantiated profiles in volumes are now properly supported in the inspector. ([#530](https://github.com/Unity-Technologies/PostProcessing/pull/530))
+- Improved volume UI & styling.
+
+## [2.0.5-preview] - 2018-04-20
+
+### Fixed
+- More XR/platform-specific related fixes.
+
+## [2.0.4-preview] - 2018-04-19
+
+### Fixed
+- Temporal Anti-aliasing creating NaN values in some cases. ([#337](https://github.com/Unity-Technologies/PostProcessing/issues/337))
+- Auto-exposure has been fixed to work the same way it did before the full-compute port.
+- XR compilation errors specific-platforms (2018.2).
+- `ArgumentNullException` when attempting to get a property sheet for a null shader. ([#515](https://github.com/Unity-Technologies/PostProcessing/pull/515))
+- Stop NaN Propagation not working for opaque-only effects.
+- HDR color grading had a slight color temperature offset.
+- PSVita compatibility.
+- Tizen warning on 2018.2.
+- Errors in the console when toggling lighting on/off in the scene view when working in Deferred.
+- Debug monitors now work properly with HDRP.
+
+### Added
+- Contribution slider for the LDR Lut.
+- Support for proper render target load/store actions on mobile (2018.2).
+
+### Changed
+- Slightly improved speed & quality of Temporal Anti-aliasing.
+- Improved volume texture blending.
+- Improved support for LDR Luts of sizes other than 1024x32. ([#507](https://github.com/Unity-Technologies/PostProcessing/issues/507))
+- Bloom's `Fast Mode` has been made faster.
+- Depth of Field focus is now independent from the screen resolution.
+- The number of variants for some shaders has been reduced to improve first-build speed. The biggest one, Uber, is down to 576 variants.
+
+## [2.0.3-preview] - 2018-03-13
+
+### Fixed
+- Disabled debug compute shaders on OpenGL ES3 to avoid crashes on a lot of Android devices.
+- `NullReferenceException` while mixing volumes and global volumes. ([#498](https://github.com/Unity-Technologies/PostProcessing/issues/498))
+
+### Changed
+- Improved performances when blending between identical textures.
+
+## [2.0.2-preview] - 2018-03-07
+
+This is the first release of *PostProcessing*.
diff --git a/com.unity.postprocessing/CHANGELOG.md.meta b/com.unity.postprocessing/CHANGELOG.md.meta
new file mode 100644
index 0000000..d950c2e
--- /dev/null
+++ b/com.unity.postprocessing/CHANGELOG.md.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 76eb0b51417a8442180aa67edda7d01a
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/Documentation~/Ambient-Occlusion.md b/com.unity.postprocessing/Documentation~/Ambient-Occlusion.md
new file mode 100644
index 0000000..d14b599
--- /dev/null
+++ b/com.unity.postprocessing/Documentation~/Ambient-Occlusion.md
@@ -0,0 +1,68 @@
+# Ambient Occlusion
+
+The **Ambient Occlusion** effect calculates points in your scene that are exposed to ambient lighting. It then darkens areas that are hidden from the ambient light, such as creases, holes, and spaces between objects which are close together.
+
+You can achieve the **Ambient Occlusion** effect in two ways: in real-time as a full-screen post-processing effect, or as a baked lighting effect (see [Baked Ambient Occlusion](https://docs.unity3d.com/Manual/LightingBakedAmbientOcclusion.html)). The real-time **Ambient Occlusion** effect can be resource-intensive, which makes it better for desktop or console platforms. Its impact on processing time depends on screen resolution and effects properties.
+
+The **Ambient Occlusion** effect in this package has two modes:
+
+- Scalable Ambient Obscurance
+- Multi-scale Volumetric Occlusion
+
+
+Scene without **Ambient Occlusion**.
+
+
+Scene with **Ambient Occlusion**.
+
+## Scalable Ambient Obscurance
+
+This is a standard implementation of ambient obscurance that works on older platforms. If you need to target a compute-enabled platform, use the [**Multi-scale Volumetric Occlusion**](multi-scale-volumetric-occlusion) mode instead.
+
+### Performance
+
+The **Scalable Ambient Obscurance** mode can be resource-intensive, especially when viewed very close to the Camera. To improve performance, use a low `Radius` setting, to sample pixels that are close and in clip space to the source pixel. This makes caching more efficient. Using a higher `Radius` setting generates samples further away from the source pixel and won’t benefit from caching, which slows down the effect.
+
+Because of the Camera’s perspective, objects near the front plane use larger radiuses than those far away, so computing the ambient occlusion pass for an object close to the camera will be slower than for an object further away that only occupies a few pixels on screen.
+
+Dropping the `Quality` setting down will improve performance too.
+
+**Scalable Ambient Obsurance** should not be used on mobile platforms or consoles as the **Multi-scale Volumetric Occlusion** mode is faster and provides better graphics for these platforms.
+
+### Requirements
+
+- Depth & Normals textures
+- Shader model 3
+
+### Properties
+
+| Property | Function |
+| :----------- | :------------------------------------------------------------ |
+| Mode | Select the type of **Ambient Occlusion** to use. |
+| Intensity | Adjust the degree of darkness **Ambient Occlusion** produces. |
+| Radius | Set the radius of sample points, which controls the extent of darkened areas. |
+| Quality | Define the number of sample points, which affects quality and performance. |
+| Color | Set the tint color of the ambient occlusion. |
+| Ambient Only | Enable this checkbox to make the **Ambient Occlusion** effect only affect ambient lighting. This option is only available with the Deferred rendering path and HDR rendering. |
+
+
+
+## Multi-scale Volumetric Occlusion
+
+This mode is optimized for consoles and desktop platforms. It has better graphics and runs faster than **Scalable Ambient Obscurance** on these platforms but requires [compute shader support](https://docs.unity3d.com/Manual/class-ComputeShader.html).
+
+### Requirements
+
+- Compute shader support
+- Shader model 4.5
+
+### Properties
+
+| Property | Function |
+| :----------------- | :------------------------------------------------------------ |
+| Mode | Select the type of **Ambient Occlusion** to use. |
+| Intensity | Adjust the degree of darkness **Ambient Occlusion** produces. |
+| Thickness Modifier | Modify the thickness of occluders. This increases dark areas but can introduce dark halos around objects. |
+| Z Bias | Modifies the z-bias to the depth buffer. This eliminates the banding aliasing artifact for MSVO. |
+| Color | Set the tint color of the ambient occlusion. |
+| Ambient Only | Enable this checkbox to make the **Ambient Occlusion** effect only affect ambient lighting. This option is only available with the Deferred rendering path and HDR rendering. |
diff --git a/com.unity.postprocessing/Documentation~/Anti-aliasing.md b/com.unity.postprocessing/Documentation~/Anti-aliasing.md
new file mode 100644
index 0000000..ba71062
--- /dev/null
+++ b/com.unity.postprocessing/Documentation~/Anti-aliasing.md
@@ -0,0 +1,89 @@
+# Anti-aliasing
+
+The **Anti-aliasing** effect softens the appearance of edges in your scene. To do this, it surrounds the edge with similar points of color. This reduces the jagged effect caused by [aliasing](https://en.wikipedia.org/wiki/Aliasing).
+
+
+
+The Post-processing anti-aliasing algorithms are image-based, which is useful when support for traditional multisampling is not available, such as the [deferred rendering](https://docs.unity3d.com/Manual/RenderTech-DeferredShading.html) path. You can configure the rendering settings in the [Quality settings](https://docs.unity3d.com/Manual/class-QualitySettings.html) window.
+
+The Post-processing stack offers the following anti-aliasing modes:
+
+- [**Fast Approximate Anti-aliasing (FXAA)**](#fast-approximate-anti-aliasing); a fast algorithm for mobile and platforms that don’t support motion vectors.
+- [**Subpixel Morphological Anti-aliasing (SMAA)**](#subpixel-morphological-anti-aliasing); a high-quality but slower algorithm for mobile and platforms that don’t support motion vectors.
+- [**Temporal Anti-aliasing (TAA)**](#temporal-anti-aliasing); an advanced technique which requires motion vectors. Ideal for desktop and console platforms.
+
+Each mode is set per-camera in the **Post-process Layer** component.
+
+
+
+## Fast Approximate Anti-aliasing (FXAA)
+
+**FXAA** is the most efficient anti-aliasing technique. It's ideal for mobile and other platforms that don’t support motion vectors, which are required for **Temporal Anti-aliasing**.
+
+### Properties
+
+| Property | Function |
+| :--------- | :----------------------------------------------------------- |
+| Mode | Select the type of **Anti-Aliasing** to use. |
+| Fast Mode | Enable **Fast Mode** for a lower quality but faster variant of FXAA. This option is ideal for mobile platforms. |
+| Keep Alpha | Enable **Keep Alpha** to keep the alpha channel untouched by post-processing. If Keep Alpha is disabled, Unity uses the alpha channel to store internal data used to speed up and improve visual quality. |
+
+### Performance
+
+Enable `Fast Mode` if you are developing for mobile devices to get a performance boost. It will also provide a small boost for consoles. `Fast Mode` does not provide any extra benefits for desktop GPUs. In this case regular mode should be used for added visual quality.
+
+### Requirements
+
+- Shader Model 3
+
+
+
+## Subpixel Morphological Anti-aliasing (SMAA)
+
+**SMAA** is a higher quality anti-aliasing effect than **FXAA** but it's also slower. Depending on the art-style of your game it can work as well as **Temporal Anti-aliasing** while avoiding some of the shortcomings of this technique.
+
+### Properties
+
+| Property | Function |
+| :------- | :----------------------------------------------- |
+| Mode | Select the type of **Anti-Aliasing** to use. |
+| Quality | Set the overall quality of the anti-aliasing filter. |
+
+### Performance
+
+Lowering the `Quality` setting makes the effect run faster. Do not use **SMAA** on mobile platforms.
+
+### Known issues and limitations
+
+- SMAA doesn't support AR/VR.
+
+### Requirements
+
+- Shader Model 3
+
+
+
+## Temporal Anti-aliasing (TAA)
+
+**TAA** is an advanced anti-aliasing technique where frames are accumulated over time in a history buffer to be used to smooth edges more effectively. It is substantially better at smoothing edges in motion but requires motion vectors and is more expensive than **FXAA**. It is ideal for desktop and console platforms.
+
+### Properties
+
+| Property | Function |
+| :------------------ | :----------------------------------------------------------- |
+| Mode | Select the type of **Anti-Aliasing** to use. |
+| Jitter Spread | Set the diameter (in texels) over which Unity spreads jitter samples. Smaller values result in crisper but a more aliased output. Larger values result in more stable but blurrier output. |
+| Stationary Blending | Set the blend coefficient for stationary fragments. This setting controls the percentage of history sample blended into final color for fragments with minimal active motion. |
+| Motion Blending | Set the blending coefficient for moving fragments. This setting controls the percentage of history sample blended into the final color for fragments with significant active motion. |
+| Sharpness | Set the sharpness to alleviate the slight loss of details in high frequency regions which can be caused by TAA. |
+
+### Known issues and limitations
+
+- Not supported on GLES2 platforms.
+- [Universal Render Pipeline (URP)](https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@7.5/manual/index.html) does not support Temporal Anti-aliasing.
+
+### Requirements
+
+- Motion vectors
+- Depth texture
+- Shader Model 3
diff --git a/com.unity.postprocessing/Documentation~/Auto-Exposure.md b/com.unity.postprocessing/Documentation~/Auto-Exposure.md
new file mode 100644
index 0000000..00d2f67
--- /dev/null
+++ b/com.unity.postprocessing/Documentation~/Auto-Exposure.md
@@ -0,0 +1,51 @@
+# Auto Exposure
+
+The **Auto Exposure** effect simulates how the human eye adjusts to changes in brightness in real-time. To do this, it dynamically adjusts the exposure of an image to match its mid-tone.
+
+In Unity, this effect generates a histogram on every frame and filters it to find the average luminance value. This histogram and the **Auto Exposure** effect requires [Compute shader](https://docs.unity3d.com/Manual/class-ComputeShader.html) support.
+
+
+Scene without **Auto Exposure**.
+
+
+Scene with **Auto Exposure**.
+
+### Properties
+
+**Exposure** settings:
+
+| Property | Function |
+| :--------------------- | :------------------------------------------------------------ |
+| Filtering | Set the lower and upper percentages of the histogram that find a stable average luminance. Values outside of this range will be discarded and won't contribute to the average luminance. |
+| Minimum | Set the minimum average luminance to consider for auto exposure in EV. |
+| Maximum | Set the maximum average luminance to consider for auto exposure in EV. |
+| Exposure Compensation | Set the middle-grey value to compensate the global exposure of the scene. |
+
+**Adaptation** settings:
+
+| Property | Function |
+| :---------- | :------------------------------------------------------------ |
+| Type | Select the Adaptation type. **Progressive** animates the Auto Exposure. **Fixed** does not animate the Auto Exposure. |
+| Speed Up | Set the Adaptation speed from a dark to a light environment. |
+| Speed Down | Set the Adaptation speed from a light to a dark environment. |
+
+### Details
+
+Use the `Filtering` range to exclude the darkest and brightest part of the image so that very dark and very bright pixels do not contribute to the average luminance. Values are in percent.
+
+`Minimum`/`Maximum` values clamp the computed average luminance into a given range.
+
+You can set the `Type` to `Fixed` and it will behave like an auto-exposure setting.
+
+You can debug the exposure in your scene with the **Post-process Debug** component. To do this, add the **Post-process Debug** component to your Camera and enable the **Light Meter** monitor.
+
+The Light Meter monitor creates a logarithmic histogram that appears in the **Game** window. This displays information about the exposure in your scene in real time. For more information, see [Debugging](#Debugging).
+
+
+
+The Light Meter monitor.
+
+### Requirements
+
+- Compute shader
+- Shader model 5
diff --git a/com.unity.postprocessing/Documentation~/Bloom.md b/com.unity.postprocessing/Documentation~/Bloom.md
new file mode 100644
index 0000000..e07aef0
--- /dev/null
+++ b/com.unity.postprocessing/Documentation~/Bloom.md
@@ -0,0 +1,43 @@
+# Bloom
+
+The **Bloom** effect makes bright areas in your image glow. To do this, it creates fringes of light that extend from bright areas in your image. This simulates the effect a real-world camera gives when light overwhelms the lens.
+
+The Bloom effect also has a **Dirtiness** feature, which you can use to apply a full-screen layer of smudges or dust to diffract the Bloom effect.
+
+
+
+### Properties
+
+**Bloom** settings:
+
+| Property | Function |
+| :---------------- | :------------------------------------------------------------ |
+| Intensity | Set the strength of the **Bloom** filter. |
+| Threshold | Set the level of brightness to filter out pixels under this level. This value is expressed in gamma-space. |
+| Soft Knee | Set the gradual threshold for transitions between under/over-threshold (0 = hard threshold, 1 = soft threshold). |
+| Clamp | Set the value for clamping pixels to control the **Bloom** amount. This value is expressed in gamma-space. |
+| Diffusion | Set the extent of veiling effects in a screen resolution-independent fashion. |
+| Anamorphic Ratio | Set the ratio to scale the **Bloom** vertically (in range [-1,0]) or horizontally (in range [0,1]). This emulates the effect of an anamorphic lens. |
+| Color | Select the color of the tint of the **Bloom** filter. |
+| Fast Mode | Enable this checkbox to boost performance by lowering the **Bloom** effect quality. |
+
+**Dirtiness** settings:
+
+| Property | Function |
+| --------- | ----------------------------------------------------- |
+| Texture | Select a Dirtiness texture to add smudges or dust to the lens. |
+| Intensity | Set the amount of lens dirtiness. |
+
+### Details
+
+With properly exposed HDR scenes, the `Threshold` should be set to ~1 so that only pixels with values above 1 leak into surrounding objects. Lower this value when working in LDR or the Bloom effect won’t be visible.
+
+### Performance
+
+Lowering the `Diffusion` parameter will make the effect faster. The further away `Anamorphic Ratio` is from 0, the slower it will be. Enable `Fast Mode` if you are developing for mobile or low-end platforms to get a significant boost in performance.
+
+Lower resolution lens dirt textures result in faster lookup and blending across volumes.
+
+### Requirements
+
+- Shader model 3
diff --git a/com.unity.postprocessing/Documentation~/Chromatic-Aberration.md b/com.unity.postprocessing/Documentation~/Chromatic-Aberration.md
new file mode 100644
index 0000000..2a740bf
--- /dev/null
+++ b/com.unity.postprocessing/Documentation~/Chromatic-Aberration.md
@@ -0,0 +1,42 @@
+# Chromatic Aberration
+
+The **Chromatic Aberration** effect splits color along boundaries in an image into their red, green, and blue channels. This reproduces the effect a real-world camera produces when light refracts and causes the wavelengths to disperse in the lens.
+
+Unity provides support for red/blue and green/purple fringing. You can define fringing colors by using an input texture.
+
+
+Scene without **Chromatic Aberration**.
+
+
+Scene with **Chromatic Aberration**.
+
+### Properties
+
+| Property | Function |
+| :------------ | :------------------------------------------------------------ |
+| Spectral Lut | Select the texture used for a custom fringing color. When left empty, Unity will use the default texture. |
+| Intensity | Set the strength of the **Chromatic Aberration** effect. |
+| Fast Mode | Use a faster variant of **Chromatic Aberration** effect for improved performance. |
+
+### Details
+
+**Chromatic Aberration** uses a `Spectral Lut` input for custom fringing. Four example spectral textures are provided in the repository:
+
+- Red/Blue (Default)
+- Blue/Red
+- Green/Purple
+- Purple/Green
+
+You can create custom spectral textures in any image editing software. While the resolution size of spectral textures are not limited, small sizes like the 3x1 textures provided work best.
+
+You can achieve a rougher effect by manually setting the **Filter Mode** of the input texture to **Point (no filter)** in the [Texture Import Settings](https://docs.unity3d.com/Manual/class-TextureImporter.html) window.
+
+### Performance
+
+The performance of the **Chromatic Aberration** effect depends on its `Intensity` value. If the `Intensity` value is high, the render uses more samples to render smooth chromatic aberrations. This makes the process take more time.
+
+**Fast Mode** is the quickest mode and recommended where possible. However, it's not as smooth as the regular mode.
+
+### Requirements
+
+- Shader Model 3
diff --git a/com.unity.postprocessing/Documentation~/Color-Grading.md b/com.unity.postprocessing/Documentation~/Color-Grading.md
new file mode 100644
index 0000000..542b8c0
--- /dev/null
+++ b/com.unity.postprocessing/Documentation~/Color-Grading.md
@@ -0,0 +1,142 @@
+# Color Grading
+
+The **Color Grading** effect alters or corrects the color and luminance of the final image that Unity produces. You can use this to alter the look and feel of your application.
+
+
+
+The **Color Grading** effect comes with three modes:
+
+- **Low Definition Range (LDR):** ideal for lower-end platforms. Grading is applied to the final rendered frame clamped in a [0,1] range and stored in a standard LUT.
+- **High Definition Range (HDR):** ideal for platforms that support HDR rendering. All color operations are applied in HDR and stored into a 3D log-encoded LUT to ensure a sufficient range coverage and precision (Alexa LogC El1000).
+- **External:** for use with custom 3D LUTs authored in external software.
+
+## Global Settings
+
+Use these settings to control how the **Color Grading** effect operates.
+
+The Lookup Texture and Contribution settings are only available for **Low Definition Range** and **External** modes.
+
+### Properties
+
+| Property | Function |
+| :-------------- | :------------------------------------------------------------ |
+| Mode | Select the **Color Grading** effect mode. |
+| Lookup Texture | **LDR:** Select a custom lookup texture (strip format, e.g. 256x16) to apply before the rest of the color grading operators. If none is provided, a neutral one will be generated internally.
**External**: A custom 3D log-encoded texture.|
+| Contribution | **LDR:** Set how much of the lookup texture will contribute to the color grading. |
+
+> **Note:** Volume blending between multiple LDR lookup textures is supported but only works correctly if they're the same size. For this reason it is recommended to stick to a single LUT size for the whole project (256x16 or 1024x32).
+
+## Tonemapping
+
+The **Tonemapping** effect remaps high dynamic range (HDR) colors into a range suitable for mediums with low dynamic range (LDR), such as CRT or LCD screens. Its most common purpose is to make an image with a low dynamic range appear to have a higher range of colors.
+
+This result increases the range of colors and contrast in an image to give a more dynamic and realistic effect. See Wikipedia: [Tone mapping](https://en.wikipedia.org/wiki/Tone_mapping).
+
+Always apply **Tonemapping** when using an HDR camera, otherwise color intensity values above 1 will be clamped at 1, altering the Scene's luminance balance.
+
+### Properties
+
+
+
+| Property | Function |
+| :----------------- | :------------------------------------------------------------ |
+| Mode | Only available in the **High Definition Range** mode. Select the Tonemapping mode from the dropdown menu. **None**: No **Tonemapping** applied. **Neutral**: Applies a range-remapping with minimal impact on color hue and saturation. **ACES**: Applies a close approximation of the reference [ACES](http://www.oscars.org/science-technology/sci-tech-projects/aces) tonemapper for a cinematic look. This effect has more contrast than **Neutral** affects color hue and saturation. When this tonemapper is enabled, all grading operations are performed in the ACES color spaces for optimal precision and results. **Custom**: A fully parametric tonemapper. This is the only tonemapper with its own settings. |
+| Toe Strength | Set a value for the transition between the toe and the mid section of the curve. A value of 0 means no toe, a value of 1 means a very hard transition. |
+| Toe Length | Set the value for how much of the dynamic range is in the toe. With a small value, the toe will be very short and quickly transition into the linear section, and with a longer value having a longer toe. |
+| Shoulder Strength | Set the value for the transition between the mid section and the shoulder of the curve. A value of 0 means no shoulder, value of 1 means a very hard transition. |
+| Shoulder Length | Set the value for how many F-stops (EV) to add to the dynamic range of the curve. |
+| Shoulder Angle | Set the value for how much overshot to add to the shoulder. |
+| Gamma | Set the value for applying a gamma function to the curve. |
+
+## White Balance
+
+**White Balance** allows you to adjust the overall tint and temperature of your image to create a colder or warmer feel in the final render.
+
+### Properties
+
+| Property | Function |
+| :----------- | :------------------------------------------------------------ |
+| Temperature | Set the white balance to a custom color temperature. |
+| Tint | Set the white balance to compensate for a green or magenta tint. |
+
+## Tone
+
+### Properties
+
+| Property | Function |
+| :------------- | :------------------------------------------------------------ |
+| Post-exposure | Only available in the **High Definition Range (HDR)** mode. Set the value for the overall exposure of the scene in EV units. This is applied after HDR effect and right before tonemapping so it won’t affect previous effects in the chain. |
+| Color Filter | Select a color for the Tint of the render. |
+| Hue Shift | Adjust the hue of all colors. |
+| Saturation | Adjust the intensity of all colors. |
+| Brightness | Only available in the **Low Definition Range (LDR)** mode. Adjust the brightness of the image.
|
+| Contrast | Adjust the overall range of tonal values. |
+
+## Channel Mixer
+
+You can use the **Channel Mixer** to adjust the color balance of your image.
+
+The **Channel Mixer** effect modifies the influence each input color channel has on the overall mix of the output channel. For example, if you increase the influence of the green channel on the overall mix of the red channel, all areas of the final image that include a green tone tint to a more reddish hue.
+
+### Properties
+
+| Property | Function |
+| :-------- | :------------------------------------------------------------ |
+| Channel | Select the output channel to modify. |
+| Red | Adjust the influence of the red channel within the overall mix. |
+| Green | Adjust the influence of the green channel within the overall mix. |
+| Blue | Adjust the influence of the blue channel within the overall mix. |
+
+## Trackballs
+
+Use **Trackballs** to perform three-way color grading. Adjust the position of the point on the trackball to shift the hue of the image towards that color in each tonal range. Each trackball affects different ranges within the image. Adjust the slider under the trackball to offset the color lightness of that range.
+
+> **Note:** you can right-click a trackball to reset it to its default value. To change the trackball's sensitivity go to `Edit -> Preferences -> PostProcessing`.
+
+
+
+### Properties
+
+| Property | Function |
+| :-------- | :------------------------------------ |
+| Lift | Adjust the dark tones (or shadows). |
+| Gamma | Adjust the mid-tones. |
+| Gain | Adjust the highlights. |
+
+## Grading Curves
+
+**Grading Curves** allows you to adjust specific ranges in hue, saturation, or luminosity. You can adjust the curves on the eight available graphs to achieve effects such as specific hue replacement or desaturating certain luminosities.
+
+### YRGB Curves
+
+**YRGB Curves** are only available in the **Low Definition Range (LDR)** mode. These curves, also called `Master`, `Red`, `Green` and `Blue` affect the selected input channel's intensity across the whole image. The X axis of the graph represents input intensity and the Y axis represents output intensity for the selected channel. Use these curves to adjust the appearance of attributes such as contrast and brightness.
+
+
+
+### Hue vs Hue
+
+Use **Hue vs Hue** to shift hues within specific ranges. This curve shifts the input hue (X axis) according to the output hue (Y axis). Use this setting to fine tune hues of specific ranges or perform color replacement.
+
+
+
+### Hue vs Sat
+
+Use **Hue vs Sat** to adjust the saturation of hues within specific ranges. This curve adjusts saturation (Y axis) according to the input hue (X axis). Use this setting to tone down particularly bright areas or create artistic effects.
+
+
+
+### Sat vs Sat
+
+Use **Sat vs Sat** to adjust the saturation of areas of certain saturation. This curve adjusts saturation (Y axis) according to the input saturation (X axis). Use this setting to fine tune saturation adjustments made with settings from the [**Tone**](#tone) section.
+
+
+
+### Lum vs Sat
+
+Use **Lum vs Sat** to adjust the saturation of areas of certain luminance. This curve adjusts saturation (Y axis) according to the input luminance (X axis). use this setting to desaturate areas of darkness to provide an interesting visual contrast.
+
+
+
+### Requirements
+
+- Shader Model 3
diff --git a/com.unity.postprocessing/Documentation~/Debugging-Post-processing-effects.md b/com.unity.postprocessing/Documentation~/Debugging-Post-processing-effects.md
new file mode 100644
index 0000000..52683e1
--- /dev/null
+++ b/com.unity.postprocessing/Documentation~/Debugging-Post-processing-effects.md
@@ -0,0 +1,101 @@
+# Debugging Post-processing effects
+
+The **Post-process Debug** component displays real-time data about post-processing effects. You can use this data to debug your post-processing effects, and to see the results of adjusting your effects in real time.
+
+When you attach the Post-Process Debug component to a GameObject with a Camera component, the Post-Process Debug component displays its data on top of that Camera's output. You can use the Post-process Debug component in the Unity Editor, or when your application is running on a device.
+
+
+
+## Using the Post-Process Debug component
+
+To use the Post-Process Debug component, create a **Post-process Debug** component on a GameObject. To do this, go to the Inspector window and select **Add component** > **Post-process Debug.**
+
+Use **Post Process Layer** to choose the post-processing layer that you want to view debug information for. If you create the Post-process Debug component on the Main Camera, Unity automatically assigns Main Camera to this field.
+To view an overlay that shows the state of an intermediate pass, select an intermediate pass from the **Debug Overlay** drop-down menu. Unity displays the overlay in the Game window.
+
+To use the [Light Meter](#light-meter) monitor, enable **Light Meter**. Unity displays a logarithmic histogram in the Game view that represents exposure. If you have the [**Auto Exposure**](https://docs.unity3d.com/Packages/com.unity.postprocessing@latest?subfolder=/manual/Auto-Exposure.html) post processing effect enabled, the histogram contains a thin line that indicates the current exposure. There is also a translucent area between the maximum and minimum exposure values. You can configure these exposure values in the **Auto Exposure** effect. The result of your changes appear in the Light Meter monitor in real-time.
+
+To view Tonemapping curves in the Light Meter histogram, enable **Show Curves**.
+
+To use the [Histogram](#histogram) monitor, enable **Histogram**. Unity displays a linear Gamma histogram in the Game view that represents exposure data in real-time in the rendered image. **Histogram** displays exposure data in more detail than **Light Meter**. Use the **Channel** drop-down menu to select the color data the Histogram displays.
+
+To use [Waveform](#waveform) monitor, enable **Waveform**. Unity displays a waveform in the Game view which represents the full spectrum of Luma (brightness) data in real-time in the rendered image.
+
+## Properties
+
+This section describes the settings that the Unity Editor displays in the Inspector for the **Post-Process Debug** component.
+
+| **Property** | **Description** |
+|--------------------|-----------------|
+| Post Process Layer | Select the post-processing layer that the Post-process Debug component uses.|
+
+### Overlay
+
+**Overlay** determines the intermediate pass that Unity displays in the Game window.
+
+| **Property** | **Description** |
+| ------------- | ------------------------------------------------------------ |
+| Debug overlay | Set the overlay view. Choose between different key intermediate passes to observe the state at this point in the frame. |
+
+## Monitors
+
+**Monitors** allow you to view data that Unity collects from the Game window in real-time.
+
+
+### Light meter
+The **Light Meter monitor** displays a logarithmic histogram in the Game window that represents exposure in the Camera’s output. You can control the exposure using the [**Auto Exposure**](https://docs.unity3d.com/Packages/com.unity.postprocessing@latest?subfolder=/manual/Auto-Exposure.html) component. When you configure the exposure values, Unity creates two new bars on the histogram:
+
+- A thin pink bar that indicates the current exposure value.
+- A translucent blue bar that indicates the area between the maximum and minimum exposure values.
+
+
+The **Light Meter Histogram** that Unity shows in the Game window.
+
+| **Property** | **Description** |
+|--------------|---------------------------------------------------------------------------------------------|
+| Light meter | Enable this checkbox to display the **Light meter** monitor in the Game window. |
+| Show Curves | Enable this checkbox to display Tonemapping curves monitor in the **Light meter** histogram |
+
+
+### Histogram
+The **Histogram** monitor displays a gamma histogram in the Game. A histogram graphs the number of pixels at each color intensity level, to illustrate how pixels in an image are distributed. It can help you determine whether an image is properly exposed or not.
+
+
+
+The **Histogram** that Unity shows in the Game window.
+
+| **Property** | **Description** |
+|--------------|-----------------|
+| Histogram |Enable this checkbox to display the **Histogram** monitor in the Game window.|
+| Channel | Select the color value.|
+
+
+### Waveform
+
+The **Waveform** monitor displays the full range of Luma (brightness) information in the Camera’s output. Unity displays the Waveform in the Game window. The horizontal axis of the graph corresponds to the render (from left to right) and the vertical axis is the brightness value.
+
+
+
+The **Waveform** that Unity shows in the Game window.
+
+| **Property** | **Description** |
+| ------------ | ------------------------------------------------------------ |
+| Waveform | Enable this checkbox to display the **Waveform** monitor in the Game window. |
+| Exposure | Set the exposure value this graph samples from. |
+
+### **Vectorscope**
+
+The **Vectorscope** monitor measures the overall range of hue and saturation within the Camera’s image in real-time. To display the data, it uses a scatter graph relative to the center of the Vectorscope.
+
+The Vectorscope measures hue values between yellow, red, magenta, blue, cyan and green. The center of the Vectorscope represents absolute zero saturation and the edges represent the highest level of saturation. To determine the hues in your scene and their saturation, look at the distribution of the Vectorscope’s scatter graph.
+
+To identify whether there is a color imbalance in the image, look at how close the middle of the Vectorscope graph is to the absolute center. If the Vectorscope graph is off-center, this indicates that there is a color cast (tint) in the image.
+
+
+
+The **Vectorscope** that Unity displays in the Game window.
+
+| **Property** | **Description** |
+|--------------|-----------------|
+| Vectorscope | Enable this checkbox to display the **Vectorscope** monitor in the Game window.|
+| Exposure |Set the exposure value this graph samples from.|
diff --git a/com.unity.postprocessing/Documentation~/Deferred-Fog.md b/com.unity.postprocessing/Documentation~/Deferred-Fog.md
new file mode 100644
index 0000000..9c43d38
--- /dev/null
+++ b/com.unity.postprocessing/Documentation~/Deferred-Fog.md
@@ -0,0 +1,25 @@
+# Deferred Fog
+
+The **Deferred Fog** effect simulates the look of fog or mist in outdoor environments. To do this, it overlays a color onto objects depending on how far away they are from the Camera.
+
+ 
+
+You can also use the Deferred fog effect to hide object clipping. This is useful if you want to bring the Camera’s far clip plane forward to improve performance.
+
+The **Deferred Fog** effect creates a screen-space fog based on the camera’s [depth texture](https://docs.unity3d.com/Manual/SL-DepthTextures.html). It supports Linear, Exponential and Exponential Squared fog types. **Deferred Fog** settings are on the **Scene** tab of the [**Lighting window**](https://docs.unity3d.com/Manual/lighting-window.html) in **Window > Rendering > Lighting Settings**.
+
+### Properties
+
+| Property | Function |
+| :-------------- | :--------------------------------- |
+| Enabled | Enable this checkbox to turn the **Deferred Fog** effect on.|
+| Exclude Skybox | Enable this checkbox to exclude fog from the [skybox](https://docs.unity3d.com/Manual/class-Skybox.html). |
+
+### Details
+
+The **Deferred Fog** effect only appears in your [**Post-process Layer**](https://docs.unity3d.com/Packages/com.unity.postprocessing@latest?subfolder=/manual/Quick-start.html#post-process-layer) if the camera is set to render with the [**Deferred rendering path**](https://docs.unity3d.com/Manual/RenderTech-DeferredShading.html). It is enabled by default and adds the support of **Deferred Fog** from the [**Lighting window**](https://docs.unity3d.com/Manual/lighting-window.html), which would otherwise only work with the [**Forward rendering path**](https://docs.unity3d.com/Manual/RenderTech-ForwardRendering.html).
+
+### Requirements
+
+- Depth texture
+- Shader Model 3
diff --git a/com.unity.postprocessing/Documentation~/Depth-of-Field.md b/com.unity.postprocessing/Documentation~/Depth-of-Field.md
new file mode 100644
index 0000000..d458213
--- /dev/null
+++ b/com.unity.postprocessing/Documentation~/Depth-of-Field.md
@@ -0,0 +1,25 @@
+# Depth of Field
+
+The **Depth of Field** effect blurs the background of your image while the objects in the foreground stay in focus. This simulates the focal properties of a real-world camera lens.
+
+ 
+
+A real-world **camera** can focus sharply on an object at a specific distance. Objects nearer or farther from the **camera’s** focal point appear slightly out of focus or blurred. This blurring gives a visual cue about an object’s distance, and introduces “bokeh” which refers to visual artifacts that appear around bright areas of the image as they fall out of focus.
+
+### Properties
+
+| Property | Function |
+| :-------------- | :------------------------------------------------------------ |
+| Focus Distance | Set the distance to the point of focus. |
+| Aperture | Set the ratio of the aperture (known as f-stop or f-number). The smaller the value is, the shallower the depth of field is. |
+| Focal Length | Set the distance between the lens and the film. The larger the value is, the shallower the depth of field is. |
+| Max Blur Size | Select the convolution kernel size of the bokeh filter from the dropdown. This setting determines the maximum radius of bokeh. It also affects the performance. The larger the kernel is, the longer the GPU time is required. |
+
+### Performance
+
+The speed of the **Depth of Field** effect is tied to **Max Blur Size**. Only use a value higher than `Medium` if you are developing for desktop computers and, depending on the post-processing budget of your game, consoles. Use the lowest value when developing for mobile platforms.
+
+### Requirements
+
+- Depth texture
+- Shader Model 3.5
diff --git a/com.unity.postprocessing/Documentation~/Grain.md b/com.unity.postprocessing/Documentation~/Grain.md
new file mode 100644
index 0000000..07aa8d6
--- /dev/null
+++ b/com.unity.postprocessing/Documentation~/Grain.md
@@ -0,0 +1,29 @@
+# Grain
+
+The **Grain** effect overlays film noise onto your image. Film noise is the effect that real-world cameras produce when small particles in the camera’s film give the image a coarse, unprocessed effect.
+Unity’s **Grain** effect is based on a coherent gradient noise. This gives your game a gritty effect that simulates the imperfections of film.
+
+The **Grain** effect available in Unity is based on a coherent gradient noise.
+
+
+Scene without the **Grain** effect.
+
+
+Scene with the **Grain** effect.
+
+### Properties
+
+| Property | Function |
+| :---------------------- | :------------------------------------------------------------ |
+| Colored | Enable the checkbox to use colored grain. |
+| Intensity | Set the value of the **Grain** strength. Higher values show more visible grain. |
+| Size | Set the value of the **Grain** particle size. |
+| Luminance Contribution | Set the value to control the noisiness response curve. This value is based on scene luminance. Lower values mean less noise in dark areas. |
+
+### Performance
+
+Disabling **Colored** makes the Grain effect run faster.
+
+### Requirements
+
+- Shader Model 3
diff --git a/com.unity.postprocessing/Documentation~/Installation.md b/com.unity.postprocessing/Documentation~/Installation.md
new file mode 100644
index 0000000..d49587b
--- /dev/null
+++ b/com.unity.postprocessing/Documentation~/Installation.md
@@ -0,0 +1,21 @@
+# Installation
+
+Use the [**Package Manager**](https://docs.unity3d.com/Manual/upm-ui.html) to install the **Post Processing** package or to update an installed package to the latest version.
+
+To install the **Post Processing** package:
+
+1. Open the Package Manager in **Window > Package Manager**.
+2. In the [Filter for scope](https://docs.unity3d.com/Manual/upm-ui-filter.html) menu, select **All packages**.
+3. In the list of packages, select **Post Processing**.
+4. In the bottom-right corner of the Package Manager window, select **Install**.
+
+For more information on the Package Manager and installing packages, see the following pages:
+* [Unity’s Package Manager](https://docs.unity3d.com/Manual/Packages.html).
+* [Adding and removing packages](https://docs.unity3d.com/Manual/upm-ui-actions.html).
+
+## Source code
+
+> **Note**: The best way to install a package is directly from the Unity registry using the Package Manager. The latest source code might contain unsupported or breaking changes.
+
+The source code for the **Post Processing** package is in the following repository:
+* [https://github.com/Unity-Technologies/PostProcessing](https://github.com/Unity-Technologies/PostProcessing)
diff --git a/com.unity.postprocessing/Documentation~/Lens-Distortion.md b/com.unity.postprocessing/Documentation~/Lens-Distortion.md
new file mode 100644
index 0000000..bc191f0
--- /dev/null
+++ b/com.unity.postprocessing/Documentation~/Lens-Distortion.md
@@ -0,0 +1,28 @@
+# Lens Distortion
+
+The **Lens Distortion** effect simulates distortion caused by the shape of a real-world camera lens. You can adjust the intensity of this effect between barrel distortion and pincushion distortion.
+
+
+Scene without **Lens Distortion**.
+
+
+Scene with **Lens Distortion**.
+
+### Properties
+
+| Property | Function |
+| :------------ | :------------------------------------------------------------ |
+| Intensity | Set the value for the total distortion amount. |
+| X Multiplier | Set the Intensity multiplier on X axis. Set it to 0 to disable distortion on this axis. |
+| Y Multiplier | Set the Intensity multiplier on Y axis. Set it to 0 to disable distortion on this axis. |
+| Center X | Set the Distortion center point (X axis). |
+| Center Y | Set the Distortion center point (Y axis). |
+| Scale | Set the value for global screen scaling. |
+
+### Known issues and limitations
+
+- Lens distortion doesn't support AR/VR.
+
+### Requirements
+
+- Shader Model 3
diff --git a/com.unity.postprocessing/Documentation~/Manipulating-the-Stack.md b/com.unity.postprocessing/Documentation~/Manipulating-the-Stack.md
new file mode 100644
index 0000000..553bb3b
--- /dev/null
+++ b/com.unity.postprocessing/Documentation~/Manipulating-the-Stack.md
@@ -0,0 +1,115 @@
+# Controlling effects using scripts
+
+This guide explains how to modify a post-processing script to create time-based events or temporary post-processing effects.
+
+## Quick Volumes
+
+Use the `QuickVolume` method to quickly spawn new volumes in the scene, to create time-based events or temporary states:
+
+```csharp
+[
+public PostProcessVolume QuickVolume(int layer, float priority, params PostProcessEffectSettings[] settings)
+]
+```
+The following example demonstrates how to use a script to create a pulsating vignette effect:
+
+```csharp
+[
+using UnityEngine;
+using UnityEngine.Rendering.PostProcessing;
+public class VignettePulse : MonoBehaviour
+{
+ PostProcessVolume m_Volume;
+ Vignette m_Vignette
+ void Start()
+ {
+ // Create an instance of a vignette
+ m_Vignette = ScriptableObject.CreateInstance();
+ m_Vignette.enabled.Override(true);
+ m_Vignette.intensity.Override(1f);
+ // Use the QuickVolume method to create a volume with a priority of 100, and assign the vignette to this volume
+ m_Volume = PostProcessManager.instance.QuickVolume(gameObject.layer, 100f, m_Vignette);
+ void Update()
+ {
+ // Change vignette intensity using a sinus curve
+ m_Vignette.intensity.value = Mathf.Sin(Time.realtimeSinceStartup);
+ }
+ void OnDestroy()
+ {
+ RuntimeUtilities.DestroyVolume(m_Volume, true, true);
+ }
+}
+```
+
+This code creates a new vignette and assigns it to a newly spawned volume. Then, on every frame, it changes the vignette intensity.To avoid memory leaks, destroy the volume and the attached profile when you don’t need them anymore.
+
+## Using tweening libraries with effects
+
+To change the parameters of effect over time or based on a gameplay event, you can manipulate Volume or effect parameters. You can do this in an Update method (as demonstrated in the vignette example above), or you can use a tweening library.
+
+A tweening library is a code library that provides utility functions for simple, code-based animations called "tweens". A few third-party tweening libraries are available for Unity for free, such as[ DOTween](http://dotween.demigiant.com/),[ iTween](http://www.pixelplacement.com/itween/index.php) or[ LeanTween](https://github.com/dentedpixel/LeanTween). The following example uses DOTween. For more information, see the [DOTween documentation](http://dotween.demigiant.com/documentation.php).
+
+This example spawns a volume with a vignette. Its weight is initially set to 0. The code uses the [sequencing feature](http://dotween.demigiant.com/documentation.php#creatingSequence) of DOTween to chain a set of tweening events that set the value of the weight parameter: fade in, pause for a second, fade out. After this sequence has completed, the code destroys the Volume and the `Vignette Pulse` component.
+
+```csharp
+using UnityEngine;
+using UnityEngine.Rendering.PostProcessing;
+using DG.Tweening;
+public class VignettePulse : MonoBehaviour
+{
+ void Start()
+ {
+ var vignette = ScriptableObject.CreateInstance();
+ vignette.enabled.Override(true);
+ vignette.intensity.Override(1f);
+ var volume = PostProcessManager.instance.QuickVolume(gameObject.layer, 100f, vignette);
+ volume.weight = 0f;
+ DOTween.Sequence()
+ .Append(DOTween.To(() => volume.weight, x => volume.weight = x, 1f, 1f))
+ .AppendInterval(1f)
+ .Append(DOTween.To(() => volume.weight, x => volume.weight = x, 0f, 1f))
+ .OnComplete(() =>
+ {
+ RuntimeUtilities.DestroyVolume(volume, true, true);
+ Destroy(this);
+ });
+ }
+}
+```
+
+## Profile Editing
+
+The above examples demonstrate how to create new effects and Volumes at runtime, but you can also manually edit an existing Profile that is used by one or more Volumes. To do this, you can use one of two fields on the `PostProcessVolume` . Each field has a slightly different effects:
+
+- Modify the shared profile directly:
+ - Class field name: [`sharedProfile`](...api/UnityEngine.Rendering.PostProcessing.PostProcessVolume.html#UnityEngine_Rendering_PostProcessing_PostProcessVolume_sharedProfile.html)
+ - Applies changes to all volumes using the same profile
+ - Modifies the asset and doesn’t reset when you exit play mode
+- Request a clone of the shared Profile that will only be used for this Volume:
+ - Class field name: [`profile`](...api/UnityEngine.Rendering.PostProcessing.PostProcessVolume.html#UnityEngine_Rendering_PostProcessing_PostProcessVolume_profile.html)
+ - Applies changes to the specified volume
+ - Resets when you exit play mode
+ - You must manually destroy the profile when you don't need it anymore
+
+The `PostProcessProfile` class contains the following utility methods to help you manage assigned effects:
+| Utility method | **Description** |
+| ------------------------------------------------------------ | ------------------------------------------------------------ |
+| [`T AddSettings()`](...api/UnityEngine.Rendering.PostProcessing.PostProcessProfile.html#UnityEngine_Rendering_PostProcessing_PostProcessProfile_AddSettings__1) | Creates, adds and returns a new effect of type `T` to the profile. It throws an exception if it already exist |
+| [`PostProcessEffectSettings AddSettings(PostProcessEffectSettings effect)`](api/UnityEngine.Rendering.PostProcessing.PostProcessProfile.html#UnityEngine_Rendering_PostProcessing_PostProcessProfile_AddSettings_UnityEngine_Rendering_PostProcessing_PostProcessEffectSettings_) | Adds and returns an effect that you created to the profile. |
+| [`void RemoveSettings()`](api/UnityEngine.Rendering.PostProcessing.PostProcessProfile.html#UnityEngine_Rendering_PostProcessing_PostProcessProfile_RemoveSettings__1) | Removes an effect from the profile. It throws an exception if it doesn't exist. |
+| [`bool TryGetSettings(out T outSetting)`](...api/UnityEngine.Rendering.PostProcessing.PostProcessProfile.html#UnityEngine_Rendering_PostProcessing_PostProcessProfile_TryGetSettings__1___0__) | Gets an effect from the profile, returns `true` if it found a profile, or `false` if it did not find a profile. |
+
+You can find more methods in the `/PostProcessing/Runtime/PostProcessProfile.cs` source file.
+
+**Important:** You must destroy any manually created profiles or effects.
+
+## Additional notes
+
+If you need to instantiate `PostProcessLayer` at runtime, you must bind your resources to it. To do this, add your component and call `Init()` on your `PostProcessLayer` with a reference to the `PostProcessResources` file as a parameter.
+
+Here is an example:
+
+```csharp
+var postProcessLayer = gameObject.AddComponent();
+postProcessLayer.Init(resources);
+```
diff --git a/com.unity.postprocessing/Documentation~/Motion-Blur.md b/com.unity.postprocessing/Documentation~/Motion-Blur.md
new file mode 100644
index 0000000..291287d
--- /dev/null
+++ b/com.unity.postprocessing/Documentation~/Motion-Blur.md
@@ -0,0 +1,27 @@
+# Motion Blur
+
+The **Motion Blur** effect blurs the image in the direction of the **Camera’s** movement. This simulates the blur effect a real-world camera creates when it moves with the lens aperture open, or when it captures an object moving faster than the camera’s exposure time.
+
+
+
+### Properties
+
+| Property | Function |
+| :------------- | :------------------------------------------------------------ |
+| Shutter Angle | Set the angle of the rotary shutter. Larger values give longer exposure and a stronger blur effect. |
+| Sample Count | Set the value for the amount of sample points. This affects quality and performance. |
+
+### Performance
+
+Using a lower `Sample Count` will improve performance.
+
+### Known issues and limitations
+
+- Motion blur doesn't support AR/VR.
+- Versions 7.0 to 7.5 of [Universal Render Pipeline (URP)](https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@7.5/manual/index.html) do not support this version of the Motion Blur effect. Instead, use [Motion Blur for URP](https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@latest?/manual/Post-Processing-Motion-Blur.html).
+
+### Requirements
+
+- Motion vectors
+- Depth texture
+- Shader Model 3
diff --git a/com.unity.postprocessing/Documentation~/Quick-start.md b/com.unity.postprocessing/Documentation~/Quick-start.md
new file mode 100644
index 0000000..3a0e1ea
--- /dev/null
+++ b/com.unity.postprocessing/Documentation~/Quick-start.md
@@ -0,0 +1,100 @@
+# Getting started with post-processing
+
+This page explains how to set up the components required to create post-processing effects in your scene.
+
+
+
+## Post-process Layer
+
+To enable post-processing in your scene, add the **Rendering** > **Post Process Layer** component to the Main Camera GameObject. This component allows you to configure anti-aliasing for this post-process layer, choose which layer it will apply the post-processing to, and select the GameObject that triggers this post-process layer.
+
+
+
+
+
+### Volume blending
+
+You can use a Volume framework to manage and blend between post-processing effects in Unity. Each Volume can either be global or have local boundaries. They each contain scene setting property values that Unity blends between, depending on the position of the Camera, in order to calculate a final value.
+
+Volumes can contain different combinations of Volume overrides that you can blend between. For example, one Volume can hold a Physically Based Sky Volume override, while another Volume holds an Exponential Fog Volume override.
+
+You can use local Volumes to change environment settings, such as fog color and density, to alter the mood of different areas of your Scene.
+
+**Volume blending** assigns a trigger for a **Post-processing Layer** and controls which layer affects the Camera.
+
+| Property | Description |
+| -------- | ------------------------------------------------------------ |
+| Trigger | This transform controls the volume blending feature. Unity assigns the Camera to the **Trigger** by default.
You can use other GameObjects to control the blending feature. For example, in a top-down game you might want to assign the player character GameObject to drive the blending instead of the Camera Transform.
When this field is set to None, it disables local volumes for this layer (global ones work normally). |
+| Layer | A mask of layers that Unity considers for volume blending. It allows you to control which layers affect the camera (volume filtering).
**Layer** also optimizes volume traversal, the update process of the volume system that blends parameters.
**Layer** is set to Nothing by default. It must have a layer assigned, otherwise volumes won’t take effect in your scene.
For best performance, keep your volumes in dedicated layers instead of the default one. For more information, see[ Layers](https://docs.unity3d.com/Manual/Layers.html). |
+
+### Anti-aliasing
+
+[**Anti-aliasing**](Anti-aliasing.html) reduces the appearance of jagged edges in your scene..
+
+The Post-process Layer component allows you to set up the anti-aliasing effect per-camera. You can use this to optimize the anti-aliasing in your scene. For example, you can enable [**Temporal Anti-aliasing (TAA)**](Anti-aliasing#temporal-anti-aliasing.html) on your Main Camera, and a less resource-intensive form of anti-aliasing like [**Fast approximate anti-aliasing** **(FXAA)**](Anti-aliasing#fast-approximate-anti-aliasing.html) on another camera.
+
+You can use this setting to optimize your cameras to only use anti-aliasing when needed.
+
+| Property | Description |
+| ------------------------- | ------------------------------------------------------------ |
+| Mode | Select the type of anti-aliasing this component uses. |
+| Stop NaN propagation | Destroys any pixels with positive or negative infinite values and pixels without any numeric data, known as Not a Number (NaN) pixels. It then replaces each pixel with a black color before Unity applies any post-processing effects. This avoids the presence of post-processing artifacts caused by broken data in the scene.
**Stop NaN propagation** can have a performance impact on some platforms. You should only enable it if you see post-processing artifacts as this setting does impact performance. |
+| Directly to Camera Target | Builds the anti-aliasing result directly to the Camera’s target. This can help with performance. You might find this useful if you are targeting low-end hardware and post-processing is causing performance issues at runtime.
**Directly to Camera Target** is not compatible with older post-processing effects that use the `OnRenderImage` API. |
+
+### Toolkit
+The Toolkit section comes with a few utilities.
+| Property | Description |
+| ------------------------------- | ------------------------------------------------------------ |
+| Export the current frame to EXR | Supports the following modes:
- **Full Frame (as displayed):** Exports the current frame of the Camera’s view. For example, if it is set to the Camera shown in the Game View, the export looks exactly like what is shown in the Game View.
- **Disable post-processing:** Exports the current frame of the Camera’s view, without any post-processing applied.
- **Break before Color Grading (linear):** Exports the current frame of the Camera’s view, but stops rendering just before **Color Grading** is applied. This is useful if you want to author grading LUTs in an external software.
- **Break before Color Grading (log):** Exports the current frame of the Camera’s view and log-encodes the output. This is useful if you want to author full-precision HDR grading LUTs in an external software. |
+| Select all layer volumes | Selects all **Post-process Volume** components that can affect this **Post-process Layer**. |
+| Select all active volumes | Selects all **Post-process Volume** components currently affecting this **Post-process Layer**. |
+### Custom Effect Sorting
+
+**Custom Effect Sorting** allows you to change the rendering order of custom effects. Custom effects in your scene appear here in a reorderable list from first to last. You can drag and drop each setting to change their order.
+
+For more information on custom effects, see [Writing Custom Effects](https://docs.unity3d.com/Packages/com.unity.postprocessing@latest?subfolder=/manual/Writing-Custom-Effects.html).
+
+
+
+## Post Process Volume
+
+The **Post-process Volume** component allows you to control the priority and blending of each local and global volume. You can also create a set of effect overrides to automatically blend post-processing settings in your scene.
+
+For example, if you have a global light vignette effect, you could control the **Intensity** setting of the vignette when the player enters a cave to make it darker, while the other post-processing settings are unchanged.
+
+You can add the Post Process Volume component to any GameObject, including the Main Camera GameObject. However, the optimal way to use this component is to create a dedicated GameObject for each volume. To do this:
+
+- Create an empty GameObject.
+- Add the Post-process Volume component to your new GameObject in the Inspector. To do this, select **Add** **Component > Post-process Volume.**
+- View your Main Camera’s Inspector, and in the Post-process Layer component, set **Layer** to the new GameObject you have just created.
+
+
+
+
+The **Post Process Volume** component is empty by default. Each post-process volume has two modes:
+
+- **Global:** A global volume has no boundaries and Unity applies it to the whole scene. You can have several of these in your scene.
+- **Local:** A local volume needs a collider or trigger component attached to it to define its boundaries. Any type of 3D collider is suitable, but complex meshes can be more resource-intensive. Local volumes have a **Blend Distance** property, which represents the outer distance from the volume surface where blending starts.
+
+| **Property** | **Description** |
+| -------------- | ------------------------------------------------------------ |
+| Is Global | Defines this volume as a Global volume. |
+| Blend Distance | The outer distance from the volume surface where blending starts.
This property only appears when **Is Global** is disabled. |
+| Weight | Reduces the global contribution of the volume and all its overrides.0 indicates no contribution and 1 indicates full contribution. |
+| Priority | Defines this volume’s order in the stack. The higher this number is, the higher this volume is placed in the stack. This means that Unity runs this volume before volumes in the stack that have a lower **Priority** number. |
+| Profile | Defines the profile for this volume. You can create a new profile using **New** or clone an existing profile.
When you assign a profile to this field, the **Clone** button appears. You can use this to duplicate the assigned profile and assign it to this volume. |
+
+## Adding post-processing effects to the stack
+Once you have assigned a post-processing profile to the [Post Process Volume](#post-process-volume) component, you can add post-processing effects to the stack. To do this, click the **Add effect** button at the bottom of the component, and choose the post-processing effect you want to use from the drop-down list. The Post Process Volume component displays all applied post-processing effects, and their properties, in a list at the bottom of the component’s Inspector.
+
+The Post Process Volume component displays the following settings for each post-processing effect in the list:
+
+
+
+A. Effect overrides toggle (checkbox): This checkbox toggles all overrides for this effect in this particular volume, but preserves your override selections when you disable and re-enable it.
+
+B. Effect name: Right-click an effect name to show a quick-action menu to copy, paste, remove, or reset settings.
+
+C. Effect toggle: Select the **On** or **Off** buttons to toggle an effect within this volume. This is useful if you want to manually disable an effect in this volume that is enabled globally or in a higher priority volume.
+
+D. Property override toggle (checkbox): Enable this override checkbox to edit an individual setting. You can also quickly toggle all property overrides on or off with the small **All** and **None** shortcuts below the effect title.
diff --git a/com.unity.postprocessing/Documentation~/Screen-Space-Reflections.md b/com.unity.postprocessing/Documentation~/Screen-Space-Reflections.md
new file mode 100644
index 0000000..90ca2e3
--- /dev/null
+++ b/com.unity.postprocessing/Documentation~/Screen-Space-Reflections.md
@@ -0,0 +1,35 @@
+# Screen Space Reflections
+
+The **Screen Space Reflection** effect creates subtle reflections that simulate wet floor surfaces or puddles. It reflects both static and dynamic GameObjects to create realistic reflections.
+
+Screen Space Reflection replaces specular highlights on a surface, which makes it an ideal effect to limit the amount of [specular light](https://docs.unity3d.com/Manual/shader-NormalSpecular.html) leaking.
+
+
+
+### Properties
+
+| Property | Function |
+| :----------------------- | :------------------------------------------------------------ |
+| Preset | Select the quality preset from the dropdown. Use **Custom** to fine tune the quality. |
+| Maximum Iteration Count (`Custom` preset only) | Set the maximum number of steps in the raymarching pass. A higher value creates more reflections. |
+| Thickness (`Custom` preset only)| Set the value of the ray thickness. A lower value detects smaller details but it is resource-intensive. |
+| Resolution (`Custom` preset only)| Select the size of the internal buffer. Select **Downsample** to maximize performance. **Supersample** is slower but produces higher quality results. |
+| Maximum March Distance | Set the maximum distance to draw reflections in the scene. |
+| Distance Fade | Set the value for the distance to fade reflections close to the near plane. This is useful to hide common artifacts. |
+| Vignette | Set the value to fade the reflections close to the screen edges. |
+
+### Performance
+
+The `Custom` preset is very resource-intensive and best for beauty shots. If you are developing for consoles, use **Medium** as the maximum, unless you have plenty of GPU time to spare. On lower resolutions you can boost the quality preset and get similar timings with a higher visual quality.
+
+### Known issues and limitations
+
+- Screen-space reflections doesn't support AR/VR.
+- [Universal Render Pipeline (URP)](https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@7.5/manual/index.html) do not support Screen Space Reflections.
+
+### Requirements
+
+- Compute shader
+- Motion vectors
+- Deferred rendering path
+- Shader Model 5.0
diff --git a/com.unity.postprocessing/Documentation~/TableOfContents.md b/com.unity.postprocessing/Documentation~/TableOfContents.md
new file mode 100644
index 0000000..2424dc5
--- /dev/null
+++ b/com.unity.postprocessing/Documentation~/TableOfContents.md
@@ -0,0 +1,23 @@
+* [Post-Processing Stack v2](index)
+* [Requirements](requirements)
+* [Installation](Installation)
+* [Getting started](Quick-Start)
+* Effects
+ * [Ambient Occlusion](Ambient-Occlusion)
+ * [Anti-aliasing](Anti-aliasing)
+ * [Auto Exposure](Auto-Exposure)
+ * [Bloom](Bloom)
+ * [Chromatic Aberration](Chromatic-Aberration)
+ * [Color Grading](Color-Grading)
+ * [Deferred Fog](Deferred-Fog)
+ * [Depth of Field](Depth-of-Field)
+ * [Grain](Grain)
+ * [Lens Distortion](Lens-Distortion)
+ * [Motion Blur](Motion-Blur)
+ * [Screen Space Reflections](Screen-Space-Reflections)
+ * [Vignette](Vignette)
+* Scripting
+ * [Controlling effects using scripts](Manipulating-the-Stack)
+ * [Writing custom effects](Writing-Custom-Effects)
+* [Known issues](known-issues)
+* [Debugging Post-processing effects](Debugging-Post-processing-effects)
diff --git a/com.unity.postprocessing/Documentation~/Vignette.md b/com.unity.postprocessing/Documentation~/Vignette.md
new file mode 100644
index 0000000..57eb02f
--- /dev/null
+++ b/com.unity.postprocessing/Documentation~/Vignette.md
@@ -0,0 +1,49 @@
+# Vignette
+
+The **Vignette** effect darkens the edges of an image. This simulates the effect in a real-world camera lens caused by thick or stacked filters, secondary lenses, or an improper lens hood. You can use the **Vignette** effect to draw attention to the center of an image.
+
+
+Scene without **Vignette** effect.
+
+
+Scene with **Vignette** effect.
+
+The Vignette effect in the post-processing stack has two modes:
+
+- [Classic](#classic)
+- [Masked](#masked)
+
+
+## Classic
+
+**Classic** mode has parametric controls for the position, shape and intensity of the Vignette. This is the most common way to use the effect.
+
+### Properties
+
+| Property | Function |
+| :-------------- | :------------------------------------------------------------ |
+| Mode | Select the type of **Vignette** to use. |
+| Color | Set the color of the Vignette. |
+| Center | Set the Vignette center point (screen center is [0.5,0.5]). |
+| Intensity | Set the amount of vignetting on screen. |
+| Smoothness | Set the smoothness of the Vignette borders. |
+| Roundness | Set the value to round the Vignette. Lower values will make a more squared vignette. |
+| Rounded | Enable this checkbox to make the vignette perfectly round. When disable, the Vignette effect is dependent on the current aspect ratio. |
+
+
+## Masked
+
+**Masked** mode uses a custom texture mask and multiplies it over the scene to create a Vignette effect. This mode can be used to create less common or irregular vignetting effects.
+
+### Properties
+
+| Property | Function |
+| :------------- | :------------------------------------------------------- |
+| Mode | Select the type of **Vignette** to use. |
+| Color | Set the color of the Vignette. Use the alpha channel for transparency. |
+| Mask | Select a black and white mask to use as a vignette. |
+| Opacity | Set the mask opacity value. |
+
+### Requirements
+
+- Shader Model 3
diff --git a/com.unity.postprocessing/Documentation~/Writing-Custom-Effects.md b/com.unity.postprocessing/Documentation~/Writing-Custom-Effects.md
new file mode 100644
index 0000000..62b830d
--- /dev/null
+++ b/com.unity.postprocessing/Documentation~/Writing-Custom-Effects.md
@@ -0,0 +1,240 @@
+# Writing custom effects
+
+This quick-start guide demonstrates how to write a custom [post-processing effect](https://docs.unity3d.com/Manual/PostProcessingOverview.html) and include it in the post-processing stack. This process does not require you to modify the codebase.
+
+Custom post-processing effects require a minimum of two files:
+
+- A C# source file
+- An [HLSL](https://en.wikipedia.org/wiki/High-Level_Shading_Language) source file
+
+Unity cross-compiles HLSL to [GLSL](https://docs.unity3d.com/Manual/SL-GLSLShaderPrograms.html), [Metal](https://docs.unity3d.com/Manual/Metal.html), and other APIs. This means it is not restricted to DirectX.
+
+This quick-start guide requires a basic knowledge of programming C# in Unity and HLSL shader programming.
+
+## C# source code
+
+The following example demonstrates how to use a C# script to create a custom grayscale post-processing effect. The script in this example calls APIs from the Post Processing framework and works with volume blending. This example is compatible with versions of Unity from 2018 onwards. It is not compatible with [HDRP](https://docs.unity3d.com/Packages/com.unity.render-pipelines.high-definition@latest?subfolder=/manual/):
+
+```csharp
+using System;
+using UnityEngine;
+using UnityEngine.Rendering.PostProcessing;
+
+[Serializable]
+[PostProcess(typeof(GrayscaleRenderer), PostProcessEvent.AfterStack, "Custom/Grayscale")]
+public sealed class Grayscale : PostProcessEffectSettings
+{
+ [Range(0f, 1f), Tooltip("Grayscale effect intensity.")]
+ public FloatParameter blend = new FloatParameter { value = 0.5f };
+}
+public sealed class GrayscaleRenderer : PostProcessEffectRenderer
+{
+ public override void Render(PostProcessRenderContext context)
+ {
+ var sheet = context.propertySheets.Get(Shader.Find("Hidden/Custom/Grayscale"));
+ sheet.properties.SetFloat("_Blend", settings.blend);
+ context.command.BlitFullscreenTriangle(context.source, context.destination, sheet, 0);
+ }
+}
+```
+
+> **Important**: This file name of this script must match the name of its class for it to serialize correctly. In this case, the script must be stored in a file named `Grayscale.cs`.
+
+### Classes
+
+A custom post-processing effect script requires two classes:
+
+- a data class to store settings
+- a logic class to render the effect
+
+### Data class
+
+The data class holds all the settings fields the user sees in the Inspector window for that volume profile. Here is how the data class works in the example script described in C# source code:
+
+```csharp
+//The Serializable attribute allows Unity to serialize this class and extend PostProcessEffectSettings.
+[Serializable]
+// The [PostProcess()] attribute tells Unity that this class holds post-processing data. The first parameter links the settings to a renderer. The second parameter creates the injection point for the effect. The third parameter is the menu entry for the effect. You can use a forward slash (/) to create sub-menu categories.
+[PostProcess(typeof(GrayscaleRenderer), PostProcessEvent.AfterStack, "Custom/Grayscale")]
+public sealed class Grayscale : PostProcessEffectSettings
+{
+ // You can create boxed fields to override or blend parameters. This example uses a FloatParameter with a fixed range from 0 to 1.
+ [Range(0f, 1f), Tooltip("Grayscale effect intensity.")]
+ public FloatParameter blend = new FloatParameter { value = 0.5f };
+}
+```
+
+#### Notes:
+
+The second parameter of the `[PostProcess()]` attribute is the injection point for the effect. There are three injection points available:
+
+- `BeforeTransparent`: Unity only applies the effect to opaque objects before Unity runs the transparent pass.
+- `BeforeStack`: Unity injects the effect before applying the built-in stack. This applies to all post processing effects except [Temporal anti-aliasing (TAA),](https://docs.unity3d.com/Packages/com.unity.postprocessing@latest?subfolder=/manual/Anti-aliasing.html) which Unity applies before any injection points.
+- `AfterStack`: Unity applies the effect after the built-in stack and before [FXAA](https://docs.unity3d.com/Packages/com.unity.postprocessing@latest?subfolder=/manual/Anti-aliasing#fast-approximate-anti-aliasing.html) (if it's enabled) and final-pass dithering.
+
+The `[PostProcess()]` attribute has an optional fourth parameter called `allowInSceneView`. You can use this parameter to enable or disable the effect in the scene. It's set to true by default, but you can disable it for temporal effects or effects that get in the way of editing the scene easily.
+
+For a full list of built-in parameter classes, see the `ParameterOverride.cs` source file in **/PostProcessing/Runtime/**.
+
+If you want to set your own requirements for the effect or disable it until a condition is met, you can override the `IsEnabledAndSupported()` method of `PostProcessEffectSettings`. For example, the following script automatically disables an effect if the blend parameter is `0`:
+
+```csharp
+public override bool IsEnabledAndSupported(PostProcessRenderContext context)
+{
+ return enabled.value
+ && blend.value > 0f;
+}
+```
+
+### Logic class
+
+The logic class tells Unity how to render this post-processing effect. Here is how the logic class works in the example script described in C# source code:
+
+```csharp
+// This renderer extends PostProcessEffectRenderer, where T is the settings type Unity attaches to this renderer.
+public sealed class GrayscaleRenderer : PostProcessEffectRenderer
+{
+ // Everything that happens in the Render() method takes a PostProcessRenderContext as parameter.
+ public override void Render(PostProcessRenderContext context)
+ {
+// Request a PropertySheet for our shader and set the uniform within it.
+ var sheet = context.propertySheets.Get(Shader.Find("Hidden/Custom/Grayscale"));
+// Send the blend parameter value to the shader.
+ sheet.properties.SetFloat("_Blend", settings.blend);
+ // This context provides a command buffer which you can use to blit a fullscreen pass using a source image as an input with a destination for the shader, sheet and pass number.
+ context.command.BlitFullscreenTriangle(context.source, context.destination, sheet, 0);
+ }
+}
+```
+
+#### Notes:
+
+The `PostProcessRenderContext` context holds data that Unity passes around effects when it renders them. You can find out what data is available in **/PostProcessing/Runtime/PostProcessRenderContext.cs**.
+
+The example grayscale effect script only uses [command buffers](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.html) which means the system relies on `MaterialPropertyBlock` to store shader data. Unity’s framework automatically pools the shader data to save time and optimize performance. This script requests a `PropertySheet` for the shader and sets the uniform inside it, so that you do not need to create `MaterialPropertyBlock` manually.
+
+`PostProcessEffectRenderer` has the following methods you can override:
+
+| Method | Description |
+| ----------------------------------------- | ------------------------------------------------------------ |
+| `void Init()` | This method is called when the renderer is created |
+| `DepthTextureMode GetLegacyCameraFlags()` | This method sets Camera flags and requests depth maps, motion vectors, etc. |
+| `void ResetHistory()` | This method is called when a "reset history" event is dispatched. Use this to clear history buffers for temporal effects. |
+| `void Release()` | This method is called when the renderer is destroyed. You can perform a cleanup here |
+
+## HLSL source code
+
+Unity uses the HLSL programming language for shader programs. For more information, see [Shading language used in Unity](https://docs.unity3d.com/Manual/SL-ShadingLanguage.html).
+
+The following example demonstrates how to create an HLSL script for a custom grayscale post-processing effect:
+
+```hlsl
+Shader "Hidden/Custom/Grayscale"
+{
+ HLSLINCLUDE
+// StdLib.hlsl holds pre-configured vertex shaders (VertDefault), varying structs (VaryingsDefault), and most of the data you need to write common effects.
+ #include "Packages/com.unity.postprocessing/PostProcessing/Shaders/StdLib.hlsl"
+ TEXTURE2D_SAMPLER2D(_MainTex, sampler_MainTex);
+// Lerp the pixel color with the luminance using the _Blend uniform.
+ float _Blend;
+ float4 Frag(VaryingsDefault i) : SV_Target
+ {
+ float4 color = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord);
+// Compute the luminance for the current pixel
+ float luminance = dot(color.rgb, float3(0.2126729, 0.7151522, 0.0721750));
+ color.rgb = lerp(color.rgb, luminance.xxx, _Blend.xxx);
+// Return the result
+ return color;
+ }
+ ENDHLSL
+ SubShader
+ {
+ Cull Off ZWrite Off ZTest Always
+ Pass
+ {
+ HLSLPROGRAM
+ #pragma vertex VertDefault
+ #pragma fragment Frag
+ ENDHLSL
+ }
+ }
+}
+
+```
+
+#### Notes:
+
+This framework uses [shader preprocessor macros](https://docs.unity3d.com/Manual/SL-BuiltinMacros.html) to define platform differences. This helps to maintain compatibility across platforms and render pipelines.
+
+This script also uses macros to declare textures. For a list of available macros, see the API files in **/PostProcessing/Shaders/API/**.
+
+This script uses HLSL blocks instead of CG blocks to avoid compatibility issues between render pipelines. Inside the HLSL block is the varying structs parameter, `VaryingsDefault i`. This parameter can use the following variables:
+```hlsl
+struct VaryingsDefault
+{
+ float4 vertex : SV_POSITION;
+ float2 texcoord : TEXCOORD0;
+ float2 texcoordStereo : TEXCOORD1;
+#if STEREO_INSTANCING_ENABLED
+ uint stereoTargetEyeIndex : SV_RenderTargetArrayIndex;
+#endif
+};
+```
+
+- `vertex`: The vertex position.
+- `texcoord`: The UV coordinate for the fragment.
+- `texcoordStereo`: The UV coordinate for the fragment in stereo mode
+- `stereoTargetEyeIndex`: The current eye index (only available with VR + stereo instancing).
+
+Unity cannot build a shader if it is not referenced in a scene. This means the effect does not work when the application is running outside of the Editor. To fix this, add your shader to a[ Resources folder](https://docs.unity3d.com/Manual/LoadingResourcesatRuntime.html) or include it in the [**Always Included Shaders**](https://docs.unity3d.com/Manual/class-GraphicsSettings.html#Always) list in **Edit > Project Settings > Graphics**.
+
+## Ordering post-processing effects
+
+Unity automatically sorts built-in effects, but it handles custom effects differently. When you create a new effect or import it into your project, Unity does the following:
+
+- Adds the custom effect to the Custom Effect Sorting list in the Post Process Layer component on a Camera.
+- Sorts each custom effect by its injection point. You can change the order of the custom effects in the [Post Process Layer](#Quick-start) component using **Custom Effect Sorting**.
+
+Unity orders custom effects within each layer, which means you can order your custom effects differently for each Camera.
+
+## Creating a custom editor
+
+Unity automatically creates editors for settings classes. If you want to control how Unity displays certain fields, you can create a custom editor.
+
+The following example uses the default editor script to create a custom editor for a `Grayscale` effect:
+
+```csharp
+using UnityEngine.Rendering.PostProcessing;
+using UnityEditor.Rendering.PostProcessing;
+
+[PostProcessEditor(typeof(Grayscale))]
+public sealed class GrayscaleEditor : PostProcessEffectEditor
+{
+ SerializedParameterOverride m_Blend;
+
+ public override void OnEnable()
+ {
+ m_Blend = FindParameterOverride(x => x.blend);
+ }
+
+ public override void OnInspectorGUI()
+ {
+ PropertyField(m_Blend);
+ }
+}
+```
+
+#### Notes:
+
+For Unity to recognise your custom editor, it has to be in an Editor folder.
+
+## FXAA compatibility with custom effects
+
+If you apply [**FXAA**](Anti-aliasing#fast-approximate-anti-aliasing.html) in a scene with custom effects, the order of your post-processing effects might stop it from working correctly. This is because FXAA looks for the LDR (Low dynamic range) luminance value of each pixel in the alpha channel of its source target to optimise performance.
+
+If you inject custom effects at the `AfterStack` injection point, as demonstrated in the example above, FXAA looks for LDR luminance in the last executed effect. If it can’t find it, FXAA won’t work correctly.
+
+You can fix this in your custom shader in one of two ways:
+
+- Make sure that the last executed effect contains LDR luminance in the alpha channel.
+- Copy the alpha from the incoming source.
diff --git a/com.unity.postprocessing/Documentation~/images/Grain_image_0.png b/com.unity.postprocessing/Documentation~/images/Grain_image_0.png
new file mode 100644
index 0000000..16c493e
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/Grain_image_0.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/Grain_image_1.png b/com.unity.postprocessing/Documentation~/images/Grain_image_1.png
new file mode 100644
index 0000000..b9bc6e8
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/Grain_image_1.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/PostProcessing-Bloom-0.png b/com.unity.postprocessing/Documentation~/images/PostProcessing-Bloom-0.png
new file mode 100644
index 0000000..96d2050
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/PostProcessing-Bloom-0.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/PostProcessing-ChromaticAberration-0.png b/com.unity.postprocessing/Documentation~/images/PostProcessing-ChromaticAberration-0.png
new file mode 100644
index 0000000..0f3d8b4
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/PostProcessing-ChromaticAberration-0.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/PostProcessing-ChromaticAberration-1.png b/com.unity.postprocessing/Documentation~/images/PostProcessing-ChromaticAberration-1.png
new file mode 100644
index 0000000..3415870
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/PostProcessing-ChromaticAberration-1.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/PostProcessing-Vignette-1.png b/com.unity.postprocessing/Documentation~/images/PostProcessing-Vignette-1.png
new file mode 100644
index 0000000..dbc7975
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/PostProcessing-Vignette-1.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/PostProcessing-Vignette-2.png b/com.unity.postprocessing/Documentation~/images/PostProcessing-Vignette-2.png
new file mode 100644
index 0000000..efb341a
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/PostProcessing-Vignette-2.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/Ppv2 _ Debugging_Light meter_Graph.png b/com.unity.postprocessing/Documentation~/images/Ppv2 _ Debugging_Light meter_Graph.png
new file mode 100644
index 0000000..33dd90d
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/Ppv2 _ Debugging_Light meter_Graph.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/Ppv2 _ Debugging_Vectorscope_Graph.png b/com.unity.postprocessing/Documentation~/images/Ppv2 _ Debugging_Vectorscope_Graph.png
new file mode 100644
index 0000000..4347594
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/Ppv2 _ Debugging_Vectorscope_Graph.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/Ppv2-Debugging-Histogram-Graph.png b/com.unity.postprocessing/Documentation~/images/Ppv2-Debugging-Histogram-Graph.png
new file mode 100644
index 0000000..aa14e99
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/Ppv2-Debugging-Histogram-Graph.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/Ppv2-Debugging-Light-Meter-Graph.png b/com.unity.postprocessing/Documentation~/images/Ppv2-Debugging-Light-Meter-Graph.png
new file mode 100644
index 0000000..33dd90d
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/Ppv2-Debugging-Light-Meter-Graph.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/Ppv2-Debugging-Vectorscope-Graph.png b/com.unity.postprocessing/Documentation~/images/Ppv2-Debugging-Vectorscope-Graph.png
new file mode 100644
index 0000000..4347594
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/Ppv2-Debugging-Vectorscope-Graph.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/Ppv2-Debugging-Waveform-Graph.png b/com.unity.postprocessing/Documentation~/images/Ppv2-Debugging-Waveform-Graph.png
new file mode 100644
index 0000000..7663a69
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/Ppv2-Debugging-Waveform-Graph.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/Ppv2_Debugging_Histogram.png b/com.unity.postprocessing/Documentation~/images/Ppv2_Debugging_Histogram.png
new file mode 100644
index 0000000..df78e34
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/Ppv2_Debugging_Histogram.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/Ppv2_Debugging_Waveform_Graph.png b/com.unity.postprocessing/Documentation~/images/Ppv2_Debugging_Waveform_Graph.png
new file mode 100644
index 0000000..7663a69
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/Ppv2_Debugging_Waveform_Graph.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/Ppv2_Light Meter.png b/com.unity.postprocessing/Documentation~/images/Ppv2_Light Meter.png
new file mode 100644
index 0000000..0548bc7
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/Ppv2_Light Meter.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/Ppv2_Post-processing-Debug.png b/com.unity.postprocessing/Documentation~/images/Ppv2_Post-processing-Debug.png
new file mode 100644
index 0000000..0597c33
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/Ppv2_Post-processing-Debug.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/aa-1.png b/com.unity.postprocessing/Documentation~/images/aa-1.png
new file mode 100644
index 0000000..21eb1c2
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/aa-1.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/aa-2.png b/com.unity.postprocessing/Documentation~/images/aa-2.png
new file mode 100644
index 0000000..b503812
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/aa-2.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/aa-3.png b/com.unity.postprocessing/Documentation~/images/aa-3.png
new file mode 100644
index 0000000..cd0007f
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/aa-3.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/ao-off.png b/com.unity.postprocessing/Documentation~/images/ao-off.png
new file mode 100644
index 0000000..c0a352c
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/ao-off.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/ao-on.png b/com.unity.postprocessing/Documentation~/images/ao-on.png
new file mode 100644
index 0000000..91ea2c2
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/ao-on.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/auto-exposure-off.png b/com.unity.postprocessing/Documentation~/images/auto-exposure-off.png
new file mode 100644
index 0000000..98b5792
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/auto-exposure-off.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/auto-exposure-on.png b/com.unity.postprocessing/Documentation~/images/auto-exposure-on.png
new file mode 100644
index 0000000..c68fe58
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/auto-exposure-on.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/autoexposure.png b/com.unity.postprocessing/Documentation~/images/autoexposure.png
new file mode 100644
index 0000000..db753b3
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/autoexposure.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/bloom.png b/com.unity.postprocessing/Documentation~/images/bloom.png
new file mode 100644
index 0000000..b73457b
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/bloom.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/chroma.png b/com.unity.postprocessing/Documentation~/images/chroma.png
new file mode 100644
index 0000000..68e2afb
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/chroma.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/custom-effect-sorting.png b/com.unity.postprocessing/Documentation~/images/custom-effect-sorting.png
new file mode 100644
index 0000000..b80a44f
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/custom-effect-sorting.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/deferredfog.png b/com.unity.postprocessing/Documentation~/images/deferredfog.png
new file mode 100644
index 0000000..3f7b0fe
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/deferredfog.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/dof.png b/com.unity.postprocessing/Documentation~/images/dof.png
new file mode 100644
index 0000000..1a3f48c
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/dof.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/grading-1.png b/com.unity.postprocessing/Documentation~/images/grading-1.png
new file mode 100644
index 0000000..b6ef7c6
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/grading-1.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/grading-10.png b/com.unity.postprocessing/Documentation~/images/grading-10.png
new file mode 100644
index 0000000..d3da775
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/grading-10.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/grading-11.png b/com.unity.postprocessing/Documentation~/images/grading-11.png
new file mode 100644
index 0000000..1ecd6ee
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/grading-11.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/grading-2.png b/com.unity.postprocessing/Documentation~/images/grading-2.png
new file mode 100644
index 0000000..7cfcef2
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/grading-2.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/grading-3.png b/com.unity.postprocessing/Documentation~/images/grading-3.png
new file mode 100644
index 0000000..339ab52
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/grading-3.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/grading-4.png b/com.unity.postprocessing/Documentation~/images/grading-4.png
new file mode 100644
index 0000000..68f2739
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/grading-4.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/grading-5.png b/com.unity.postprocessing/Documentation~/images/grading-5.png
new file mode 100644
index 0000000..a5d0012
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/grading-5.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/grading-6.png b/com.unity.postprocessing/Documentation~/images/grading-6.png
new file mode 100644
index 0000000..900259a
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/grading-6.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/grading-7.png b/com.unity.postprocessing/Documentation~/images/grading-7.png
new file mode 100644
index 0000000..3cd56fe
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/grading-7.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/grading-8.png b/com.unity.postprocessing/Documentation~/images/grading-8.png
new file mode 100644
index 0000000..b919341
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/grading-8.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/grading-9.png b/com.unity.postprocessing/Documentation~/images/grading-9.png
new file mode 100644
index 0000000..bbd74f7
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/grading-9.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/grain.png b/com.unity.postprocessing/Documentation~/images/grain.png
new file mode 100644
index 0000000..3271913
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/grain.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/home-after.png b/com.unity.postprocessing/Documentation~/images/home-after.png
new file mode 100644
index 0000000..11c5ba3
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/home-after.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/home-before.png b/com.unity.postprocessing/Documentation~/images/home-before.png
new file mode 100644
index 0000000..16ff58f
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/home-before.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/hue-vs-hue.png b/com.unity.postprocessing/Documentation~/images/hue-vs-hue.png
new file mode 100644
index 0000000..b3ab5ab
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/hue-vs-hue.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/hue-vs-sat.png b/com.unity.postprocessing/Documentation~/images/hue-vs-sat.png
new file mode 100644
index 0000000..0db61dc
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/hue-vs-sat.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/lens-distortion.png b/com.unity.postprocessing/Documentation~/images/lens-distortion.png
new file mode 100644
index 0000000..9d0cb1f
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/lens-distortion.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/lensdistortion.png b/com.unity.postprocessing/Documentation~/images/lensdistortion.png
new file mode 100644
index 0000000..54b4911
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/lensdistortion.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/lum-vs-sat.png b/com.unity.postprocessing/Documentation~/images/lum-vs-sat.png
new file mode 100644
index 0000000..f17b1dc
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/lum-vs-sat.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/motionblur.png b/com.unity.postprocessing/Documentation~/images/motionblur.png
new file mode 100644
index 0000000..984f771
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/motionblur.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/no-lens-distortion.png b/com.unity.postprocessing/Documentation~/images/no-lens-distortion.png
new file mode 100644
index 0000000..39e30d5
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/no-lens-distortion.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/quickstart-1.png b/com.unity.postprocessing/Documentation~/images/quickstart-1.png
new file mode 100644
index 0000000..9983f16
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/quickstart-1.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/quickstart-2.png b/com.unity.postprocessing/Documentation~/images/quickstart-2.png
new file mode 100644
index 0000000..30fe17f
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/quickstart-2.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/quickstart-3.png b/com.unity.postprocessing/Documentation~/images/quickstart-3.png
new file mode 100644
index 0000000..5bc2896
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/quickstart-3.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/sat-vs-sat.png b/com.unity.postprocessing/Documentation~/images/sat-vs-sat.png
new file mode 100644
index 0000000..5971afb
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/sat-vs-sat.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/ssao-1.png b/com.unity.postprocessing/Documentation~/images/ssao-1.png
new file mode 100644
index 0000000..5128158
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/ssao-1.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/ssao-2.png b/com.unity.postprocessing/Documentation~/images/ssao-2.png
new file mode 100644
index 0000000..4012afc
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/ssao-2.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/ssr.png b/com.unity.postprocessing/Documentation~/images/ssr.png
new file mode 100644
index 0000000..63ed7bc
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/ssr.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/tonemapping.png b/com.unity.postprocessing/Documentation~/images/tonemapping.png
new file mode 100644
index 0000000..6b70420
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/tonemapping.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/trackballs.png b/com.unity.postprocessing/Documentation~/images/trackballs.png
new file mode 100644
index 0000000..fe18b0b
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/trackballs.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/vignette-1.png b/com.unity.postprocessing/Documentation~/images/vignette-1.png
new file mode 100644
index 0000000..83192a7
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/vignette-1.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/vignette-2.png b/com.unity.postprocessing/Documentation~/images/vignette-2.png
new file mode 100644
index 0000000..1616b21
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/vignette-2.png differ
diff --git a/com.unity.postprocessing/Documentation~/images/yrgb-curves.png b/com.unity.postprocessing/Documentation~/images/yrgb-curves.png
new file mode 100644
index 0000000..e8b9b72
Binary files /dev/null and b/com.unity.postprocessing/Documentation~/images/yrgb-curves.png differ
diff --git a/com.unity.postprocessing/Documentation~/index.md b/com.unity.postprocessing/Documentation~/index.md
new file mode 100644
index 0000000..f826845
--- /dev/null
+++ b/com.unity.postprocessing/Documentation~/index.md
@@ -0,0 +1,15 @@
+## Post Processing Stack v2 overview
+
+Post-processing is a generic term for a full-screen image processing effect that occurs after the camera draws the scene but before the scene is rendered on the screen. Post-processing can drastically improve the visuals of your product with little setup time.
+
+You can use post-processing effects to simulate physical camera and film properties.
+
+For information about requirements and compatibility, see section [Requirements](requirements.html).
+
+The images below demonstrate a scene with and without post-processing:
+
+
+
+
+
+
diff --git a/com.unity.postprocessing/Documentation~/known-issues.md b/com.unity.postprocessing/Documentation~/known-issues.md
new file mode 100644
index 0000000..d158d08
--- /dev/null
+++ b/com.unity.postprocessing/Documentation~/known-issues.md
@@ -0,0 +1,5 @@
+# Known issues
+
+- The **Post Processing** package doesn't work on MacOS X 10.11.6 when running Metal in the editor due to a driver bug on this specific version of the OS.
+
+For limitations and known issues for each effect, see the specific effect page.
diff --git a/com.unity.postprocessing/Documentation~/requirements.md b/com.unity.postprocessing/Documentation~/requirements.md
new file mode 100644
index 0000000..664e64f
--- /dev/null
+++ b/com.unity.postprocessing/Documentation~/requirements.md
@@ -0,0 +1,23 @@
+# Requirements and compatibility
+
+This page contains information on system requirements and compatibility of this Post-processing module.
+
+## Unity Editor compatibility
+
+The **Post processing** package is compatible with the following versions of the Unity Editor:
+
+* Unity 2018.1 and later.
+
+## Render pipeline compatibility
+
+This package is compatible with the following render pipeline versions:
+
+* Built-in render pipeline.
+* Universal Render Pipeline (URP) 7.x, with Unity 2018 LTS, and 2019 LTS. Certain effects are not compatible with URP.
+* Scriptable Render Pipeline (SRP).
+
+## Unity Player system requirements
+
+This package does not add any platform-specific requirements to Unity. For more information on Unity system requirements, see [System requirements for Unity](https://docs.unity3d.com/Manual/system-requirements.html).
+
+Some **Post Processing** effects have extra requirements in addition to the common Unity Player system requirements. For system requirements for each effect, see the specific effect page.
diff --git a/com.unity.postprocessing/LICENSE.md b/com.unity.postprocessing/LICENSE.md
new file mode 100644
index 0000000..bab8330
--- /dev/null
+++ b/com.unity.postprocessing/LICENSE.md
@@ -0,0 +1,5 @@
+com.unity.postprocessing copyright © 2020 Unity Technologies ApS
+
+Licensed under the Unity Companion License for Unity-dependent projects--see [Unity Companion License](http://www.unity3d.com/legal/licenses/Unity_Companion_License).
+
+Unless expressly provided otherwise, the Software under this license is made available strictly on an “AS IS” BASIS WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. Please review the license for details on these and other terms and conditions.
diff --git a/com.unity.postprocessing/LICENSE.md.meta b/com.unity.postprocessing/LICENSE.md.meta
new file mode 100644
index 0000000..c0254d1
--- /dev/null
+++ b/com.unity.postprocessing/LICENSE.md.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 19d205ceab90d42038ad1d376affc356
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing.meta b/com.unity.postprocessing/PostProcessing.meta
new file mode 100644
index 0000000..30be565
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 0d256a256b5667448bb3f33f75dbb4bf
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor.meta b/com.unity.postprocessing/PostProcessing/Editor.meta
new file mode 100644
index 0000000..0b9e415
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 10af18f17ff5ecf47bc4dbd1551b36d2
+folderAsset: yes
+timeCreated: 1488201031
+licenseType: Pro
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Attributes.meta b/com.unity.postprocessing/PostProcessing/Editor/Attributes.meta
new file mode 100644
index 0000000..b57a722
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Attributes.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: f5422948b83b1d34c86e710f0d9fea30
+folderAsset: yes
+timeCreated: 1492690959
+licenseType: Pro
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Attributes/DecoratorAttribute.cs b/com.unity.postprocessing/PostProcessing/Editor/Attributes/DecoratorAttribute.cs
new file mode 100644
index 0000000..bf46ff5
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Attributes/DecoratorAttribute.cs
@@ -0,0 +1,27 @@
+using System;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ ///
+ /// Tells a class which inspector attribute it's a decorator
+ /// for.
+ ///
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
+ public sealed class DecoratorAttribute : Attribute
+ {
+ ///
+ /// The attribute type that this decorator can inspect.
+ ///
+ public readonly Type attributeType;
+
+ ///
+ /// Creates a new attribute.
+ ///
+ /// The type that this decorator can inspect
+ public DecoratorAttribute(Type attributeType)
+ {
+ this.attributeType = attributeType;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Attributes/DecoratorAttribute.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/Attributes/DecoratorAttribute.cs.meta
new file mode 100644
index 0000000..5fb571d
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Attributes/DecoratorAttribute.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 9753335d6f48da542be1c720aa07bbf5
+timeCreated: 1493109769
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Attributes/PostProcessEditorAttribute.cs b/com.unity.postprocessing/PostProcessing/Editor/Attributes/PostProcessEditorAttribute.cs
new file mode 100644
index 0000000..86d8048
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Attributes/PostProcessEditorAttribute.cs
@@ -0,0 +1,28 @@
+using System;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ ///
+ /// Tells a class which run-time type it's an editor
+ /// for. When you make a custom editor for an effect, you need put this attribute on the editor
+ /// class.
+ ///
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
+ public sealed class PostProcessEditorAttribute : Attribute
+ {
+ ///
+ /// The type that this editor can edit.
+ ///
+ public readonly Type settingsType;
+
+ ///
+ /// Creates a new attribute.
+ ///
+ /// The type that this editor can edit
+ public PostProcessEditorAttribute(Type settingsType)
+ {
+ this.settingsType = settingsType;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Attributes/PostProcessEditorAttribute.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/Attributes/PostProcessEditorAttribute.cs.meta
new file mode 100644
index 0000000..c28444c
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Attributes/PostProcessEditorAttribute.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 70ea2ab329ffbac43a0a02daa61dbe6b
+timeCreated: 1492690987
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/BaseEditor.cs b/com.unity.postprocessing/PostProcessing/Editor/BaseEditor.cs
new file mode 100644
index 0000000..51ecfdc
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/BaseEditor.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Linq.Expressions;
+using UnityEngine;
+using UnityEngine.Rendering.PostProcessing;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ ///
+ /// Small wrapper on top of to ease the access of the underlying component
+ /// and its serialized fields.
+ ///
+ /// The type of the target component to make an editor for
+ ///
+ ///
+ /// public class MyMonoBehaviour : MonoBehaviour
+ /// {
+ /// public float myProperty = 1.0f;
+ /// }
+ ///
+ /// [CustomEditor(typeof(MyMonoBehaviour))]
+ /// public sealed class MyMonoBehaviourEditor : BaseEditor<MyMonoBehaviour>
+ /// {
+ /// SerializedProperty m_MyProperty;
+ ///
+ /// void OnEnable()
+ /// {
+ /// m_MyProperty = FindProperty(x => x.myProperty);
+ /// }
+ ///
+ /// public override void OnInspectorGUI()
+ /// {
+ /// EditorGUILayout.PropertyField(m_MyProperty);
+ /// }
+ /// }
+ ///
+ ///
+ public class BaseEditor : Editor
+ where T : MonoBehaviour
+ {
+ ///
+ /// The target component.
+ ///
+ protected T m_Target
+ {
+ get { return (T)target; }
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected SerializedProperty FindProperty(Expression> expr)
+ {
+ return serializedObject.FindProperty(RuntimeUtilities.GetFieldPath(expr));
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/BaseEditor.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/BaseEditor.cs.meta
new file mode 100644
index 0000000..f865b53
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/BaseEditor.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 69a4fc27499557744827c787d71fdf08
+timeCreated: 1488275908
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Decorators.meta b/com.unity.postprocessing/PostProcessing/Editor/Decorators.meta
new file mode 100644
index 0000000..872280e
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Decorators.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 21a375b704549664589881dfc892e7e7
+folderAsset: yes
+timeCreated: 1493051174
+licenseType: Pro
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Decorators/AttributeDecorator.cs b/com.unity.postprocessing/PostProcessing/Editor/Decorators/AttributeDecorator.cs
new file mode 100644
index 0000000..98ba5f6
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Decorators/AttributeDecorator.cs
@@ -0,0 +1,35 @@
+using System;
+using UnityEngine;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ ///
+ /// The base abstract class for all attribute decorators.
+ ///
+ public abstract class AttributeDecorator
+ {
+ ///
+ /// Override this and return false if you want to customize the override checkbox
+ /// position, else it'll automatically draw it and put the property content in a
+ /// horizontal scope.
+ ///
+ /// true if the override checkbox should be automatically put next to the
+ /// property, false if it uses a custom position
+ public virtual bool IsAutoProperty()
+ {
+ return true;
+ }
+
+ ///
+ /// The rendering method called for the custom GUI.
+ ///
+ /// The property to draw the UI for
+ /// The override checkbox property
+ /// The title and tooltip for the property
+ /// A reference to the property attribute set on the original field
+ ///
+ /// true if the property UI got rendered successfully, false to
+ /// fallback on the default editor UI for this property
+ public abstract bool OnGUI(SerializedProperty property, SerializedProperty overrideState, GUIContent title, Attribute attribute);
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Decorators/AttributeDecorator.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/Decorators/AttributeDecorator.cs.meta
new file mode 100644
index 0000000..ffd22a3
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Decorators/AttributeDecorator.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 6b2666165a17bbd4e851c1382898651e
+timeCreated: 1493051184
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Decorators/Decorators.cs b/com.unity.postprocessing/PostProcessing/Editor/Decorators/Decorators.cs
new file mode 100644
index 0000000..e5fcce9
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Decorators/Decorators.cs
@@ -0,0 +1,143 @@
+using System;
+using UnityEngine;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ [Decorator(typeof(RangeAttribute))]
+ internal sealed class RangeDecorator : AttributeDecorator
+ {
+ public override bool OnGUI(SerializedProperty property, SerializedProperty overrideState, GUIContent title, Attribute attribute)
+ {
+ var attr = (RangeAttribute)attribute;
+
+ if (property.propertyType == SerializedPropertyType.Float)
+ {
+ property.floatValue = EditorGUILayout.Slider(title, property.floatValue, attr.min, attr.max);
+ return true;
+ }
+
+ if (property.propertyType == SerializedPropertyType.Integer)
+ {
+ property.intValue = EditorGUILayout.IntSlider(title, property.intValue, (int)attr.min, (int)attr.max);
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ [Decorator(typeof(UnityEngine.Rendering.PostProcessing.MinAttribute))]
+ internal sealed class MinDecorator : AttributeDecorator
+ {
+ public override bool OnGUI(SerializedProperty property, SerializedProperty overrideState, GUIContent title, Attribute attribute)
+ {
+ var attr = (UnityEngine.Rendering.PostProcessing.MinAttribute)attribute;
+
+ if (property.propertyType == SerializedPropertyType.Float)
+ {
+ float v = EditorGUILayout.FloatField(title, property.floatValue);
+ property.floatValue = Mathf.Max(v, attr.min);
+ return true;
+ }
+
+ if (property.propertyType == SerializedPropertyType.Integer)
+ {
+ int v = EditorGUILayout.IntField(title, property.intValue);
+ property.intValue = Mathf.Max(v, (int)attr.min);
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ [Decorator(typeof(UnityEngine.Rendering.PostProcessing.MaxAttribute))]
+ internal sealed class MaxDecorator : AttributeDecorator
+ {
+ public override bool OnGUI(SerializedProperty property, SerializedProperty overrideState, GUIContent title, Attribute attribute)
+ {
+ var attr = (UnityEngine.Rendering.PostProcessing.MaxAttribute)attribute;
+
+ if (property.propertyType == SerializedPropertyType.Float)
+ {
+ float v = EditorGUILayout.FloatField(title, property.floatValue);
+ property.floatValue = Mathf.Min(v, attr.max);
+ return true;
+ }
+
+ if (property.propertyType == SerializedPropertyType.Integer)
+ {
+ int v = EditorGUILayout.IntField(title, property.intValue);
+ property.intValue = Mathf.Min(v, (int)attr.max);
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ [Decorator(typeof(UnityEngine.Rendering.PostProcessing.MinMaxAttribute))]
+ internal sealed class MinMaxDecorator : AttributeDecorator
+ {
+ public override bool OnGUI(SerializedProperty property, SerializedProperty overrideState, GUIContent title, Attribute attribute)
+ {
+ var attr = (UnityEngine.Rendering.PostProcessing.MinMaxAttribute)attribute;
+
+ if (property.propertyType == SerializedPropertyType.Float)
+ {
+ float v = EditorGUILayout.FloatField(title, property.floatValue);
+ property.floatValue = Mathf.Clamp(v, attr.min, attr.max);
+ return true;
+ }
+
+ if (property.propertyType == SerializedPropertyType.Integer)
+ {
+ int v = EditorGUILayout.IntField(title, property.intValue);
+ property.intValue = Mathf.Clamp(v, (int)attr.min, (int)attr.max);
+ return true;
+ }
+
+ if (property.propertyType == SerializedPropertyType.Vector2)
+ {
+ var v = property.vector2Value;
+ EditorGUILayout.MinMaxSlider(title, ref v.x, ref v.y, attr.min, attr.max);
+ property.vector2Value = v;
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ [Decorator(typeof(ColorUsageAttribute))]
+ internal sealed class ColorUsageDecorator : AttributeDecorator
+ {
+ public override bool OnGUI(SerializedProperty property, SerializedProperty overrideState, GUIContent title, Attribute attribute)
+ {
+ var attr = (ColorUsageAttribute)attribute;
+
+ if (property.propertyType != SerializedPropertyType.Color)
+ return false;
+
+#if UNITY_2018_1_OR_NEWER
+ property.colorValue = EditorGUILayout.ColorField(title, property.colorValue, true, attr.showAlpha, attr.hdr);
+#else
+ ColorPickerHDRConfig hdrConfig = null;
+
+ if (attr.hdr)
+ {
+ hdrConfig = new ColorPickerHDRConfig(
+ attr.minBrightness,
+ attr.maxBrightness,
+ attr.minExposureValue,
+ attr.maxExposureValue
+ );
+ }
+
+ property.colorValue = EditorGUILayout.ColorField(title, property.colorValue, true, attr.showAlpha, attr.hdr, hdrConfig);
+#endif
+
+ return true;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Decorators/Decorators.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/Decorators/Decorators.cs.meta
new file mode 100644
index 0000000..773f5fd
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Decorators/Decorators.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: d6ae47710b8593e41960a944bb29e6c3
+timeCreated: 1493051241
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Decorators/TrackballDecorator.cs b/com.unity.postprocessing/PostProcessing/Editor/Decorators/TrackballDecorator.cs
new file mode 100644
index 0000000..beb49d6
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Decorators/TrackballDecorator.cs
@@ -0,0 +1,212 @@
+using System;
+using UnityEngine;
+using UnityEngine.Rendering.PostProcessing;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ [Decorator(typeof(TrackballAttribute))]
+ internal sealed class TrackballDecorator : AttributeDecorator
+ {
+ static readonly int k_ThumbHash = "colorWheelThumb".GetHashCode();
+ static Material s_Material;
+
+ bool m_ResetState;
+ Vector2 m_CursorPos;
+
+ public override bool IsAutoProperty()
+ {
+ return false;
+ }
+
+ public override bool OnGUI(SerializedProperty property, SerializedProperty overrideState, GUIContent title, Attribute attribute)
+ {
+ if (property.propertyType != SerializedPropertyType.Vector4)
+ return false;
+
+ var value = property.vector4Value;
+
+ using (new EditorGUILayout.VerticalScope())
+ {
+ using (new EditorGUI.DisabledScope(!overrideState.boolValue))
+ DrawWheel(ref value, overrideState.boolValue, (TrackballAttribute)attribute);
+
+ DrawLabelAndOverride(title, overrideState);
+ }
+
+ if (m_ResetState)
+ {
+ value = Vector4.zero;
+ m_ResetState = false;
+ }
+
+ property.vector4Value = value;
+
+ return true;
+ }
+
+ void DrawWheel(ref Vector4 value, bool overrideState, TrackballAttribute attr)
+ {
+ var wheelRect = GUILayoutUtility.GetAspectRect(1f);
+ float size = wheelRect.width;
+ float hsize = size / 2f;
+ float radius = 0.38f * size;
+
+ Vector3 hsv;
+ Color.RGBToHSV(value, out hsv.x, out hsv.y, out hsv.z);
+ float offset = value.w;
+
+ // Thumb
+ var thumbPos = Vector2.zero;
+ float theta = hsv.x * (Mathf.PI * 2f);
+ thumbPos.x = Mathf.Cos(theta + (Mathf.PI / 2f));
+ thumbPos.y = Mathf.Sin(theta - (Mathf.PI / 2f));
+ thumbPos *= hsv.y * radius;
+
+ // Draw the wheel
+ if (Event.current.type == EventType.Repaint)
+ {
+ // Retina support
+ float scale = EditorGUIUtility.pixelsPerPoint;
+
+ if (s_Material == null)
+ s_Material = new Material(Shader.Find("Hidden/PostProcessing/Editor/Trackball")) { hideFlags = HideFlags.HideAndDontSave };
+
+ // Wheel texture
+#if UNITY_2018_1_OR_NEWER
+ const RenderTextureReadWrite kReadWrite = RenderTextureReadWrite.sRGB;
+#else
+ const RenderTextureReadWrite kReadWrite = RenderTextureReadWrite.Linear;
+#endif
+
+ var oldRT = RenderTexture.active;
+ var rt = RenderTexture.GetTemporary((int)(size * scale), (int)(size * scale), 0, RenderTextureFormat.ARGB32, kReadWrite);
+ s_Material.SetFloat("_Offset", offset);
+ s_Material.SetFloat("_DisabledState", overrideState ? 1f : 0.5f);
+ s_Material.SetVector("_Resolution", new Vector2(size * scale, size * scale / 2f));
+ Graphics.Blit(null, rt, s_Material, EditorGUIUtility.isProSkin ? 0 : 1);
+ RenderTexture.active = oldRT;
+
+ GUI.DrawTexture(wheelRect, rt);
+ RenderTexture.ReleaseTemporary(rt);
+
+ var thumbSize = Styling.wheelThumbSize;
+ var thumbSizeH = thumbSize / 2f;
+ Styling.wheelThumb.Draw(new Rect(wheelRect.x + hsize + thumbPos.x - thumbSizeH.x, wheelRect.y + hsize + thumbPos.y - thumbSizeH.y, thumbSize.x, thumbSize.y), false, false, false, false);
+ }
+
+ // Input
+ var bounds = wheelRect;
+ bounds.x += hsize - radius;
+ bounds.y += hsize - radius;
+ bounds.width = bounds.height = radius * 2f;
+ hsv = GetInput(bounds, hsv, thumbPos, radius);
+ value = Color.HSVToRGB(hsv.x, hsv.y, 1f);
+ value.w = offset;
+
+ // Offset
+ var sliderRect = GUILayoutUtility.GetRect(1f, 17f);
+ float padding = sliderRect.width * 0.05f; // 5% padding
+ sliderRect.xMin += padding;
+ sliderRect.xMax -= padding;
+ value.w = GUI.HorizontalSlider(sliderRect, value.w, -1f, 1f);
+
+ if (attr.mode == TrackballAttribute.Mode.None)
+ return;
+
+ // Values
+ var displayValue = Vector3.zero;
+
+ switch (attr.mode)
+ {
+ case TrackballAttribute.Mode.Lift:
+ displayValue = ColorUtilities.ColorToLift(value);
+ break;
+ case TrackballAttribute.Mode.Gamma:
+ displayValue = ColorUtilities.ColorToInverseGamma(value);
+ break;
+ case TrackballAttribute.Mode.Gain:
+ displayValue = ColorUtilities.ColorToGain(value);
+ break;
+ }
+
+ using (new EditorGUI.DisabledGroupScope(true))
+ {
+ var valuesRect = GUILayoutUtility.GetRect(1f, 17f);
+ valuesRect.width /= 3f;
+ GUI.Label(valuesRect, displayValue.x.ToString("F2"), EditorStyles.centeredGreyMiniLabel);
+ valuesRect.x += valuesRect.width;
+ GUI.Label(valuesRect, displayValue.y.ToString("F2"), EditorStyles.centeredGreyMiniLabel);
+ valuesRect.x += valuesRect.width;
+ GUI.Label(valuesRect, displayValue.z.ToString("F2"), EditorStyles.centeredGreyMiniLabel);
+ valuesRect.x += valuesRect.width;
+ }
+ }
+
+ void DrawLabelAndOverride(GUIContent title, SerializedProperty overrideState)
+ {
+ // Title
+ var areaRect = GUILayoutUtility.GetRect(1f, 17f);
+ var labelSize = Styling.wheelLabel.CalcSize(title);
+ var labelRect = new Rect(areaRect.x + areaRect.width / 2 - labelSize.x / 2, areaRect.y, labelSize.x, labelSize.y);
+ GUI.Label(labelRect, title, Styling.wheelLabel);
+
+ // Override checkbox
+ var overrideRect = new Rect(labelRect.x - 17, labelRect.y + 3, 17f, 17f);
+ EditorUtilities.DrawOverrideCheckbox(overrideRect, overrideState);
+ }
+
+ Vector3 GetInput(Rect bounds, Vector3 hsv, Vector2 thumbPos, float radius)
+ {
+ var e = Event.current;
+ var id = GUIUtility.GetControlID(k_ThumbHash, FocusType.Passive, bounds);
+ var mousePos = e.mousePosition;
+
+ if (e.type == EventType.MouseDown && GUIUtility.hotControl == 0 && bounds.Contains(mousePos))
+ {
+ if (e.button == 0)
+ {
+ var center = new Vector2(bounds.x + radius, bounds.y + radius);
+ float dist = Vector2.Distance(center, mousePos);
+
+ if (dist <= radius)
+ {
+ e.Use();
+ m_CursorPos = new Vector2(thumbPos.x + radius, thumbPos.y + radius);
+ GUIUtility.hotControl = id;
+ GUI.changed = true;
+ }
+ }
+ else if (e.button == 1)
+ {
+ e.Use();
+ GUI.changed = true;
+ m_ResetState = true;
+ }
+ }
+ else if (e.type == EventType.MouseDrag && e.button == 0 && GUIUtility.hotControl == id)
+ {
+ e.Use();
+ GUI.changed = true;
+ m_CursorPos += e.delta * GlobalSettings.trackballSensitivity;
+ GetWheelHueSaturation(m_CursorPos.x, m_CursorPos.y, radius, out hsv.x, out hsv.y);
+ }
+ else if (e.rawType == EventType.MouseUp && e.button == 0 && GUIUtility.hotControl == id)
+ {
+ e.Use();
+ GUIUtility.hotControl = 0;
+ }
+
+ return hsv;
+ }
+
+ void GetWheelHueSaturation(float x, float y, float radius, out float hue, out float saturation)
+ {
+ float dx = (x - radius) / radius;
+ float dy = (y - radius) / radius;
+ float d = Mathf.Sqrt(dx * dx + dy * dy);
+ hue = Mathf.Atan2(dx, -dy);
+ hue = 1f - ((hue > 0) ? hue : (Mathf.PI * 2f) + hue) / (Mathf.PI * 2f);
+ saturation = Mathf.Clamp01(d);
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Decorators/TrackballDecorator.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/Decorators/TrackballDecorator.cs.meta
new file mode 100644
index 0000000..52832a6
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Decorators/TrackballDecorator.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 26ed99f46b86df8449003e6ec0f65144
+timeCreated: 1493900975
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/EffectListEditor.cs b/com.unity.postprocessing/PostProcessing/Editor/EffectListEditor.cs
new file mode 100644
index 0000000..52f3502
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/EffectListEditor.cs
@@ -0,0 +1,345 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+using UnityEngine.Assertions;
+using UnityEngine.Rendering.PostProcessing;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ ///
+ /// This class is used to draw the user interface in the inspector for all the settings
+ /// contained in a .
+ ///
+ public sealed class EffectListEditor
+ {
+ ///
+ /// A reference to the being displayed by this editor.
+ ///
+ public PostProcessProfile asset { get; private set; }
+
+ Editor m_BaseEditor;
+
+ SerializedObject m_SerializedObject;
+ SerializedProperty m_SettingsProperty;
+
+ Dictionary m_EditorTypes; // SettingsType => EditorType
+ List m_Editors;
+
+ ///
+ /// Creates a new instance to be used inside an existing .
+ ///
+ /// A reference to the parent editor instance.
+ public EffectListEditor(Editor editor)
+ {
+ Assert.IsNotNull(editor);
+ m_BaseEditor = editor;
+ }
+
+ ///
+ /// Initializes the editor. This method should be called before is
+ /// called.
+ ///
+ /// A reference to the that will be
+ /// displayed.
+ /// A of the given instance.
+ public void Init(PostProcessProfile asset, SerializedObject serializedObject)
+ {
+ Assert.IsNotNull(asset);
+ Assert.IsNotNull(serializedObject);
+
+ this.asset = asset;
+ m_SerializedObject = serializedObject;
+ m_SettingsProperty = serializedObject.FindProperty("settings");
+ Assert.IsNotNull(m_SettingsProperty);
+
+ m_EditorTypes = new Dictionary();
+ m_Editors = new List();
+
+ // Gets the list of all available postfx editors
+ var editorTypes = RuntimeUtilities.GetAllTypesDerivedFrom()
+ .Where(
+ t => t.IsDefined(typeof(PostProcessEditorAttribute), false)
+ && !t.IsAbstract
+ );
+
+ // Map them to their corresponding settings type
+ foreach (var editorType in editorTypes)
+ {
+ var attribute = editorType.GetAttribute();
+ m_EditorTypes.Add(attribute.settingsType, editorType);
+ }
+
+ // Create editors for existing settings
+ for (int i = 0; i < this.asset.settings.Count; i++)
+ CreateEditor(this.asset.settings[i], m_SettingsProperty.GetArrayElementAtIndex(i));
+
+ // Keep track of undo/redo to redraw the inspector when that happens
+ Undo.undoRedoPerformed += OnUndoRedoPerformed;
+ }
+
+ void OnUndoRedoPerformed()
+ {
+ asset.isDirty = true;
+
+ // Dumb hack to make sure the serialized object is up to date on undo (else there'll be
+ // a state mismatch when this class is used in a GameObject inspector).
+ m_SerializedObject.Update();
+ m_SerializedObject.ApplyModifiedProperties();
+
+ // Seems like there's an issue with the inspector not repainting after some undo events
+ // This will take care of that
+ m_BaseEditor.Repaint();
+ }
+
+ void CreateEditor(PostProcessEffectSettings settings, SerializedProperty property, int index = -1)
+ {
+ var settingsType = settings.GetType();
+ Type editorType;
+
+ if (!m_EditorTypes.TryGetValue(settingsType, out editorType))
+ editorType = typeof(DefaultPostProcessEffectEditor);
+
+ var editor = (PostProcessEffectBaseEditor)Activator.CreateInstance(editorType);
+ editor.Init(settings, m_BaseEditor);
+ editor.baseProperty = property.Copy();
+
+ if (index < 0)
+ m_Editors.Add(editor);
+ else
+ m_Editors[index] = editor;
+ }
+
+ // Clears & recreate all editors - mainly used when the volume has been modified outside of
+ // the editor (user scripts, inspector reset etc).
+ void RefreshEditors()
+ {
+ // Disable all editors first
+ foreach (var editor in m_Editors)
+ editor.OnDisable();
+
+ // Remove them
+ m_Editors.Clear();
+
+ // Recreate editors for existing settings, if any
+ for (int i = 0; i < asset.settings.Count; i++)
+ CreateEditor(asset.settings[i], m_SettingsProperty.GetArrayElementAtIndex(i));
+ }
+
+ ///
+ /// This method should be called when the editor is destroyed or disabled.
+ ///
+ public void Clear()
+ {
+ if (m_Editors == null)
+ return; // Hasn't been inited yet
+
+ foreach (var editor in m_Editors)
+ editor.OnDisable();
+
+ m_Editors.Clear();
+ m_EditorTypes.Clear();
+
+ Undo.undoRedoPerformed -= OnUndoRedoPerformed;
+ }
+
+ ///
+ /// Draws the settings for the referenced in the editor.
+ ///
+ public void OnGUI()
+ {
+ if (asset == null)
+ return;
+
+ if (asset.isDirty)
+ {
+ RefreshEditors();
+ asset.isDirty = false;
+ }
+
+ bool isEditable = !VersionControl.Provider.isActive
+ || AssetDatabase.IsOpenForEdit(asset, StatusQueryOptions.UseCachedIfPossible);
+
+ using (new EditorGUI.DisabledScope(!isEditable))
+ {
+ EditorGUILayout.LabelField(EditorUtilities.GetContent("Overrides"), EditorStyles.boldLabel);
+
+ // Override list
+ for (int i = 0; i < m_Editors.Count; i++)
+ {
+ var editor = m_Editors[i];
+ string title = editor.GetDisplayTitle();
+ int id = i; // Needed for closure capture below
+
+ EditorUtilities.DrawSplitter();
+ bool displayContent = EditorUtilities.DrawHeader(
+ title,
+ editor.baseProperty,
+ editor.activeProperty,
+ editor.target,
+ () => ResetEffectOverride(editor.target.GetType(), id),
+ () => RemoveEffectOverride(id)
+ );
+
+ if (displayContent)
+ {
+ using (new EditorGUI.DisabledScope(!editor.activeProperty.boolValue))
+ editor.OnInternalInspectorGUI();
+ }
+ }
+
+ if (m_Editors.Count > 0)
+ {
+ EditorUtilities.DrawSplitter();
+ EditorGUILayout.Space();
+ }
+ else
+ {
+ EditorGUILayout.HelpBox("No override set on this volume.", MessageType.Info);
+ }
+
+ if (GUILayout.Button("Add effect...", EditorStyles.miniButton))
+ {
+ var menu = new GenericMenu();
+
+ var typeMap = PostProcessManager.instance.settingsTypes;
+ foreach (var kvp in typeMap)
+ {
+ var type = kvp.Key;
+ var title = EditorUtilities.GetContent(kvp.Value.menuItem);
+ bool exists = asset.HasSettings(type);
+
+ if (!exists)
+ menu.AddItem(title, false, () => AddEffectOverride(type));
+ else
+ menu.AddDisabledItem(title);
+ }
+
+ menu.ShowAsContext();
+ }
+
+ EditorGUILayout.Space();
+ }
+ }
+
+ void AddEffectOverride(Type type)
+ {
+ m_SerializedObject.Update();
+
+ var effect = CreateNewEffect(type);
+ Undo.RegisterCreatedObjectUndo(effect, "Add Effect Override");
+
+ // Store this new effect as a subasset so we can reference it safely afterwards. Only when its not an instantiated profile
+ if (EditorUtility.IsPersistent(asset))
+ AssetDatabase.AddObjectToAsset(effect, asset);
+
+ // Grow the list first, then add - that's how serialized lists work in Unity
+ m_SettingsProperty.arraySize++;
+ var effectProp = m_SettingsProperty.GetArrayElementAtIndex(m_SettingsProperty.arraySize - 1);
+ effectProp.objectReferenceValue = effect;
+
+ // Create & store the internal editor object for this effect
+ CreateEditor(effect, effectProp);
+
+ m_SerializedObject.ApplyModifiedProperties();
+
+ // Force save / refresh. Important to do this last because SaveAssets can cause effect to become null!
+ if (EditorUtility.IsPersistent(asset))
+ {
+ EditorUtility.SetDirty(asset);
+ AssetDatabase.SaveAssets();
+ }
+ }
+
+ void RemoveEffectOverride(int id)
+ {
+ // Huh. Hack to keep foldout state on the next element...
+ bool nextFoldoutState = false;
+ if (id < m_Editors.Count - 1)
+ nextFoldoutState = m_Editors[id + 1].baseProperty.isExpanded;
+
+ // Remove from the cached editors list
+ m_Editors[id].OnDisable();
+ m_Editors.RemoveAt(id);
+
+ m_SerializedObject.Update();
+
+ var property = m_SettingsProperty.GetArrayElementAtIndex(id);
+ var effect = property.objectReferenceValue;
+
+ // Unassign it (should be null already but serialization does funky things
+ property.objectReferenceValue = null;
+
+ // ...and remove the array index itself from the list
+ m_SettingsProperty.DeleteArrayElementAtIndex(id);
+
+ // Finally refresh editor reference to the serialized settings list
+ for (int i = 0; i < m_Editors.Count; i++)
+ m_Editors[i].baseProperty = m_SettingsProperty.GetArrayElementAtIndex(i).Copy();
+
+ if (id < m_Editors.Count)
+ m_Editors[id].baseProperty.isExpanded = nextFoldoutState;
+
+ m_SerializedObject.ApplyModifiedProperties();
+
+ // Destroy the setting object after ApplyModifiedProperties(). If we do it before, redo
+ // actions will be in the wrong order and the reference to the setting object in the
+ // list will be lost.
+ Undo.DestroyObjectImmediate(effect);
+
+ // Force save / refresh
+ EditorUtility.SetDirty(asset);
+ AssetDatabase.SaveAssets();
+ }
+
+ // Reset is done by deleting and removing the object from the list and adding a new one in
+ // the place as it was before
+ void ResetEffectOverride(Type type, int id)
+ {
+ // Remove from the cached editors list
+ m_Editors[id].OnDisable();
+ m_Editors[id] = null;
+
+ m_SerializedObject.Update();
+
+ var property = m_SettingsProperty.GetArrayElementAtIndex(id);
+ var prevSettings = property.objectReferenceValue;
+
+ // Unassign it but down remove it from the array to keep the index available
+ property.objectReferenceValue = null;
+
+ // Create a new object
+ var newEffect = CreateNewEffect(type);
+ Undo.RegisterCreatedObjectUndo(newEffect, "Reset Effect Override");
+
+ // Store this new effect as a subasset so we can reference it safely afterwards
+ AssetDatabase.AddObjectToAsset(newEffect, asset);
+
+ // Put it in the reserved space
+ property.objectReferenceValue = newEffect;
+
+ // Create & store the internal editor object for this effect
+ CreateEditor(newEffect, property, id);
+
+ m_SerializedObject.ApplyModifiedProperties();
+
+ // Same as RemoveEffectOverride, destroy at the end so it's recreated first on Undo to
+ // make sure the GUID exists before undoing the list state
+ Undo.DestroyObjectImmediate(prevSettings);
+
+ // Force save / refresh
+ EditorUtility.SetDirty(asset);
+ AssetDatabase.SaveAssets();
+ }
+
+ PostProcessEffectSettings CreateNewEffect(Type type)
+ {
+ var effect = (PostProcessEffectSettings)ScriptableObject.CreateInstance(type);
+ effect.hideFlags = HideFlags.HideInInspector | HideFlags.HideInHierarchy;
+ effect.name = type.Name;
+ effect.enabled.value = true;
+ return effect;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/EffectListEditor.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/EffectListEditor.cs.meta
new file mode 100644
index 0000000..201d41e
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/EffectListEditor.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 9f9fffe306f3969418c31ee836b6ffee
+timeCreated: 1494328254
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Effects.meta b/com.unity.postprocessing/PostProcessing/Editor/Effects.meta
new file mode 100644
index 0000000..c7143a1
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Effects.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 1da84851b99c43746afb49e79ae2b1d6
+folderAsset: yes
+timeCreated: 1492696579
+licenseType: Pro
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Effects/AmbientOcclusionEditor.cs b/com.unity.postprocessing/PostProcessing/Editor/Effects/AmbientOcclusionEditor.cs
new file mode 100644
index 0000000..c200d59
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Effects/AmbientOcclusionEditor.cs
@@ -0,0 +1,69 @@
+using UnityEngine;
+using UnityEngine.Rendering.PostProcessing;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ [PostProcessEditor(typeof(AmbientOcclusion))]
+ internal sealed class AmbientOcclusionEditor : PostProcessEffectEditor
+ {
+ SerializedParameterOverride m_Mode;
+ SerializedParameterOverride m_Intensity;
+ SerializedParameterOverride m_Color;
+ SerializedParameterOverride m_AmbientOnly;
+ SerializedParameterOverride m_ThicknessModifier;
+ SerializedParameterOverride m_ZBias;
+ SerializedParameterOverride m_DirectLightingStrength;
+ SerializedParameterOverride m_Quality;
+ SerializedParameterOverride m_Radius;
+
+ public override void OnEnable()
+ {
+ m_Mode = FindParameterOverride(x => x.mode);
+ m_Intensity = FindParameterOverride(x => x.intensity);
+ m_Color = FindParameterOverride(x => x.color);
+ m_AmbientOnly = FindParameterOverride(x => x.ambientOnly);
+ m_ThicknessModifier = FindParameterOverride(x => x.thicknessModifier);
+ m_ZBias = FindParameterOverride(x => x.zBias);
+ m_DirectLightingStrength = FindParameterOverride(x => x.directLightingStrength);
+ m_Quality = FindParameterOverride(x => x.quality);
+ m_Radius = FindParameterOverride(x => x.radius);
+ }
+
+ public override void OnInspectorGUI()
+ {
+ PropertyField(m_Mode);
+ int aoMode = m_Mode.value.intValue;
+
+ if (RuntimeUtilities.scriptableRenderPipelineActive && aoMode == (int)AmbientOcclusionMode.ScalableAmbientObscurance)
+ {
+ EditorGUILayout.HelpBox("Scalable ambient obscurance doesn't work with scriptable render pipelines.", MessageType.Warning);
+ return;
+ }
+
+ PropertyField(m_Intensity);
+
+ if (aoMode == (int)AmbientOcclusionMode.ScalableAmbientObscurance)
+ {
+ PropertyField(m_Radius);
+ PropertyField(m_Quality);
+ }
+ else if (aoMode == (int)AmbientOcclusionMode.MultiScaleVolumetricObscurance)
+ {
+ if (!SystemInfo.supportsComputeShaders)
+ EditorGUILayout.HelpBox("Multi-scale volumetric obscurance requires compute shader support.", MessageType.Warning);
+
+ PropertyField(m_ThicknessModifier);
+ PropertyField(m_ZBias);
+
+ if (RuntimeUtilities.scriptableRenderPipelineActive)
+ PropertyField(m_DirectLightingStrength);
+ }
+
+ PropertyField(m_Color);
+ PropertyField(m_AmbientOnly);
+
+ if (m_AmbientOnly.overrideState.boolValue && m_AmbientOnly.value.boolValue && !RuntimeUtilities.scriptableRenderPipelineActive)
+ EditorGUILayout.HelpBox("Ambient-only only works with cameras rendering in Deferred + HDR", MessageType.Info);
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Effects/AmbientOcclusionEditor.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/Effects/AmbientOcclusionEditor.cs.meta
new file mode 100644
index 0000000..05a9d62
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Effects/AmbientOcclusionEditor.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 67909952e72978b4ea41880509c936ff
+timeCreated: 1505217529
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Effects/AutoExposureEditor.cs b/com.unity.postprocessing/PostProcessing/Editor/Effects/AutoExposureEditor.cs
new file mode 100644
index 0000000..cdf1e78
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Effects/AutoExposureEditor.cs
@@ -0,0 +1,63 @@
+using UnityEngine;
+using UnityEngine.Rendering.PostProcessing;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ [PostProcessEditor(typeof(AutoExposure))]
+ internal sealed class AutoExposureEditor : PostProcessEffectEditor
+ {
+ SerializedParameterOverride m_Filtering;
+
+ SerializedParameterOverride m_MinLuminance;
+ SerializedParameterOverride m_MaxLuminance;
+ SerializedParameterOverride m_KeyValue;
+
+ SerializedParameterOverride m_EyeAdaptation;
+ SerializedParameterOverride m_SpeedUp;
+ SerializedParameterOverride m_SpeedDown;
+
+ public override void OnEnable()
+ {
+ m_Filtering = FindParameterOverride(x => x.filtering);
+
+ m_MinLuminance = FindParameterOverride(x => x.minLuminance);
+ m_MaxLuminance = FindParameterOverride(x => x.maxLuminance);
+ m_KeyValue = FindParameterOverride(x => x.keyValue);
+
+ m_EyeAdaptation = FindParameterOverride(x => x.eyeAdaptation);
+ m_SpeedUp = FindParameterOverride(x => x.speedUp);
+ m_SpeedDown = FindParameterOverride(x => x.speedDown);
+ }
+
+ public override void OnInspectorGUI()
+ {
+ if (!SystemInfo.supportsComputeShaders)
+ EditorGUILayout.HelpBox("Auto exposure requires compute shader support.", MessageType.Warning);
+
+ EditorUtilities.DrawHeaderLabel("Exposure");
+
+ PropertyField(m_Filtering);
+ PropertyField(m_MinLuminance);
+ PropertyField(m_MaxLuminance);
+
+ // Clamp min/max adaptation values
+ float minLum = m_MinLuminance.value.floatValue;
+ float maxLum = m_MaxLuminance.value.floatValue;
+ m_MinLuminance.value.floatValue = Mathf.Min(minLum, maxLum);
+ m_MaxLuminance.value.floatValue = Mathf.Max(minLum, maxLum);
+
+ PropertyField(m_KeyValue);
+
+ EditorGUILayout.Space();
+ EditorUtilities.DrawHeaderLabel("Adaptation");
+
+ PropertyField(m_EyeAdaptation);
+
+ if (m_EyeAdaptation.value.intValue == (int)EyeAdaptation.Progressive)
+ {
+ PropertyField(m_SpeedUp);
+ PropertyField(m_SpeedDown);
+ }
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Effects/AutoExposureEditor.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/Effects/AutoExposureEditor.cs.meta
new file mode 100644
index 0000000..d901e9c
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Effects/AutoExposureEditor.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 3051d2fb25301fa4a81e797109712feb
+timeCreated: 1493022639
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Effects/BloomEditor.cs b/com.unity.postprocessing/PostProcessing/Editor/Effects/BloomEditor.cs
new file mode 100644
index 0000000..e0b0c17
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Effects/BloomEditor.cs
@@ -0,0 +1,65 @@
+using UnityEngine.Rendering.PostProcessing;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ [PostProcessEditor(typeof(Bloom))]
+ internal sealed class BloomEditor : PostProcessEffectEditor
+ {
+ SerializedParameterOverride m_Intensity;
+ SerializedParameterOverride m_Threshold;
+ SerializedParameterOverride m_SoftKnee;
+ SerializedParameterOverride m_Clamp;
+ SerializedParameterOverride m_Diffusion;
+ SerializedParameterOverride m_AnamorphicRatio;
+ SerializedParameterOverride m_Color;
+ SerializedParameterOverride m_FastMode;
+
+ SerializedParameterOverride m_DirtTexture;
+ SerializedParameterOverride m_DirtIntensity;
+
+ public override void OnEnable()
+ {
+ m_Intensity = FindParameterOverride(x => x.intensity);
+ m_Threshold = FindParameterOverride(x => x.threshold);
+ m_SoftKnee = FindParameterOverride(x => x.softKnee);
+ m_Clamp = FindParameterOverride(x => x.clamp);
+ m_Diffusion = FindParameterOverride(x => x.diffusion);
+ m_AnamorphicRatio = FindParameterOverride(x => x.anamorphicRatio);
+ m_Color = FindParameterOverride(x => x.color);
+ m_FastMode = FindParameterOverride(x => x.fastMode);
+
+ m_DirtTexture = FindParameterOverride(x => x.dirtTexture);
+ m_DirtIntensity = FindParameterOverride(x => x.dirtIntensity);
+ }
+
+ public override void OnInspectorGUI()
+ {
+ EditorUtilities.DrawHeaderLabel("Bloom");
+
+ PropertyField(m_Intensity);
+ PropertyField(m_Threshold);
+ PropertyField(m_SoftKnee);
+ PropertyField(m_Clamp);
+ PropertyField(m_Diffusion);
+ PropertyField(m_AnamorphicRatio);
+ PropertyField(m_Color);
+ PropertyField(m_FastMode);
+
+ if (m_FastMode.overrideState.boolValue && !m_FastMode.value.boolValue && EditorUtilities.isTargetingConsolesOrMobiles)
+ EditorGUILayout.HelpBox("For performance reasons it is recommended to use Fast Mode on mobile and console platforms.", MessageType.Warning);
+
+ EditorGUILayout.Space();
+ EditorUtilities.DrawHeaderLabel("Dirtiness");
+
+ PropertyField(m_DirtTexture);
+ PropertyField(m_DirtIntensity);
+
+ if (EditorUtilities.isVREnabled)
+ {
+ if ((m_DirtIntensity.overrideState.boolValue && m_DirtIntensity.value.floatValue > 0f)
+ || (m_DirtTexture.overrideState.boolValue && m_DirtTexture.value.objectReferenceValue != null))
+ EditorGUILayout.HelpBox("Using a dirt texture in VR is not recommended.", MessageType.Warning);
+ }
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Effects/BloomEditor.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/Effects/BloomEditor.cs.meta
new file mode 100644
index 0000000..38ac202
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Effects/BloomEditor.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 47feae56b7bdcf4499b96c2aa3c6ce07
+timeCreated: 1493116477
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Effects/ChromaticAberrationEditor.cs b/com.unity.postprocessing/PostProcessing/Editor/Effects/ChromaticAberrationEditor.cs
new file mode 100644
index 0000000..daf32a5
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Effects/ChromaticAberrationEditor.cs
@@ -0,0 +1,31 @@
+using UnityEngine.Rendering.PostProcessing;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ [PostProcessEditor(typeof(ChromaticAberration))]
+ internal sealed class ChromaticAberrationEditor : PostProcessEffectEditor
+ {
+ SerializedParameterOverride m_SpectralLut;
+ SerializedParameterOverride m_Intensity;
+ SerializedParameterOverride m_FastMode;
+
+ public override void OnEnable()
+ {
+ m_SpectralLut = FindParameterOverride(x => x.spectralLut);
+ m_Intensity = FindParameterOverride(x => x.intensity);
+ m_FastMode = FindParameterOverride(x => x.fastMode);
+ }
+
+ public override void OnInspectorGUI()
+ {
+ base.OnInspectorGUI();
+
+ PropertyField(m_SpectralLut);
+ PropertyField(m_Intensity);
+ PropertyField(m_FastMode);
+
+ if (m_FastMode.overrideState.boolValue && !m_FastMode.value.boolValue && EditorUtilities.isTargetingConsolesOrMobiles)
+ EditorGUILayout.HelpBox("For performance reasons it is recommended to use Fast Mode on mobile and console platforms.", MessageType.Warning);
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Effects/ChromaticAberrationEditor.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/Effects/ChromaticAberrationEditor.cs.meta
new file mode 100644
index 0000000..adb717a
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Effects/ChromaticAberrationEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f8e5f5614c0d72445b292f4b16ab660b
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Effects/ColorGradingEditor.cs b/com.unity.postprocessing/PostProcessing/Editor/Effects/ColorGradingEditor.cs
new file mode 100644
index 0000000..8658443
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Effects/ColorGradingEditor.cs
@@ -0,0 +1,754 @@
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.Rendering.PostProcessing;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ [PostProcessEditor(typeof(ColorGrading))]
+ internal sealed class ColorGradingEditor : PostProcessEffectEditor
+ {
+ SerializedParameterOverride m_GradingMode;
+
+ static GUIContent[] s_Curves =
+ {
+ new GUIContent("Master"),
+ new GUIContent("Red"),
+ new GUIContent("Green"),
+ new GUIContent("Blue"),
+ new GUIContent("Hue Vs Hue"),
+ new GUIContent("Hue Vs Sat"),
+ new GUIContent("Sat Vs Sat"),
+ new GUIContent("Lum Vs Sat")
+ };
+
+ SerializedParameterOverride m_ExternalLut;
+
+ SerializedParameterOverride m_Tonemapper;
+ SerializedParameterOverride m_ToneCurveToeStrength;
+ SerializedParameterOverride m_ToneCurveToeLength;
+ SerializedParameterOverride m_ToneCurveShoulderStrength;
+ SerializedParameterOverride m_ToneCurveShoulderLength;
+ SerializedParameterOverride m_ToneCurveShoulderAngle;
+ SerializedParameterOverride m_ToneCurveGamma;
+
+ SerializedParameterOverride m_LdrLut;
+ SerializedParameterOverride m_LdrLutContribution;
+
+ SerializedParameterOverride m_Temperature;
+ SerializedParameterOverride m_Tint;
+
+ SerializedParameterOverride m_ColorFilter;
+ SerializedParameterOverride m_HueShift;
+ SerializedParameterOverride m_Saturation;
+ SerializedParameterOverride m_Brightness;
+ SerializedParameterOverride m_PostExposure;
+ SerializedParameterOverride m_Contrast;
+
+ SerializedParameterOverride m_MixerRedOutRedIn;
+ SerializedParameterOverride m_MixerRedOutGreenIn;
+ SerializedParameterOverride m_MixerRedOutBlueIn;
+
+ SerializedParameterOverride m_MixerGreenOutRedIn;
+ SerializedParameterOverride m_MixerGreenOutGreenIn;
+ SerializedParameterOverride m_MixerGreenOutBlueIn;
+
+ SerializedParameterOverride m_MixerBlueOutRedIn;
+ SerializedParameterOverride m_MixerBlueOutGreenIn;
+ SerializedParameterOverride m_MixerBlueOutBlueIn;
+
+ SerializedParameterOverride m_Lift;
+ SerializedParameterOverride m_Gamma;
+ SerializedParameterOverride m_Gain;
+
+ SerializedParameterOverride m_MasterCurve;
+ SerializedParameterOverride m_RedCurve;
+ SerializedParameterOverride m_GreenCurve;
+ SerializedParameterOverride m_BlueCurve;
+
+ SerializedParameterOverride m_HueVsHueCurve;
+ SerializedParameterOverride m_HueVsSatCurve;
+ SerializedParameterOverride m_SatVsSatCurve;
+ SerializedParameterOverride m_LumVsSatCurve;
+
+ // Internal references to the actual animation curves
+ // Needed for the curve editor
+ SerializedProperty m_RawMasterCurve;
+ SerializedProperty m_RawRedCurve;
+ SerializedProperty m_RawGreenCurve;
+ SerializedProperty m_RawBlueCurve;
+
+ SerializedProperty m_RawHueVsHueCurve;
+ SerializedProperty m_RawHueVsSatCurve;
+ SerializedProperty m_RawSatVsSatCurve;
+ SerializedProperty m_RawLumVsSatCurve;
+
+ CurveEditor m_CurveEditor;
+ Dictionary m_CurveDict;
+
+ // Custom tone curve drawing
+ const int k_CustomToneCurveResolution = 48;
+ const float k_CustomToneCurveRangeY = 1.025f;
+ readonly Vector3[] m_RectVertices = new Vector3[4];
+ readonly Vector3[] m_LineVertices = new Vector3[2];
+ readonly Vector3[] m_CurveVertices = new Vector3[k_CustomToneCurveResolution];
+ Rect m_CustomToneCurveRect;
+ readonly HableCurve m_HableCurve = new HableCurve();
+
+ public override void OnEnable()
+ {
+ m_GradingMode = FindParameterOverride(x => x.gradingMode);
+
+ m_ExternalLut = FindParameterOverride(x => x.externalLut);
+
+ m_Tonemapper = FindParameterOverride(x => x.tonemapper);
+ m_ToneCurveToeStrength = FindParameterOverride(x => x.toneCurveToeStrength);
+ m_ToneCurveToeLength = FindParameterOverride(x => x.toneCurveToeLength);
+ m_ToneCurveShoulderStrength = FindParameterOverride(x => x.toneCurveShoulderStrength);
+ m_ToneCurveShoulderLength = FindParameterOverride(x => x.toneCurveShoulderLength);
+ m_ToneCurveShoulderAngle = FindParameterOverride(x => x.toneCurveShoulderAngle);
+ m_ToneCurveGamma = FindParameterOverride(x => x.toneCurveGamma);
+
+ m_LdrLut = FindParameterOverride(x => x.ldrLut);
+ m_LdrLutContribution = FindParameterOverride(x => x.ldrLutContribution);
+
+ m_Temperature = FindParameterOverride(x => x.temperature);
+ m_Tint = FindParameterOverride(x => x.tint);
+
+ m_ColorFilter = FindParameterOverride(x => x.colorFilter);
+ m_HueShift = FindParameterOverride(x => x.hueShift);
+ m_Saturation = FindParameterOverride(x => x.saturation);
+ m_Brightness = FindParameterOverride(x => x.brightness);
+ m_PostExposure = FindParameterOverride(x => x.postExposure);
+ m_Contrast = FindParameterOverride(x => x.contrast);
+
+ m_MixerRedOutRedIn = FindParameterOverride(x => x.mixerRedOutRedIn);
+ m_MixerRedOutGreenIn = FindParameterOverride(x => x.mixerRedOutGreenIn);
+ m_MixerRedOutBlueIn = FindParameterOverride(x => x.mixerRedOutBlueIn);
+
+ m_MixerGreenOutRedIn = FindParameterOverride(x => x.mixerGreenOutRedIn);
+ m_MixerGreenOutGreenIn = FindParameterOverride(x => x.mixerGreenOutGreenIn);
+ m_MixerGreenOutBlueIn = FindParameterOverride(x => x.mixerGreenOutBlueIn);
+
+ m_MixerBlueOutRedIn = FindParameterOverride(x => x.mixerBlueOutRedIn);
+ m_MixerBlueOutGreenIn = FindParameterOverride(x => x.mixerBlueOutGreenIn);
+ m_MixerBlueOutBlueIn = FindParameterOverride(x => x.mixerBlueOutBlueIn);
+
+ m_Lift = FindParameterOverride(x => x.lift);
+ m_Gamma = FindParameterOverride(x => x.gamma);
+ m_Gain = FindParameterOverride(x => x.gain);
+
+ m_MasterCurve = FindParameterOverride(x => x.masterCurve);
+ m_RedCurve = FindParameterOverride(x => x.redCurve);
+ m_GreenCurve = FindParameterOverride(x => x.greenCurve);
+ m_BlueCurve = FindParameterOverride(x => x.blueCurve);
+
+ m_HueVsHueCurve = FindParameterOverride(x => x.hueVsHueCurve);
+ m_HueVsSatCurve = FindParameterOverride(x => x.hueVsSatCurve);
+ m_SatVsSatCurve = FindParameterOverride(x => x.satVsSatCurve);
+ m_LumVsSatCurve = FindParameterOverride(x => x.lumVsSatCurve);
+
+ m_RawMasterCurve = FindProperty(x => x.masterCurve.value.curve);
+ m_RawRedCurve = FindProperty(x => x.redCurve.value.curve);
+ m_RawGreenCurve = FindProperty(x => x.greenCurve.value.curve);
+ m_RawBlueCurve = FindProperty(x => x.blueCurve.value.curve);
+
+ m_RawHueVsHueCurve = FindProperty(x => x.hueVsHueCurve.value.curve);
+ m_RawHueVsSatCurve = FindProperty(x => x.hueVsSatCurve.value.curve);
+ m_RawSatVsSatCurve = FindProperty(x => x.satVsSatCurve.value.curve);
+ m_RawLumVsSatCurve = FindProperty(x => x.lumVsSatCurve.value.curve);
+
+ m_CurveEditor = new CurveEditor();
+ m_CurveDict = new Dictionary();
+
+ // Prepare the curve editor
+ SetupCurve(m_RawMasterCurve, new Color(1f, 1f, 1f), 2, false);
+ SetupCurve(m_RawRedCurve, new Color(1f, 0f, 0f), 2, false);
+ SetupCurve(m_RawGreenCurve, new Color(0f, 1f, 0f), 2, false);
+ SetupCurve(m_RawBlueCurve, new Color(0f, 0.5f, 1f), 2, false);
+ SetupCurve(m_RawHueVsHueCurve, new Color(1f, 1f, 1f), 0, true);
+ SetupCurve(m_RawHueVsSatCurve, new Color(1f, 1f, 1f), 0, true);
+ SetupCurve(m_RawSatVsSatCurve, new Color(1f, 1f, 1f), 0, false);
+ SetupCurve(m_RawLumVsSatCurve, new Color(1f, 1f, 1f), 0, false);
+ }
+
+ public override void OnInspectorGUI()
+ {
+ PropertyField(m_GradingMode);
+
+ var gradingMode = (GradingMode)m_GradingMode.value.intValue;
+
+ // Check if we're in gamma or linear and display a warning if we're trying to do hdr
+ // color grading while being in gamma mode
+ if (gradingMode != GradingMode.LowDefinitionRange)
+ {
+ if (QualitySettings.activeColorSpace == ColorSpace.Gamma)
+ EditorGUILayout.HelpBox("ColorSpace in project settings is set to Gamma, HDR color grading won't look correct. Switch to Linear or use LDR color grading mode instead.", MessageType.Warning);
+ }
+
+ if (m_GradingMode.overrideState.boolValue && gradingMode == GradingMode.External)
+ {
+ if (!SystemInfo.supports3DRenderTextures || !SystemInfo.supportsComputeShaders)
+ EditorGUILayout.HelpBox("HDR color grading requires compute shader & 3D render texture support.", MessageType.Warning);
+ }
+
+ if (gradingMode == GradingMode.LowDefinitionRange)
+ DoStandardModeGUI(false);
+ else if (gradingMode == GradingMode.HighDefinitionRange)
+ DoStandardModeGUI(true);
+ else if (gradingMode == GradingMode.External)
+ DoExternalModeGUI();
+
+ EditorGUILayout.Space();
+ }
+
+ void SetupCurve(SerializedProperty prop, Color color, uint minPointCount, bool loop)
+ {
+ var state = CurveEditor.CurveState.defaultState;
+ state.color = color;
+ state.visible = false;
+ state.minPointCount = minPointCount;
+ state.onlyShowHandlesOnSelection = true;
+ state.zeroKeyConstantValue = 0.5f;
+ state.loopInBounds = loop;
+ m_CurveEditor.Add(prop, state);
+ m_CurveDict.Add(prop, color);
+ }
+
+ void DoExternalModeGUI()
+ {
+ PropertyField(m_ExternalLut);
+
+ var lut = m_ExternalLut.value.objectReferenceValue;
+ if (lut != null)
+ {
+ if (lut.GetType() == typeof(Texture3D))
+ {
+ var o = (Texture3D)lut;
+ if (o.width == o.height && o.height == o.depth)
+ return;
+ }
+ else if (lut.GetType() == typeof(RenderTexture))
+ {
+ var o = (RenderTexture)lut;
+ if (o.width == o.height && o.height == o.volumeDepth)
+ return;
+ }
+
+ EditorGUILayout.HelpBox("Custom LUTs have to be log-encoded 3D textures or 3D render textures with cube format.", MessageType.Warning);
+ }
+ }
+
+ void DoStandardModeGUI(bool hdr)
+ {
+ if (!hdr)
+ {
+ PropertyField(m_LdrLut);
+ PropertyField(m_LdrLutContribution);
+
+ var lut = (target as ColorGrading).ldrLut.value;
+ CheckLutImportSettings(lut);
+ }
+
+ if (hdr)
+ {
+ EditorGUILayout.Space();
+ EditorUtilities.DrawHeaderLabel("Tonemapping");
+ PropertyField(m_Tonemapper);
+
+ if (m_Tonemapper.value.intValue == (int)Tonemapper.Custom)
+ {
+ DrawCustomToneCurve();
+ PropertyField(m_ToneCurveToeStrength);
+ PropertyField(m_ToneCurveToeLength);
+ PropertyField(m_ToneCurveShoulderStrength);
+ PropertyField(m_ToneCurveShoulderLength);
+ PropertyField(m_ToneCurveShoulderAngle);
+ PropertyField(m_ToneCurveGamma);
+ }
+ }
+
+ EditorGUILayout.Space();
+ EditorUtilities.DrawHeaderLabel("White Balance");
+
+ PropertyField(m_Temperature);
+ PropertyField(m_Tint);
+
+ EditorGUILayout.Space();
+ EditorUtilities.DrawHeaderLabel("Tone");
+
+ if (hdr)
+ PropertyField(m_PostExposure);
+
+ PropertyField(m_ColorFilter);
+ PropertyField(m_HueShift);
+ PropertyField(m_Saturation);
+
+ if (!hdr)
+ PropertyField(m_Brightness);
+
+ PropertyField(m_Contrast);
+
+ EditorGUILayout.Space();
+ int currentChannel = GlobalSettings.currentChannelMixer;
+
+ using (new EditorGUILayout.HorizontalScope())
+ {
+ EditorGUILayout.PrefixLabel("Channel Mixer", GUIStyle.none, Styling.headerLabel);
+
+ EditorGUI.BeginChangeCheck();
+ {
+ using (new EditorGUILayout.HorizontalScope())
+ {
+ GUILayoutUtility.GetRect(9f, 18f, GUILayout.ExpandWidth(false)); // Dirty hack to do proper right column alignement
+ if (GUILayout.Toggle(currentChannel == 0, EditorUtilities.GetContent("Red|Red output channel."), EditorStyles.miniButtonLeft)) currentChannel = 0;
+ if (GUILayout.Toggle(currentChannel == 1, EditorUtilities.GetContent("Green|Green output channel."), EditorStyles.miniButtonMid)) currentChannel = 1;
+ if (GUILayout.Toggle(currentChannel == 2, EditorUtilities.GetContent("Blue|Blue output channel."), EditorStyles.miniButtonRight)) currentChannel = 2;
+ }
+ }
+ if (EditorGUI.EndChangeCheck())
+ GUI.FocusControl(null);
+ }
+
+ GlobalSettings.currentChannelMixer = currentChannel;
+
+ if (currentChannel == 0)
+ {
+ PropertyField(m_MixerRedOutRedIn);
+ PropertyField(m_MixerRedOutGreenIn);
+ PropertyField(m_MixerRedOutBlueIn);
+ }
+ else if (currentChannel == 1)
+ {
+ PropertyField(m_MixerGreenOutRedIn);
+ PropertyField(m_MixerGreenOutGreenIn);
+ PropertyField(m_MixerGreenOutBlueIn);
+ }
+ else
+ {
+ PropertyField(m_MixerBlueOutRedIn);
+ PropertyField(m_MixerBlueOutGreenIn);
+ PropertyField(m_MixerBlueOutBlueIn);
+ }
+
+ EditorGUILayout.Space();
+ EditorUtilities.DrawHeaderLabel("Trackballs");
+
+ using (new EditorGUILayout.HorizontalScope())
+ {
+ PropertyField(m_Lift);
+ GUILayout.Space(4f);
+ PropertyField(m_Gamma);
+ GUILayout.Space(4f);
+ PropertyField(m_Gain);
+ }
+
+ EditorGUILayout.Space();
+ EditorUtilities.DrawHeaderLabel("Grading Curves");
+
+ DoCurvesGUI(hdr);
+ }
+
+ void CheckLutImportSettings(Texture lut)
+ {
+ if (lut != null)
+ {
+ var importer = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(lut)) as TextureImporter;
+
+ // Fails when using an internal texture as you can't change import settings on
+ // builtin resources, thus the check for null
+ if (importer != null)
+ {
+ bool valid = importer.anisoLevel == 0
+ && importer.mipmapEnabled == false
+ && importer.sRGBTexture == false
+ && importer.textureCompression == TextureImporterCompression.Uncompressed
+ && importer.wrapMode == TextureWrapMode.Clamp;
+
+ if (!valid)
+ EditorUtilities.DrawFixMeBox("Invalid LUT import settings.", () => SetLutImportSettings(importer));
+ }
+
+ if (lut.width != lut.height * lut.height)
+ {
+ EditorGUILayout.HelpBox("The Lookup Texture size is invalid. Width should be Height * Height.", MessageType.Error);
+ }
+ }
+ }
+
+ void SetLutImportSettings(TextureImporter importer)
+ {
+ importer.textureType = TextureImporterType.Default;
+ importer.mipmapEnabled = false;
+ importer.anisoLevel = 0;
+ importer.sRGBTexture = false;
+ importer.npotScale = TextureImporterNPOTScale.None;
+ importer.textureCompression = TextureImporterCompression.Uncompressed;
+ importer.alphaSource = TextureImporterAlphaSource.None;
+ importer.wrapMode = TextureWrapMode.Clamp;
+ importer.SaveAndReimport();
+ AssetDatabase.Refresh();
+ }
+
+ void DrawCustomToneCurve()
+ {
+ EditorGUILayout.Space();
+
+ // Reserve GUI space
+ using (new GUILayout.HorizontalScope())
+ {
+ GUILayout.Space(EditorGUI.indentLevel * 15f);
+ m_CustomToneCurveRect = GUILayoutUtility.GetRect(128, 80);
+ }
+
+ if (Event.current.type != EventType.Repaint)
+ return;
+
+ // Prepare curve data
+ float toeStrength = m_ToneCurveToeStrength.value.floatValue;
+ float toeLength = m_ToneCurveToeLength.value.floatValue;
+ float shoulderStrength = m_ToneCurveShoulderStrength.value.floatValue;
+ float shoulderLength = m_ToneCurveShoulderLength.value.floatValue;
+ float shoulderAngle = m_ToneCurveShoulderAngle.value.floatValue;
+ float gamma = m_ToneCurveGamma.value.floatValue;
+ m_HableCurve.Init(
+ toeStrength,
+ toeLength,
+ shoulderStrength,
+ shoulderLength,
+ shoulderAngle,
+ gamma
+ );
+
+ float endPoint = m_HableCurve.whitePoint;
+
+ // Background
+ m_RectVertices[0] = PointInRect(0f, 0f, endPoint);
+ m_RectVertices[1] = PointInRect(endPoint, 0f, endPoint);
+ m_RectVertices[2] = PointInRect(endPoint, k_CustomToneCurveRangeY, endPoint);
+ m_RectVertices[3] = PointInRect(0f, k_CustomToneCurveRangeY, endPoint);
+ Handles.DrawSolidRectangleWithOutline(m_RectVertices, Color.white * 0.1f, Color.white * 0.4f);
+
+ // Vertical guides
+ if (endPoint < m_CustomToneCurveRect.width / 3)
+ {
+ int steps = Mathf.CeilToInt(endPoint);
+ for (var i = 1; i < steps; i++)
+ DrawLine(i, 0, i, k_CustomToneCurveRangeY, 0.4f, endPoint);
+ }
+
+ // Label
+ Handles.Label(m_CustomToneCurveRect.position + Vector2.right, "Custom Tone Curve", EditorStyles.miniLabel);
+
+ // Draw the acual curve
+ var vcount = 0;
+ while (vcount < k_CustomToneCurveResolution)
+ {
+ float x = endPoint * vcount / (k_CustomToneCurveResolution - 1);
+ float y = m_HableCurve.Eval(x);
+
+ if (y < k_CustomToneCurveRangeY)
+ {
+ m_CurveVertices[vcount++] = PointInRect(x, y, endPoint);
+ }
+ else
+ {
+ if (vcount > 1)
+ {
+ // Extend the last segment to the top edge of the rect.
+ var v1 = m_CurveVertices[vcount - 2];
+ var v2 = m_CurveVertices[vcount - 1];
+ var clip = (m_CustomToneCurveRect.y - v1.y) / (v2.y - v1.y);
+ m_CurveVertices[vcount - 1] = v1 + (v2 - v1) * clip;
+ }
+ break;
+ }
+ }
+
+ if (vcount > 1)
+ {
+ Handles.color = Color.white * 0.9f;
+ Handles.DrawAAPolyLine(2f, vcount, m_CurveVertices);
+ }
+ }
+
+ void DrawLine(float x1, float y1, float x2, float y2, float grayscale, float rangeX)
+ {
+ m_LineVertices[0] = PointInRect(x1, y1, rangeX);
+ m_LineVertices[1] = PointInRect(x2, y2, rangeX);
+ Handles.color = Color.white * grayscale;
+ Handles.DrawAAPolyLine(2f, m_LineVertices);
+ }
+
+ Vector3 PointInRect(float x, float y, float rangeX)
+ {
+ x = Mathf.Lerp(m_CustomToneCurveRect.x, m_CustomToneCurveRect.xMax, x / rangeX);
+ y = Mathf.Lerp(m_CustomToneCurveRect.yMax, m_CustomToneCurveRect.y, y / k_CustomToneCurveRangeY);
+ return new Vector3(x, y, 0);
+ }
+
+ void ResetVisibleCurves()
+ {
+ foreach (var curve in m_CurveDict)
+ {
+ var state = m_CurveEditor.GetCurveState(curve.Key);
+ state.visible = false;
+ m_CurveEditor.SetCurveState(curve.Key, state);
+ }
+ }
+
+ void SetCurveVisible(SerializedProperty rawProp, SerializedProperty overrideProp)
+ {
+ var state = m_CurveEditor.GetCurveState(rawProp);
+ state.visible = true;
+ state.editable = overrideProp.boolValue;
+ m_CurveEditor.SetCurveState(rawProp, state);
+ }
+
+ void CurveOverrideToggle(SerializedProperty overrideProp)
+ {
+ overrideProp.boolValue = GUILayout.Toggle(overrideProp.boolValue, EditorUtilities.GetContent("Override"), EditorStyles.toolbarButton);
+ }
+
+ static Material s_MaterialGrid;
+
+ void DoCurvesGUI(bool hdr)
+ {
+ EditorGUILayout.Space();
+ ResetVisibleCurves();
+
+ using (new EditorGUI.DisabledGroupScope(serializedObject.isEditingMultipleObjects))
+ {
+ int curveEditingId = 0;
+ SerializedProperty currentCurveRawProp = null;
+
+ // Top toolbar
+ using (new GUILayout.HorizontalScope(EditorStyles.toolbar))
+ {
+ curveEditingId = DoCurveSelectionPopup(GlobalSettings.currentCurve, hdr);
+ curveEditingId = Mathf.Clamp(curveEditingId, hdr ? 4 : 0, 7);
+
+ EditorGUILayout.Space();
+
+ switch (curveEditingId)
+ {
+ case 0:
+ CurveOverrideToggle(m_MasterCurve.overrideState);
+ SetCurveVisible(m_RawMasterCurve, m_MasterCurve.overrideState);
+ currentCurveRawProp = m_RawMasterCurve;
+ break;
+ case 1:
+ CurveOverrideToggle(m_RedCurve.overrideState);
+ SetCurveVisible(m_RawRedCurve, m_RedCurve.overrideState);
+ currentCurveRawProp = m_RawRedCurve;
+ break;
+ case 2:
+ CurveOverrideToggle(m_GreenCurve.overrideState);
+ SetCurveVisible(m_RawGreenCurve, m_GreenCurve.overrideState);
+ currentCurveRawProp = m_RawGreenCurve;
+ break;
+ case 3:
+ CurveOverrideToggle(m_BlueCurve.overrideState);
+ SetCurveVisible(m_RawBlueCurve, m_BlueCurve.overrideState);
+ currentCurveRawProp = m_RawBlueCurve;
+ break;
+ case 4:
+ CurveOverrideToggle(m_HueVsHueCurve.overrideState);
+ SetCurveVisible(m_RawHueVsHueCurve, m_HueVsHueCurve.overrideState);
+ currentCurveRawProp = m_RawHueVsHueCurve;
+ break;
+ case 5:
+ CurveOverrideToggle(m_HueVsSatCurve.overrideState);
+ SetCurveVisible(m_RawHueVsSatCurve, m_HueVsSatCurve.overrideState);
+ currentCurveRawProp = m_RawHueVsSatCurve;
+ break;
+ case 6:
+ CurveOverrideToggle(m_SatVsSatCurve.overrideState);
+ SetCurveVisible(m_RawSatVsSatCurve, m_SatVsSatCurve.overrideState);
+ currentCurveRawProp = m_RawSatVsSatCurve;
+ break;
+ case 7:
+ CurveOverrideToggle(m_LumVsSatCurve.overrideState);
+ SetCurveVisible(m_RawLumVsSatCurve, m_LumVsSatCurve.overrideState);
+ currentCurveRawProp = m_RawLumVsSatCurve;
+ break;
+ }
+
+ GUILayout.FlexibleSpace();
+
+ if (GUILayout.Button("Reset", EditorStyles.toolbarButton))
+ {
+ switch (curveEditingId)
+ {
+ case 0:
+ m_RawMasterCurve.animationCurveValue = AnimationCurve.Linear(0f, 0f, 1f, 1f);
+ break;
+ case 1:
+ m_RawRedCurve.animationCurveValue = AnimationCurve.Linear(0f, 0f, 1f, 1f);
+ break;
+ case 2:
+ m_RawGreenCurve.animationCurveValue = AnimationCurve.Linear(0f, 0f, 1f, 1f);
+ break;
+ case 3:
+ m_RawBlueCurve.animationCurveValue = AnimationCurve.Linear(0f, 0f, 1f, 1f);
+ break;
+ case 4:
+ m_RawHueVsHueCurve.animationCurveValue = new AnimationCurve();
+ break;
+ case 5:
+ m_RawHueVsSatCurve.animationCurveValue = new AnimationCurve();
+ break;
+ case 6:
+ m_RawSatVsSatCurve.animationCurveValue = new AnimationCurve();
+ break;
+ case 7:
+ m_RawLumVsSatCurve.animationCurveValue = new AnimationCurve();
+ break;
+ }
+ }
+
+ GlobalSettings.currentCurve = curveEditingId;
+ }
+
+ // Curve area
+ var settings = m_CurveEditor.settings;
+ var rect = GUILayoutUtility.GetAspectRect(2f);
+ var innerRect = settings.padding.Remove(rect);
+
+ if (Event.current.type == EventType.Repaint)
+ {
+ // Background
+ EditorGUI.DrawRect(rect, new Color(0.15f, 0.15f, 0.15f, 1f));
+
+ if (curveEditingId == 4 || curveEditingId == 5)
+ DrawBackgroundTexture(innerRect, 0);
+ else if (curveEditingId == 6 || curveEditingId == 7)
+ DrawBackgroundTexture(innerRect, 1);
+
+ // Bounds
+ Handles.color = Color.white * (GUI.enabled ? 1f : 0.5f);
+ Handles.DrawSolidRectangleWithOutline(innerRect, Color.clear, new Color(0.8f, 0.8f, 0.8f, 0.5f));
+
+ // Grid setup
+ Handles.color = new Color(1f, 1f, 1f, 0.05f);
+ int hLines = (int)Mathf.Sqrt(innerRect.width);
+ int vLines = (int)(hLines / (innerRect.width / innerRect.height));
+
+ // Vertical grid
+ int gridOffset = Mathf.FloorToInt(innerRect.width / hLines);
+ int gridPadding = ((int)(innerRect.width) % hLines) / 2;
+
+ for (int i = 1; i < hLines; i++)
+ {
+ var offset = gridOffset * i * Vector2.right;
+ offset.x += gridPadding;
+ Handles.DrawLine(innerRect.position + offset, new Vector2(innerRect.x, innerRect.yMax - 1) + offset);
+ }
+
+ // Horizontal grid
+ gridOffset = Mathf.FloorToInt(innerRect.height / vLines);
+ gridPadding = ((int)(innerRect.height) % vLines) / 2;
+
+ for (int i = 1; i < vLines; i++)
+ {
+ var offset = gridOffset * i * Vector2.up;
+ offset.y += gridPadding;
+ Handles.DrawLine(innerRect.position + offset, new Vector2(innerRect.xMax - 1, innerRect.y) + offset);
+ }
+ }
+
+ // Curve editor
+ if (m_CurveEditor.OnGUI(rect))
+ {
+ Repaint();
+ GUI.changed = true;
+ }
+
+ if (Event.current.type == EventType.Repaint)
+ {
+ // Borders
+ Handles.color = Color.black;
+ Handles.DrawLine(new Vector2(rect.x, rect.y - 18f), new Vector2(rect.xMax, rect.y - 18f));
+ Handles.DrawLine(new Vector2(rect.x, rect.y - 19f), new Vector2(rect.x, rect.yMax));
+ Handles.DrawLine(new Vector2(rect.x, rect.yMax), new Vector2(rect.xMax, rect.yMax));
+ Handles.DrawLine(new Vector2(rect.xMax, rect.yMax), new Vector2(rect.xMax, rect.y - 18f));
+
+ bool editable = m_CurveEditor.GetCurveState(currentCurveRawProp).editable;
+ string editableString = editable ? string.Empty : "(Not Overriding)\n";
+
+ // Selection info
+ var selection = m_CurveEditor.GetSelection();
+ var infoRect = innerRect;
+ infoRect.x += 5f;
+ infoRect.width = 100f;
+ infoRect.height = 30f;
+
+ if (selection.curve != null && selection.keyframeIndex > -1)
+ {
+ var key = selection.keyframe.Value;
+ GUI.Label(infoRect, string.Format("{0}\n{1}", key.time.ToString("F3"), key.value.ToString("F3")), Styling.preLabel);
+ }
+ else
+ {
+ GUI.Label(infoRect, editableString, Styling.preLabel);
+ }
+ }
+ }
+ }
+
+ void DrawBackgroundTexture(Rect rect, int pass)
+ {
+ if (s_MaterialGrid == null)
+ s_MaterialGrid = new Material(Shader.Find("Hidden/PostProcessing/Editor/CurveGrid")) { hideFlags = HideFlags.HideAndDontSave };
+
+ float scale = EditorGUIUtility.pixelsPerPoint;
+
+#if UNITY_2018_1_OR_NEWER
+ const RenderTextureReadWrite kReadWrite = RenderTextureReadWrite.sRGB;
+#else
+ const RenderTextureReadWrite kReadWrite = RenderTextureReadWrite.Linear;
+#endif
+
+ var oldRt = RenderTexture.active;
+ var rt = RenderTexture.GetTemporary(Mathf.CeilToInt(rect.width * scale), Mathf.CeilToInt(rect.height * scale), 0, RenderTextureFormat.ARGB32, kReadWrite);
+ s_MaterialGrid.SetFloat("_DisabledState", GUI.enabled ? 1f : 0.5f);
+ s_MaterialGrid.SetFloat("_PixelScaling", EditorGUIUtility.pixelsPerPoint);
+
+ Graphics.Blit(null, rt, s_MaterialGrid, pass);
+ RenderTexture.active = oldRt;
+
+ GUI.DrawTexture(rect, rt);
+ RenderTexture.ReleaseTemporary(rt);
+ }
+
+ int DoCurveSelectionPopup(int id, bool hdr)
+ {
+ GUILayout.Label(s_Curves[id], EditorStyles.toolbarPopup, GUILayout.MaxWidth(150f));
+
+ var lastRect = GUILayoutUtility.GetLastRect();
+ var e = Event.current;
+
+ if (e.type == EventType.MouseDown && e.button == 0 && lastRect.Contains(e.mousePosition))
+ {
+ var menu = new GenericMenu();
+
+ for (int i = 0; i < s_Curves.Length; i++)
+ {
+ if (i == 4)
+ menu.AddSeparator("");
+
+ if (hdr && i < 4)
+ menu.AddDisabledItem(s_Curves[i]);
+ else
+ {
+ int current = i; // Capture local for closure
+ menu.AddItem(s_Curves[i], current == id, () => GlobalSettings.currentCurve = current);
+ }
+ }
+
+ menu.DropDown(new Rect(lastRect.xMin, lastRect.yMax, 1f, 1f));
+ }
+
+ return id;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Effects/ColorGradingEditor.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/Effects/ColorGradingEditor.cs.meta
new file mode 100644
index 0000000..fdc2a13
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Effects/ColorGradingEditor.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: f79c8927d684af6499f512361e23bace
+timeCreated: 1493026581
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Effects/DefaultPostProcessEffectEditor.cs b/com.unity.postprocessing/PostProcessing/Editor/Effects/DefaultPostProcessEffectEditor.cs
new file mode 100644
index 0000000..490fd73
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Effects/DefaultPostProcessEffectEditor.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using UnityEngine.Rendering.PostProcessing;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ ///
+ /// A default effect editor that gathers all parameters and list them vertically in the
+ /// inspector.
+ ///
+ public class DefaultPostProcessEffectEditor : PostProcessEffectBaseEditor
+ {
+ List m_Parameters;
+
+ ///
+ /// Called when the editor is initialized.
+ ///
+ public override void OnEnable()
+ {
+ m_Parameters = new List();
+
+ var fields = target.GetType()
+ .GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
+ .Where(t => t.FieldType.IsSubclassOf(typeof(ParameterOverride)) && t.Name != "enabled" && ((t.IsPublic && t.GetCustomAttributes(typeof(NonSerializedAttribute), false).Length == 0)
+ || (t.GetCustomAttributes(typeof(UnityEngine.SerializeField), false).Length > 0))
+)
+ .ToList();
+
+ foreach (var field in fields)
+ {
+ var property = serializedObject.FindProperty(field.Name);
+ var attributes = field.GetCustomAttributes(false).Cast().ToArray();
+ var parameter = new SerializedParameterOverride(property, attributes);
+ m_Parameters.Add(parameter);
+ }
+ }
+
+ ///
+ /// Called every time the inspector is being redrawn. This is where you should add your UI
+ /// drawing code.
+ ///
+ public override void OnInspectorGUI()
+ {
+ foreach (var parameter in m_Parameters)
+ PropertyField(parameter);
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Effects/DefaultPostProcessEffectEditor.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/Effects/DefaultPostProcessEffectEditor.cs.meta
new file mode 100644
index 0000000..9289be6
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Effects/DefaultPostProcessEffectEditor.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 4b0cd5ddb61a56b4f86ea0fd0a102fe7
+timeCreated: 1492705253
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Effects/DepthOfFieldEditor.cs b/com.unity.postprocessing/PostProcessing/Editor/Effects/DepthOfFieldEditor.cs
new file mode 100644
index 0000000..9e58d67
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Effects/DepthOfFieldEditor.cs
@@ -0,0 +1,33 @@
+using UnityEngine;
+using UnityEngine.Rendering.PostProcessing;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ [PostProcessEditor(typeof(DepthOfField))]
+ internal sealed class DepthOfFieldEditor : PostProcessEffectEditor
+ {
+ SerializedParameterOverride m_FocusDistance;
+ SerializedParameterOverride m_Aperture;
+ SerializedParameterOverride m_FocalLength;
+ SerializedParameterOverride m_KernelSize;
+
+ public override void OnEnable()
+ {
+ m_FocusDistance = FindParameterOverride(x => x.focusDistance);
+ m_Aperture = FindParameterOverride(x => x.aperture);
+ m_FocalLength = FindParameterOverride(x => x.focalLength);
+ m_KernelSize = FindParameterOverride(x => x.kernelSize);
+ }
+
+ public override void OnInspectorGUI()
+ {
+ if (SystemInfo.graphicsShaderLevel < 35)
+ EditorGUILayout.HelpBox("Depth Of Field is only supported on the following platforms:\nDX11+, OpenGL 3.2+, OpenGL ES 3+, Metal, Vulkan, PS4/XB1 consoles.", MessageType.Warning);
+
+ PropertyField(m_FocusDistance);
+ PropertyField(m_Aperture);
+ PropertyField(m_FocalLength);
+ PropertyField(m_KernelSize);
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Effects/DepthOfFieldEditor.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/Effects/DepthOfFieldEditor.cs.meta
new file mode 100644
index 0000000..826cd59
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Effects/DepthOfFieldEditor.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: eb4c0b518e013c8418135b3bd8a91b6c
+timeCreated: 1513004657
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Effects/LensDistortionEditor.cs b/com.unity.postprocessing/PostProcessing/Editor/Effects/LensDistortionEditor.cs
new file mode 100644
index 0000000..7310e8b
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Effects/LensDistortionEditor.cs
@@ -0,0 +1,16 @@
+using UnityEngine.Rendering.PostProcessing;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ [PostProcessEditor(typeof(LensDistortion))]
+ internal sealed class LensDistortionEditor : DefaultPostProcessEffectEditor
+ {
+ public override void OnInspectorGUI()
+ {
+ if (EditorUtilities.isVREnabled)
+ EditorGUILayout.HelpBox("Lens Distortion is available only for non-stereo cameras.", MessageType.Warning);
+
+ base.OnInspectorGUI();
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Effects/LensDistortionEditor.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/Effects/LensDistortionEditor.cs.meta
new file mode 100644
index 0000000..f3b8147
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Effects/LensDistortionEditor.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 7758395f983044344b2c8ea743e956c3
+timeCreated: 1519742257
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Effects/MotionBlurEditor.cs b/com.unity.postprocessing/PostProcessing/Editor/Effects/MotionBlurEditor.cs
new file mode 100644
index 0000000..3fee812
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Effects/MotionBlurEditor.cs
@@ -0,0 +1,16 @@
+using UnityEngine.Rendering.PostProcessing;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ [PostProcessEditor(typeof(MotionBlur))]
+ internal sealed class MotionBlurEditor : DefaultPostProcessEffectEditor
+ {
+ public override void OnInspectorGUI()
+ {
+ if (EditorUtilities.isVREnabled)
+ EditorGUILayout.HelpBox("Motion Blur is available only for non-stereo cameras.", MessageType.Warning);
+
+ base.OnInspectorGUI();
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Effects/MotionBlurEditor.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/Effects/MotionBlurEditor.cs.meta
new file mode 100644
index 0000000..5143d3a
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Effects/MotionBlurEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: de3d46fc4bda066408aeba6fb8e44d6a
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Effects/ScreenSpaceReflectionsEditor.cs b/com.unity.postprocessing/PostProcessing/Editor/Effects/ScreenSpaceReflectionsEditor.cs
new file mode 100644
index 0000000..8fe1451
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Effects/ScreenSpaceReflectionsEditor.cs
@@ -0,0 +1,58 @@
+using UnityEngine;
+using UnityEngine.Rendering.PostProcessing;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ [PostProcessEditor(typeof(ScreenSpaceReflections))]
+ internal sealed class ScreenSpaceReflectionsEditor : PostProcessEffectEditor
+ {
+ SerializedParameterOverride m_Preset;
+ SerializedParameterOverride m_MaximumIterationCount;
+ SerializedParameterOverride m_Thickness;
+ SerializedParameterOverride m_Resolution;
+ SerializedParameterOverride m_MaximumMarchDistance;
+ SerializedParameterOverride m_DistanceFade;
+ SerializedParameterOverride m_Vignette;
+
+ public override void OnEnable()
+ {
+ m_Preset = FindParameterOverride(x => x.preset);
+ m_MaximumIterationCount = FindParameterOverride(x => x.maximumIterationCount);
+ m_Thickness = FindParameterOverride(x => x.thickness);
+ m_Resolution = FindParameterOverride(x => x.resolution);
+ m_MaximumMarchDistance = FindParameterOverride(x => x.maximumMarchDistance);
+ m_DistanceFade = FindParameterOverride(x => x.distanceFade);
+ m_Vignette = FindParameterOverride(x => x.vignette);
+ }
+
+ public override void OnInspectorGUI()
+ {
+ if (RuntimeUtilities.scriptableRenderPipelineActive)
+ {
+ EditorGUILayout.HelpBox("This effect doesn't work with scriptable render pipelines yet.", MessageType.Warning);
+ return;
+ }
+
+ if (Camera.main != null && Camera.main.actualRenderingPath != RenderingPath.DeferredShading)
+ EditorGUILayout.HelpBox("This effect only works with the deferred rendering path.", MessageType.Warning);
+
+ if (!SystemInfo.supportsComputeShaders)
+ EditorGUILayout.HelpBox("This effect requires compute shader support.", MessageType.Warning);
+
+ PropertyField(m_Preset);
+
+ if (m_Preset.value.intValue == (int)ScreenSpaceReflectionPreset.Custom)
+ {
+ PropertyField(m_MaximumIterationCount);
+ PropertyField(m_Thickness);
+ PropertyField(m_Resolution);
+
+ EditorGUILayout.Space();
+ }
+
+ PropertyField(m_MaximumMarchDistance);
+ PropertyField(m_DistanceFade);
+ PropertyField(m_Vignette);
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Effects/ScreenSpaceReflectionsEditor.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/Effects/ScreenSpaceReflectionsEditor.cs.meta
new file mode 100644
index 0000000..1d8d116
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Effects/ScreenSpaceReflectionsEditor.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: d798d5719bf3b434eafb013385f872eb
+timeCreated: 1505226497
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Effects/VignetteEditor.cs b/com.unity.postprocessing/PostProcessing/Editor/Effects/VignetteEditor.cs
new file mode 100644
index 0000000..0351076
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Effects/VignetteEditor.cs
@@ -0,0 +1,91 @@
+using UnityEngine;
+using UnityEngine.Rendering.PostProcessing;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ [PostProcessEditor(typeof(Vignette))]
+ internal sealed class VignetteEditor : PostProcessEffectEditor
+ {
+ SerializedParameterOverride m_Mode;
+ SerializedParameterOverride m_Color;
+
+ SerializedParameterOverride m_Center;
+ SerializedParameterOverride m_Intensity;
+ SerializedParameterOverride m_Smoothness;
+ SerializedParameterOverride m_Roundness;
+ SerializedParameterOverride m_Rounded;
+
+ SerializedParameterOverride m_Mask;
+ SerializedParameterOverride m_Opacity;
+
+ public override void OnEnable()
+ {
+ m_Mode = FindParameterOverride(x => x.mode);
+ m_Color = FindParameterOverride(x => x.color);
+
+ m_Center = FindParameterOverride(x => x.center);
+ m_Intensity = FindParameterOverride(x => x.intensity);
+ m_Smoothness = FindParameterOverride(x => x.smoothness);
+ m_Roundness = FindParameterOverride(x => x.roundness);
+ m_Rounded = FindParameterOverride(x => x.rounded);
+
+ m_Mask = FindParameterOverride(x => x.mask);
+ m_Opacity = FindParameterOverride(x => x.opacity);
+ }
+
+ public override void OnInspectorGUI()
+ {
+ PropertyField(m_Mode);
+ PropertyField(m_Color);
+
+ if (m_Mode.value.intValue == (int)VignetteMode.Classic)
+ {
+ PropertyField(m_Center);
+ PropertyField(m_Intensity);
+ PropertyField(m_Smoothness);
+ PropertyField(m_Roundness);
+ PropertyField(m_Rounded);
+ }
+ else
+ {
+ PropertyField(m_Mask);
+
+ var mask = (target as Vignette).mask.value;
+
+ // Checks import settings on the mask
+ if (mask != null)
+ {
+ var importer = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(mask)) as TextureImporter;
+
+ // Fails when using an internal texture as you can't change import settings on
+ // builtin resources, thus the check for null
+ if (importer != null)
+ {
+ bool valid = importer.anisoLevel == 0
+ && importer.mipmapEnabled == false
+ && importer.alphaSource == TextureImporterAlphaSource.FromGrayScale
+ && importer.textureCompression == TextureImporterCompression.Uncompressed
+ && importer.wrapMode == TextureWrapMode.Clamp;
+
+ if (!valid)
+ EditorUtilities.DrawFixMeBox("Invalid mask import settings.", () => SetMaskImportSettings(importer));
+ }
+ }
+
+ PropertyField(m_Opacity);
+ }
+ }
+
+ void SetMaskImportSettings(TextureImporter importer)
+ {
+ importer.textureType = TextureImporterType.SingleChannel;
+ importer.alphaSource = TextureImporterAlphaSource.FromGrayScale;
+ importer.textureCompression = TextureImporterCompression.Uncompressed;
+ importer.anisoLevel = 0;
+ importer.mipmapEnabled = false;
+ importer.wrapMode = TextureWrapMode.Clamp;
+ importer.SaveAndReimport();
+ AssetDatabase.Refresh();
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Effects/VignetteEditor.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/Effects/VignetteEditor.cs.meta
new file mode 100644
index 0000000..d4da4fd
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Effects/VignetteEditor.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 3869d037332a74744a54736f00d62763
+timeCreated: 1492696599
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/PostProcessDebugEditor.cs b/com.unity.postprocessing/PostProcessing/Editor/PostProcessDebugEditor.cs
new file mode 100644
index 0000000..2455861
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/PostProcessDebugEditor.cs
@@ -0,0 +1,144 @@
+using UnityEngine;
+using UnityEngine.Rendering.PostProcessing;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ [CustomEditor(typeof(PostProcessDebug))]
+ sealed class PostProcessDebugEditor : BaseEditor
+ {
+ SerializedProperty m_PostProcessLayer;
+ SerializedProperty m_LightMeterEnabled;
+ SerializedProperty m_HistogramEnabled;
+ SerializedProperty m_WaveformEnabled;
+ SerializedProperty m_VectorscopeEnabled;
+ SerializedProperty m_Overlay;
+
+ SerializedObject m_LayerObject;
+
+ SerializedProperty m_LightMeterShowCurves;
+ SerializedProperty m_HistogramChannel;
+ SerializedProperty m_WaveformExposure;
+ SerializedProperty m_VectorscopeExposure;
+
+ SerializedProperty m_LinearDepth;
+ SerializedProperty m_MotionColorIntensity;
+ SerializedProperty m_MotionGridSize;
+ SerializedProperty m_ColorBlindness;
+ SerializedProperty m_ColorBlindnessStrength;
+
+ void OnEnable()
+ {
+ m_PostProcessLayer = FindProperty(x => x.postProcessLayer);
+ m_LightMeterEnabled = FindProperty(x => x.lightMeter);
+ m_HistogramEnabled = FindProperty(x => x.histogram);
+ m_WaveformEnabled = FindProperty(x => x.waveform);
+ m_VectorscopeEnabled = FindProperty(x => x.vectorscope);
+ m_Overlay = FindProperty(x => x.debugOverlay);
+
+ if (m_PostProcessLayer.objectReferenceValue != null)
+ RebuildProperties();
+ }
+
+ void RebuildProperties()
+ {
+ if (m_PostProcessLayer.objectReferenceValue == null)
+ return;
+
+ m_LayerObject = new SerializedObject(m_Target.postProcessLayer);
+
+ m_LightMeterShowCurves = m_LayerObject.FindProperty("debugLayer.lightMeter.showCurves");
+ m_HistogramChannel = m_LayerObject.FindProperty("debugLayer.histogram.channel");
+ m_WaveformExposure = m_LayerObject.FindProperty("debugLayer.waveform.exposure");
+ m_VectorscopeExposure = m_LayerObject.FindProperty("debugLayer.vectorscope.exposure");
+
+ m_LinearDepth = m_LayerObject.FindProperty("debugLayer.overlaySettings.linearDepth");
+ m_MotionColorIntensity = m_LayerObject.FindProperty("debugLayer.overlaySettings.motionColorIntensity");
+ m_MotionGridSize = m_LayerObject.FindProperty("debugLayer.overlaySettings.motionGridSize");
+ m_ColorBlindness = m_LayerObject.FindProperty("debugLayer.overlaySettings.colorBlindnessType");
+ m_ColorBlindnessStrength = m_LayerObject.FindProperty("debugLayer.overlaySettings.colorBlindnessStrength");
+ }
+
+ public override void OnInspectorGUI()
+ {
+ serializedObject.Update();
+
+ using (var changed = new EditorGUI.ChangeCheckScope())
+ {
+ EditorGUILayout.PropertyField(m_PostProcessLayer);
+ serializedObject.ApplyModifiedProperties(); // Needed to rebuild properties after a change
+ serializedObject.Update();
+
+ if (changed.changed)
+ RebuildProperties();
+ }
+
+ if (RuntimeUtilities.scriptableRenderPipelineActive)
+ {
+ EditorGUILayout.Space();
+ EditorGUILayout.HelpBox("A scriptable render pipeline is active, these features might not be available.", MessageType.Info);
+ }
+
+ if (m_PostProcessLayer.objectReferenceValue != null)
+ {
+ m_LayerObject.Update();
+
+ // Overlays
+ EditorGUILayout.Space();
+ EditorGUILayout.LabelField(EditorUtilities.GetContent("Overlay"), EditorStyles.boldLabel);
+ EditorGUI.indentLevel++;
+ EditorGUILayout.PropertyField(m_Overlay);
+ DoOverlayGUI(DebugOverlay.Depth, m_LinearDepth);
+ DoOverlayGUI(DebugOverlay.MotionVectors, m_MotionColorIntensity, m_MotionGridSize);
+ DoOverlayGUI(DebugOverlay.ColorBlindnessSimulation, m_ColorBlindness, m_ColorBlindnessStrength);
+
+ // Special cases
+ if (m_Overlay.intValue == (int)DebugOverlay.NANTracker && m_Target.postProcessLayer.stopNaNPropagation)
+ EditorGUILayout.HelpBox("Disable \"Stop NaN Propagation\" in the Post-process layer or NaNs will be overwritten!", MessageType.Warning);
+
+ EditorGUI.indentLevel--;
+
+ // Monitors
+ EditorGUILayout.Space();
+ EditorGUILayout.LabelField(EditorUtilities.GetContent("Monitors"), EditorStyles.boldLabel);
+ EditorGUI.indentLevel++;
+ DoMonitorGUI(EditorUtilities.GetContent("Light Meter"), m_LightMeterEnabled, m_LightMeterShowCurves);
+ DoMonitorGUI(EditorUtilities.GetContent("Histogram"), m_HistogramEnabled, m_HistogramChannel);
+ DoMonitorGUI(EditorUtilities.GetContent("Waveform"), m_WaveformEnabled, m_WaveformExposure);
+ DoMonitorGUI(EditorUtilities.GetContent("Vectorscope"), m_VectorscopeEnabled, m_VectorscopeExposure);
+ EditorGUI.indentLevel--;
+
+ m_LayerObject.ApplyModifiedProperties();
+ }
+
+ serializedObject.ApplyModifiedProperties();
+ }
+
+ void DoMonitorGUI(GUIContent content, SerializedProperty prop, params SerializedProperty[] settings)
+ {
+ EditorGUILayout.PropertyField(prop, content);
+
+ if (settings == null || settings.Length == 0)
+ return;
+
+ if (prop.boolValue)
+ {
+ EditorGUI.indentLevel++;
+ foreach (var p in settings)
+ EditorGUILayout.PropertyField(p);
+ EditorGUI.indentLevel--;
+ }
+ }
+
+ void DoOverlayGUI(DebugOverlay overlay, params SerializedProperty[] settings)
+ {
+ if (m_Overlay.intValue != (int)overlay)
+ return;
+
+ if (settings == null || settings.Length == 0)
+ return;
+
+ foreach (var p in settings)
+ EditorGUILayout.PropertyField(p);
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/PostProcessDebugEditor.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/PostProcessDebugEditor.cs.meta
new file mode 100644
index 0000000..c58dbc5
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/PostProcessDebugEditor.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 75be0b76c5da33a41a2e679cfb7f453c
+timeCreated: 1499771607
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/PostProcessEffectBaseEditor.cs b/com.unity.postprocessing/PostProcessing/Editor/PostProcessEffectBaseEditor.cs
new file mode 100644
index 0000000..a5c0b89
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/PostProcessEffectBaseEditor.cs
@@ -0,0 +1,216 @@
+using System;
+using UnityEngine;
+using UnityEngine.Rendering.PostProcessing;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ ///
+ /// The base class for all post-processing effect related editors. If you want to customize the
+ /// look of a custom post-processing effect, inherit from
+ /// instead.
+ ///
+ ///
+ public class PostProcessEffectBaseEditor
+ {
+ internal PostProcessEffectSettings target { get; private set; }
+ internal SerializedObject serializedObject { get; private set; }
+
+ internal SerializedProperty baseProperty;
+ internal SerializedProperty activeProperty;
+
+ SerializedProperty m_Enabled;
+ Editor m_Inspector;
+
+ internal PostProcessEffectBaseEditor()
+ {
+ }
+
+ ///
+ /// Repaints the inspector.
+ ///
+ public void Repaint()
+ {
+ m_Inspector.Repaint();
+ }
+
+ internal void Init(PostProcessEffectSettings target, Editor inspector)
+ {
+ this.target = target;
+ m_Inspector = inspector;
+ serializedObject = new SerializedObject(target);
+ m_Enabled = serializedObject.FindProperty("enabled.value");
+ activeProperty = serializedObject.FindProperty("active");
+ OnEnable();
+ }
+
+ ///
+ /// Called when the editor is initialized.
+ ///
+ public virtual void OnEnable()
+ {
+ }
+
+ ///
+ /// Called when the editor is de-initialized.
+ ///
+ public virtual void OnDisable()
+ {
+ }
+
+ internal void OnInternalInspectorGUI()
+ {
+ serializedObject.Update();
+ TopRowFields();
+ OnInspectorGUI();
+ EditorGUILayout.Space();
+ serializedObject.ApplyModifiedProperties();
+ }
+
+ ///
+ /// Called every time the inspector is being redrawn. This is where you should add your UI
+ /// drawing code.
+ ///
+ public virtual void OnInspectorGUI()
+ {
+ }
+
+ ///
+ /// Returns the label to use as the effect title. You can override this to return a custom
+ /// label, else it will use the effect type as the title.
+ ///
+ /// The label to use as the effect title
+ public virtual string GetDisplayTitle()
+ {
+ return ObjectNames.NicifyVariableName(target.GetType().Name);
+ }
+
+ void TopRowFields()
+ {
+ using (new EditorGUILayout.HorizontalScope())
+ {
+ if (GUILayout.Button(EditorUtilities.GetContent("All|Toggle all overrides on. To maximize performances you should only toggle overrides that you actually need."), Styling.miniLabelButton, GUILayout.Width(17f), GUILayout.ExpandWidth(false)))
+ SetAllOverridesTo(true);
+
+ if (GUILayout.Button(EditorUtilities.GetContent("None|Toggle all overrides off."), Styling.miniLabelButton, GUILayout.Width(32f), GUILayout.ExpandWidth(false)))
+ SetAllOverridesTo(false);
+
+ GUILayout.FlexibleSpace();
+
+ bool enabled = m_Enabled.boolValue;
+ enabled = GUILayout.Toggle(enabled, EditorUtilities.GetContent("On|Enable this effect."), EditorStyles.miniButtonLeft, GUILayout.Width(35f), GUILayout.ExpandWidth(false));
+ enabled = !GUILayout.Toggle(!enabled, EditorUtilities.GetContent("Off|Disable this effect."), EditorStyles.miniButtonRight, GUILayout.Width(35f), GUILayout.ExpandWidth(false));
+ m_Enabled.boolValue = enabled;
+ }
+ }
+
+ void SetAllOverridesTo(bool state)
+ {
+ Undo.RecordObject(target, "Toggle All");
+ target.SetAllOverridesTo(state);
+ serializedObject.Update();
+ }
+
+ ///
+ /// Draws a property UI element.
+ ///
+ /// The property to draw
+ protected void PropertyField(SerializedParameterOverride property)
+ {
+ var title = EditorUtilities.GetContent(property.displayName);
+ PropertyField(property, title);
+ }
+
+ ///
+ /// Draws a property UI element with a custom title and/or tooltip.
+ ///
+ /// The property to draw
+ /// A custom title and/or tooltip
+ protected void PropertyField(SerializedParameterOverride property, GUIContent title)
+ {
+ // Check for DisplayNameAttribute first
+ var displayNameAttr = property.GetAttribute();
+ if (displayNameAttr != null)
+ title.text = displayNameAttr.displayName;
+
+ // Add tooltip if it's missing and an attribute is available
+ if (string.IsNullOrEmpty(title.tooltip))
+ {
+ var tooltipAttr = property.GetAttribute();
+ if (tooltipAttr != null)
+ title.tooltip = tooltipAttr.tooltip;
+ }
+
+ // Look for a compatible attribute decorator
+ AttributeDecorator decorator = null;
+ Attribute attribute = null;
+
+ foreach (var attr in property.attributes)
+ {
+ // Use the first decorator we found
+ if (decorator == null)
+ {
+ decorator = EditorUtilities.GetDecorator(attr.GetType());
+ attribute = attr;
+ }
+
+ // Draw unity built-in Decorators (Space, Header)
+ if (attr is PropertyAttribute)
+ {
+ if (attr is SpaceAttribute)
+ {
+ EditorGUILayout.GetControlRect(false, (attr as SpaceAttribute).height);
+ }
+ else if (attr is HeaderAttribute)
+ {
+ var rect = EditorGUILayout.GetControlRect(false, 24f);
+ rect.y += 8f;
+ rect = EditorGUI.IndentedRect(rect);
+ EditorGUI.LabelField(rect, (attr as HeaderAttribute).header, Styling.headerLabel);
+ }
+ }
+ }
+
+ bool invalidProp = false;
+
+ if (decorator != null && !decorator.IsAutoProperty())
+ {
+ if (decorator.OnGUI(property.value, property.overrideState, title, attribute))
+ return;
+
+ // Attribute is invalid for the specified property; use default unity field instead
+ invalidProp = true;
+ }
+
+ using (new EditorGUILayout.HorizontalScope())
+ {
+ // Override checkbox
+ var overrideRect = GUILayoutUtility.GetRect(17f, 17f, GUILayout.ExpandWidth(false));
+ overrideRect.yMin += 4f;
+ EditorUtilities.DrawOverrideCheckbox(overrideRect, property.overrideState);
+
+ // Property
+ using (new EditorGUI.DisabledScope(!property.overrideState.boolValue))
+ {
+ if (decorator != null && !invalidProp)
+ {
+ if (decorator.OnGUI(property.value, property.overrideState, title, attribute))
+ return;
+ }
+
+ // Default unity field
+ if (property.value.hasVisibleChildren
+ && property.value.propertyType != SerializedPropertyType.Vector2
+ && property.value.propertyType != SerializedPropertyType.Vector3)
+ {
+ GUILayout.Space(12f);
+ EditorGUILayout.PropertyField(property.value, title, true);
+ }
+ else
+ {
+ EditorGUILayout.PropertyField(property.value, title);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/PostProcessEffectBaseEditor.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/PostProcessEffectBaseEditor.cs.meta
new file mode 100644
index 0000000..9cf37b8
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/PostProcessEffectBaseEditor.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 5a7e5d36c781f1a469ea8f981b785506
+timeCreated: 1492689813
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/PostProcessEffectEditor.cs b/com.unity.postprocessing/PostProcessing/Editor/PostProcessEffectEditor.cs
new file mode 100644
index 0000000..f948cf6
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/PostProcessEffectEditor.cs
@@ -0,0 +1,88 @@
+using System;
+using System.Linq.Expressions;
+using UnityEngine.Rendering.PostProcessing;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ ///
+ /// The class to inherit from when designing custom effect editors.
+ ///
+ /// The effect type to create an editor for
+ public class PostProcessEffectEditor : PostProcessEffectBaseEditor
+ where T : PostProcessEffectSettings
+ {
+ ///
+ /// Find a serialized property using an expression instead of a string. This is safer as it
+ /// helps avoiding typos and make code refactoring easier.
+ ///
+ /// The serialized value type
+ /// The expression to parse to reach the property
+ /// A or null if none was found
+ ///
+ ///
+ /// [Serializable]
+ /// public class MyEffect : PostProcessEffectSettings
+ /// {
+ /// public float myParameter = 1f;
+ /// }
+ ///
+ /// [PostProcessEditor(typeof(MyEffect))]
+ /// public class MyEffectEditor : PostProcessEffectEditor<MyEffect>
+ /// {
+ /// SerializedProperty m_MyParameter;
+ ///
+ /// public override void OnEnable()
+ /// {
+ /// m_MyParameter = FindProperty(x => x.myParameter);
+ /// }
+ /// }
+ ///
+ ///
+ ///
+ /// If you're trying to retrieve a , you should
+ /// use instead.
+ ///
+ ///
+ ///
+ protected SerializedProperty FindProperty(Expression> expr)
+ {
+ return serializedObject.FindProperty(RuntimeUtilities.GetFieldPath(expr));
+ }
+
+ ///
+ /// Find a serialized parameter override using an expression instead of a string. This is
+ /// safer as it helps avoiding typos and make code refactoring easier.
+ ///
+ /// The serialized value type
+ /// The expression to parse to reach the parameter override
+ /// A or null if none was
+ /// found
+ ///
+ ///
+ /// [Serializable]
+ /// public class MyEffect : PostProcessEffectSettings
+ /// {
+ /// public FloatParameter myParameter = new FloatParameter { value = 1f };
+ /// }
+ ///
+ /// [PostProcessEditor(typeof(MyEffect))]
+ /// public class MyEffectEditor : PostProcessEffectEditor<MyEffect>
+ /// {
+ /// SerializedParameterOverride m_MyParameter;
+ ///
+ /// public override void OnEnable()
+ /// {
+ /// m_MyParameter = FindParameterOverride(x => x.myParameter);
+ /// }
+ /// }
+ ///
+ ///
+ ///
+ protected SerializedParameterOverride FindParameterOverride(Expression> expr)
+ {
+ var property = serializedObject.FindProperty(RuntimeUtilities.GetFieldPath(expr));
+ var attributes = RuntimeUtilities.GetMemberAttributes(expr);
+ return new SerializedParameterOverride(property, attributes);
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/PostProcessEffectEditor.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/PostProcessEffectEditor.cs.meta
new file mode 100644
index 0000000..dd6be58
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/PostProcessEffectEditor.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: e81ec1796a6c9844f9ab3847494d7911
+timeCreated: 1492690838
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/PostProcessLayerEditor.cs b/com.unity.postprocessing/PostProcessing/Editor/PostProcessLayerEditor.cs
new file mode 100644
index 0000000..20f363c
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/PostProcessLayerEditor.cs
@@ -0,0 +1,472 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+using UnityEngine.Rendering.PostProcessing;
+using UnityEditorInternal;
+using System.IO;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ using SerializedBundleRef = PostProcessLayer.SerializedBundleRef;
+ using EXRFlags = Texture2D.EXRFlags;
+
+ [CanEditMultipleObjects, CustomEditor(typeof(PostProcessLayer))]
+ sealed class PostProcessLayerEditor : BaseEditor
+ {
+ SerializedProperty m_StopNaNPropagation;
+#pragma warning disable 414
+ SerializedProperty m_DirectToCameraTarget;
+#pragma warning restore 414
+ SerializedProperty m_VolumeTrigger;
+ SerializedProperty m_VolumeLayer;
+
+ SerializedProperty m_AntialiasingMode;
+ SerializedProperty m_TaaJitterSpread;
+ SerializedProperty m_TaaSharpness;
+ SerializedProperty m_TaaStationaryBlending;
+ SerializedProperty m_TaaMotionBlending;
+ SerializedProperty m_SmaaQuality;
+ SerializedProperty m_FxaaFastMode;
+ SerializedProperty m_FxaaKeepAlpha;
+
+ SerializedProperty m_FsrQualityMode;
+ SerializedProperty m_FsrPerformSharpen;
+ SerializedProperty m_FsrSharpness;
+ SerializedProperty m_FsrEnableFP16;
+ SerializedProperty m_FsrExposureSource;
+ SerializedProperty m_FsrExposureTexture;
+ SerializedProperty m_FsrPreExposure;
+ SerializedProperty m_FsrAutoReactive;
+ SerializedProperty m_FsrAutoReactiveParams;
+ SerializedProperty m_FsrReactiveMaskTexture;
+ SerializedProperty m_FsrAutoTcr;
+ SerializedProperty m_FsrAutoTcrParams;
+ SerializedProperty m_FsrTcrMaskTexture;
+
+ SerializedProperty m_FogEnabled;
+ SerializedProperty m_FogExcludeSkybox;
+
+ SerializedProperty m_ShowToolkit;
+ SerializedProperty m_ShowCustomSorter;
+
+ Dictionary m_CustomLists;
+
+#if UNITY_2017_3_OR_NEWER
+ Camera m_TargetCameraComponent;
+#endif
+
+ static GUIContent[] s_AntialiasingMethodNames =
+ {
+ new GUIContent("No Anti-aliasing"),
+ new GUIContent("Fast Approximate Anti-aliasing (FXAA)"),
+ new GUIContent("Subpixel Morphological Anti-aliasing (SMAA)"),
+ new GUIContent("Temporal Anti-aliasing (TAA)"),
+ new GUIContent("FidelityFX Super Resolution 2 (FSR2)")
+ };
+
+ enum ExportMode
+ {
+ FullFrame,
+ DisablePost,
+ BreakBeforeColorGradingLinear,
+ BreakBeforeColorGradingLog
+ }
+
+ void OnEnable()
+ {
+ m_StopNaNPropagation = FindProperty(x => x.stopNaNPropagation);
+ m_DirectToCameraTarget = FindProperty(x => x.finalBlitToCameraTarget);
+ m_VolumeTrigger = FindProperty(x => x.volumeTrigger);
+ m_VolumeLayer = FindProperty(x => x.volumeLayer);
+
+ m_AntialiasingMode = FindProperty(x => x.antialiasingMode);
+ m_TaaJitterSpread = FindProperty(x => x.temporalAntialiasing.jitterSpread);
+ m_TaaSharpness = FindProperty(x => x.temporalAntialiasing.sharpness);
+ m_TaaStationaryBlending = FindProperty(x => x.temporalAntialiasing.stationaryBlending);
+ m_TaaMotionBlending = FindProperty(x => x.temporalAntialiasing.motionBlending);
+ m_SmaaQuality = FindProperty(x => x.subpixelMorphologicalAntialiasing.quality);
+ m_FxaaFastMode = FindProperty(x => x.fastApproximateAntialiasing.fastMode);
+ m_FxaaKeepAlpha = FindProperty(x => x.fastApproximateAntialiasing.keepAlpha);
+
+ m_FsrQualityMode = FindProperty(x => x.superResolution.qualityMode);
+ m_FsrPerformSharpen = FindProperty(x => x.superResolution.performSharpenPass);
+ m_FsrSharpness = FindProperty(x => x.superResolution.sharpness);
+ m_FsrEnableFP16 = FindProperty(x => x.superResolution.enableFP16);
+ m_FsrExposureSource = FindProperty(x => x.superResolution.exposureSource);
+ m_FsrExposureTexture = FindProperty(x => x.superResolution.exposure);
+ m_FsrPreExposure = FindProperty(x => x.superResolution.preExposure);
+ m_FsrAutoReactive = FindProperty(x => x.superResolution.autoGenerateReactiveMask);
+ m_FsrAutoReactiveParams = FindProperty(x => x.superResolution.generateReactiveParameters);
+ m_FsrReactiveMaskTexture = FindProperty(x => x.superResolution.reactiveMask);
+ m_FsrAutoTcr = FindProperty(x => x.superResolution.autoGenerateTransparencyAndComposition);
+ m_FsrAutoTcrParams = FindProperty(x => x.superResolution.generateTransparencyAndCompositionParameters);
+ m_FsrTcrMaskTexture = FindProperty(x => x.superResolution.transparencyAndCompositionMask);
+
+ m_FogEnabled = FindProperty(x => x.fog.enabled);
+ m_FogExcludeSkybox = FindProperty(x => x.fog.excludeSkybox);
+
+ m_ShowToolkit = serializedObject.FindProperty("m_ShowToolkit");
+ m_ShowCustomSorter = serializedObject.FindProperty("m_ShowCustomSorter");
+
+#if UNITY_2017_3_OR_NEWER
+ m_TargetCameraComponent = m_Target.GetComponent();
+#endif
+ }
+
+ void OnDisable()
+ {
+ m_CustomLists = null;
+ }
+
+ public override void OnInspectorGUI()
+ {
+ serializedObject.Update();
+
+ var camera = m_Target.GetComponent();
+
+ DoVolumeBlending();
+ DoAntialiasing();
+ DoFog(camera);
+
+ EditorGUILayout.PropertyField(m_StopNaNPropagation, EditorUtilities.GetContent("Stop NaN Propagation|Automatically replaces NaN/Inf in shaders by a black pixel to avoid breaking some effects. This will slightly affect performances and should only be used if you experience NaN issues that you can't fix. Has no effect on GLES2 platforms."));
+
+#if UNITY_2019_1_OR_NEWER
+ if (!RuntimeUtilities.scriptableRenderPipelineActive)
+ EditorGUILayout.PropertyField(m_DirectToCameraTarget, EditorUtilities.GetContent("Directly to Camera Target|Use the final blit to the camera render target for postprocessing. This has less overhead but breaks compatibility with legacy image effect that use OnRenderImage."));
+#endif
+
+ EditorGUILayout.Space();
+
+ DoToolkit();
+ DoCustomEffectSorter();
+
+ EditorUtilities.DrawSplitter();
+ EditorGUILayout.Space();
+
+ serializedObject.ApplyModifiedProperties();
+ }
+
+ void DoVolumeBlending()
+ {
+ EditorGUILayout.LabelField(EditorUtilities.GetContent("Volume blending"), EditorStyles.boldLabel);
+ EditorGUI.indentLevel++;
+ {
+ // The layout system sort of break alignement when mixing inspector fields with
+ // custom layouted fields, do the layout manually instead
+ var indentOffset = EditorGUI.indentLevel * 15f;
+ var lineRect = GUILayoutUtility.GetRect(1, EditorGUIUtility.singleLineHeight);
+ var labelRect = new Rect(lineRect.x, lineRect.y, EditorGUIUtility.labelWidth - indentOffset, lineRect.height);
+ var fieldRect = new Rect(labelRect.xMax, lineRect.y, lineRect.width - labelRect.width - 60f, lineRect.height);
+ var buttonRect = new Rect(fieldRect.xMax, lineRect.y, 60f, lineRect.height);
+
+ EditorGUI.PrefixLabel(labelRect, EditorUtilities.GetContent("Trigger|A transform that will act as a trigger for volume blending."));
+ m_VolumeTrigger.objectReferenceValue = (Transform)EditorGUI.ObjectField(fieldRect, m_VolumeTrigger.objectReferenceValue, typeof(Transform), true);
+ if (GUI.Button(buttonRect, EditorUtilities.GetContent("This|Assigns the current GameObject as a trigger."), EditorStyles.miniButton))
+ m_VolumeTrigger.objectReferenceValue = m_Target.transform;
+
+ if (m_VolumeTrigger.objectReferenceValue == null)
+ EditorGUILayout.HelpBox("No trigger has been set, the camera will only be affected by global volumes.", MessageType.Info);
+
+ EditorGUILayout.PropertyField(m_VolumeLayer, EditorUtilities.GetContent("Layer|This camera will only be affected by volumes in the selected scene-layers."));
+
+ int mask = m_VolumeLayer.intValue;
+ if (mask == 0)
+ EditorGUILayout.HelpBox("No layer has been set, the trigger will never be affected by volumes.", MessageType.Warning);
+ else if (mask == -1 || ((mask & 1) != 0))
+ EditorGUILayout.HelpBox("Do not use \"Everything\" or \"Default\" as a layer mask as it will slow down the volume blending process! Put post-processing volumes in their own dedicated layer for best performances.", MessageType.Warning);
+ }
+ EditorGUI.indentLevel--;
+
+ EditorGUILayout.Space();
+ }
+
+ void DoAntialiasing()
+ {
+ EditorGUILayout.LabelField(EditorUtilities.GetContent("Anti-aliasing"), EditorStyles.boldLabel);
+ EditorGUI.indentLevel++;
+ {
+ m_AntialiasingMode.intValue = EditorGUILayout.Popup(EditorUtilities.GetContent("Mode|The anti-aliasing method to use. FXAA is fast but low quality. SMAA works well for non-HDR scenes. TAA is a bit slower but higher quality and works well with HDR."), m_AntialiasingMode.intValue, s_AntialiasingMethodNames);
+
+ if (m_AntialiasingMode.intValue == (int)PostProcessLayer.Antialiasing.TemporalAntialiasing)
+ {
+#if !UNITY_2017_3_OR_NEWER
+ if (RuntimeUtilities.isSinglePassStereoSelected)
+ EditorGUILayout.HelpBox("TAA requires Unity 2017.3+ for Single-pass stereo rendering support.", MessageType.Warning);
+#endif
+#if UNITY_2017_3_OR_NEWER
+ if (m_TargetCameraComponent != null && RuntimeUtilities.IsDynamicResolutionEnabled(m_TargetCameraComponent))
+ EditorGUILayout.HelpBox("TAA is not supported with Dynamic Resolution.", MessageType.Warning);
+#endif
+
+ EditorGUILayout.PropertyField(m_TaaJitterSpread);
+ EditorGUILayout.PropertyField(m_TaaStationaryBlending);
+ EditorGUILayout.PropertyField(m_TaaMotionBlending);
+ EditorGUILayout.PropertyField(m_TaaSharpness);
+ }
+ else if (m_AntialiasingMode.intValue == (int)PostProcessLayer.Antialiasing.SubpixelMorphologicalAntialiasing)
+ {
+ if (RuntimeUtilities.isSinglePassStereoSelected)
+ EditorGUILayout.HelpBox("SMAA doesn't work with Single-pass stereo rendering.", MessageType.Warning);
+
+ EditorGUILayout.PropertyField(m_SmaaQuality);
+
+ if (m_SmaaQuality.intValue != (int)SubpixelMorphologicalAntialiasing.Quality.Low && EditorUtilities.isTargetingConsolesOrMobiles)
+ EditorGUILayout.HelpBox("For performance reasons it is recommended to use Low Quality on mobile and console platforms.", MessageType.Warning);
+ }
+ else if (m_AntialiasingMode.intValue == (int)PostProcessLayer.Antialiasing.FastApproximateAntialiasing)
+ {
+ EditorGUILayout.PropertyField(m_FxaaFastMode);
+ EditorGUILayout.PropertyField(m_FxaaKeepAlpha);
+
+ if (!m_FxaaFastMode.boolValue && EditorUtilities.isTargetingConsolesOrMobiles)
+ EditorGUILayout.HelpBox("For performance reasons it is recommended to use Fast Mode on mobile and console platforms.", MessageType.Warning);
+ }
+ else if (m_AntialiasingMode.intValue == (int)PostProcessLayer.Antialiasing.SuperResolution)
+ {
+ EditorGUILayout.PropertyField(m_FsrQualityMode);
+ EditorGUILayout.PropertyField(m_FsrPerformSharpen);
+ EditorGUILayout.PropertyField(m_FsrSharpness);
+ EditorGUILayout.PropertyField(m_FsrEnableFP16);
+ EditorGUILayout.PropertyField(m_FsrExposureSource);
+ if (m_FsrExposureSource.intValue == (int)SuperResolution.ExposureSource.Manual) EditorGUILayout.PropertyField(m_FsrExposureTexture);
+ EditorGUILayout.PropertyField(m_FsrPreExposure);
+ EditorGUILayout.PropertyField(m_FsrAutoReactive);
+ EditorGUILayout.PropertyField(m_FsrAutoReactive.boolValue ? m_FsrAutoReactiveParams : m_FsrReactiveMaskTexture);
+ EditorGUILayout.PropertyField(m_FsrAutoTcr);
+ EditorGUILayout.PropertyField(m_FsrAutoTcr.boolValue ? m_FsrAutoTcrParams : m_FsrTcrMaskTexture);
+ }
+ }
+ EditorGUI.indentLevel--;
+
+ EditorGUILayout.Space();
+ }
+
+ void DoFog(Camera camera)
+ {
+ if (camera == null || camera.actualRenderingPath != RenderingPath.DeferredShading)
+ return;
+
+ EditorGUILayout.LabelField(EditorUtilities.GetContent("Deferred Fog"), EditorStyles.boldLabel);
+ EditorGUI.indentLevel++;
+ {
+ EditorGUILayout.PropertyField(m_FogEnabled);
+
+ if (m_FogEnabled.boolValue)
+ {
+ EditorGUILayout.PropertyField(m_FogExcludeSkybox);
+ EditorGUILayout.HelpBox("This adds fog compatibility to the deferred rendering path; actual fog settings should be set in the Lighting panel.", MessageType.Info);
+ }
+ }
+ EditorGUI.indentLevel--;
+
+ EditorGUILayout.Space();
+ }
+
+ void DoToolkit()
+ {
+ EditorUtilities.DrawSplitter();
+ m_ShowToolkit.boolValue = EditorUtilities.DrawHeader("Toolkit", m_ShowToolkit.boolValue);
+
+ if (m_ShowToolkit.boolValue)
+ {
+ GUILayout.Space(2);
+
+ if (GUILayout.Button(EditorUtilities.GetContent("Export frame to EXR..."), EditorStyles.miniButton))
+ {
+ var menu = new GenericMenu();
+ menu.AddItem(EditorUtilities.GetContent("Full Frame (as displayed)"), false, () => ExportFrameToExr(ExportMode.FullFrame));
+ menu.AddItem(EditorUtilities.GetContent("Disable post-processing"), false, () => ExportFrameToExr(ExportMode.DisablePost));
+ menu.AddItem(EditorUtilities.GetContent("Break before Color Grading (Linear)"), false, () => ExportFrameToExr(ExportMode.BreakBeforeColorGradingLinear));
+ menu.AddItem(EditorUtilities.GetContent("Break before Color Grading (Log)"), false, () => ExportFrameToExr(ExportMode.BreakBeforeColorGradingLog));
+ menu.ShowAsContext();
+ }
+
+ if (GUILayout.Button(EditorUtilities.GetContent("Select all layer volumes|Selects all the volumes that will influence this layer."), EditorStyles.miniButton))
+ {
+ var volumes = RuntimeUtilities.GetAllSceneObjects()
+ .Where(x => (m_VolumeLayer.intValue & (1 << x.gameObject.layer)) != 0)
+ .Select(x => x.gameObject)
+ .Cast()
+ .ToArray();
+
+ if (volumes.Length > 0)
+ Selection.objects = volumes;
+ }
+
+ if (GUILayout.Button(EditorUtilities.GetContent("Select all active volumes|Selects all volumes currently affecting the layer."), EditorStyles.miniButton))
+ {
+ var volumes = new List();
+ PostProcessManager.instance.GetActiveVolumes(m_Target, volumes);
+
+ if (volumes.Count > 0)
+ {
+ Selection.objects = volumes
+ .Select(x => x.gameObject)
+ .Cast()
+ .ToArray();
+ }
+ }
+
+ GUILayout.Space(3);
+ }
+ }
+
+ void DoCustomEffectSorter()
+ {
+ EditorUtilities.DrawSplitter();
+ m_ShowCustomSorter.boolValue = EditorUtilities.DrawHeader("Custom Effect Sorting", m_ShowCustomSorter.boolValue);
+
+ if (m_ShowCustomSorter.boolValue)
+ {
+ bool isInPrefab = false;
+
+ // Init lists if needed
+ if (m_CustomLists == null)
+ {
+ // In some cases the editor will refresh before components which means
+ // components might not have been fully initialized yet. In this case we also
+ // need to make sure that we're not in a prefab as sorteBundles isn't a
+ // serializable object and won't exist until put on a scene.
+ if (m_Target.sortedBundles == null)
+ {
+ isInPrefab = string.IsNullOrEmpty(m_Target.gameObject.scene.name);
+
+ if (!isInPrefab)
+ {
+ // sortedBundles will be initialized and ready to use on the next frame
+ Repaint();
+ }
+ }
+ else
+ {
+ // Create a reorderable list for each injection event
+ m_CustomLists = new Dictionary();
+ foreach (var evt in Enum.GetValues(typeof(PostProcessEvent)).Cast())
+ {
+ var bundles = m_Target.sortedBundles[evt];
+ var listName = ObjectNames.NicifyVariableName(evt.ToString());
+
+ var list = new ReorderableList(bundles, typeof(SerializedBundleRef), true, true, false, false);
+
+ list.drawHeaderCallback = (rect) =>
+ {
+ EditorGUI.LabelField(rect, listName);
+ };
+
+ list.drawElementCallback = (rect, index, isActive, isFocused) =>
+ {
+ var sbr = (SerializedBundleRef)list.list[index];
+ EditorGUI.LabelField(rect, sbr.bundle.attribute.menuItem);
+ };
+
+ list.onReorderCallback = (l) =>
+ {
+ EditorUtility.SetDirty(m_Target);
+ };
+
+ m_CustomLists.Add(evt, list);
+ }
+ }
+ }
+
+ GUILayout.Space(5);
+
+ if (isInPrefab)
+ {
+ EditorGUILayout.HelpBox("Not supported in prefabs.", MessageType.Info);
+ GUILayout.Space(3);
+ return;
+ }
+
+ bool anyList = false;
+ if (m_CustomLists != null)
+ {
+ foreach (var kvp in m_CustomLists)
+ {
+ var list = kvp.Value;
+
+ // Skip empty lists to avoid polluting the inspector
+ if (list.count == 0)
+ continue;
+
+ list.DoLayoutList();
+ anyList = true;
+ }
+ }
+
+ if (!anyList)
+ {
+ EditorGUILayout.HelpBox("No custom effect loaded.", MessageType.Info);
+ GUILayout.Space(3);
+ }
+ }
+ }
+
+ void ExportFrameToExr(ExportMode mode)
+ {
+ string path = EditorUtility.SaveFilePanel("Export EXR...", "", "Frame", "exr");
+
+ if (string.IsNullOrEmpty(path))
+ return;
+
+ EditorUtility.DisplayProgressBar("Export EXR", "Rendering...", 0f);
+
+ var camera = m_Target.GetComponent();
+ var w = camera.pixelWidth;
+ var h = camera.pixelHeight;
+
+ var texOut = new Texture2D(w, h, TextureFormat.RGBAFloat, false, true);
+ var target = RenderTexture.GetTemporary(w, h, 24, RenderTextureFormat.ARGBFloat, RenderTextureReadWrite.Linear);
+
+ var lastActive = RenderTexture.active;
+ var lastTargetSet = camera.targetTexture;
+ var lastPostFXState = m_Target.enabled;
+ var lastBreakColorGradingState = m_Target.breakBeforeColorGrading;
+
+ if (mode == ExportMode.DisablePost)
+ m_Target.enabled = false;
+ else if (mode == ExportMode.BreakBeforeColorGradingLinear || mode == ExportMode.BreakBeforeColorGradingLog)
+ m_Target.breakBeforeColorGrading = true;
+
+ camera.targetTexture = target;
+ camera.Render();
+ camera.targetTexture = lastTargetSet;
+
+ EditorUtility.DisplayProgressBar("Export EXR", "Reading...", 0.25f);
+
+ m_Target.enabled = lastPostFXState;
+ m_Target.breakBeforeColorGrading = lastBreakColorGradingState;
+
+ if (mode == ExportMode.BreakBeforeColorGradingLog)
+ {
+ // Convert to log
+ var material = new Material(Shader.Find("Hidden/PostProcessing/Editor/ConvertToLog"));
+ var newTarget = RenderTexture.GetTemporary(w, h, 0, RenderTextureFormat.ARGBFloat, RenderTextureReadWrite.Linear);
+ Graphics.Blit(target, newTarget, material, 0);
+ RenderTexture.ReleaseTemporary(target);
+ DestroyImmediate(material);
+ target = newTarget;
+ }
+
+ RenderTexture.active = target;
+ texOut.ReadPixels(new Rect(0, 0, w, h), 0, 0);
+ texOut.Apply();
+ RenderTexture.active = lastActive;
+
+ EditorUtility.DisplayProgressBar("Export EXR", "Encoding...", 0.5f);
+
+ var bytes = texOut.EncodeToEXR(EXRFlags.OutputAsFloat | EXRFlags.CompressZIP);
+
+ EditorUtility.DisplayProgressBar("Export EXR", "Saving...", 0.75f);
+
+ File.WriteAllBytes(path, bytes);
+
+ EditorUtility.ClearProgressBar();
+ AssetDatabase.Refresh();
+
+ RenderTexture.ReleaseTemporary(target);
+ DestroyImmediate(texOut);
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/PostProcessLayerEditor.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/PostProcessLayerEditor.cs.meta
new file mode 100644
index 0000000..1819aa2
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/PostProcessLayerEditor.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 2c89984c2a3e6cd4492c6f695f07bae6
+timeCreated: 1488275719
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/PostProcessProfileEditor.cs b/com.unity.postprocessing/PostProcessing/Editor/PostProcessProfileEditor.cs
new file mode 100644
index 0000000..2f586c3
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/PostProcessProfileEditor.cs
@@ -0,0 +1,29 @@
+using UnityEngine.Rendering.PostProcessing;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ [CustomEditor(typeof(PostProcessProfile))]
+ sealed class PostProcessProfileEditor : Editor
+ {
+ EffectListEditor m_EffectList;
+
+ void OnEnable()
+ {
+ m_EffectList = new EffectListEditor(this);
+ m_EffectList.Init(target as PostProcessProfile, serializedObject);
+ }
+
+ void OnDisable()
+ {
+ if (m_EffectList != null)
+ m_EffectList.Clear();
+ }
+
+ public override void OnInspectorGUI()
+ {
+ serializedObject.Update();
+ m_EffectList.OnGUI();
+ serializedObject.ApplyModifiedProperties();
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/PostProcessProfileEditor.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/PostProcessProfileEditor.cs.meta
new file mode 100644
index 0000000..6357b95
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/PostProcessProfileEditor.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 1fcb2f1e4a7d9ba42bc5940a5611f302
+timeCreated: 1494339151
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/PostProcessVolumeEditor.cs b/com.unity.postprocessing/PostProcessing/Editor/PostProcessVolumeEditor.cs
new file mode 100644
index 0000000..a8de440
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/PostProcessVolumeEditor.cs
@@ -0,0 +1,166 @@
+using UnityEngine;
+using UnityEngine.Rendering.PostProcessing;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ [CanEditMultipleObjects, CustomEditor(typeof(PostProcessVolume))]
+ sealed class PostProcessVolumeEditor : BaseEditor
+ {
+ SerializedProperty m_Profile;
+
+ SerializedProperty m_IsGlobal;
+ SerializedProperty m_BlendRadius;
+ SerializedProperty m_Weight;
+ SerializedProperty m_Priority;
+
+ EffectListEditor m_EffectList;
+
+ void OnEnable()
+ {
+ m_Profile = FindProperty(x => x.sharedProfile);
+
+ m_IsGlobal = FindProperty(x => x.isGlobal);
+ m_BlendRadius = FindProperty(x => x.blendDistance);
+ m_Weight = FindProperty(x => x.weight);
+ m_Priority = FindProperty(x => x.priority);
+
+ m_EffectList = new EffectListEditor(this);
+ RefreshEffectListEditor(m_Target.sharedProfile);
+ }
+
+ void OnDisable()
+ {
+ if (m_EffectList != null)
+ m_EffectList.Clear();
+ }
+
+ void RefreshEffectListEditor(PostProcessProfile asset)
+ {
+ m_EffectList.Clear();
+
+ if (asset != null)
+ m_EffectList.Init(asset, new SerializedObject(asset));
+ }
+
+ public override void OnInspectorGUI()
+ {
+ serializedObject.Update();
+
+ EditorGUILayout.PropertyField(m_IsGlobal);
+
+ if (!m_IsGlobal.boolValue) // Blend radius is not needed for global volumes
+ EditorGUILayout.PropertyField(m_BlendRadius);
+
+ EditorGUILayout.PropertyField(m_Weight);
+ EditorGUILayout.PropertyField(m_Priority);
+
+ bool assetHasChanged = false;
+ bool showCopy = m_Profile.objectReferenceValue != null;
+ bool multiEdit = m_Profile.hasMultipleDifferentValues;
+
+ // The layout system sort of break alignement when mixing inspector fields with custom
+ // layouted fields, do the layout manually instead
+ int buttonWidth = showCopy ? 45 : 60;
+ float indentOffset = EditorGUI.indentLevel * 15f;
+ var lineRect = GUILayoutUtility.GetRect(1, EditorGUIUtility.singleLineHeight);
+ var labelRect = new Rect(lineRect.x, lineRect.y, EditorGUIUtility.labelWidth - indentOffset, lineRect.height);
+ var fieldRect = new Rect(labelRect.xMax, lineRect.y, lineRect.width - labelRect.width - buttonWidth * (showCopy ? 2 : 1), lineRect.height);
+ var buttonNewRect = new Rect(fieldRect.xMax, lineRect.y, buttonWidth, lineRect.height);
+ var buttonCopyRect = new Rect(buttonNewRect.xMax, lineRect.y, buttonWidth, lineRect.height);
+
+ EditorGUI.PrefixLabel(labelRect, EditorUtilities.GetContent(m_Target.HasInstantiatedProfile() ? "Profile (Instance)|A copy of a profile asset." : "Profile|A reference to a profile asset."));
+
+ using (var scope = new EditorGUI.ChangeCheckScope())
+ {
+ EditorGUI.BeginProperty(fieldRect, GUIContent.none, m_Profile);
+ PostProcessProfile profile = null;
+
+ if (m_Target.HasInstantiatedProfile())
+ profile = (PostProcessProfile)EditorGUI.ObjectField(fieldRect, m_Target.profile, typeof(PostProcessProfile), false);
+ else
+ profile = (PostProcessProfile)EditorGUI.ObjectField(fieldRect, m_Profile.objectReferenceValue, typeof(PostProcessProfile), false);
+
+ if (scope.changed)
+ {
+ assetHasChanged = true;
+
+ m_Profile.objectReferenceValue = profile;
+
+ if (m_Target.HasInstantiatedProfile()) // Clear the instantiated profile, from now on we're using shared again.
+ m_Target.profile = null;
+ }
+
+ EditorGUI.EndProperty();
+ }
+
+ using (new EditorGUI.DisabledScope(multiEdit))
+ {
+ if (GUI.Button(buttonNewRect, EditorUtilities.GetContent("New|Create a new profile."), showCopy ? EditorStyles.miniButtonLeft : EditorStyles.miniButton))
+ {
+ // By default, try to put assets in a folder next to the currently active
+ // scene file. If the user isn't a scene, put them in root instead.
+ var targetName = m_Target.name;
+ var scene = m_Target.gameObject.scene;
+ var asset = ProfileFactory.CreatePostProcessProfile(scene, targetName);
+ m_Profile.objectReferenceValue = asset;
+ m_Target.profile = null; // Make sure we're not using an instantiated profile anymore
+
+ assetHasChanged = true;
+ }
+
+ if (showCopy && GUI.Button(buttonCopyRect, EditorUtilities.GetContent(m_Target.HasInstantiatedProfile() ? "Save|Save the instantiated profile" : "Clone|Create a new profile and copy the content of the currently assigned profile."), EditorStyles.miniButtonRight))
+ {
+ // Duplicate the currently assigned profile and save it as a new profile
+ var origin = profileRef;
+ var path = AssetDatabase.GetAssetPath(m_Profile.objectReferenceValue);
+ path = AssetDatabase.GenerateUniqueAssetPath(path);
+
+ var asset = Instantiate(origin);
+ asset.settings.Clear();
+ AssetDatabase.CreateAsset(asset, path);
+
+ foreach (var item in origin.settings)
+ {
+ var itemCopy = Instantiate(item);
+ itemCopy.hideFlags = HideFlags.HideInInspector | HideFlags.HideInHierarchy;
+ itemCopy.name = item.name;
+ asset.settings.Add(itemCopy);
+ AssetDatabase.AddObjectToAsset(itemCopy, asset);
+ }
+
+ AssetDatabase.SaveAssets();
+ AssetDatabase.Refresh();
+
+ m_Profile.objectReferenceValue = asset;
+ m_Target.profile = null; // Make sure we're not using an instantiated profile anymore
+ assetHasChanged = true;
+ }
+ }
+
+ EditorGUILayout.Space();
+
+ if (m_Profile.objectReferenceValue == null && !m_Target.HasInstantiatedProfile())
+ {
+ if (assetHasChanged)
+ m_EffectList.Clear(); // Asset wasn't null before, do some cleanup
+
+ EditorGUILayout.HelpBox("Assign a Post-process Profile to this volume using the \"Asset\" field or create one automatically by clicking the \"New\" button.\nAssets are automatically put in a folder next to your scene file. If you scene hasn't been saved yet they will be created at the root of the Assets folder.", MessageType.Info);
+ }
+ else
+ {
+ if (assetHasChanged || profileRef != m_EffectList.asset) //Refresh when the user just dragged in a new asset, or when it was instantiated by code.
+ RefreshEffectListEditor(profileRef);
+
+ if (!multiEdit)
+ m_EffectList.OnGUI();
+ }
+
+ serializedObject.ApplyModifiedProperties();
+ }
+
+ public PostProcessProfile profileRef
+ {
+ get { return m_Target.HasInstantiatedProfile() ? m_Target.profile : m_Target.sharedProfile; }
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/PostProcessVolumeEditor.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/PostProcessVolumeEditor.cs.meta
new file mode 100644
index 0000000..237ca4d
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/PostProcessVolumeEditor.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 4e487364a0cd33f4a9ef2ed93819d4d7
+timeCreated: 1488201040
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Tools.meta b/com.unity.postprocessing/PostProcessing/Editor/Tools.meta
new file mode 100644
index 0000000..813d5f4
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Tools.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: e58158d9d8b440d4ca944a07d6cde9af
+folderAsset: yes
+timeCreated: 1496736709
+licenseType: Pro
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Tools/CubeLutAssetFactory.cs b/com.unity.postprocessing/PostProcessing/Editor/Tools/CubeLutAssetFactory.cs
new file mode 100644
index 0000000..9bd09ec
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Tools/CubeLutAssetFactory.cs
@@ -0,0 +1,58 @@
+using System;
+using System.IO;
+using System.Text;
+using UnityEngine;
+using UnityEngine.Rendering.PostProcessing;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ // CUBE lut specs:
+ // http://wwwimages.adobe.com/content/dam/Adobe/en/products/speedgrade/cc/pdfs/cube-lut-specification-1.0.pdf
+ static class CubeLutAssetFactory
+ {
+ const int kVersion = 1;
+ const int kSize = 33;
+
+#if POSTFX_DEBUG_MENUS
+ [MenuItem("Tools/Post-processing/Create Utility Luts")]
+#endif
+ static void CreateLuts()
+ {
+ Dump("Linear to Unity Log r" + kVersion, ColorUtilities.LinearToLogC);
+ Dump("Unity Log to Linear r" + kVersion, ColorUtilities.LogCToLinear);
+ Dump("sRGB to Unity Log r" + kVersion, x => ColorUtilities.LinearToLogC(Mathf.GammaToLinearSpace(x)));
+ Dump("Unity Log to sRGB r" + kVersion, x => Mathf.LinearToGammaSpace(ColorUtilities.LogCToLinear(x)));
+ Dump("Linear to sRGB r" + kVersion, Mathf.LinearToGammaSpace);
+ Dump("sRGB to Linear r" + kVersion, Mathf.GammaToLinearSpace);
+
+ AssetDatabase.Refresh();
+ }
+
+ static void Dump(string title, Func eval)
+ {
+ var sb = new StringBuilder();
+ sb.AppendFormat("TITLE \"{0}\"\n", title);
+ sb.AppendFormat("LUT_3D_SIZE {0}\n", kSize);
+ sb.AppendFormat("DOMAIN_MIN {0} {0} {0}\n", 0f);
+ sb.AppendFormat("DOMAIN_MAX {0} {0} {0}\n", 1f);
+
+ const float kSizeMinusOne = (float)kSize - 1f;
+
+ for (int x = 0; x < kSize; x++)
+ for (int y = 0; y < kSize; y++)
+ for (int z = 0; z < kSize; z++)
+ {
+ float ox = eval((float)x / kSizeMinusOne);
+ float oy = eval((float)y / kSizeMinusOne);
+ float oz = eval((float)z / kSizeMinusOne);
+
+ // Resolve & Photoshop use BGR as default, let's make it easier for users
+ sb.AppendFormat("{0} {1} {2}\n", oz, oy, ox);
+ }
+
+ var content = sb.ToString();
+ var path = Path.Combine(Application.dataPath, string.Format("{0}.cube", title));
+ File.WriteAllText(path, content);
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Tools/CubeLutAssetFactory.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/Tools/CubeLutAssetFactory.cs.meta
new file mode 100644
index 0000000..e3de84f
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Tools/CubeLutAssetFactory.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 4d506bd5da20d0248bfa343c6693d655
+timeCreated: 1496740688
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Tools/CubeLutAssetImporter.cs b/com.unity.postprocessing/PostProcessing/Editor/Tools/CubeLutAssetImporter.cs
new file mode 100644
index 0000000..137d19f
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Tools/CubeLutAssetImporter.cs
@@ -0,0 +1,218 @@
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Text;
+using UnityEngine;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ sealed class CubeLutAssetImporter : AssetPostprocessor
+ {
+ static List s_Excluded = new List()
+ {
+ "Linear_to_sRGB_r1",
+ "Linear_to_Unity_Log_r1",
+ "sRGB_to_Linear_r1",
+ "sRGB_to_Unity_Log_r1",
+ "Unity_Log_to_Linear_r1",
+ "Unity_Log_to_sRGB_r1"
+ };
+
+ static void OnPostprocessAllAssets(string[] imported, string[] deleted, string[] moved, string[] movedFrom)
+ {
+ foreach (string path in imported)
+ {
+ string ext = Path.GetExtension(path);
+ string filename = Path.GetFileNameWithoutExtension(path);
+
+ if (string.IsNullOrEmpty(ext) || s_Excluded.Contains(filename))
+ continue;
+
+ ext = ext.ToLowerInvariant();
+ if (ext.Equals(".cube"))
+ ImportCubeLut(path);
+ }
+ }
+
+ // Basic CUBE lut parser
+ // Specs: http://wwwimages.adobe.com/content/dam/Adobe/en/products/speedgrade/cc/pdfs/cube-lut-specification-1.0.pdf
+ static void ImportCubeLut(string path)
+ {
+ // Remove the 'Assets' part of the path & build absolute path
+ string fullpath = path.Substring(7);
+ fullpath = Path.Combine(Application.dataPath, fullpath);
+
+ // Read the lut data
+ string[] lines = File.ReadAllLines(fullpath);
+
+ // Start parsing
+ int i = 0;
+ int size = -1;
+ int sizeCube = -1;
+ var table = new List();
+ var domainMin = Color.black;
+ var domainMax = Color.white;
+
+ while (true)
+ {
+ if (i >= lines.Length)
+ {
+ if (table.Count != sizeCube)
+ Debug.LogError("Premature end of file");
+
+ break;
+ }
+
+ string line = FilterLine(lines[i]);
+
+ if (string.IsNullOrEmpty(line))
+ goto next;
+
+ // Header data
+ if (line.StartsWith("TITLE"))
+ goto next; // Skip the title tag, we don't need it
+
+ if (line.StartsWith("LUT_3D_SIZE"))
+ {
+ string sizeStr = line.Substring(11).TrimStart();
+
+ if (!int.TryParse(sizeStr, out size))
+ {
+ Debug.LogError("Invalid data on line " + i);
+ break;
+ }
+
+ if (size < 2 || size > 256)
+ {
+ Debug.LogError("LUT size out of range");
+ break;
+ }
+
+ sizeCube = size * size * size;
+ goto next;
+ }
+
+ if (line.StartsWith("DOMAIN_MIN"))
+ {
+ if (!ParseDomain(i, line, ref domainMin)) break;
+ goto next;
+ }
+
+ if (line.StartsWith("DOMAIN_MAX"))
+ {
+ if (!ParseDomain(i, line, ref domainMax)) break;
+ goto next;
+ }
+
+ // Table
+ string[] row = line.Split();
+
+ if (row.Length != 3)
+ {
+ Debug.LogError("Invalid data on line " + i);
+ break;
+ }
+
+ var color = Color.black;
+ for (int j = 0; j < 3; j++)
+ {
+ float d;
+ if (!float.TryParse(row[j], NumberStyles.Float, CultureInfo.InvariantCulture.NumberFormat, out d))
+ {
+ Debug.LogError("Invalid data on line " + i);
+ break;
+ }
+
+ color[j] = d;
+ }
+
+ table.Add(color);
+
+ next:
+ i++;
+ }
+
+ if (sizeCube != table.Count)
+ {
+ Debug.LogError("Wrong table size - Expected " + sizeCube + " elements, got " + table.Count);
+ return;
+ }
+
+ // Check if the Texture3D already exists, update it in this case (better workflow for
+ // the user)
+ string assetPath = Path.ChangeExtension(path, ".asset");
+ var tex = AssetDatabase.LoadAssetAtPath(assetPath);
+
+ if (tex != null)
+ {
+ tex.SetPixels(table.ToArray(), 0);
+ tex.Apply();
+ }
+ else
+ {
+ // Generate a new Texture3D
+ tex = new Texture3D(size, size, size, TextureFormat.RGBAHalf, false)
+ {
+ anisoLevel = 0,
+ filterMode = FilterMode.Bilinear,
+ wrapMode = TextureWrapMode.Clamp,
+ };
+
+ tex.SetPixels(table.ToArray(), 0);
+ tex.Apply();
+
+ // Save to disk
+ AssetDatabase.CreateAsset(tex, assetPath);
+ }
+
+ AssetDatabase.SaveAssets();
+ AssetDatabase.Refresh();
+ }
+
+ static string FilterLine(string line)
+ {
+ var filtered = new StringBuilder();
+ line = line.TrimStart().TrimEnd();
+ int len = line.Length;
+ int i = 0;
+
+ while (i < len)
+ {
+ char c = line[i];
+
+ if (c == '#') // Filters comment out
+ break;
+
+ filtered.Append(c);
+ i++;
+ }
+
+ return filtered.ToString();
+ }
+
+ static bool ParseDomain(int i, string line, ref Color domain)
+ {
+ string[] domainStrs = line.Substring(10).TrimStart().Split();
+
+ if (domainStrs.Length != 3)
+ {
+ Debug.LogError("Invalid data on line " + i);
+ return false;
+ }
+
+ for (int j = 0; j < 3; j++)
+ {
+ float d;
+ if (!float.TryParse(domainStrs[j], NumberStyles.Float, CultureInfo.InvariantCulture.NumberFormat, out d))
+ {
+ Debug.LogError("Invalid data on line " + i);
+ return false;
+ }
+
+ domain[j] = d;
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Tools/CubeLutAssetImporter.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/Tools/CubeLutAssetImporter.cs.meta
new file mode 100644
index 0000000..e53d8c5
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Tools/CubeLutAssetImporter.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 3e4b5d9a1abab984cbe0cbdb31fca939
+timeCreated: 1496737252
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Tools/DefineSetter.cs b/com.unity.postprocessing/PostProcessing/Editor/Tools/DefineSetter.cs
new file mode 100644
index 0000000..b6c9611
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Tools/DefineSetter.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Linq;
+#if UNITY_2021_3_OR_NEWER
+using UnityEditor.Build;
+#endif
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ [InitializeOnLoad]
+ sealed class DefineSetter
+ {
+ const string k_Define = "UNITY_POST_PROCESSING_STACK_V2";
+
+ static DefineSetter()
+ {
+ var targets = Enum.GetValues(typeof(BuildTargetGroup))
+ .Cast()
+ .Where(x => x != BuildTargetGroup.Unknown)
+ .Where(x => !IsObsolete(x));
+
+ foreach (var target in targets)
+ {
+#if UNITY_2021_3_OR_NEWER
+ var namedTarget = NamedBuildTarget.FromBuildTargetGroup(target);
+ var defines = PlayerSettings.GetScriptingDefineSymbols(namedTarget).Trim();
+#else
+ var defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(target).Trim();
+#endif
+
+ var list = defines.Split(';', ' ')
+ .Where(x => !string.IsNullOrEmpty(x))
+ .ToList();
+
+ if (list.Contains(k_Define))
+ continue;
+
+ list.Add(k_Define);
+ defines = list.Aggregate((a, b) => a + ";" + b);
+
+#if UNITY_2021_3_OR_NEWER
+ PlayerSettings.SetScriptingDefineSymbols(namedTarget, defines);
+#else
+ PlayerSettings.SetScriptingDefineSymbolsForGroup(target, defines);
+#endif
+ }
+ }
+
+
+ static bool IsObsolete(BuildTargetGroup group)
+ {
+ var attrs = typeof(BuildTargetGroup)
+ .GetField(group.ToString())
+ .GetCustomAttributes(typeof(ObsoleteAttribute), false);
+
+ return attrs != null && attrs.Length > 0;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Tools/DefineSetter.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/Tools/DefineSetter.cs.meta
new file mode 100644
index 0000000..d68eb21
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Tools/DefineSetter.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 21c950a797aa518438786fc341790e14
+timeCreated: 1499857026
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Tools/ProfileFactory.cs b/com.unity.postprocessing/PostProcessing/Editor/Tools/ProfileFactory.cs
new file mode 100644
index 0000000..8dfd4af
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Tools/ProfileFactory.cs
@@ -0,0 +1,82 @@
+using UnityEngine;
+using UnityEditor.ProjectWindowCallback;
+using System.IO;
+using UnityEngine.SceneManagement;
+using UnityEngine.Rendering.PostProcessing;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ ///
+ /// An utility class to help the creation of new post-processing profile assets.
+ ///
+ public sealed class ProfileFactory
+ {
+ [MenuItem("Assets/Create/Post-processing Profile", priority = 201)]
+ static void CreatePostProcessProfile()
+ {
+ //var icon = EditorGUIUtility.FindTexture("ScriptableObject Icon");
+ ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0, ScriptableObject.CreateInstance(), "New Post-processing Profile.asset", null, null);
+ }
+
+ ///
+ /// Creates a post-processing profile asset at the given location.
+ ///
+ /// The path to use relative to the project folder
+ /// The newly created profile
+ public static PostProcessProfile CreatePostProcessProfileAtPath(string path)
+ {
+ var profile = ScriptableObject.CreateInstance();
+ profile.name = Path.GetFileName(path);
+ AssetDatabase.CreateAsset(profile, path);
+ AssetDatabase.SaveAssets();
+ AssetDatabase.Refresh();
+ return profile;
+ }
+
+ ///
+ /// Creates a post-processing profile asset and automatically put it in a sub folder next
+ /// to the given scene.
+ ///
+ /// A scene
+ /// A name for the new profile
+ /// The newly created profile
+ public static PostProcessProfile CreatePostProcessProfile(Scene scene, string targetName)
+ {
+ var path = string.Empty;
+
+ if (string.IsNullOrEmpty(scene.path))
+ {
+ path = "Assets/";
+ }
+ else
+ {
+ var scenePath = Path.GetDirectoryName(scene.path);
+ var extPath = scene.name + "_Profiles";
+ var profilePath = scenePath + "/" + extPath;
+
+ if (!AssetDatabase.IsValidFolder(profilePath))
+ AssetDatabase.CreateFolder(scenePath, extPath);
+
+ path = profilePath + "/";
+ }
+
+ path += targetName + " Profile.asset";
+ path = AssetDatabase.GenerateUniqueAssetPath(path);
+
+ var profile = ScriptableObject.CreateInstance();
+ AssetDatabase.CreateAsset(profile, path);
+ AssetDatabase.SaveAssets();
+ AssetDatabase.Refresh();
+ return profile;
+ }
+ }
+
+ class DoCreatePostProcessProfile : EndNameEditAction
+ {
+ public override void Action(int instanceId, string pathName, string resourceFile)
+ {
+ var profile = ProfileFactory.CreatePostProcessProfileAtPath(pathName);
+ ProjectWindowUtil.ShowCreatedAsset(profile);
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Tools/ProfileFactory.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/Tools/ProfileFactory.cs.meta
new file mode 100644
index 0000000..3ae3175
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Tools/ProfileFactory.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: ac5668592895c1742a0c6e9d111f870b
+timeCreated: 1498836357
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Tools/ResourceAssetFactory.cs b/com.unity.postprocessing/PostProcessing/Editor/Tools/ResourceAssetFactory.cs
new file mode 100644
index 0000000..0ea2470
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Tools/ResourceAssetFactory.cs
@@ -0,0 +1,19 @@
+using UnityEngine;
+using UnityEngine.Rendering.PostProcessing;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ static class ResourceAssetFactory
+ {
+#if POSTFX_DEBUG_MENUS
+ [MenuItem("Tools/Post-processing/Create Resources Asset")]
+#endif
+ static void CreateAsset()
+ {
+ var asset = ScriptableObject.CreateInstance();
+ AssetDatabase.CreateAsset(asset, "Assets/PostProcessResources.asset");
+ AssetDatabase.SaveAssets();
+ AssetDatabase.Refresh();
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Tools/ResourceAssetFactory.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/Tools/ResourceAssetFactory.cs.meta
new file mode 100644
index 0000000..7ac577f
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Tools/ResourceAssetFactory.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: d4351734f8a0aaa42a51a99db92e92e2
+timeCreated: 1496736723
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Tools/VolumeFactory.cs b/com.unity.postprocessing/PostProcessing/Editor/Tools/VolumeFactory.cs
new file mode 100644
index 0000000..c518a07
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Tools/VolumeFactory.cs
@@ -0,0 +1,21 @@
+using UnityEngine;
+using UnityEngine.Rendering.PostProcessing;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ internal static class VolumeFactory
+ {
+ [MenuItem("GameObject/3D Object/Post-process Volume")]
+ static void CreateVolume()
+ {
+ var gameObject = new GameObject("Post-process Volume");
+ var collider = gameObject.AddComponent();
+ collider.size = Vector3.one;
+ collider.isTrigger = true;
+ gameObject.AddComponent();
+
+ Selection.objects = new[] { gameObject };
+ EditorApplication.ExecuteMenuItem("GameObject/Move To View");
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Tools/VolumeFactory.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/Tools/VolumeFactory.cs.meta
new file mode 100644
index 0000000..9c81e30
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Tools/VolumeFactory.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 0f3902e2aa2609f47ab0c956e56ea0bf
+timeCreated: 1497707764
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Unity.Postprocessing.Editor.asmdef b/com.unity.postprocessing/PostProcessing/Editor/Unity.Postprocessing.Editor.asmdef
new file mode 100644
index 0000000..a96f35c
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Unity.Postprocessing.Editor.asmdef
@@ -0,0 +1,36 @@
+{
+ "name": "Unity.Postprocessing.Editor",
+ "rootNamespace": "",
+ "references": [
+ "Unity.Postprocessing.Runtime",
+ "Unity.XR.Management",
+ "Unity.XR.Management.Editor"
+ ],
+ "includePlatforms": [
+ "Editor"
+ ],
+ "excludePlatforms": [],
+ "allowUnsafeCode": false,
+ "overrideReferences": false,
+ "precompiledReferences": [],
+ "autoReferenced": true,
+ "defineConstraints": [],
+ "versionDefines": [
+ {
+ "name": "com.unity.xr.management",
+ "expression": "4.0.1",
+ "define": "XR_MANAGEMENT_4_0_1_OR_NEWER"
+ },
+ {
+ "name": "com.unity.modules.vr",
+ "expression": "1.0.0",
+ "define": "ENABLE_VR_MODULE"
+ },
+ {
+ "name": "com.unity.modules.xr",
+ "expression": "1.0.0",
+ "define": "ENABLE_XR_MODULE"
+ }
+ ],
+ "noEngineReferences": false
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Unity.Postprocessing.Editor.asmdef.meta b/com.unity.postprocessing/PostProcessing/Editor/Unity.Postprocessing.Editor.asmdef.meta
new file mode 100644
index 0000000..e586d97
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Unity.Postprocessing.Editor.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: a35efad8797223d499f8c68b1f545dbc
+AssemblyDefinitionImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Utils.meta b/com.unity.postprocessing/PostProcessing/Editor/Utils.meta
new file mode 100644
index 0000000..6ed3793
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Utils.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 018e19d6c1b36224b85b5c0ddd6a895e
+folderAsset: yes
+timeCreated: 1489051059
+licenseType: Pro
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Utils/CurveEditor.cs b/com.unity.postprocessing/PostProcessing/Editor/Utils/CurveEditor.cs
new file mode 100644
index 0000000..72fac1d
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Utils/CurveEditor.cs
@@ -0,0 +1,859 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ internal sealed class CurveEditor
+ {
+ #region Enums
+
+ enum EditMode
+ {
+ None,
+ Moving,
+ TangentEdit
+ }
+
+ enum Tangent
+ {
+ In,
+ Out
+ }
+
+ #endregion
+
+ #region Structs
+
+ public struct Settings
+ {
+ public Rect bounds;
+ public RectOffset padding;
+ public Color selectionColor;
+ public float curvePickingDistance;
+ public float keyTimeClampingDistance;
+
+ public static Settings defaultSettings
+ {
+ get
+ {
+ return new Settings
+ {
+ bounds = new Rect(0f, 0f, 1f, 1f),
+ padding = new RectOffset(10, 10, 10, 10),
+ selectionColor = Color.yellow,
+ curvePickingDistance = 6f,
+ keyTimeClampingDistance = 1e-4f
+ };
+ }
+ }
+ }
+
+ public struct CurveState
+ {
+ public bool visible;
+ public bool editable;
+ public uint minPointCount;
+ public float zeroKeyConstantValue;
+ public Color color;
+ public float width;
+ public float handleWidth;
+ public bool showNonEditableHandles;
+ public bool onlyShowHandlesOnSelection;
+ public bool loopInBounds;
+
+ public static CurveState defaultState
+ {
+ get
+ {
+ return new CurveState
+ {
+ visible = true,
+ editable = true,
+ minPointCount = 2,
+ zeroKeyConstantValue = 0f,
+ color = Color.white,
+ width = 2f,
+ handleWidth = 2f,
+ showNonEditableHandles = true,
+ onlyShowHandlesOnSelection = false,
+ loopInBounds = false
+ };
+ }
+ }
+ }
+
+ public struct Selection
+ {
+ public SerializedProperty curve;
+ public int keyframeIndex;
+ public Keyframe? keyframe;
+
+ public Selection(SerializedProperty curve, int keyframeIndex, Keyframe? keyframe)
+ {
+ this.curve = curve;
+ this.keyframeIndex = keyframeIndex;
+ this.keyframe = keyframe;
+ }
+ }
+
+ internal struct MenuAction
+ {
+ internal SerializedProperty curve;
+ internal int index;
+ internal Vector3 position;
+
+ internal MenuAction(SerializedProperty curve)
+ {
+ this.curve = curve;
+ this.index = -1;
+ this.position = Vector3.zero;
+ }
+
+ internal MenuAction(SerializedProperty curve, int index)
+ {
+ this.curve = curve;
+ this.index = index;
+ this.position = Vector3.zero;
+ }
+
+ internal MenuAction(SerializedProperty curve, Vector3 position)
+ {
+ this.curve = curve;
+ this.index = -1;
+ this.position = position;
+ }
+ }
+
+ #endregion
+
+ #region Fields & properties
+
+ public Settings settings { get; private set; }
+
+ readonly Dictionary m_Curves;
+ Rect m_CurveArea;
+
+ SerializedProperty m_SelectedCurve;
+ int m_SelectedKeyframeIndex = -1;
+
+ EditMode m_EditMode = EditMode.None;
+ Tangent m_TangentEditMode;
+
+ bool m_Dirty;
+
+ #endregion
+
+ #region Constructors & destructors
+
+ public CurveEditor()
+ : this(Settings.defaultSettings)
+ { }
+
+ public CurveEditor(Settings settings)
+ {
+ this.settings = settings;
+ m_Curves = new Dictionary();
+ }
+
+ #endregion
+
+ #region Public API
+
+ public void Add(params SerializedProperty[] curves)
+ {
+ foreach (var curve in curves)
+ Add(curve, CurveState.defaultState);
+ }
+
+ public void Add(SerializedProperty curve)
+ {
+ Add(curve, CurveState.defaultState);
+ }
+
+ public void Add(SerializedProperty curve, CurveState state)
+ {
+ // Make sure the property is in fact an AnimationCurve
+ var animCurve = curve.animationCurveValue;
+ if (animCurve == null)
+ throw new ArgumentException("curve");
+
+ if (m_Curves.ContainsKey(curve))
+ Debug.LogWarning("Curve has already been added to the editor");
+
+ m_Curves.Add(curve, state);
+ }
+
+ public void Remove(SerializedProperty curve)
+ {
+ m_Curves.Remove(curve);
+ }
+
+ public void RemoveAll()
+ {
+ m_Curves.Clear();
+ }
+
+ public CurveState GetCurveState(SerializedProperty curve)
+ {
+ CurveState state;
+ if (!m_Curves.TryGetValue(curve, out state))
+ throw new KeyNotFoundException("curve");
+
+ return state;
+ }
+
+ public void SetCurveState(SerializedProperty curve, CurveState state)
+ {
+ if (!m_Curves.ContainsKey(curve))
+ throw new KeyNotFoundException("curve");
+
+ m_Curves[curve] = state;
+ }
+
+ public Selection GetSelection()
+ {
+ Keyframe? key = null;
+ if (m_SelectedKeyframeIndex > -1)
+ {
+ var curve = m_SelectedCurve.animationCurveValue;
+
+ if (m_SelectedKeyframeIndex >= curve.length)
+ m_SelectedKeyframeIndex = -1;
+ else
+ key = curve[m_SelectedKeyframeIndex];
+ }
+
+ return new Selection(m_SelectedCurve, m_SelectedKeyframeIndex, key);
+ }
+
+ public void SetKeyframe(SerializedProperty curve, int keyframeIndex, Keyframe keyframe)
+ {
+ var animCurve = curve.animationCurveValue;
+ SetKeyframe(animCurve, keyframeIndex, keyframe);
+ SaveCurve(curve, animCurve);
+ }
+
+ public bool OnGUI(Rect rect)
+ {
+ if (Event.current.type == EventType.Repaint)
+ m_Dirty = false;
+
+ GUI.BeginClip(rect);
+ {
+ var area = new Rect(Vector2.zero, rect.size);
+ m_CurveArea = settings.padding.Remove(area);
+
+ foreach (var curve in m_Curves)
+ OnCurveGUI(area, curve.Key, curve.Value);
+
+ OnGeneralUI(area);
+ }
+ GUI.EndClip();
+
+ return m_Dirty;
+ }
+
+ #endregion
+
+ #region UI & events
+
+ void OnCurveGUI(Rect rect, SerializedProperty curve, CurveState state)
+ {
+ // Discard invisible curves
+ if (!state.visible)
+ return;
+
+ var animCurve = curve.animationCurveValue;
+ var keys = animCurve.keys;
+ var length = keys.Length;
+
+ // Curve drawing
+ // Slightly dim non-editable curves
+ var color = state.color;
+ if (!state.editable || !GUI.enabled)
+ color.a *= 0.5f;
+
+ Handles.color = color;
+ var bounds = settings.bounds;
+
+ if (length == 0)
+ {
+ var p1 = CurveToCanvas(new Vector3(bounds.xMin, state.zeroKeyConstantValue));
+ var p2 = CurveToCanvas(new Vector3(bounds.xMax, state.zeroKeyConstantValue));
+ Handles.DrawAAPolyLine(state.width, p1, p2);
+ }
+ else if (length == 1)
+ {
+ var p1 = CurveToCanvas(new Vector3(bounds.xMin, keys[0].value));
+ var p2 = CurveToCanvas(new Vector3(bounds.xMax, keys[0].value));
+ Handles.DrawAAPolyLine(state.width, p1, p2);
+ }
+ else
+ {
+ var prevKey = keys[0];
+ for (int k = 1; k < length; k++)
+ {
+ var key = keys[k];
+ var pts = BezierSegment(prevKey, key);
+
+ if (float.IsInfinity(prevKey.outTangent) || float.IsInfinity(key.inTangent))
+ {
+ var s = HardSegment(prevKey, key);
+ Handles.DrawAAPolyLine(state.width, s[0], s[1], s[2]);
+ }
+ else Handles.DrawBezier(pts[0], pts[3], pts[1], pts[2], color, null, state.width);
+
+ prevKey = key;
+ }
+
+ // Curve extents & loops
+ if (keys[0].time > bounds.xMin)
+ {
+ if (state.loopInBounds)
+ {
+ var p1 = keys[length - 1];
+ p1.time -= settings.bounds.width;
+ var p2 = keys[0];
+ var pts = BezierSegment(p1, p2);
+
+ if (float.IsInfinity(p1.outTangent) || float.IsInfinity(p2.inTangent))
+ {
+ var s = HardSegment(p1, p2);
+ Handles.DrawAAPolyLine(state.width, s[0], s[1], s[2]);
+ }
+ else Handles.DrawBezier(pts[0], pts[3], pts[1], pts[2], color, null, state.width);
+ }
+ else
+ {
+ var p1 = CurveToCanvas(new Vector3(bounds.xMin, keys[0].value));
+ var p2 = CurveToCanvas(keys[0]);
+ Handles.DrawAAPolyLine(state.width, p1, p2);
+ }
+ }
+
+ if (keys[length - 1].time < bounds.xMax)
+ {
+ if (state.loopInBounds)
+ {
+ var p1 = keys[length - 1];
+ var p2 = keys[0];
+ p2.time += settings.bounds.width;
+ var pts = BezierSegment(p1, p2);
+
+ if (float.IsInfinity(p1.outTangent) || float.IsInfinity(p2.inTangent))
+ {
+ var s = HardSegment(p1, p2);
+ Handles.DrawAAPolyLine(state.width, s[0], s[1], s[2]);
+ }
+ else Handles.DrawBezier(pts[0], pts[3], pts[1], pts[2], color, null, state.width);
+ }
+ else
+ {
+ var p1 = CurveToCanvas(keys[length - 1]);
+ var p2 = CurveToCanvas(new Vector3(bounds.xMax, keys[length - 1].value));
+ Handles.DrawAAPolyLine(state.width, p1, p2);
+ }
+ }
+ }
+
+ // Make sure selection is correct (undo can break it)
+ bool isCurrentlySelectedCurve = curve == m_SelectedCurve;
+
+ if (isCurrentlySelectedCurve && m_SelectedKeyframeIndex >= length)
+ m_SelectedKeyframeIndex = -1;
+
+ if (!state.editable)
+ m_SelectedKeyframeIndex = -1;
+
+ float enabledFactor = GUI.enabled ? 1f : 0.8f;
+
+ // Handles & keys
+ for (int k = 0; k < length; k++)
+ {
+ bool isCurrentlySelectedKeyframe = k == m_SelectedKeyframeIndex;
+ var e = Event.current;
+
+ var pos = CurveToCanvas(keys[k]);
+ var hitRect = new Rect(pos.x - 8f, pos.y - 8f, 16f, 16f);
+ var offset = isCurrentlySelectedCurve
+ ? new RectOffset(5, 5, 5, 5)
+ : new RectOffset(6, 6, 6, 6);
+
+ var outTangent = pos + CurveTangentToCanvas(keys[k].outTangent).normalized * 40f;
+ var inTangent = pos - CurveTangentToCanvas(keys[k].inTangent).normalized * 40f;
+ var inTangentHitRect = new Rect(inTangent.x - 7f, inTangent.y - 7f, 14f, 14f);
+ var outTangentHitrect = new Rect(outTangent.x - 7f, outTangent.y - 7f, 14f, 14f);
+
+ // Draw
+ if (state.editable || state.showNonEditableHandles)
+ {
+ if (e.type == EventType.Repaint)
+ {
+ var selectedColor = (isCurrentlySelectedCurve && isCurrentlySelectedKeyframe)
+ ? settings.selectionColor
+ : state.color;
+
+ // Keyframe
+ EditorGUI.DrawRect(offset.Remove(hitRect), selectedColor * enabledFactor);
+
+ // Tangents
+ if (isCurrentlySelectedCurve && (!state.onlyShowHandlesOnSelection || (state.onlyShowHandlesOnSelection && isCurrentlySelectedKeyframe)))
+ {
+ Handles.color = selectedColor * enabledFactor;
+
+ if (k > 0 || state.loopInBounds)
+ {
+ Handles.DrawAAPolyLine(state.handleWidth, pos, inTangent);
+ EditorGUI.DrawRect(offset.Remove(inTangentHitRect), selectedColor);
+ }
+
+ if (k < length - 1 || state.loopInBounds)
+ {
+ Handles.DrawAAPolyLine(state.handleWidth, pos, outTangent);
+ EditorGUI.DrawRect(offset.Remove(outTangentHitrect), selectedColor);
+ }
+ }
+ }
+ }
+
+ // Events
+ if (state.editable)
+ {
+ // Keyframe move
+ if (m_EditMode == EditMode.Moving && e.type == EventType.MouseDrag && isCurrentlySelectedCurve && isCurrentlySelectedKeyframe)
+ {
+ EditMoveKeyframe(animCurve, keys, k);
+ }
+
+ // Tangent editing
+ if (m_EditMode == EditMode.TangentEdit && e.type == EventType.MouseDrag && isCurrentlySelectedCurve && isCurrentlySelectedKeyframe)
+ {
+ bool alreadyBroken = !(Mathf.Approximately(keys[k].inTangent, keys[k].outTangent) || (float.IsInfinity(keys[k].inTangent) && float.IsInfinity(keys[k].outTangent)));
+ EditMoveTangent(animCurve, keys, k, m_TangentEditMode, e.shift || !(alreadyBroken || e.control));
+ }
+
+ // Keyframe selection & context menu
+ if (e.type == EventType.MouseDown && rect.Contains(e.mousePosition))
+ {
+ if (hitRect.Contains(e.mousePosition))
+ {
+ if (e.button == 0)
+ {
+ SelectKeyframe(curve, k);
+ m_EditMode = EditMode.Moving;
+ e.Use();
+ }
+ else if (e.button == 1)
+ {
+ // Keyframe context menu
+ var menu = new GenericMenu();
+ menu.AddItem(new GUIContent("Delete Key"), false, (x) =>
+ {
+ var action = (MenuAction)x;
+ var curveValue = action.curve.animationCurveValue;
+ action.curve.serializedObject.Update();
+ RemoveKeyframe(curveValue, action.index);
+ m_SelectedKeyframeIndex = -1;
+ SaveCurve(action.curve, curveValue);
+ action.curve.serializedObject.ApplyModifiedProperties();
+ }, new MenuAction(curve, k));
+ menu.ShowAsContext();
+ e.Use();
+ }
+ }
+ }
+
+ // Tangent selection & edit mode
+ if (e.type == EventType.MouseDown && rect.Contains(e.mousePosition))
+ {
+ if (inTangentHitRect.Contains(e.mousePosition) && (k > 0 || state.loopInBounds))
+ {
+ SelectKeyframe(curve, k);
+ m_EditMode = EditMode.TangentEdit;
+ m_TangentEditMode = Tangent.In;
+ e.Use();
+ }
+ else if (outTangentHitrect.Contains(e.mousePosition) && (k < length - 1 || state.loopInBounds))
+ {
+ SelectKeyframe(curve, k);
+ m_EditMode = EditMode.TangentEdit;
+ m_TangentEditMode = Tangent.Out;
+ e.Use();
+ }
+ }
+
+ // Mouse up - clean up states
+ if (e.rawType == EventType.MouseUp && m_EditMode != EditMode.None)
+ {
+ m_EditMode = EditMode.None;
+ }
+
+ // Set cursors
+ {
+ EditorGUIUtility.AddCursorRect(hitRect, MouseCursor.MoveArrow);
+
+ if (k > 0 || state.loopInBounds)
+ EditorGUIUtility.AddCursorRect(inTangentHitRect, MouseCursor.RotateArrow);
+
+ if (k < length - 1 || state.loopInBounds)
+ EditorGUIUtility.AddCursorRect(outTangentHitrect, MouseCursor.RotateArrow);
+ }
+ }
+ }
+
+ Handles.color = Color.white;
+ SaveCurve(curve, animCurve);
+ }
+
+ void OnGeneralUI(Rect rect)
+ {
+ var e = Event.current;
+
+ // Selection
+ if (e.type == EventType.MouseDown)
+ {
+ GUI.FocusControl(null);
+ m_SelectedCurve = null;
+ m_SelectedKeyframeIndex = -1;
+ bool used = false;
+
+ var hit = CanvasToCurve(e.mousePosition);
+ float curvePickValue = CurveToCanvas(hit).y;
+
+ // Try and select a curve
+ foreach (var curve in m_Curves)
+ {
+ if (!curve.Value.editable || !curve.Value.visible)
+ continue;
+
+ var prop = curve.Key;
+ var state = curve.Value;
+ var animCurve = prop.animationCurveValue;
+ float hitY = animCurve.length == 0
+ ? state.zeroKeyConstantValue
+ : animCurve.Evaluate(hit.x);
+
+ var curvePos = CurveToCanvas(new Vector3(hit.x, hitY));
+
+ if (Mathf.Abs(curvePos.y - curvePickValue) < settings.curvePickingDistance)
+ {
+ m_SelectedCurve = prop;
+
+ if (e.clickCount == 2 && e.button == 0)
+ {
+ // Create a keyframe on double-click on this curve
+ EditCreateKeyframe(animCurve, hit, true, state.zeroKeyConstantValue);
+ SaveCurve(prop, animCurve);
+ }
+ else if (e.button == 1)
+ {
+ // Curve context menu
+ var menu = new GenericMenu();
+ menu.AddItem(new GUIContent("Add Key"), false, (x) =>
+ {
+ var action = (MenuAction)x;
+ var curveValue = action.curve.animationCurveValue;
+ action.curve.serializedObject.Update();
+ EditCreateKeyframe(curveValue, hit, true, 0f);
+ SaveCurve(action.curve, curveValue);
+ action.curve.serializedObject.ApplyModifiedProperties();
+ }, new MenuAction(prop, hit));
+ menu.ShowAsContext();
+ e.Use();
+ used = true;
+ }
+ }
+ }
+
+ if (e.clickCount == 2 && e.button == 0 && m_SelectedCurve == null)
+ {
+ // Create a keyframe on every curve on double-click
+ foreach (var curve in m_Curves)
+ {
+ if (!curve.Value.editable || !curve.Value.visible)
+ continue;
+
+ var prop = curve.Key;
+ var state = curve.Value;
+ var animCurve = prop.animationCurveValue;
+ EditCreateKeyframe(animCurve, hit, e.alt, state.zeroKeyConstantValue);
+ SaveCurve(prop, animCurve);
+ }
+ }
+ else if (!used && e.button == 1)
+ {
+ // Global context menu
+ var menu = new GenericMenu();
+ menu.AddItem(new GUIContent("Add Key At Position"), false, () => ContextMenuAddKey(hit, false));
+ menu.AddItem(new GUIContent("Add Key On Curves"), false, () => ContextMenuAddKey(hit, true));
+ menu.ShowAsContext();
+ }
+
+ e.Use();
+ }
+
+ // Delete selected key(s)
+ if (e.type == EventType.KeyDown && (e.keyCode == KeyCode.Delete || e.keyCode == KeyCode.Backspace))
+ {
+ if (m_SelectedKeyframeIndex != -1 && m_SelectedCurve != null)
+ {
+ var animCurve = m_SelectedCurve.animationCurveValue;
+ var length = animCurve.length;
+
+ if (m_Curves[m_SelectedCurve].minPointCount < length && length >= 0)
+ {
+ EditDeleteKeyframe(animCurve, m_SelectedKeyframeIndex);
+ m_SelectedKeyframeIndex = -1;
+ SaveCurve(m_SelectedCurve, animCurve);
+ }
+
+ e.Use();
+ }
+ }
+ }
+
+ void SaveCurve(SerializedProperty prop, AnimationCurve curve)
+ {
+ prop.animationCurveValue = curve;
+ }
+
+ void Invalidate()
+ {
+ m_Dirty = true;
+ }
+
+ #endregion
+
+ #region Keyframe manipulations
+
+ void SelectKeyframe(SerializedProperty curve, int keyframeIndex)
+ {
+ m_SelectedKeyframeIndex = keyframeIndex;
+ m_SelectedCurve = curve;
+ Invalidate();
+ }
+
+ void ContextMenuAddKey(Vector3 hit, bool createOnCurve)
+ {
+ SerializedObject serializedObject = null;
+
+ foreach (var curve in m_Curves)
+ {
+ if (!curve.Value.editable || !curve.Value.visible)
+ continue;
+
+ var prop = curve.Key;
+ var state = curve.Value;
+
+ if (serializedObject == null)
+ {
+ serializedObject = prop.serializedObject;
+ serializedObject.Update();
+ }
+
+ var animCurve = prop.animationCurveValue;
+ EditCreateKeyframe(animCurve, hit, createOnCurve, state.zeroKeyConstantValue);
+ SaveCurve(prop, animCurve);
+ }
+
+ if (serializedObject != null)
+ serializedObject.ApplyModifiedProperties();
+
+ Invalidate();
+ }
+
+ void EditCreateKeyframe(AnimationCurve curve, Vector3 position, bool createOnCurve, float zeroKeyConstantValue)
+ {
+ float tangent = EvaluateTangent(curve, position.x);
+
+ if (createOnCurve)
+ {
+ position.y = curve.length == 0
+ ? zeroKeyConstantValue
+ : curve.Evaluate(position.x);
+ }
+
+ AddKeyframe(curve, new Keyframe(position.x, position.y, tangent, tangent));
+ }
+
+ void EditDeleteKeyframe(AnimationCurve curve, int keyframeIndex)
+ {
+ RemoveKeyframe(curve, keyframeIndex);
+ }
+
+ void AddKeyframe(AnimationCurve curve, Keyframe newValue)
+ {
+ curve.AddKey(newValue);
+ Invalidate();
+ }
+
+ void RemoveKeyframe(AnimationCurve curve, int keyframeIndex)
+ {
+ curve.RemoveKey(keyframeIndex);
+ Invalidate();
+ }
+
+ void SetKeyframe(AnimationCurve curve, int keyframeIndex, Keyframe newValue)
+ {
+ var keys = curve.keys;
+
+ if (keyframeIndex > 0)
+ newValue.time = Mathf.Max(keys[keyframeIndex - 1].time + settings.keyTimeClampingDistance, newValue.time);
+
+ if (keyframeIndex < keys.Length - 1)
+ newValue.time = Mathf.Min(keys[keyframeIndex + 1].time - settings.keyTimeClampingDistance, newValue.time);
+
+ curve.MoveKey(keyframeIndex, newValue);
+ Invalidate();
+ }
+
+ void EditMoveKeyframe(AnimationCurve curve, Keyframe[] keys, int keyframeIndex)
+ {
+ var key = CanvasToCurve(Event.current.mousePosition);
+ float inTgt = keys[keyframeIndex].inTangent;
+ float outTgt = keys[keyframeIndex].outTangent;
+ SetKeyframe(curve, keyframeIndex, new Keyframe(key.x, key.y, inTgt, outTgt));
+ }
+
+ void EditMoveTangent(AnimationCurve curve, Keyframe[] keys, int keyframeIndex, Tangent targetTangent, bool linkTangents)
+ {
+ var pos = CanvasToCurve(Event.current.mousePosition);
+
+ float time = keys[keyframeIndex].time;
+ float value = keys[keyframeIndex].value;
+
+ pos -= new Vector3(time, value);
+
+ if (targetTangent == Tangent.In && pos.x > 0f)
+ pos.x = 0f;
+
+ if (targetTangent == Tangent.Out && pos.x < 0f)
+ pos.x = 0f;
+
+ float tangent;
+
+ if (Mathf.Approximately(pos.x, 0f))
+ tangent = pos.y < 0f ? float.PositiveInfinity : float.NegativeInfinity;
+ else
+ tangent = pos.y / pos.x;
+
+ float inTangent = keys[keyframeIndex].inTangent;
+ float outTangent = keys[keyframeIndex].outTangent;
+
+ if (targetTangent == Tangent.In || linkTangents)
+ inTangent = tangent;
+ if (targetTangent == Tangent.Out || linkTangents)
+ outTangent = tangent;
+
+ SetKeyframe(curve, keyframeIndex, new Keyframe(time, value, inTangent, outTangent));
+ }
+
+ #endregion
+
+ #region Maths utilities
+
+ Vector3 CurveToCanvas(Keyframe keyframe)
+ {
+ return CurveToCanvas(new Vector3(keyframe.time, keyframe.value));
+ }
+
+ Vector3 CurveToCanvas(Vector3 position)
+ {
+ var bounds = settings.bounds;
+ var output = new Vector3((position.x - bounds.x) / (bounds.xMax - bounds.x), (position.y - bounds.y) / (bounds.yMax - bounds.y));
+ output.x = output.x * (m_CurveArea.xMax - m_CurveArea.xMin) + m_CurveArea.xMin;
+ output.y = (1f - output.y) * (m_CurveArea.yMax - m_CurveArea.yMin) + m_CurveArea.yMin;
+ return output;
+ }
+
+ Vector3 CanvasToCurve(Vector3 position)
+ {
+ var bounds = settings.bounds;
+ var output = position;
+ output.x = (output.x - m_CurveArea.xMin) / (m_CurveArea.xMax - m_CurveArea.xMin);
+ output.y = (output.y - m_CurveArea.yMin) / (m_CurveArea.yMax - m_CurveArea.yMin);
+ output.x = Mathf.Lerp(bounds.x, bounds.xMax, output.x);
+ output.y = Mathf.Lerp(bounds.yMax, bounds.y, output.y);
+ return output;
+ }
+
+ Vector3 CurveTangentToCanvas(float tangent)
+ {
+ if (!float.IsInfinity(tangent))
+ {
+ var bounds = settings.bounds;
+ float ratio = (m_CurveArea.width / m_CurveArea.height) / ((bounds.xMax - bounds.x) / (bounds.yMax - bounds.y));
+ return new Vector3(1f, -tangent / ratio).normalized;
+ }
+
+ return float.IsPositiveInfinity(tangent) ? Vector3.up : Vector3.down;
+ }
+
+ Vector3[] BezierSegment(Keyframe start, Keyframe end)
+ {
+ var segment = new Vector3[4];
+
+ segment[0] = CurveToCanvas(new Vector3(start.time, start.value));
+ segment[3] = CurveToCanvas(new Vector3(end.time, end.value));
+
+ float middle = start.time + ((end.time - start.time) * 0.333333f);
+ float middle2 = start.time + ((end.time - start.time) * 0.666666f);
+
+ segment[1] = CurveToCanvas(new Vector3(middle, ProjectTangent(start.time, start.value, start.outTangent, middle)));
+ segment[2] = CurveToCanvas(new Vector3(middle2, ProjectTangent(end.time, end.value, end.inTangent, middle2)));
+
+ return segment;
+ }
+
+ Vector3[] HardSegment(Keyframe start, Keyframe end)
+ {
+ var segment = new Vector3[3];
+
+ segment[0] = CurveToCanvas(start);
+ segment[1] = CurveToCanvas(new Vector3(end.time, start.value));
+ segment[2] = CurveToCanvas(end);
+
+ return segment;
+ }
+
+ float ProjectTangent(float inPosition, float inValue, float inTangent, float projPosition)
+ {
+ return inValue + ((projPosition - inPosition) * inTangent);
+ }
+
+ float EvaluateTangent(AnimationCurve curve, float time)
+ {
+ int prev = -1, next = 0;
+ for (int i = 0; i < curve.keys.Length; i++)
+ {
+ if (time > curve.keys[i].time)
+ {
+ prev = i;
+ next = i + 1;
+ }
+ else break;
+ }
+
+ if (next == 0)
+ return 0f;
+
+ if (prev == curve.keys.Length - 1)
+ return 0f;
+
+ const float kD = 1e-3f;
+ float tp = Mathf.Max(time - kD, curve.keys[prev].time);
+ float tn = Mathf.Min(time + kD, curve.keys[next].time);
+
+ float vp = curve.Evaluate(tp);
+ float vn = curve.Evaluate(tn);
+
+ if (Mathf.Approximately(tn, tp))
+ return (vn - vp > 0f) ? float.PositiveInfinity : float.NegativeInfinity;
+
+ return (vn - vp) / (tn - tp);
+ }
+
+ #endregion
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Utils/CurveEditor.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/Utils/CurveEditor.cs.meta
new file mode 100644
index 0000000..c76f2b0
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Utils/CurveEditor.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: ce0f0631fee52da41884853337cab99d
+timeCreated: 1493979438
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Utils/EditorUtilities.cs b/com.unity.postprocessing/PostProcessing/Editor/Utils/EditorUtilities.cs
new file mode 100644
index 0000000..276f775
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Utils/EditorUtilities.cs
@@ -0,0 +1,391 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+using UnityEngine.Assertions;
+using UnityEngine.Rendering.PostProcessing;
+
+#if XR_MANAGEMENT_4_0_1_OR_NEWER
+using UnityEditor.XR.Management;
+#endif
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ ///
+ /// A set of editor utilities used in post-processing editors.
+ ///
+ public static class EditorUtilities
+ {
+ static Dictionary s_GUIContentCache;
+ static Dictionary s_AttributeDecorators;
+
+ static PostProcessEffectSettings s_ClipboardContent;
+
+ ///
+ /// Returns true if the current target is a console, false otherwise.
+ ///
+ public static bool isTargetingConsoles
+ {
+ get
+ {
+ var t = EditorUserBuildSettings.activeBuildTarget;
+ return t == BuildTarget.PS4
+#if UNITY_PS5
+ || t == BuildTarget.PS5
+#endif
+ || t == BuildTarget.XboxOne
+#if UNITY_GAMECORE
+ || t == BuildTarget.GameCoreXboxSeries
+ || t == BuildTarget.GameCoreXboxOne
+#endif
+ || t == BuildTarget.Switch;
+ }
+ }
+
+ ///
+ /// Returns true if the current target is a mobile, false otherwise.
+ ///
+ public static bool isTargetingMobiles
+ {
+ get
+ {
+ var t = EditorUserBuildSettings.activeBuildTarget;
+ return t == BuildTarget.Android
+ || t == BuildTarget.iOS
+ || t == BuildTarget.tvOS
+#if !UNITY_2018_2_OR_NEWER
+ || t == BuildTarget.Tizen
+#endif
+#if !UNITY_2018_3_OR_NEWER
+ || t == BuildTarget.N3DS
+ || t == BuildTarget.PSP2
+#endif
+ ;
+ }
+ }
+
+ ///
+ /// Returns true if the current target is a console or a mobile, false
+ /// otherwise.
+ ///
+ public static bool isTargetingConsolesOrMobiles
+ {
+ get { return isTargetingConsoles || isTargetingMobiles; }
+ }
+
+ static EditorUtilities()
+ {
+ s_GUIContentCache = new Dictionary();
+ s_AttributeDecorators = new Dictionary();
+ ReloadDecoratorTypes();
+ }
+
+ [Callbacks.DidReloadScripts]
+ static void OnEditorReload()
+ {
+ ReloadDecoratorTypes();
+ }
+
+ static void ReloadDecoratorTypes()
+ {
+ s_AttributeDecorators.Clear();
+
+ // Look for all the valid attribute decorators
+ var types = RuntimeUtilities.GetAllTypesDerivedFrom()
+ .Where(
+ t => t.IsDefined(typeof(DecoratorAttribute), false)
+ && !t.IsAbstract
+ );
+
+ // Store them
+ foreach (var type in types)
+ {
+ var attr = type.GetAttribute();
+ var decorator = (AttributeDecorator)Activator.CreateInstance(type);
+ s_AttributeDecorators.Add(attr.attributeType, decorator);
+ }
+ }
+
+ internal static AttributeDecorator GetDecorator(Type attributeType)
+ {
+ AttributeDecorator decorator;
+ return !s_AttributeDecorators.TryGetValue(attributeType, out decorator)
+ ? null
+ : decorator;
+ }
+
+ ///
+ /// Gets a for the given label and tooltip. These are recycled
+ /// internally and help reduce the garbage collector pressure in the editor.
+ ///
+ /// The label and tooltip separated by a |
+ /// character
+ /// A recycled
+ public static GUIContent GetContent(string textAndTooltip)
+ {
+ if (string.IsNullOrEmpty(textAndTooltip))
+ return GUIContent.none;
+
+ GUIContent content;
+
+ if (!s_GUIContentCache.TryGetValue(textAndTooltip, out content))
+ {
+ var s = textAndTooltip.Split('|');
+ content = new GUIContent(s[0]);
+
+ if (s.Length > 1 && !string.IsNullOrEmpty(s[1]))
+ content.tooltip = s[1];
+
+ s_GUIContentCache.Add(textAndTooltip, content);
+ }
+
+ return content;
+ }
+
+ ///
+ /// Draws a UI box with a description and a "Fix Me" button next to it.
+ ///
+ /// The description
+ /// The action to execute when the button is clicked
+ public static void DrawFixMeBox(string text, Action action)
+ {
+ Assert.IsNotNull(action);
+
+ EditorGUILayout.HelpBox(text, MessageType.Warning);
+
+ GUILayout.Space(-32);
+ using (new EditorGUILayout.HorizontalScope())
+ {
+ GUILayout.FlexibleSpace();
+
+ if (GUILayout.Button("Fix", GUILayout.Width(60)))
+ action();
+
+ GUILayout.Space(8);
+ }
+ GUILayout.Space(11);
+ }
+
+ ///
+ /// Draws a horizontal split line.
+ ///
+ public static void DrawSplitter()
+ {
+ var rect = GUILayoutUtility.GetRect(1f, 1f);
+
+ // Splitter rect should be full-width
+ rect.xMin = 0f;
+ rect.width += 4f;
+
+ if (Event.current.type != EventType.Repaint)
+ return;
+
+ EditorGUI.DrawRect(rect, Styling.splitter);
+ }
+
+ ///
+ /// Draws a toggle using the "override checkbox" style.
+ ///
+ /// The position and size of the toggle
+ /// The override state property for the toggle
+ public static void DrawOverrideCheckbox(Rect rect, SerializedProperty property)
+ {
+ property.boolValue = GUI.Toggle(rect, property.boolValue, GetContent("|Override this setting for this volume."), Styling.smallTickbox);
+ }
+
+ ///
+ /// Draws a header label.
+ ///
+ /// The label to display as a header
+ public static void DrawHeaderLabel(string title)
+ {
+ EditorGUILayout.LabelField(title, Styling.headerLabel);
+ }
+
+ internal static bool DrawHeader(string title, bool state)
+ {
+ var backgroundRect = GUILayoutUtility.GetRect(1f, 17f);
+
+ var labelRect = backgroundRect;
+ labelRect.xMin += 16f;
+ labelRect.xMax -= 20f;
+
+ var foldoutRect = backgroundRect;
+ foldoutRect.y += 1f;
+ foldoutRect.width = 13f;
+ foldoutRect.height = 13f;
+
+ // Background rect should be full-width
+ backgroundRect.xMin = 0f;
+ backgroundRect.width += 4f;
+
+ // Background
+ EditorGUI.DrawRect(backgroundRect, Styling.headerBackground);
+
+ // Title
+ EditorGUI.LabelField(labelRect, GetContent(title), EditorStyles.boldLabel);
+
+ // Foldout
+ state = GUI.Toggle(foldoutRect, state, GUIContent.none, EditorStyles.foldout);
+
+ var e = Event.current;
+ if (e.type == EventType.MouseDown && backgroundRect.Contains(e.mousePosition) && e.button == 0)
+ {
+ state = !state;
+ e.Use();
+ }
+
+ return state;
+ }
+
+ internal static bool DrawHeader(string title, SerializedProperty group, SerializedProperty activeField, PostProcessEffectSettings target, Action resetAction, Action removeAction)
+ {
+ Assert.IsNotNull(group);
+ Assert.IsNotNull(activeField);
+ Assert.IsNotNull(target);
+
+ var backgroundRect = GUILayoutUtility.GetRect(1f, 17f);
+
+ var labelRect = backgroundRect;
+ labelRect.xMin += 32f;
+ labelRect.xMax -= 20f;
+
+ var foldoutRect = backgroundRect;
+ foldoutRect.y += 1f;
+ foldoutRect.width = 13f;
+ foldoutRect.height = 13f;
+
+ var toggleRect = backgroundRect;
+ toggleRect.x += 16f;
+ toggleRect.y += 2f;
+ toggleRect.width = 13f;
+ toggleRect.height = 13f;
+
+ var menuIcon = Styling.paneOptionsIcon;
+#if UNITY_2019_3_OR_NEWER
+ var menuRect = new Rect(labelRect.xMax + 4f, labelRect.y, menuIcon.width, menuIcon.height);
+#else
+ var menuRect = new Rect(labelRect.xMax + 4f, labelRect.y + 4f, menuIcon.width, menuIcon.height);
+#endif
+
+ // Background rect should be full-width
+ backgroundRect.xMin = 0f;
+ backgroundRect.width += 4f;
+
+ // Background
+ EditorGUI.DrawRect(backgroundRect, Styling.headerBackground);
+
+ // Title
+ using (new EditorGUI.DisabledScope(!activeField.boolValue))
+ EditorGUI.LabelField(labelRect, GetContent(title), EditorStyles.boldLabel);
+
+ // foldout
+ group.serializedObject.Update();
+ group.isExpanded = GUI.Toggle(foldoutRect, group.isExpanded, GUIContent.none, EditorStyles.foldout);
+ group.serializedObject.ApplyModifiedProperties();
+
+ // Active checkbox
+ activeField.serializedObject.Update();
+ activeField.boolValue = GUI.Toggle(toggleRect, activeField.boolValue, GUIContent.none, Styling.smallTickbox);
+ activeField.serializedObject.ApplyModifiedProperties();
+
+ // Dropdown menu icon
+ GUI.DrawTexture(menuRect, menuIcon);
+
+ // Handle events
+ var e = Event.current;
+
+ if (e.type == EventType.MouseDown)
+ {
+ if (menuRect.Contains(e.mousePosition))
+ {
+ ShowHeaderContextMenu(new Vector2(menuRect.x, menuRect.yMax), target, resetAction, removeAction);
+ e.Use();
+ }
+ else if (labelRect.Contains(e.mousePosition))
+ {
+ if (e.button == 0)
+ group.isExpanded = !group.isExpanded;
+ else
+ ShowHeaderContextMenu(e.mousePosition, target, resetAction, removeAction);
+
+ e.Use();
+ }
+ }
+
+ return group.isExpanded;
+ }
+
+ static void ShowHeaderContextMenu(Vector2 position, PostProcessEffectSettings target, Action resetAction, Action removeAction)
+ {
+ Assert.IsNotNull(resetAction);
+ Assert.IsNotNull(removeAction);
+
+ var menu = new GenericMenu();
+ menu.AddItem(GetContent("Reset"), false, () => resetAction());
+ menu.AddItem(GetContent("Remove"), false, () => removeAction());
+ menu.AddSeparator(string.Empty);
+ menu.AddItem(GetContent("Copy Settings"), false, () => CopySettings(target));
+
+ if (CanPaste(target))
+ menu.AddItem(GetContent("Paste Settings"), false, () => PasteSettings(target));
+ else
+ menu.AddDisabledItem(GetContent("Paste Settings"));
+
+ menu.DropDown(new Rect(position, Vector2.zero));
+ }
+
+ static void CopySettings(PostProcessEffectSettings target)
+ {
+ Assert.IsNotNull(target);
+
+ if (s_ClipboardContent != null)
+ {
+ RuntimeUtilities.Destroy(s_ClipboardContent);
+ s_ClipboardContent = null;
+ }
+
+ s_ClipboardContent = (PostProcessEffectSettings)ScriptableObject.CreateInstance(target.GetType());
+ EditorUtility.CopySerializedIfDifferent(target, s_ClipboardContent);
+ }
+
+ static void PasteSettings(PostProcessEffectSettings target)
+ {
+ Assert.IsNotNull(target);
+ Assert.IsNotNull(s_ClipboardContent);
+ Assert.AreEqual(s_ClipboardContent.GetType(), target.GetType());
+
+ Undo.RecordObject(target, "Paste Settings");
+ EditorUtility.CopySerializedIfDifferent(s_ClipboardContent, target);
+ }
+
+ static bool CanPaste(PostProcessEffectSettings target)
+ {
+ return s_ClipboardContent != null
+ && s_ClipboardContent.GetType() == target.GetType();
+ }
+
+ internal static bool isVREnabled
+ {
+ get
+ {
+#if ENABLE_VR_MODULE && ENABLE_VR
+#if ENABLE_XR_MODULE && XR_MANAGEMENT_4_0_1_OR_NEWER
+ // If XR manager extension is available, we can query it to know if any XR extension is currently active
+ var buildTargetSettings = XRGeneralSettingsPerBuildTarget.XRGeneralSettingsForBuildTarget(BuildTargetGroup.Standalone);
+ return (buildTargetSettings != null && buildTargetSettings.AssignedSettings != null &&
+ buildTargetSettings.AssignedSettings.activeLoaders.Count > 0);
+#elif !UNITY_2020_1_OR_NEWER
+ // This will only work with 2019.3 and older since it rely on the old VR module
+ return UnityEditorInternal.VR.VREditor.GetVREnabledOnTargetGroup(BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget));
+#else
+ // If we reach this code-path, it means we can't really detect if VR/XR is active in the Editor, so return false
+ return false;
+#endif
+#else
+ return false;
+#endif
+ }
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Utils/EditorUtilities.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/Utils/EditorUtilities.cs.meta
new file mode 100644
index 0000000..2ce480e
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Utils/EditorUtilities.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 09e002b759745fa499d539b9021af38e
+timeCreated: 1489050987
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Utils/GlobalSettings.cs b/com.unity.postprocessing/PostProcessing/Editor/Utils/GlobalSettings.cs
new file mode 100644
index 0000000..6940697
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Utils/GlobalSettings.cs
@@ -0,0 +1,116 @@
+using UnityEngine;
+using UnityEngine.Rendering.PostProcessing;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ static class GlobalSettings
+ {
+ static class Keys
+ {
+ internal const string trackballSensitivity = "PostProcessing.Trackball.Sensitivity";
+ internal const string volumeGizmoColor = "PostProcessing.Volume.GizmoColor";
+ internal const string currentChannelMixer = "PostProcessing.ChannelMixer.CurrentChannel";
+ internal const string currentCurve = "PostProcessing.Curve.Current";
+ }
+
+ static bool m_Loaded = false;
+
+ static float m_TrackballSensitivity = 0.2f;
+ internal static float trackballSensitivity
+ {
+ get { return m_TrackballSensitivity; }
+ set { TrySave(ref m_TrackballSensitivity, value, Keys.trackballSensitivity); }
+ }
+
+ static Color m_VolumeGizmoColor = new Color(0.2f, 0.8f, 0.1f, 0.5f);
+ internal static Color volumeGizmoColor
+ {
+ get { return m_VolumeGizmoColor; }
+ set { TrySave(ref m_VolumeGizmoColor, value, Keys.volumeGizmoColor); }
+ }
+
+ static int m_CurrentChannelMixer = 0;
+ internal static int currentChannelMixer
+ {
+ get { return m_CurrentChannelMixer; }
+ set { TrySave(ref m_CurrentChannelMixer, value, Keys.currentChannelMixer); }
+ }
+
+ static int m_CurrentCurve = 0;
+ internal static int currentCurve
+ {
+ get { return m_CurrentCurve; }
+ set { TrySave(ref m_CurrentCurve, value, Keys.currentCurve); }
+ }
+
+ static GlobalSettings()
+ {
+ Load();
+ }
+
+#if UNITY_2018_3_OR_NEWER
+ [SettingsProvider]
+ static SettingsProvider PreferenceGUI()
+ {
+ return new SettingsProvider("Preferences/Post-processing", SettingsScope.User)
+ {
+ guiHandler = searchContext => OpenGUI()
+ };
+ }
+
+#else
+ [PreferenceItem("Post-processing")]
+ static void PreferenceGUI()
+ {
+ OpenGUI();
+ }
+
+#endif
+
+ static void OpenGUI()
+ {
+ if (!m_Loaded)
+ Load();
+
+ EditorGUILayout.Space();
+
+ trackballSensitivity = EditorGUILayout.Slider("Trackballs Sensitivity", trackballSensitivity, 0.05f, 1f);
+ volumeGizmoColor = EditorGUILayout.ColorField("Volume Gizmo Color", volumeGizmoColor);
+ }
+
+ static void Load()
+ {
+ m_TrackballSensitivity = EditorPrefs.GetFloat(Keys.trackballSensitivity, 0.2f);
+ m_VolumeGizmoColor = GetColor(Keys.volumeGizmoColor, new Color(0.2f, 0.8f, 0.1f, 0.5f));
+ m_CurrentChannelMixer = EditorPrefs.GetInt(Keys.currentChannelMixer, 0);
+ m_CurrentCurve = EditorPrefs.GetInt(Keys.currentCurve, 0);
+
+ m_Loaded = true;
+ }
+
+ static Color GetColor(string key, Color defaultValue)
+ {
+ int value = EditorPrefs.GetInt(key, (int)ColorUtilities.ToHex(defaultValue));
+ return ColorUtilities.ToRGBA((uint)value);
+ }
+
+ static void TrySave(ref T field, T newValue, string key)
+ {
+ if (field.Equals(newValue))
+ return;
+
+ if (typeof(T) == typeof(float))
+ EditorPrefs.SetFloat(key, (float)(object)newValue);
+ else if (typeof(T) == typeof(int))
+ EditorPrefs.SetInt(key, (int)(object)newValue);
+ else if (typeof(T) == typeof(bool))
+ EditorPrefs.SetBool(key, (bool)(object)newValue);
+ else if (typeof(T) == typeof(string))
+ EditorPrefs.SetString(key, (string)(object)newValue);
+ else if (typeof(T) == typeof(Color))
+ EditorPrefs.SetInt(key, (int)ColorUtilities.ToHex((Color)(object)newValue));
+
+ field = newValue;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Utils/GlobalSettings.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/Utils/GlobalSettings.cs.meta
new file mode 100644
index 0000000..de260de
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Utils/GlobalSettings.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: eff4db1c9252e5247b661dec568df962
+timeCreated: 1494714307
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Utils/SerializedParameterOverride.cs b/com.unity.postprocessing/PostProcessing/Editor/Utils/SerializedParameterOverride.cs
new file mode 100644
index 0000000..db1b1d6
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Utils/SerializedParameterOverride.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Linq;
+using UnityEngine.Rendering.PostProcessing;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ ///
+ /// A wrapper used for serialization and easy access to the
+ /// underlying property and override state.
+ ///
+ public sealed class SerializedParameterOverride
+ {
+ ///
+ /// The override state property of the serialized parameter.
+ ///
+ public SerializedProperty overrideState { get; private set; }
+
+ ///
+ /// The value property of the serialized parameter.
+ ///
+ public SerializedProperty value { get; private set; }
+
+ ///
+ /// An array of all attributes set on the original parameter.
+ ///
+ public Attribute[] attributes { get; private set; }
+
+ internal SerializedProperty baseProperty;
+
+ ///
+ /// Returns the display name of the property.
+ ///
+ public string displayName
+ {
+ get { return baseProperty.displayName; }
+ }
+
+ internal SerializedParameterOverride(SerializedProperty property, Attribute[] attributes)
+ {
+ baseProperty = property.Copy();
+
+ var localCopy = baseProperty.Copy();
+ localCopy.Next(true);
+ overrideState = localCopy.Copy();
+ localCopy.Next(false);
+ value = localCopy.Copy();
+
+ this.attributes = attributes;
+ }
+
+ ///
+ /// Gets the attribute of type T from the original parameter.
+ ///
+ /// The type of attribute to look for
+ /// And attribute or type T, or null if none has been found
+ public T GetAttribute()
+ where T : Attribute
+ {
+ return (T)attributes.FirstOrDefault(x => x is T);
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Utils/SerializedParameterOverride.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/Utils/SerializedParameterOverride.cs.meta
new file mode 100644
index 0000000..ab8030f
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Utils/SerializedParameterOverride.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: f48a0d4b798943a448e8d2e5d891133c
+timeCreated: 1492899655
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Utils/Styling.cs b/com.unity.postprocessing/PostProcessing/Editor/Utils/Styling.cs
new file mode 100644
index 0000000..e411830
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Utils/Styling.cs
@@ -0,0 +1,114 @@
+using UnityEngine;
+using UnityEngine.Rendering.PostProcessing;
+
+namespace UnityEditor.Rendering.PostProcessing
+{
+ ///
+ /// Common styles used for Post-processing editor controls.
+ ///
+ public static class Styling
+ {
+ ///
+ /// Style for the override checkbox.
+ ///
+ public static readonly GUIStyle smallTickbox;
+
+ ///
+ /// Style for the labels in the toolbar of each effect.
+ ///
+ public static readonly GUIStyle miniLabelButton;
+
+ static readonly Color splitterDark;
+ static readonly Color splitterLight;
+
+ ///
+ /// Color of UI splitters.
+ ///
+ public static Color splitter { get { return EditorGUIUtility.isProSkin ? splitterDark : splitterLight; } }
+
+ static readonly Texture2D paneOptionsIconDark;
+ static readonly Texture2D paneOptionsIconLight;
+
+ ///
+ /// Option icon used in effect headers.
+ ///
+ public static Texture2D paneOptionsIcon { get { return EditorGUIUtility.isProSkin ? paneOptionsIconDark : paneOptionsIconLight; } }
+
+ ///
+ /// Style for effect header labels.
+ ///
+ public static readonly GUIStyle headerLabel;
+
+ static readonly Color headerBackgroundDark;
+ static readonly Color headerBackgroundLight;
+
+ ///
+ /// Color of effect header backgrounds.
+ ///
+ public static Color headerBackground { get { return EditorGUIUtility.isProSkin ? headerBackgroundDark : headerBackgroundLight; } }
+
+ ///
+ /// Style for the trackball labels.
+ ///
+ public static readonly GUIStyle wheelLabel;
+
+ ///
+ /// Style for the trackball cursors.
+ ///
+ public static readonly GUIStyle wheelThumb;
+
+ ///
+ /// Size of the trackball cursors.
+ ///
+ public static readonly Vector2 wheelThumbSize;
+
+ ///
+ /// Style for the curve editor position info.
+ ///
+ public static readonly GUIStyle preLabel;
+
+ static Styling()
+ {
+ smallTickbox = new GUIStyle("ShurikenToggle");
+
+ miniLabelButton = new GUIStyle(EditorStyles.miniLabel);
+ miniLabelButton.normal = new GUIStyleState
+ {
+ background = RuntimeUtilities.transparentTexture,
+ scaledBackgrounds = null,
+ textColor = Color.grey
+ };
+ var activeState = new GUIStyleState
+ {
+ background = RuntimeUtilities.transparentTexture,
+ scaledBackgrounds = null,
+ textColor = Color.white
+ };
+ miniLabelButton.active = activeState;
+ miniLabelButton.onNormal = activeState;
+ miniLabelButton.onActive = activeState;
+
+ splitterDark = new Color(0.12f, 0.12f, 0.12f, 1.333f);
+ splitterLight = new Color(0.6f, 0.6f, 0.6f, 1.333f);
+
+ headerBackgroundDark = new Color(0.1f, 0.1f, 0.1f, 0.2f);
+ headerBackgroundLight = new Color(1f, 1f, 1f, 0.2f);
+
+ paneOptionsIconDark = (Texture2D)EditorGUIUtility.Load("Builtin Skins/DarkSkin/Images/pane options.png");
+ paneOptionsIconLight = (Texture2D)EditorGUIUtility.Load("Builtin Skins/LightSkin/Images/pane options.png");
+
+ headerLabel = new GUIStyle(EditorStyles.miniLabel);
+
+ wheelThumb = new GUIStyle("ColorPicker2DThumb");
+
+ wheelThumbSize = new Vector2(
+ !Mathf.Approximately(wheelThumb.fixedWidth, 0f) ? wheelThumb.fixedWidth : wheelThumb.padding.horizontal,
+ !Mathf.Approximately(wheelThumb.fixedHeight, 0f) ? wheelThumb.fixedHeight : wheelThumb.padding.vertical
+ );
+
+ wheelLabel = new GUIStyle(EditorStyles.miniLabel);
+
+ preLabel = new GUIStyle("ShurikenLabel");
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Editor/Utils/Styling.cs.meta b/com.unity.postprocessing/PostProcessing/Editor/Utils/Styling.cs.meta
new file mode 100644
index 0000000..daf42e9
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Editor/Utils/Styling.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: c884467f149574e44b21c869b7fc3401
+timeCreated: 1492697266
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Gizmos.meta b/com.unity.postprocessing/PostProcessing/Gizmos.meta
new file mode 100644
index 0000000..cf2b531
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Gizmos.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 62591175d691aac46a9db652057e905c
+folderAsset: yes
+timeCreated: 1488200725
+licenseType: Pro
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Gizmos/PostProcessLayer.png b/com.unity.postprocessing/PostProcessing/Gizmos/PostProcessLayer.png
new file mode 100644
index 0000000..c0a61de
Binary files /dev/null and b/com.unity.postprocessing/PostProcessing/Gizmos/PostProcessLayer.png differ
diff --git a/com.unity.postprocessing/PostProcessing/Gizmos/PostProcessLayer.png.meta b/com.unity.postprocessing/PostProcessing/Gizmos/PostProcessLayer.png.meta
new file mode 100644
index 0000000..ee62d08
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Gizmos/PostProcessLayer.png.meta
@@ -0,0 +1,76 @@
+fileFormatVersion: 2
+guid: 5f51e0b22aa8cb84b9f422576ce87ff9
+timeCreated: 1488200847
+licenseType: Pro
+TextureImporter:
+ fileIDToRecycleName: {}
+ serializedVersion: 4
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 0
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ filterMode: 1
+ aniso: 0
+ mipBias: -1
+ wrapMode: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spritePixelsToUnits: 100
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 0
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ - buildTarget: Standalone
+ maxTextureSize: 2048
+ textureFormat: -1
+ textureCompression: 0
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ spritePackingTag:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/PostProcessResources.asset b/com.unity.postprocessing/PostProcessing/PostProcessResources.asset
new file mode 100644
index 0000000..ae78db2
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/PostProcessResources.asset
@@ -0,0 +1,155 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &11400000
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_PrefabParentObject: {fileID: 0}
+ m_PrefabInternal: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 30f4b897495c7ad40b2d47143e02aaba, type: 3}
+ m_Name: PostProcessResources
+ m_EditorClassIdentifier:
+ blueNoise64:
+ - {fileID: 2800000, guid: 50b54341495978843a6f85583ed4417d, type: 3}
+ - {fileID: 2800000, guid: 3c2f1fb7e4b66e74191b7c328ada52d9, type: 3}
+ - {fileID: 2800000, guid: a469f920b21fc7c4fb5b950917ce2fb2, type: 3}
+ - {fileID: 2800000, guid: 373f9bf6b0841af4ebf26d25e4a3f4e2, type: 3}
+ - {fileID: 2800000, guid: 6fa5cf178eaaa5f42b820f636bb6e0bd, type: 3}
+ - {fileID: 2800000, guid: a1ae041906217ae44a774d4ca139af50, type: 3}
+ - {fileID: 2800000, guid: 79b86f3419b87f3429164a956da8cfab, type: 3}
+ - {fileID: 2800000, guid: 3ac02e7e783571c468f9c086d2384ba7, type: 3}
+ - {fileID: 2800000, guid: c55042318a938344ab23cd7f09dd0076, type: 3}
+ - {fileID: 2800000, guid: 71583cfd8899717428d5b1a95fa39cda, type: 3}
+ - {fileID: 2800000, guid: afe1e502240079342a0a980484b6da8b, type: 3}
+ - {fileID: 2800000, guid: 771903fe7b4674445829e52e91cff019, type: 3}
+ - {fileID: 2800000, guid: 980acadb960f8424c94307ec0e585b4e, type: 3}
+ - {fileID: 2800000, guid: 68613e6a221be1a4b9f31d7fa1c2d1bf, type: 3}
+ - {fileID: 2800000, guid: f6439b54b28f3884eb67579dec0b6f21, type: 3}
+ - {fileID: 2800000, guid: 2ee161d8945169243b5698fec114e1b7, type: 3}
+ - {fileID: 2800000, guid: 153f7d6dfbe713d4884df0f1e243ba92, type: 3}
+ - {fileID: 2800000, guid: bf95b6fdc179b0e4f890c841406193fc, type: 3}
+ - {fileID: 2800000, guid: 74aca53eb7273624baffc2bf5e5cc173, type: 3}
+ - {fileID: 2800000, guid: 729a3ae164bcb3b4380459386adcf331, type: 3}
+ - {fileID: 2800000, guid: 6dda07f1420a968449cf4c6620c44d9f, type: 3}
+ - {fileID: 2800000, guid: b7f000750830ddb4bbc80065b9314ce9, type: 3}
+ - {fileID: 2800000, guid: df01d03f056c6f445b4b8a0ae054207c, type: 3}
+ - {fileID: 2800000, guid: bfe953600e8fb1849a804ee08ace7b4c, type: 3}
+ - {fileID: 2800000, guid: 32c6a5f7143b86c44bd5cdee2ff3f8ad, type: 3}
+ - {fileID: 2800000, guid: f4b8ab78b57749d4e96d36f6d8a395d0, type: 3}
+ - {fileID: 2800000, guid: 09f6c01f98a3ded4daf1afc52a3c260f, type: 3}
+ - {fileID: 2800000, guid: bdd06fb88ef36ed4a85dd506352c2d80, type: 3}
+ - {fileID: 2800000, guid: 02c0a84bd64c6f044954d8bde9b46ec8, type: 3}
+ - {fileID: 2800000, guid: aa80dc44aa4fe4c43bb9d51d90cf2958, type: 3}
+ - {fileID: 2800000, guid: 0fa10b21877c61b4db40ba5708815f81, type: 3}
+ - {fileID: 2800000, guid: 6b0a189df0bd4d5448eaefb4e673ace8, type: 3}
+ - {fileID: 2800000, guid: 87a5e40cc271ea648b583616f6ebe7fe, type: 3}
+ - {fileID: 2800000, guid: b71bb466b71fd13449dd736f63caeb67, type: 3}
+ - {fileID: 2800000, guid: 319b8e66db3faa4438cf6982e9c89b2f, type: 3}
+ - {fileID: 2800000, guid: 0a79c155edf9b2d429d4736abee5acdb, type: 3}
+ - {fileID: 2800000, guid: 351e95d0e20a54849bd4ce5f9b498934, type: 3}
+ - {fileID: 2800000, guid: 1d6958e30e40a254dbe5a54c573eeb3c, type: 3}
+ - {fileID: 2800000, guid: 9660a4ca1ca8425408ac25c641932977, type: 3}
+ - {fileID: 2800000, guid: 547dbd5f858c74047ba3f213e4408307, type: 3}
+ - {fileID: 2800000, guid: 1a9ce5640cde5934aae0022f020464a6, type: 3}
+ - {fileID: 2800000, guid: cd9006dc442cc244e89b3f492384d46a, type: 3}
+ - {fileID: 2800000, guid: b266511438fae724f9d3ce6bd26583e8, type: 3}
+ - {fileID: 2800000, guid: 71bc1b6b66e8b784b972199b7e90204e, type: 3}
+ - {fileID: 2800000, guid: 15e54aa23a938444389469d53765d741, type: 3}
+ - {fileID: 2800000, guid: b9960364038cbfa4aa49d7b2032d3110, type: 3}
+ - {fileID: 2800000, guid: 8ecbbcae4cc747a4abbc4adce795d25e, type: 3}
+ - {fileID: 2800000, guid: 1378a33cdd085d64c9da863d2484ff21, type: 3}
+ - {fileID: 2800000, guid: aff59c63d25d43f4c938f248837c30fb, type: 3}
+ - {fileID: 2800000, guid: 3f7c3687170b90e4a8d2ee6b142670f4, type: 3}
+ - {fileID: 2800000, guid: d8c290e38ff0425409d0ae6a98c95e41, type: 3}
+ - {fileID: 2800000, guid: d5a51525b27e3ee4aadbeb39cbcf0750, type: 3}
+ - {fileID: 2800000, guid: d2e8e90fac2e6a341a38e1c3963c218d, type: 3}
+ - {fileID: 2800000, guid: c94b57b5a32a22d43ade66e09f6a4bd2, type: 3}
+ - {fileID: 2800000, guid: 936dea238abb0864ab3985a995e16a29, type: 3}
+ - {fileID: 2800000, guid: 5e542d0126a2c7848b66bffc428905fd, type: 3}
+ - {fileID: 2800000, guid: 70f23eaf7d8ae9147aa542d20e93733b, type: 3}
+ - {fileID: 2800000, guid: e138166e7a7c70f49943be7edda35d35, type: 3}
+ - {fileID: 2800000, guid: 85a45a6d8b2ffb84987d2b028ecfb220, type: 3}
+ - {fileID: 2800000, guid: d96974690c77f50489eb60ec84bd8dac, type: 3}
+ - {fileID: 2800000, guid: 404fa8def46b1c447817e1ebdaa7144e, type: 3}
+ - {fileID: 2800000, guid: 119591e0bb084e848835d237546b3882, type: 3}
+ - {fileID: 2800000, guid: a03c400b0e3959f428ee99dfc6cfc263, type: 3}
+ - {fileID: 2800000, guid: 4a11d65ce13d5f542a0ff136cc2f3fba, type: 3}
+ blueNoise256:
+ - {fileID: 2800000, guid: 6017f374382d64245a0a4aab668e6f38, type: 3}
+ - {fileID: 2800000, guid: 0f8fa14b3731cda4e947062e734d5e1e, type: 3}
+ - {fileID: 2800000, guid: 1abfe0e165ca1e9428b455ffc9a2d9ef, type: 3}
+ - {fileID: 2800000, guid: c072b653e98a06e40857d76ca8c7eecd, type: 3}
+ - {fileID: 2800000, guid: b52d5033b68309943a2386c270a90f44, type: 3}
+ - {fileID: 2800000, guid: acde5141d5f4f7a4188394bd52c4dc38, type: 3}
+ - {fileID: 2800000, guid: 999434725cbc2be4eb54043b36efd4a8, type: 3}
+ - {fileID: 2800000, guid: 70d0a1182b29d6347ac70374c3593bba, type: 3}
+ smaaLuts:
+ area: {fileID: 2800000, guid: 73ec4ae984a0a0f44a2be737e41a6f2f, type: 3}
+ search: {fileID: 2800000, guid: d99701099481a2f489610e977df6dcbc, type: 3}
+ shaders:
+ bloom: {fileID: 4800000, guid: c1e1d3119c6fd4646aea0b4b74cacc1a, type: 3}
+ copy: {fileID: 4800000, guid: cdbdb71de5f9c454b980f6d0e87f0afb, type: 3}
+ copyStd: {fileID: 4800000, guid: 4bf4cff0d0bac3d43894e2e8839feb40, type: 3}
+ copyStdFromTexArray: {fileID: 4800000, guid: 02d2da9bc88d25c4d878c1ed4e0b3854,
+ type: 3}
+ copyStdFromDoubleWide: {fileID: 4800000, guid: e8ce9961912f3214586fe8709b9012c1,
+ type: 3}
+ discardAlpha: {fileID: 4800000, guid: 5ab0816423f0dfe45841cab3b05ec9ef, type: 3}
+ depthOfField: {fileID: 4800000, guid: 0ef78d24e85a44f4da9d5b5eaa00e50b, type: 3}
+ finalPass: {fileID: 4800000, guid: f75014305794b3948a3c6d5ccd550e05, type: 3}
+ grainBaker: {fileID: 4800000, guid: 0d8afcb51cc9f0349a6d190da929b838, type: 3}
+ motionBlur: {fileID: 4800000, guid: 2c459b89a7c8b1a4fbefe0d81341651c, type: 3}
+ temporalAntialiasing: {fileID: 4800000, guid: 51bcf79c50dc92e47ba87821b61100c3,
+ type: 3}
+ subpixelMorphologicalAntialiasing: {fileID: 4800000, guid: 81af42a93ade3dd46a9b583d4eec76d6,
+ type: 3}
+ texture2dLerp: {fileID: 4800000, guid: 34a819c9e33402547a81619693adc8d5, type: 3}
+ uber: {fileID: 4800000, guid: 382151503e2a43a4ebb7366d1632731d, type: 3}
+ lut2DBaker: {fileID: 4800000, guid: 7ad194cbe7d006f4bace915156972026, type: 3}
+ lightMeter: {fileID: 4800000, guid: b34a29e523cb9d545881e193a079f2df, type: 3}
+ gammaHistogram: {fileID: 4800000, guid: f7ea35cfb33fcad4ab8f2429ec103bef, type: 3}
+ waveform: {fileID: 4800000, guid: 3020ac7ece79a7f4eb789a236f8bd6c5, type: 3}
+ vectorscope: {fileID: 4800000, guid: a71093f2a4fe26a40805c22739e10e4a, type: 3}
+ debugOverlays: {fileID: 4800000, guid: b958ad1c92bd3d64c9e61318b8681dab, type: 3}
+ deferredFog: {fileID: 4800000, guid: 4117fce9491711c4094d33a048e36e73, type: 3}
+ scalableAO: {fileID: 4800000, guid: d7640629310e79646af0f46eb55ae466, type: 3}
+ multiScaleAO: {fileID: 4800000, guid: 67f9497810829eb4791ec19e95781e51, type: 3}
+ screenSpaceReflections: {fileID: 4800000, guid: f997a3dc9254c44459323cced085150c,
+ type: 3}
+ computeShaders:
+ autoExposure: {fileID: 7200000, guid: 34845e0ca016b7448842e965db5890a5, type: 3}
+ exposureHistogram: {fileID: 7200000, guid: 8c2fcbdf9bc58664f89917f7b9d79501, type: 3}
+ lut3DBaker: {fileID: 7200000, guid: 42496b74c071f5749950ca1abe33e945, type: 3}
+ texture3dLerp: {fileID: 7200000, guid: 31e9175024adfd44aba2530ff9b77494, type: 3}
+ gammaHistogram: {fileID: 7200000, guid: 18183ebfeeab97749b43e38b928604a7, type: 3}
+ waveform: {fileID: 7200000, guid: 92c63830cd50c0b4fbb8233613839958, type: 3}
+ vectorscope: {fileID: 7200000, guid: e1efca7c36fd01840aae0dd10378de5c, type: 3}
+ multiScaleAODownsample1: {fileID: 7200000, guid: 4c63bc487e6c29a4a99f85a6c47b292b,
+ type: 3}
+ multiScaleAODownsample2: {fileID: 7200000, guid: e4d3e4779e48a374f91d48d4c0aedb7b,
+ type: 3}
+ multiScaleAORender: {fileID: 7200000, guid: 34a460e8a2e66c243a9c12024e5a798d,
+ type: 3}
+ multiScaleAOUpsample: {fileID: 7200000, guid: 600d6212b59bb40409d19d750b5fd1e9,
+ type: 3}
+ gaussianDownsample: {fileID: 7200000, guid: 6dba4103d23a7904fbc49099355aff3e,
+ type: 3}
+ namedShaders:
+ - name: FSR2/ffx_fsr2_compute_luminance_pyramid_pass
+ shader: {fileID: 7200000, guid: 0894ebeefb6aa7d4680c71dffbda3fee, type: 3}
+ - name: FSR2/ffx_fsr2_reconstruct_previous_depth_pass
+ shader: {fileID: 7200000, guid: 6ef1b4c25874e334dad5ba3ac6345e32, type: 3}
+ - name: FSR2/ffx_fsr2_depth_clip_pass
+ shader: {fileID: 7200000, guid: 8026d9d8542eab6499c32d5d46beb2b6, type: 3}
+ - name: FSR2/ffx_fsr2_lock_pass
+ shader: {fileID: 7200000, guid: 3c96d72b39a840c428c901628dab92c0, type: 3}
+ - name: FSR2/ffx_fsr2_accumulate_pass
+ shader: {fileID: 7200000, guid: 702560780e923c84394c9b22ba460a9c, type: 3}
+ - name: FSR2/ffx_fsr2_rcas_pass
+ shader: {fileID: 7200000, guid: 5a82801f160ff6a4eb47db567216e592, type: 3}
+ - name: FSR2/ffx_fsr2_autogen_reactive_pass
+ shader: {fileID: 7200000, guid: d18fb8811ca4753469c439784546104e, type: 3}
+ - name: FSR2/ffx_fsr2_tcr_autogen_pass
+ shader: {fileID: 7200000, guid: b478fba0a6a87b44b8be7c35deb5f0dc, type: 3}
diff --git a/com.unity.postprocessing/PostProcessing/PostProcessResources.asset.meta b/com.unity.postprocessing/PostProcessing/PostProcessResources.asset.meta
new file mode 100644
index 0000000..b8f940c
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/PostProcessResources.asset.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: d82512f9c8e5d4a4d938b575d47f88d4
+timeCreated: 1493713586
+licenseType: Pro
+NativeFormatImporter:
+ mainObjectFileID: 11400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime.meta b/com.unity.postprocessing/PostProcessing/Runtime.meta
new file mode 100644
index 0000000..b58a1ac
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 1bdda73de20b6a54592f998f94de3b64
+folderAsset: yes
+timeCreated: 1484302934
+licenseType: Pro
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Attributes.meta b/com.unity.postprocessing/PostProcessing/Runtime/Attributes.meta
new file mode 100644
index 0000000..b90a0f6
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Attributes.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 18b9eca2f52e6624db241af91bab06c9
+folderAsset: yes
+timeCreated: 1488204491
+licenseType: Pro
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Attributes/DisplayNameAttribute.cs b/com.unity.postprocessing/PostProcessing/Runtime/Attributes/DisplayNameAttribute.cs
new file mode 100644
index 0000000..1045b6b
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Attributes/DisplayNameAttribute.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// Use this attribute to change the label of a field displayed in the inspector.
+ ///
+ [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
+ public sealed class DisplayNameAttribute : Attribute
+ {
+ ///
+ /// The label displayed in the inspector.
+ ///
+ public readonly string displayName;
+
+ ///
+ /// Creates a new attribute.
+ ///
+ /// The label to display in the inspector
+ public DisplayNameAttribute(string displayName)
+ {
+ this.displayName = displayName;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Attributes/DisplayNameAttribute.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Attributes/DisplayNameAttribute.cs.meta
new file mode 100644
index 0000000..5422d69
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Attributes/DisplayNameAttribute.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 912e288507f1e724492c7c721fa1deb8
+timeCreated: 1493047701
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Attributes/MaxAttribute.cs b/com.unity.postprocessing/PostProcessing/Runtime/Attributes/MaxAttribute.cs
new file mode 100644
index 0000000..826879f
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Attributes/MaxAttribute.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// Use this attribute to clamp floating point values to a maximum value in the inspector.
+ ///
+ [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
+ public sealed class MaxAttribute : Attribute
+ {
+ ///
+ /// The maximum value the field will be clamped to.
+ ///
+ public readonly float max;
+
+ ///
+ /// Creates a new attribute.
+ ///
+ /// The maximum value the field will be clamped to
+ public MaxAttribute(float max)
+ {
+ this.max = max;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Attributes/MaxAttribute.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Attributes/MaxAttribute.cs.meta
new file mode 100644
index 0000000..06fe9c2
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Attributes/MaxAttribute.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 8c72b20f77adb59439f8eed4f25a950a
+timeCreated: 1493113243
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Attributes/MinAttribute.cs b/com.unity.postprocessing/PostProcessing/Runtime/Attributes/MinAttribute.cs
new file mode 100644
index 0000000..8a624f8
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Attributes/MinAttribute.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// Use this attribute to clamp floating point values to a minimum value in the inspector.
+ ///
+ [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
+ public sealed class MinAttribute : Attribute
+ {
+ ///
+ /// The minimum value the field will be clamped to.
+ ///
+ public readonly float min;
+
+ ///
+ /// Creates a new attribute.
+ ///
+ /// The minimum value the field will be clamped to
+ public MinAttribute(float min)
+ {
+ this.min = min;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Attributes/MinAttribute.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Attributes/MinAttribute.cs.meta
new file mode 100644
index 0000000..93d3ab3
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Attributes/MinAttribute.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 63007e9c3f71cad46a59f223a8b32d46
+timeCreated: 1493113232
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Attributes/MinMaxAttribute.cs b/com.unity.postprocessing/PostProcessing/Runtime/Attributes/MinMaxAttribute.cs
new file mode 100644
index 0000000..aa5d087
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Attributes/MinMaxAttribute.cs
@@ -0,0 +1,32 @@
+using System;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// Use this attribute to specify a range between a min and a max value.
+ ///
+ [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
+ public sealed class MinMaxAttribute : Attribute
+ {
+ ///
+ /// The minimum limit of the user defined range.
+ ///
+ public readonly float min;
+
+ ///
+ /// The maximum limit of the user defined range.
+ ///
+ public readonly float max;
+
+ ///
+ /// Creates a new attribute.
+ ///
+ /// The minimum limit of the user defined range
+ /// The maximum limit of the user defined range
+ public MinMaxAttribute(float min, float max)
+ {
+ this.min = min;
+ this.max = max;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Attributes/MinMaxAttribute.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Attributes/MinMaxAttribute.cs.meta
new file mode 100644
index 0000000..a0e5848
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Attributes/MinMaxAttribute.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 1d2cae9d8c54de04fab072666ddd1e57
+timeCreated: 1493113280
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Attributes/PostProcessAttribute.cs b/com.unity.postprocessing/PostProcessing/Runtime/Attributes/PostProcessAttribute.cs
new file mode 100644
index 0000000..0219249
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Attributes/PostProcessAttribute.cs
@@ -0,0 +1,60 @@
+using System;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// Use this attribute to associate a to a
+ /// type.
+ ///
+ ///
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
+ public sealed class PostProcessAttribute : Attribute
+ {
+ ///
+ /// The renderer type to associate with a .
+ ///
+ public readonly Type renderer;
+
+ ///
+ /// The injection point for the effect.
+ ///
+ public readonly PostProcessEvent eventType;
+
+ ///
+ /// The menu item name to set for the effect. You can use a `/` character to add sub-menus.
+ ///
+ public readonly string menuItem;
+
+ ///
+ /// Should this effect be allowed in the Scene View?
+ ///
+ public readonly bool allowInSceneView;
+
+ internal readonly bool builtinEffect;
+
+ ///
+ /// Creates a new attribute.
+ ///
+ /// The renderer type to associate with a
+ /// The injection point for the effect
+ /// The menu item name to set for the effect. You can use a `/` character to add sub-menus.
+ /// Should this effect be allowed in the Scene View?
+ public PostProcessAttribute(Type renderer, PostProcessEvent eventType, string menuItem, bool allowInSceneView = true)
+ {
+ this.renderer = renderer;
+ this.eventType = eventType;
+ this.menuItem = menuItem;
+ this.allowInSceneView = allowInSceneView;
+ builtinEffect = false;
+ }
+
+ internal PostProcessAttribute(Type renderer, string menuItem, bool allowInSceneView = true)
+ {
+ this.renderer = renderer;
+ this.menuItem = menuItem;
+ this.allowInSceneView = allowInSceneView;
+ builtinEffect = true;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Attributes/PostProcessAttribute.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Attributes/PostProcessAttribute.cs.meta
new file mode 100644
index 0000000..f189e4c
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Attributes/PostProcessAttribute.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 28cff9aae95df994e98129a9b35627de
+timeCreated: 1488204519
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Attributes/TrackballAttribute.cs b/com.unity.postprocessing/PostProcessing/Runtime/Attributes/TrackballAttribute.cs
new file mode 100644
index 0000000..f7c2a31
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Attributes/TrackballAttribute.cs
@@ -0,0 +1,52 @@
+using System;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// Use this attribute to draw a trackball in the inspector.
+ ///
+ [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
+ public sealed class TrackballAttribute : Attribute
+ {
+ ///
+ /// Trackball modes. These are used to compute and display pre-filtered trackball vales in
+ /// the inspector.
+ ///
+ public enum Mode
+ {
+ ///
+ /// Don't display pre-filtered values.
+ ///
+ None,
+
+ ///
+ /// Display pre-filtered lift values.
+ ///
+ Lift,
+
+ ///
+ /// Display pre-filtered gamma values.
+ ///
+ Gamma,
+
+ ///
+ /// Display pre-filtered grain values.
+ ///
+ Gain
+ }
+
+ ///
+ /// The mode used to display pre-filtered values in the inspector.
+ ///
+ public readonly Mode mode;
+
+ ///
+ /// Creates a new attribute.
+ ///
+ /// A mode used to display pre-filtered values in the inspector
+ public TrackballAttribute(Mode mode)
+ {
+ this.mode = mode;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Attributes/TrackballAttribute.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Attributes/TrackballAttribute.cs.meta
new file mode 100644
index 0000000..5efefc9
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Attributes/TrackballAttribute.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 44788f6e7bbf9174181bfe4689e66131
+timeCreated: 1493900877
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects.meta b/com.unity.postprocessing/PostProcessing/Runtime/Effects.meta
new file mode 100644
index 0000000..01457a5
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: d220742cb204f8e4e9fe5f7b1efa7b54
+folderAsset: yes
+timeCreated: 1487844780
+licenseType: Pro
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/AmbientOcclusion.cs b/com.unity.postprocessing/PostProcessing/Runtime/Effects/AmbientOcclusion.cs
new file mode 100644
index 0000000..9812775
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/AmbientOcclusion.cs
@@ -0,0 +1,282 @@
+using System;
+using UnityEngine.Experimental.Rendering;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// Ambient occlusion modes.
+ ///
+ public enum AmbientOcclusionMode
+ {
+ ///
+ /// A standard implementation of ambient obscurance that works on non modern platforms. If
+ /// you target a compute-enabled platform we recommend that you use
+ /// instead.
+ ///
+ ScalableAmbientObscurance,
+
+ ///
+ /// A modern version of ambient occlusion heavily optimized for consoles and desktop
+ /// platforms.
+ ///
+ MultiScaleVolumetricObscurance
+ }
+
+ ///
+ /// Quality settings for .
+ ///
+ public enum AmbientOcclusionQuality
+ {
+ ///
+ /// 4 samples + downsampling.
+ ///
+ Lowest,
+
+ ///
+ /// 6 samples + downsampling.
+ ///
+ Low,
+
+ ///
+ /// 10 samples + downsampling.
+ ///
+ Medium,
+
+ ///
+ /// 8 samples.
+ ///
+ High,
+
+ ///
+ /// 12 samples.
+ ///
+ Ultra
+ }
+
+ ///
+ /// A volume parameter holding a value.
+ ///
+ [Serializable]
+ public sealed class AmbientOcclusionModeParameter : ParameterOverride { }
+
+ ///
+ /// A volume parameter holding a value.
+ ///
+ [Serializable]
+ public sealed class AmbientOcclusionQualityParameter : ParameterOverride { }
+
+ ///
+ /// This class holds settings for the Ambient Occlusion effect.
+ ///
+ [Serializable]
+ [PostProcess(typeof(AmbientOcclusionRenderer), "Unity/Ambient Occlusion")]
+ public sealed class AmbientOcclusion : PostProcessEffectSettings
+ {
+ // Shared parameters
+
+ ///
+ /// The ambient occlusion method to use.
+ ///
+ [Tooltip("The ambient occlusion method to use. \"Multi Scale Volumetric Obscurance\" is higher quality and faster on desktop & console platforms but requires compute shader support.")]
+ public AmbientOcclusionModeParameter mode = new AmbientOcclusionModeParameter { value = AmbientOcclusionMode.MultiScaleVolumetricObscurance };
+
+ ///
+ /// The degree of darkness added by ambient occlusion.
+ ///
+ [Range(0f, 4f), Tooltip("The degree of darkness added by ambient occlusion. Higher values produce darker areas.")]
+ public FloatParameter intensity = new FloatParameter { value = 0f };
+
+ ///
+ /// A custom color to use for the ambient occlusion.
+ ///
+ [ColorUsage(false), Tooltip("The custom color to use for the ambient occlusion. The default is black.")]
+ public ColorParameter color = new ColorParameter { value = Color.black };
+
+ ///
+ /// Only affects ambient lighting. This mode is only available with the Deferred rendering
+ /// path and HDR rendering. Objects rendered with the Forward rendering path won't get any
+ /// ambient occlusion.
+ ///
+ [Tooltip("Check this box to mark this Volume as to only affect ambient lighting. This mode is only available with the Deferred rendering path and HDR rendering. Objects rendered with the Forward rendering path won't get any ambient occlusion.")]
+ public BoolParameter ambientOnly = new BoolParameter { value = true };
+
+ // MSVO-only parameters
+
+ ///
+ /// The tolerance of the noise filter to changes in the depth pyramid.
+ ///
+ [Range(-8f, 0f)]
+ public FloatParameter noiseFilterTolerance = new FloatParameter { value = 0f }; // Hidden
+
+ ///
+ /// The tolerance of the bilateral blur filter to depth changes.
+ ///
+ [Range(-8f, -1f)]
+ public FloatParameter blurTolerance = new FloatParameter { value = -4.6f }; // Hidden
+
+ ///
+ /// The tolerance of the upsampling pass to depth changes.
+ ///
+ [Range(-12f, -1f)]
+ public FloatParameter upsampleTolerance = new FloatParameter { value = -12f }; // Hidden
+
+ ///
+ /// Modifies the thickness of occluders. This increases dark areas but also introduces dark
+ /// halo around objects.
+ ///
+ [Range(1f, 10f), Tooltip("This modifies the thickness of occluders. It increases the size of dark areas and also introduces a dark halo around objects.")]
+ public FloatParameter thicknessModifier = new FloatParameter { value = 1f };
+
+ ///
+ /// Add a bias distance to sampled depth in AO to reduce self-shadowing aliasing artifacts.
+ ///
+ [Range(0f, 0.001f), Tooltip("Add a bias distance to sampled depth in AO to reduce self-shadowing aliasing artifacts. ")]
+ public FloatParameter zBias = new FloatParameter { value = 0.0001f };
+
+ // HDRP-only parameters
+
+ ///
+ /// Modifies he influence of direct lighting on ambient occlusion. This is only used in the
+ /// HD Render Pipeline currently.
+ ///
+ [Range(0f, 1f), Tooltip("Modifies the influence of direct lighting on ambient occlusion.")]
+ public FloatParameter directLightingStrength = new FloatParameter { value = 0f };
+
+ // SAO-only parameters
+
+ ///
+ /// Radius of sample points, which affects extent of darkened areas.
+ ///
+ [Tooltip("The radius of sample points. This affects the size of darkened areas.")]
+ public FloatParameter radius = new FloatParameter { value = 0.25f };
+
+ ///
+ /// The number of sample points, which affects quality and performance. Lowest, Low and Medium
+ /// passes are downsampled. High and Ultra are not and should only be used on high-end
+ /// hardware.
+ ///
+ [Tooltip("The number of sample points. This affects both quality and performance. For \"Lowest\", \"Low\", and \"Medium\", passes are downsampled. For \"High\" and \"Ultra\", they are not and therefore you should only \"High\" and \"Ultra\" on high-end hardware.")]
+ public AmbientOcclusionQualityParameter quality = new AmbientOcclusionQualityParameter { value = AmbientOcclusionQuality.Medium };
+
+ // SRPs can call this method without a context set (see HDRP).
+ // We need a better way to handle this than checking for a null context, context should
+ // never be null.
+
+ ///
+ /// Returns true if the effect is currently enabled and supported.
+ ///
+ /// The current post-processing render context
+ /// true if the effect is currently enabled and supported
+ public override bool IsEnabledAndSupported(PostProcessRenderContext context)
+ {
+ bool state = enabled.value
+ && intensity.value > 0f;
+
+ if (mode.value == AmbientOcclusionMode.ScalableAmbientObscurance)
+ {
+ state &= !RuntimeUtilities.scriptableRenderPipelineActive;
+
+ if (context != null)
+ {
+ state &= context.resources.shaders.scalableAO
+ && context.resources.shaders.scalableAO.isSupported;
+ }
+ }
+ else if (mode.value == AmbientOcclusionMode.MultiScaleVolumetricObscurance)
+ {
+ if (context != null)
+ {
+ state &= context.resources.shaders.multiScaleAO
+ && context.resources.shaders.multiScaleAO.isSupported
+ && context.resources.computeShaders.multiScaleAODownsample1
+ && context.resources.computeShaders.multiScaleAODownsample2
+ && context.resources.computeShaders.multiScaleAORender
+ && context.resources.computeShaders.multiScaleAOUpsample;
+ }
+
+ state &= SystemInfo.supportsComputeShaders
+ && !RuntimeUtilities.isAndroidOpenGL
+#if UNITY_2023_2_OR_NEWER
+ && SystemInfo.IsFormatSupported(GraphicsFormat.R32_SFloat, GraphicsFormatUsage.Render | GraphicsFormatUsage.Sparse)
+ && SystemInfo.IsFormatSupported(GraphicsFormat.R16_SFloat, GraphicsFormatUsage.Render | GraphicsFormatUsage.Sparse)
+ && SystemInfo.IsFormatSupported(GraphicsFormat.R8_UNorm, GraphicsFormatUsage.Render | GraphicsFormatUsage.Sparse);
+#else
+ && SystemInfo.IsFormatSupported(GraphicsFormat.R32_SFloat, FormatUsage.Render)
+ && SystemInfo.IsFormatSupported(GraphicsFormat.R32_SFloat, FormatUsage.Sparse)
+ && SystemInfo.IsFormatSupported(GraphicsFormat.R16_SFloat, FormatUsage.Render)
+ && SystemInfo.IsFormatSupported(GraphicsFormat.R16_SFloat, FormatUsage.Sparse)
+ && SystemInfo.IsFormatSupported(GraphicsFormat.R8_UNorm, FormatUsage.Render)
+ && SystemInfo.IsFormatSupported(GraphicsFormat.R8_UNorm, FormatUsage.Sparse);
+#endif
+ }
+
+ return state;
+ }
+ }
+
+ internal interface IAmbientOcclusionMethod
+ {
+ DepthTextureMode GetCameraFlags();
+ void RenderAfterOpaque(PostProcessRenderContext context);
+ void RenderAmbientOnly(PostProcessRenderContext context);
+ void CompositeAmbientOnly(PostProcessRenderContext context);
+ void Release();
+ }
+
+ [UnityEngine.Scripting.Preserve]
+ internal sealed class AmbientOcclusionRenderer : PostProcessEffectRenderer
+ {
+ IAmbientOcclusionMethod[] m_Methods;
+
+ public override void Init()
+ {
+ if (m_Methods == null)
+ {
+ m_Methods = new IAmbientOcclusionMethod[]
+ {
+ new ScalableAO(settings),
+ new MultiScaleVO(settings),
+ };
+ }
+ }
+
+ public bool IsAmbientOnly(PostProcessRenderContext context)
+ {
+ var camera = context.camera;
+ return settings.ambientOnly.value
+ && camera.actualRenderingPath == RenderingPath.DeferredShading
+ && camera.allowHDR;
+ }
+
+ public IAmbientOcclusionMethod Get()
+ {
+ return m_Methods[(int)settings.mode.value];
+ }
+
+ public override DepthTextureMode GetCameraFlags()
+ {
+ return Get().GetCameraFlags();
+ }
+
+ public override void Release()
+ {
+ foreach (var m in m_Methods)
+ m.Release();
+ }
+
+ public ScalableAO GetScalableAO()
+ {
+ return (ScalableAO)m_Methods[(int)AmbientOcclusionMode.ScalableAmbientObscurance];
+ }
+
+ public MultiScaleVO GetMultiScaleVO()
+ {
+ return (MultiScaleVO)m_Methods[(int)AmbientOcclusionMode.MultiScaleVolumetricObscurance];
+ }
+
+ // Unused
+ public override void Render(PostProcessRenderContext context)
+ {
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/AmbientOcclusion.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Effects/AmbientOcclusion.cs.meta
new file mode 100644
index 0000000..940bb4b
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/AmbientOcclusion.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: c1cb7e9e120078f43bce4f0b1be547a7
+timeCreated: 1498493415
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/AutoExposure.cs b/com.unity.postprocessing/PostProcessing/Runtime/Effects/AutoExposure.cs
new file mode 100644
index 0000000..79b8696
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/AutoExposure.cs
@@ -0,0 +1,201 @@
+using System;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// Eye adaptation modes.
+ ///
+ public enum EyeAdaptation
+ {
+ ///
+ /// Progressive (smooth) eye adaptation.
+ ///
+ Progressive,
+
+ ///
+ /// Fixed (instant) eye adaptation.
+ ///
+ Fixed
+ }
+
+ ///
+ /// A volume parameter holding a value.
+ ///
+ [Serializable]
+ public sealed class EyeAdaptationParameter : ParameterOverride { }
+
+ ///
+ /// This class holds settings for the Auto Exposure effect.
+ ///
+ [Serializable]
+ [PostProcess(typeof(AutoExposureRenderer), "Unity/Auto Exposure")]
+ public sealed class AutoExposure : PostProcessEffectSettings
+ {
+ ///
+ /// These values are the lower and upper percentages of the histogram that will be used to
+ /// find a stable average luminance. Values outside of this range will be discarded and wont
+ /// contribute to the average luminance.
+ ///
+ [MinMax(1f, 99f), DisplayName("Filtering (%)"), Tooltip("Filters the bright and dark parts of the histogram when computing the average luminance. This is to avoid very dark pixels and very bright pixels from contributing to the auto exposure. Unit is in percent.")]
+ public Vector2Parameter filtering = new Vector2Parameter { value = new Vector2(50f, 95f) };
+
+ ///
+ /// Minimum average luminance to consider for auto exposure (in EV).
+ ///
+ [Range(LogHistogram.rangeMin, LogHistogram.rangeMax), DisplayName("Minimum (EV)"), Tooltip("Minimum average luminance to consider for auto exposure. Unit is EV.")]
+ public FloatParameter minLuminance = new FloatParameter { value = 0f };
+
+ ///
+ /// Maximum average luminance to consider for auto exposure (in EV).
+ ///
+ [Range(LogHistogram.rangeMin, LogHistogram.rangeMax), DisplayName("Maximum (EV)"), Tooltip("Maximum average luminance to consider for auto exposure. Unit is EV.")]
+ public FloatParameter maxLuminance = new FloatParameter { value = 0f };
+
+ ///
+ /// Middle-grey value. Use this to compensate the global exposure of the scene.
+ ///
+ [Min(0f), DisplayName("Exposure Compensation"), Tooltip("Use this to scale the global exposure of the scene.")]
+ public FloatParameter keyValue = new FloatParameter { value = 1f };
+
+ ///
+ /// The type of eye adaptation to use.
+ ///
+ [DisplayName("Type"), Tooltip("Use \"Progressive\" if you want auto exposure to be animated. Use \"Fixed\" otherwise.")]
+ public EyeAdaptationParameter eyeAdaptation = new EyeAdaptationParameter { value = EyeAdaptation.Progressive };
+
+ ///
+ /// The adaptation speed from a dark to a light environment.
+ ///
+ [Min(0f), Tooltip("Adaptation speed from a dark to a light environment.")]
+ public FloatParameter speedUp = new FloatParameter { value = 2f };
+
+ ///
+ /// The adaptation speed from a light to a dark environment.
+ ///
+ [Min(0f), Tooltip("Adaptation speed from a light to a dark environment.")]
+ public FloatParameter speedDown = new FloatParameter { value = 1f };
+
+ ///
+ /// Returns true if the effect is currently enabled and supported.
+ ///
+ /// The current post-processing render context
+ /// true if the effect is currently enabled and supported
+ public override bool IsEnabledAndSupported(PostProcessRenderContext context)
+ {
+ return enabled.value
+ && SystemInfo.supportsComputeShaders
+ && !RuntimeUtilities.isAndroidOpenGL
+ && RenderTextureFormat.RFloat.IsSupported()
+ && context.resources.computeShaders.autoExposure
+ && context.resources.computeShaders.exposureHistogram;
+ }
+ }
+
+ [UnityEngine.Scripting.Preserve]
+ internal sealed class AutoExposureRenderer : PostProcessEffectRenderer
+ {
+ const int k_NumEyes = 2;
+ const int k_NumAutoExposureTextures = 2;
+
+ readonly RenderTexture[][] m_AutoExposurePool = new RenderTexture[k_NumEyes][];
+ int[] m_AutoExposurePingPong = new int[k_NumEyes];
+ RenderTexture m_CurrentAutoExposure;
+
+ public AutoExposureRenderer()
+ {
+ for (int eye = 0; eye < k_NumEyes; eye++)
+ {
+ m_AutoExposurePool[eye] = new RenderTexture[k_NumAutoExposureTextures];
+ m_AutoExposurePingPong[eye] = 0;
+ }
+ }
+
+ void CheckTexture(int eye, int id)
+ {
+ if (m_AutoExposurePool[eye][id] == null || !m_AutoExposurePool[eye][id].IsCreated())
+ {
+ m_AutoExposurePool[eye][id] = new RenderTexture(1, 1, 0, RenderTextureFormat.RFloat) { enableRandomWrite = true };
+ m_AutoExposurePool[eye][id].Create();
+ }
+ }
+
+ public override void Render(PostProcessRenderContext context)
+ {
+ var cmd = context.command;
+ cmd.BeginSample("AutoExposureLookup");
+
+ // Prepare autoExpo texture pool
+ CheckTexture(context.xrActiveEye, 0);
+ CheckTexture(context.xrActiveEye, 1);
+
+ // Make sure filtering values are correct to avoid apocalyptic consequences
+ float lowPercent = settings.filtering.value.x;
+ float highPercent = settings.filtering.value.y;
+ const float kMinDelta = 1e-2f;
+ highPercent = Mathf.Clamp(highPercent, 1f + kMinDelta, 99f);
+ lowPercent = Mathf.Clamp(lowPercent, 1f, highPercent - kMinDelta);
+
+ // Clamp min/max adaptation values as well
+ float minLum = settings.minLuminance.value;
+ float maxLum = settings.maxLuminance.value;
+ settings.minLuminance.value = Mathf.Min(minLum, maxLum);
+ settings.maxLuminance.value = Mathf.Max(minLum, maxLum);
+
+ // Compute average luminance & auto exposure
+ bool firstFrame = m_ResetHistory || !Application.isPlaying;
+ string adaptation = null;
+
+ if (firstFrame || settings.eyeAdaptation.value == EyeAdaptation.Fixed)
+ adaptation = "KAutoExposureAvgLuminance_fixed";
+ else
+ adaptation = "KAutoExposureAvgLuminance_progressive";
+
+ var compute = context.resources.computeShaders.autoExposure;
+ int kernel = compute.FindKernel(adaptation);
+ cmd.SetComputeBufferParam(compute, kernel, "_HistogramBuffer", context.logHistogram.data);
+ cmd.SetComputeVectorParam(compute, "_Params1", new Vector4(lowPercent * 0.01f, highPercent * 0.01f, RuntimeUtilities.Exp2(settings.minLuminance.value), RuntimeUtilities.Exp2(settings.maxLuminance.value)));
+ cmd.SetComputeVectorParam(compute, "_Params2", new Vector4(settings.speedDown.value, settings.speedUp.value, settings.keyValue.value, Time.deltaTime));
+ cmd.SetComputeVectorParam(compute, "_ScaleOffsetRes", context.logHistogram.GetHistogramScaleOffsetRes(context));
+
+ if (firstFrame)
+ {
+ // We don't want eye adaptation when not in play mode because the GameView isn't
+ // animated, thus making it harder to tweak. Just use the final audo exposure value.
+ m_CurrentAutoExposure = m_AutoExposurePool[context.xrActiveEye][0];
+ cmd.SetComputeTextureParam(compute, kernel, "_Destination", m_CurrentAutoExposure);
+ cmd.DispatchCompute(compute, kernel, 1, 1, 1);
+
+ // Copy current exposure to the other pingpong target to avoid adapting from black
+ RuntimeUtilities.CopyTexture(cmd, m_AutoExposurePool[context.xrActiveEye][0], m_AutoExposurePool[context.xrActiveEye][1]);
+ m_ResetHistory = false;
+ }
+ else
+ {
+ int pp = m_AutoExposurePingPong[context.xrActiveEye];
+ var src = m_AutoExposurePool[context.xrActiveEye][++pp % 2];
+ var dst = m_AutoExposurePool[context.xrActiveEye][++pp % 2];
+
+ cmd.SetComputeTextureParam(compute, kernel, "_Source", src);
+ cmd.SetComputeTextureParam(compute, kernel, "_Destination", dst);
+ cmd.DispatchCompute(compute, kernel, 1, 1, 1);
+
+ m_AutoExposurePingPong[context.xrActiveEye] = ++pp % 2;
+ m_CurrentAutoExposure = dst;
+ }
+
+ cmd.EndSample("AutoExposureLookup");
+
+ context.autoExposureTexture = m_CurrentAutoExposure;
+ context.autoExposure = settings;
+ }
+
+ public override void Release()
+ {
+ foreach (var rtEyeSet in m_AutoExposurePool)
+ {
+ foreach (var rt in rtEyeSet)
+ RuntimeUtilities.Destroy(rt);
+ }
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/AutoExposure.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Effects/AutoExposure.cs.meta
new file mode 100644
index 0000000..4ada827
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/AutoExposure.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: b3f6f3f7c722b4544b97e3c75840aa33
+timeCreated: 1491826543
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/Bloom.cs b/com.unity.postprocessing/PostProcessing/Runtime/Effects/Bloom.cs
new file mode 100644
index 0000000..8f230f4
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/Bloom.cs
@@ -0,0 +1,274 @@
+using System;
+using UnityEngine.Serialization;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ // For now and by popular request, this bloom effect is geared toward artists so they have full
+ // control over how it looks at the expense of physical correctness.
+ // Eventually we will need a "true" natural bloom effect with proper energy conservation.
+
+ ///
+ /// This class holds settings for the Bloom effect.
+ ///
+ [Serializable]
+ [PostProcess(typeof(BloomRenderer), "Unity/Bloom")]
+ public sealed class Bloom : PostProcessEffectSettings
+ {
+ ///
+ /// The strength of the bloom filter.
+ ///
+ [Min(0f), Tooltip("Strength of the bloom filter. Values higher than 1 will make bloom contribute more energy to the final render.")]
+ public FloatParameter intensity = new FloatParameter { value = 0f };
+
+ ///
+ /// Filters out pixels under this level of brightness. This value is expressed in
+ /// gamma-space.
+ ///
+ [Min(0f), Tooltip("Filters out pixels under this level of brightness. Value is in gamma-space.")]
+ public FloatParameter threshold = new FloatParameter { value = 1f };
+
+ ///
+ /// Makes transition between under/over-threshold gradual (0 = hard threshold, 1 = soft
+ /// threshold).
+ ///
+ [Range(0f, 1f), Tooltip("Makes transitions between under/over-threshold gradual. 0 for a hard threshold, 1 for a soft threshold).")]
+ public FloatParameter softKnee = new FloatParameter { value = 0.5f };
+
+ ///
+ /// Clamps pixels to control the bloom amount. This value is expressed in gamma-space.
+ ///
+ [Tooltip("Clamps pixels to control the bloom amount. Value is in gamma-space.")]
+ public FloatParameter clamp = new FloatParameter { value = 65472f };
+
+ ///
+ /// Changes extent of veiling effects in a screen resolution-independent fashion. For
+ /// maximum quality stick to integer values. Because this value changes the internal
+ /// iteration count, animating it isn't recommended as it may introduce small hiccups in
+ /// the perceived radius.
+ ///
+ [Range(1f, 10f), Tooltip("Changes the extent of veiling effects. For maximum quality, use integer values. Because this value changes the internal iteration count, You should not animating it as it may introduce issues with the perceived radius.")]
+ public FloatParameter diffusion = new FloatParameter { value = 7f };
+
+ ///
+ /// Distorts the bloom to give an anamorphic look. Negative values distort vertically,
+ /// positive values distort horizontally.
+ ///
+ [Range(-1f, 1f), Tooltip("Distorts the bloom to give an anamorphic look. Negative values distort vertically, positive values distort horizontally.")]
+ public FloatParameter anamorphicRatio = new FloatParameter { value = 0f };
+
+ ///
+ /// The tint of the Bloom filter.
+ ///
+#if UNITY_2018_1_OR_NEWER
+ [ColorUsage(false, true), Tooltip("Global tint of the bloom filter.")]
+#else
+ [ColorUsage(false, true, 0f, 8f, 0.125f, 3f), Tooltip("Global tint of the bloom filter.")]
+#endif
+ public ColorParameter color = new ColorParameter { value = Color.white };
+
+ ///
+ /// Boost performances by lowering the effect quality.
+ ///
+ [FormerlySerializedAs("mobileOptimized")]
+ [Tooltip("Boost performance by lowering the effect quality. This settings is meant to be used on mobile and other low-end platforms but can also provide a nice performance boost on desktops and consoles.")]
+ public BoolParameter fastMode = new BoolParameter { value = false };
+
+ ///
+ /// The dirtiness texture to add smudges or dust to the lens.
+ ///
+ [Tooltip("The lens dirt texture used to add smudges or dust to the bloom effect."), DisplayName("Texture")]
+ public TextureParameter dirtTexture = new TextureParameter { value = null };
+
+ ///
+ /// The amount of lens dirtiness.
+ ///
+ [Min(0f), Tooltip("The intensity of the lens dirtiness."), DisplayName("Intensity")]
+ public FloatParameter dirtIntensity = new FloatParameter { value = 0f };
+
+ ///
+ /// Returns true if the effect is currently enabled and supported.
+ ///
+ /// The current post-processing render context
+ /// true if the effect is currently enabled and supported
+ public override bool IsEnabledAndSupported(PostProcessRenderContext context)
+ {
+ return enabled.value
+ && intensity.value > 0f;
+ }
+ }
+
+ [UnityEngine.Scripting.Preserve]
+ internal sealed class BloomRenderer : PostProcessEffectRenderer
+ {
+ enum Pass
+ {
+ Prefilter13,
+ Prefilter4,
+ Downsample13,
+ Downsample4,
+ UpsampleTent,
+ UpsampleBox,
+ DebugOverlayThreshold,
+ DebugOverlayTent,
+ DebugOverlayBox
+ }
+
+ // [down,up]
+ Level[] m_Pyramid;
+ const int k_MaxPyramidSize = 16; // Just to make sure we handle 64k screens... Future-proof!
+
+ struct Level
+ {
+ internal int down;
+ internal int up;
+ }
+
+ public override void Init()
+ {
+ m_Pyramid = new Level[k_MaxPyramidSize];
+
+ for (int i = 0; i < k_MaxPyramidSize; i++)
+ {
+ m_Pyramid[i] = new Level
+ {
+ down = Shader.PropertyToID("_BloomMipDown" + i),
+ up = Shader.PropertyToID("_BloomMipUp" + i)
+ };
+ }
+ }
+
+ public override void Render(PostProcessRenderContext context)
+ {
+ var cmd = context.command;
+ cmd.BeginSample("BloomPyramid");
+
+ var sheet = context.propertySheets.Get(context.resources.shaders.bloom);
+
+ // Apply auto exposure adjustment in the prefiltering pass
+ sheet.properties.SetTexture(ShaderIDs.AutoExposureTex, context.autoExposureTexture);
+
+ // Negative anamorphic ratio values distort vertically - positive is horizontal
+ float ratio = Mathf.Clamp(settings.anamorphicRatio, -1, 1);
+ float rw = ratio < 0 ? -ratio : 0f;
+ float rh = ratio > 0 ? ratio : 0f;
+
+ // Do bloom on a half-res buffer, full-res doesn't bring much and kills performances on
+ // fillrate limited platforms
+ int tw = Mathf.FloorToInt(context.screenWidth / (2f - rw));
+ int th = Mathf.FloorToInt(context.screenHeight / (2f - rh));
+ bool singlePassDoubleWide = (context.stereoActive && (context.stereoRenderingMode == PostProcessRenderContext.StereoRenderingMode.SinglePass) && (context.camera.stereoTargetEye == StereoTargetEyeMask.Both));
+ int tw_stereo = singlePassDoubleWide ? tw * 2 : tw;
+
+ // Determine the iteration count
+ int s = Mathf.Max(tw, th);
+ float logs = Mathf.Log(s, 2f) + Mathf.Min(settings.diffusion.value, 10f) - 10f;
+ int logs_i = Mathf.FloorToInt(logs);
+ int iterations = Mathf.Clamp(logs_i, 1, k_MaxPyramidSize);
+ float sampleScale = 0.5f + logs - logs_i;
+ sheet.properties.SetFloat(ShaderIDs.SampleScale, sampleScale);
+
+ // Prefiltering parameters
+ float lthresh = Mathf.GammaToLinearSpace(settings.threshold.value);
+ float knee = lthresh * settings.softKnee.value + 1e-5f;
+ var threshold = new Vector4(lthresh, lthresh - knee, knee * 2f, 0.25f / knee);
+ sheet.properties.SetVector(ShaderIDs.Threshold, threshold);
+ float lclamp = Mathf.GammaToLinearSpace(settings.clamp.value);
+ sheet.properties.SetVector(ShaderIDs.Params, new Vector4(lclamp, 0f, 0f, 0f));
+
+ int qualityOffset = settings.fastMode ? 1 : 0;
+
+ // Downsample
+ var lastDown = context.source;
+ for (int i = 0; i < iterations; i++)
+ {
+ int mipDown = m_Pyramid[i].down;
+ int mipUp = m_Pyramid[i].up;
+ int pass = i == 0
+ ? (int)Pass.Prefilter13 + qualityOffset
+ : (int)Pass.Downsample13 + qualityOffset;
+
+ context.GetScreenSpaceTemporaryRT(cmd, mipDown, 0, context.sourceFormat, RenderTextureReadWrite.Default, FilterMode.Bilinear, tw_stereo, th);
+ context.GetScreenSpaceTemporaryRT(cmd, mipUp, 0, context.sourceFormat, RenderTextureReadWrite.Default, FilterMode.Bilinear, tw_stereo, th);
+ cmd.BlitFullscreenTriangle(lastDown, mipDown, sheet, pass);
+
+ lastDown = mipDown;
+ tw_stereo = (singlePassDoubleWide && ((tw_stereo / 2) % 2 > 0)) ? 1 + tw_stereo / 2 : tw_stereo / 2;
+ tw_stereo = Mathf.Max(tw_stereo, 1);
+ th = Mathf.Max(th / 2, 1);
+ }
+
+ // Upsample
+ int lastUp = m_Pyramid[iterations - 1].down;
+ for (int i = iterations - 2; i >= 0; i--)
+ {
+ int mipDown = m_Pyramid[i].down;
+ int mipUp = m_Pyramid[i].up;
+ cmd.SetGlobalTexture(ShaderIDs.BloomTex, mipDown);
+ cmd.BlitFullscreenTriangle(lastUp, mipUp, sheet, (int)Pass.UpsampleTent + qualityOffset);
+ lastUp = mipUp;
+ }
+
+ var linearColor = settings.color.value.linear;
+ float intensity = RuntimeUtilities.Exp2(settings.intensity.value / 10f) - 1f;
+ var shaderSettings = new Vector4(sampleScale, intensity, settings.dirtIntensity.value, iterations);
+
+ // Debug overlays
+ if (context.IsDebugOverlayEnabled(DebugOverlay.BloomThreshold))
+ {
+ context.PushDebugOverlay(cmd, context.source, sheet, (int)Pass.DebugOverlayThreshold);
+ }
+ else if (context.IsDebugOverlayEnabled(DebugOverlay.BloomBuffer))
+ {
+ sheet.properties.SetVector(ShaderIDs.ColorIntensity, new Vector4(linearColor.r, linearColor.g, linearColor.b, intensity));
+ context.PushDebugOverlay(cmd, m_Pyramid[0].up, sheet, (int)Pass.DebugOverlayTent + qualityOffset);
+ }
+
+ // Lens dirtiness
+ // Keep the aspect ratio correct & center the dirt texture, we don't want it to be
+ // stretched or squashed
+ var dirtTexture = settings.dirtTexture.value == null
+ ? RuntimeUtilities.blackTexture
+ : settings.dirtTexture.value;
+
+ var dirtRatio = (float)dirtTexture.width / (float)dirtTexture.height;
+ var screenRatio = (float)context.screenWidth / (float)context.screenHeight;
+ var dirtTileOffset = new Vector4(1f, 1f, 0f, 0f);
+
+ if (dirtRatio > screenRatio)
+ {
+ dirtTileOffset.x = screenRatio / dirtRatio;
+ dirtTileOffset.z = (1f - dirtTileOffset.x) * 0.5f;
+ }
+ else if (screenRatio > dirtRatio)
+ {
+ dirtTileOffset.y = dirtRatio / screenRatio;
+ dirtTileOffset.w = (1f - dirtTileOffset.y) * 0.5f;
+ }
+
+ // Shader properties
+ var uberSheet = context.uberSheet;
+ if (settings.fastMode)
+ uberSheet.EnableKeyword("BLOOM_LOW");
+ else
+ uberSheet.EnableKeyword("BLOOM");
+ uberSheet.properties.SetVector(ShaderIDs.Bloom_DirtTileOffset, dirtTileOffset);
+ uberSheet.properties.SetVector(ShaderIDs.Bloom_Settings, shaderSettings);
+ uberSheet.properties.SetColor(ShaderIDs.Bloom_Color, linearColor);
+ uberSheet.properties.SetTexture(ShaderIDs.Bloom_DirtTex, dirtTexture);
+ cmd.SetGlobalTexture(ShaderIDs.BloomTex, lastUp);
+
+ // Cleanup
+ for (int i = 0; i < iterations; i++)
+ {
+ if (m_Pyramid[i].down != lastUp)
+ cmd.ReleaseTemporaryRT(m_Pyramid[i].down);
+ if (m_Pyramid[i].up != lastUp)
+ cmd.ReleaseTemporaryRT(m_Pyramid[i].up);
+ }
+
+ cmd.EndSample("BloomPyramid");
+
+ context.bloomBufferNameID = lastUp;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/Bloom.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Effects/Bloom.cs.meta
new file mode 100644
index 0000000..aa52d21
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/Bloom.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 48a79b01ea5641d4aa6daa2e23605641
+timeCreated: 1491826542
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/ChromaticAberration.cs b/com.unity.postprocessing/PostProcessing/Runtime/Effects/ChromaticAberration.cs
new file mode 100644
index 0000000..ee93909
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/ChromaticAberration.cs
@@ -0,0 +1,101 @@
+using System;
+using UnityEngine.Serialization;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// This class holds settings for the Chromatic Aberration effect.
+ ///
+ [Serializable]
+ [PostProcess(typeof(ChromaticAberrationRenderer), "Unity/Chromatic Aberration")]
+ public sealed class ChromaticAberration : PostProcessEffectSettings
+ {
+ ///
+ /// A texture used for custom fringing color (it will use a default one when null).
+ ///
+ [Tooltip("Shifts the hue of chromatic aberrations.")]
+ public TextureParameter spectralLut = new TextureParameter { value = null };
+
+ ///
+ /// The amount of tangential distortion.
+ ///
+ [Range(0f, 1f), Tooltip("Amount of tangential distortion.")]
+ public FloatParameter intensity = new FloatParameter { value = 0f };
+
+ ///
+ /// If true, it will use a faster variant of the effect for improved performances.
+ ///
+ [FormerlySerializedAs("mobileOptimized")]
+ [Tooltip("Boost performances by lowering the effect quality. This settings is meant to be used on mobile and other low-end platforms but can also provide a nice performance boost on desktops and consoles.")]
+ public BoolParameter fastMode = new BoolParameter { value = false };
+
+ ///
+ /// Returns true if the effect is currently enabled and supported.
+ ///
+ /// The current post-processing render context
+ /// true if the effect is currently enabled and supported
+ public override bool IsEnabledAndSupported(PostProcessRenderContext context)
+ {
+ return enabled.value
+ && intensity.value > 0f;
+ }
+ }
+
+ [UnityEngine.Scripting.Preserve]
+ internal sealed class ChromaticAberrationRenderer : PostProcessEffectRenderer
+ {
+ Texture2D m_InternalSpectralLut;
+
+ public override void Render(PostProcessRenderContext context)
+ {
+ var spectralLut = settings.spectralLut.value;
+
+ if (spectralLut == null)
+ {
+ if (m_InternalSpectralLut == null)
+ {
+ m_InternalSpectralLut = new Texture2D(3, 1, TextureFormat.RGB24, false)
+ {
+ name = "Chromatic Aberration Spectrum Lookup",
+ filterMode = FilterMode.Bilinear,
+ wrapMode = TextureWrapMode.Clamp,
+ anisoLevel = 0,
+ hideFlags = HideFlags.DontSave
+ };
+
+ m_InternalSpectralLut.SetPixels(new[]
+ {
+ new Color(1f, 0f, 0f),
+ new Color(0f, 1f, 0f),
+ new Color(0f, 0f, 1f)
+ });
+
+ m_InternalSpectralLut.Apply();
+ }
+
+ spectralLut = m_InternalSpectralLut;
+ }
+
+ var sheet = context.uberSheet;
+ bool fastMode = settings.fastMode
+#if !UNITY_2023_1_OR_NEWER
+ || SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLES2;
+#else
+ ;
+#endif
+
+ sheet.EnableKeyword(fastMode
+ ? "CHROMATIC_ABERRATION_LOW"
+ : "CHROMATIC_ABERRATION"
+ );
+ sheet.properties.SetFloat(ShaderIDs.ChromaticAberration_Amount, settings.intensity * 0.05f);
+ sheet.properties.SetTexture(ShaderIDs.ChromaticAberration_SpectralLut, spectralLut);
+ }
+
+ public override void Release()
+ {
+ RuntimeUtilities.Destroy(m_InternalSpectralLut);
+ m_InternalSpectralLut = null;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/ChromaticAberration.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Effects/ChromaticAberration.cs.meta
new file mode 100644
index 0000000..f3ff2b8
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/ChromaticAberration.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 6050e2d5de785ce4d931e4dbdbf2d755
+timeCreated: 1491826543
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/ColorGrading.cs b/com.unity.postprocessing/PostProcessing/Runtime/Effects/ColorGrading.cs
new file mode 100644
index 0000000..481530b
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/ColorGrading.cs
@@ -0,0 +1,849 @@
+using System;
+
+using UnityEngine.Experimental.Rendering;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// Color grading modes.
+ ///
+ public enum GradingMode
+ {
+ ///
+ /// This mode is aimed at lower-end platforms but it can be used on any platform. Grading is
+ /// applied to the final rendered frame clamped in a [0,1] range and stored in a standard
+ /// LUT.
+ ///
+ LowDefinitionRange,
+
+ ///
+ /// This mode is aimed at platforms that support HDR rendering. All the color operations
+ /// will be applied in HDR and stored into a 3D log-encoded LUT to ensure a sufficient range
+ /// coverage and precision (Alexa LogC El1000).
+ ///
+ HighDefinitionRange,
+
+ ///
+ /// This mode allows you to provide a custom 3D LUT authored in an external software.
+ ///
+ External
+ }
+
+ ///
+ /// Tonemapping methods.
+ ///
+ public enum Tonemapper
+ {
+ ///
+ /// No tonemapping will be applied.
+ ///
+ None,
+
+ ///
+ /// This method only does range-remapping with minimal impact on color hue & saturation and
+ /// is generally a great starting point for extensive color grading.
+ ///
+ Neutral,
+
+ ///
+ /// This method uses a close approximation of the reference ACES tonemapper for a more
+ /// filmic look. Because of that, it is more contrasted than and has
+ /// an effect on actual color hue & saturation. Note that if you enable this tonemapper all
+ /// the grading operations will be done in the ACES color spaces for optimal precision and
+ /// results.
+ ///
+ ACES,
+
+ ///
+ /// This method offers a fully parametric, artist-friendly tonemapper.
+ ///
+ Custom
+ }
+
+ ///
+ /// A volume parameter holding a value.
+ ///
+ [Serializable]
+ public sealed class GradingModeParameter : ParameterOverride { }
+
+ ///
+ /// A volume parameter holding a value.
+ ///
+ [Serializable]
+ public sealed class TonemapperParameter : ParameterOverride { }
+
+ ///
+ /// This class holds settings for the Color Grading effect.
+ ///
+ // TODO: Could use some refactoring, too much duplicated code here
+ [Serializable]
+ [PostProcess(typeof(ColorGradingRenderer), "Unity/Color Grading")]
+ public sealed class ColorGrading : PostProcessEffectSettings
+ {
+ ///
+ /// The grading mode to use.
+ ///
+ [DisplayName("Mode"), Tooltip("Select a color grading mode that fits your dynamic range and workflow. Use HDR if your camera is set to render in HDR and your target platform supports it. Use LDR for low-end mobiles or devices that don't support HDR. Use External if you prefer authoring a Log LUT in an external software.")]
+ public GradingModeParameter gradingMode = new GradingModeParameter { value = GradingMode.HighDefinitionRange };
+
+ ///
+ /// A custom 3D log-encoded texture.
+ ///
+ ///
+ /// This is only used when working with .
+ ///
+ [DisplayName("Lookup Texture"), Tooltip("A custom 3D log-encoded texture.")]
+ public TextureParameter externalLut = new TextureParameter { value = null };
+
+ ///
+ /// The tonemapping algorithm to use at the end of the color grading process.
+ ///
+ ///
+ /// This is only used when working with .
+ ///
+ [DisplayName("Mode"), Tooltip("Select a tonemapping algorithm to use at the end of the color grading process.")]
+ public TonemapperParameter tonemapper = new TonemapperParameter { value = Tonemapper.None };
+
+ ///
+ /// Affects the transition between the toe and the mid section of the curve. A value of 0
+ /// means no toe, a value of 1 means a very hard transition.
+ ///
+ ///
+ /// This is only used when is active.
+ ///
+ [DisplayName("Toe Strength"), Range(0f, 1f), Tooltip("Affects the transition between the toe and the mid section of the curve. A value of 0 means no toe, a value of 1 means a very hard transition.")]
+ public FloatParameter toneCurveToeStrength = new FloatParameter { value = 0f };
+
+ ///
+ /// Affects how much of the dynamic range is in the toe. With a small value, the toe will be
+ /// very short and quickly transition into the linear section, and with a longer value
+ /// having a longer toe.
+ ///
+ ///
+ /// This is only used when is active.
+ ///
+ [DisplayName("Toe Length"), Range(0f, 1f), Tooltip("Affects how much of the dynamic range is in the toe. With a small value, the toe will be very short and quickly transition into the linear section, with a larger value, the toe will be longer.")]
+ public FloatParameter toneCurveToeLength = new FloatParameter { value = 0.5f };
+
+ ///
+ /// Affects the transition between the mid section and the shoulder of the curve. A value of
+ /// 0 means no shoulder, value of 1 means a very hard transition.
+ ///
+ ///
+ /// This is only used when is active.
+ ///
+ [DisplayName("Shoulder Strength"), Range(0f, 1f), Tooltip("Affects the transition between the mid section and the shoulder of the curve. A value of 0 means no shoulder, a value of 1 means a very hard transition.")]
+ public FloatParameter toneCurveShoulderStrength = new FloatParameter { value = 0f };
+
+ ///
+ /// Affects how many F-stops (EV) to add to the dynamic range of the curve.
+ ///
+ ///
+ /// This is only used when is active.
+ ///
+ [DisplayName("Shoulder Length"), Min(0f), Tooltip("Affects how many F-stops (EV) to add to the dynamic range of the curve.")]
+ public FloatParameter toneCurveShoulderLength = new FloatParameter { value = 0.5f };
+
+ ///
+ /// Affects how much overshot to add to the shoulder.
+ ///
+ ///
+ /// This is only used when is active.
+ ///
+ [DisplayName("Shoulder Angle"), Range(0f, 1f), Tooltip("Affects how much overshoot to add to the shoulder.")]
+ public FloatParameter toneCurveShoulderAngle = new FloatParameter { value = 0f };
+
+ ///
+ /// Applies a gamma function to the curve.
+ ///
+ ///
+ /// This is only used when is active.
+ ///
+ [DisplayName("Gamma"), Min(0.001f), Tooltip("Applies a gamma function to the curve.")]
+ public FloatParameter toneCurveGamma = new FloatParameter { value = 1f };
+
+ ///
+ /// A custom lookup texture (strip format, e.g. 256x16) to apply before the rest of the
+ /// color grading operators. If none is provided, a neutral one will be generated
+ /// internally.
+ ///
+ ///
+ /// This is only used when working with .
+ ///
+ [DisplayName("Lookup Texture"), Tooltip("Custom lookup texture (strip format, for example 256x16) to apply before the rest of the color grading operators. If none is provided, a neutral one will be generated internally.")]
+ public TextureParameter ldrLut = new TextureParameter { value = null, defaultState = TextureParameterDefault.Lut2D }; // LDR only
+
+ ///
+ /// How much of the lookup texture will contribute to the color grading.
+ ///
+ ///
+ /// This is only used when working with .
+ ///
+ [DisplayName("Contribution"), Range(0f, 1f), Tooltip("How much of the lookup texture will contribute to the color grading effect.")]
+ public FloatParameter ldrLutContribution = new FloatParameter { value = 1f };
+
+ ///
+ /// Sets the white balance to a custom color temperature.
+ ///
+ [DisplayName("Temperature"), Range(-100f, 100f), Tooltip("Sets the white balance to a custom color temperature.")]
+ public FloatParameter temperature = new FloatParameter { value = 0f };
+
+ ///
+ /// Sets the white balance to compensate for a green or magenta tint.
+ ///
+ [DisplayName("Tint"), Range(-100f, 100f), Tooltip("Sets the white balance to compensate for a green or magenta tint.")]
+ public FloatParameter tint = new FloatParameter { value = 0f };
+
+ ///
+ /// Tints the render by multiplying a color.
+ ///
+#if UNITY_2018_1_OR_NEWER
+ [DisplayName("Color Filter"), ColorUsage(false, true), Tooltip("Tint the render by multiplying a color.")]
+#else
+ [DisplayName("Color Filter"), ColorUsage(false, true, 0f, 8f, 0.125f, 3f), Tooltip("Tint the render by multiplying a color.")]
+#endif
+ public ColorParameter colorFilter = new ColorParameter { value = Color.white };
+
+ ///
+ /// Shifts the hue of all colors.
+ ///
+ [DisplayName("Hue Shift"), Range(-180f, 180f), Tooltip("Shift the hue of all colors.")]
+ public FloatParameter hueShift = new FloatParameter { value = 0f };
+
+ ///
+ /// Pushes the intensity of all colors.
+ ///
+ [DisplayName("Saturation"), Range(-100f, 100f), Tooltip("Pushes the intensity of all colors.")]
+ public FloatParameter saturation = new FloatParameter { value = 0f };
+
+ ///
+ /// Makes the image brighter or darker.
+ ///
+ ///
+ /// This is only used when working with .
+ ///
+ [DisplayName("Brightness"), Range(-100f, 100f), Tooltip("Makes the image brighter or darker.")]
+ public FloatParameter brightness = new FloatParameter { value = 0f }; // LDR only
+
+ ///
+ /// Adjusts the overall exposure of the scene in EV units. This is applied after HDR effect
+ /// and right before tonemapping so it won't affect previous effects in the chain.
+ ///
+ ///
+ /// This is only used when working with .
+ ///
+ [DisplayName("Post-exposure (EV)"), Tooltip("Adjusts the overall exposure of the scene in EV units. This is applied after the HDR effect and right before tonemapping so it won't affect previous effects in the chain.")]
+ public FloatParameter postExposure = new FloatParameter { value = 0f }; // HDR only
+
+ ///
+ /// Expands or shrinks the overall range of tonal values.
+ ///
+ [DisplayName("Contrast"), Range(-100f, 100f), Tooltip("Expands or shrinks the overall range of tonal values.")]
+ public FloatParameter contrast = new FloatParameter { value = 0f };
+
+ ///
+ /// Modifies the influence of the red channel within the overall mix.
+ ///
+ [DisplayName("Red"), Range(-200f, 200f), Tooltip("Modify influence of the red channel in the overall mix.")]
+ public FloatParameter mixerRedOutRedIn = new FloatParameter { value = 100f };
+
+ ///
+ /// Modifies the influence of the green channel within the overall mix.
+ ///
+ [DisplayName("Green"), Range(-200f, 200f), Tooltip("Modify influence of the green channel in the overall mix.")]
+ public FloatParameter mixerRedOutGreenIn = new FloatParameter { value = 0f };
+
+ ///
+ /// Modifies the influence of the blue channel within the overall mix.
+ ///
+ [DisplayName("Blue"), Range(-200f, 200f), Tooltip("Modify influence of the blue channel in the overall mix.")]
+ public FloatParameter mixerRedOutBlueIn = new FloatParameter { value = 0f };
+
+ ///
+ /// Modifies the influence of the red channel within the overall mix.
+ ///
+ [DisplayName("Red"), Range(-200f, 200f), Tooltip("Modify influence of the red channel in the overall mix.")]
+ public FloatParameter mixerGreenOutRedIn = new FloatParameter { value = 0f };
+
+ ///
+ /// Modifies the influence of the green channel within the overall mix.
+ ///
+ [DisplayName("Green"), Range(-200f, 200f), Tooltip("Modify influence of the green channel in the overall mix.")]
+ public FloatParameter mixerGreenOutGreenIn = new FloatParameter { value = 100f };
+
+ ///
+ /// Modifies the influence of the blue channel within the overall mix.
+ ///
+ [DisplayName("Blue"), Range(-200f, 200f), Tooltip("Modify influence of the blue channel in the overall mix.")]
+ public FloatParameter mixerGreenOutBlueIn = new FloatParameter { value = 0f };
+
+ ///
+ /// Modifies the influence of the red channel within the overall mix.
+ ///
+ [DisplayName("Red"), Range(-200f, 200f), Tooltip("Modify influence of the red channel in the overall mix.")]
+ public FloatParameter mixerBlueOutRedIn = new FloatParameter { value = 0f };
+
+ ///
+ /// Modifies the influence of the green channel within the overall mix.
+ ///
+ [DisplayName("Green"), Range(-200f, 200f), Tooltip("Modify influence of the green channel in the overall mix.")]
+ public FloatParameter mixerBlueOutGreenIn = new FloatParameter { value = 0f };
+
+ ///
+ /// Modifies the influence of the blue channel within the overall mix.
+ ///
+ [DisplayName("Blue"), Range(-200f, 200f), Tooltip("Modify influence of the blue channel in the overall mix.")]
+ public FloatParameter mixerBlueOutBlueIn = new FloatParameter { value = 100f };
+
+ ///
+ /// Controls the darkest portions of the render.
+ ///
+ ///
+ /// The neutral value is (1, 1, 1, 0).
+ ///
+ [DisplayName("Lift"), Tooltip("Controls the darkest portions of the render."), Trackball(TrackballAttribute.Mode.Lift)]
+ public Vector4Parameter lift = new Vector4Parameter { value = new Vector4(1f, 1f, 1f, 0f) };
+
+ ///
+ /// A power function that controls mid-range tones.
+ ///
+ ///
+ /// The neutral value is (1, 1, 1, 0).
+ ///
+ [DisplayName("Gamma"), Tooltip("Power function that controls mid-range tones."), Trackball(TrackballAttribute.Mode.Gamma)]
+ public Vector4Parameter gamma = new Vector4Parameter { value = new Vector4(1f, 1f, 1f, 0f) };
+
+ ///
+ /// Controls the lightest portions of the render.
+ ///
+ ///
+ /// The neutral value is (1, 1, 1, 0).
+ ///
+ [DisplayName("Gain"), Tooltip("Controls the lightest portions of the render."), Trackball(TrackballAttribute.Mode.Gain)]
+ public Vector4Parameter gain = new Vector4Parameter { value = new Vector4(1f, 1f, 1f, 0f) };
+
+ ///
+ /// Remaps the luminosity values.
+ ///
+ ///
+ /// This is only used when working with .
+ ///
+ public SplineParameter masterCurve = new SplineParameter { value = new Spline(new AnimationCurve(new Keyframe(0f, 0f, 1f, 1f), new Keyframe(1f, 1f, 1f, 1f)), 0f, false, new Vector2(0f, 1f)) };
+
+ ///
+ /// Remaps the red channel.
+ ///
+ ///
+ /// This is only used when working with .
+ ///
+ public SplineParameter redCurve = new SplineParameter { value = new Spline(new AnimationCurve(new Keyframe(0f, 0f, 1f, 1f), new Keyframe(1f, 1f, 1f, 1f)), 0f, false, new Vector2(0f, 1f)) };
+
+ ///
+ /// Remaps the green channel/
+ ///
+ ///
+ /// This is only used when working with .
+ ///
+ public SplineParameter greenCurve = new SplineParameter { value = new Spline(new AnimationCurve(new Keyframe(0f, 0f, 1f, 1f), new Keyframe(1f, 1f, 1f, 1f)), 0f, false, new Vector2(0f, 1f)) };
+
+ ///
+ /// Remaps the blue channel.
+ ///
+ ///
+ /// This is only used when working with .
+ ///
+ public SplineParameter blueCurve = new SplineParameter { value = new Spline(new AnimationCurve(new Keyframe(0f, 0f, 1f, 1f), new Keyframe(1f, 1f, 1f, 1f)), 0f, false, new Vector2(0f, 1f)) };
+
+ ///
+ /// Remaps the hue according to the current hue.
+ ///
+ public SplineParameter hueVsHueCurve = new SplineParameter { value = new Spline(new AnimationCurve(), 0.5f, true, new Vector2(0f, 1f)) };
+
+ ///
+ /// Remaps the saturation according to the current hue.
+ ///
+ public SplineParameter hueVsSatCurve = new SplineParameter { value = new Spline(new AnimationCurve(), 0.5f, true, new Vector2(0f, 1f)) };
+
+ ///
+ /// Remaps the saturation according to the current saturation.
+ ///
+ public SplineParameter satVsSatCurve = new SplineParameter { value = new Spline(new AnimationCurve(), 0.5f, false, new Vector2(0f, 1f)) };
+
+ ///
+ /// Remaps the saturation according to the current luminance.
+ ///
+ public SplineParameter lumVsSatCurve = new SplineParameter { value = new Spline(new AnimationCurve(), 0.5f, false, new Vector2(0f, 1f)) };
+
+ ///
+ /// Returns true if the effect is currently enabled and supported.
+ ///
+ /// The current post-processing render context
+ /// true if the effect is currently enabled and supported
+ public override bool IsEnabledAndSupported(PostProcessRenderContext context)
+ {
+ if (gradingMode.value == GradingMode.External)
+ {
+ if (!SystemInfo.supports3DRenderTextures || !SystemInfo.supportsComputeShaders)
+ return false;
+ }
+
+ return enabled.value;
+ }
+ }
+
+ [UnityEngine.Scripting.Preserve]
+ internal sealed class ColorGradingRenderer : PostProcessEffectRenderer
+ {
+ enum Pass
+ {
+ LutGenLDRFromScratch,
+ LutGenLDR,
+ LutGenHDR2D
+ }
+
+ Texture2D m_GradingCurves;
+ readonly Color[] m_Pixels = new Color[Spline.k_Precision * 2]; // Avoids GC stress
+
+ RenderTexture m_InternalLdrLut;
+ RenderTexture m_InternalLogLut;
+ const int k_Lut2DSize = 32;
+ const int k_Lut3DSize = 33;
+
+ readonly HableCurve m_HableCurve = new HableCurve();
+
+ public override void Render(PostProcessRenderContext context)
+ {
+ var gradingMode = settings.gradingMode.value;
+ var supportComputeTex3D = SystemInfo.supports3DRenderTextures
+ && SystemInfo.supportsComputeShaders
+ && context.resources.computeShaders.lut3DBaker != null
+ && SystemInfo.graphicsDeviceType != GraphicsDeviceType.OpenGLCore
+ && SystemInfo.graphicsDeviceType != GraphicsDeviceType.OpenGLES3;
+
+ if (gradingMode == GradingMode.External)
+ RenderExternalPipeline3D(context);
+ else if (gradingMode == GradingMode.HighDefinitionRange && supportComputeTex3D)
+ RenderHDRPipeline3D(context);
+ else if (gradingMode == GradingMode.HighDefinitionRange)
+ RenderHDRPipeline2D(context);
+ else
+ RenderLDRPipeline2D(context);
+ }
+
+ // Do color grading using an externally authored 3D lut; it requires Texture3D support and
+ // compute shaders in case blending is required - Desktop / Consoles / Some high-end mobiles
+ void RenderExternalPipeline3D(PostProcessRenderContext context)
+ {
+ var lut = settings.externalLut.value;
+
+ if (lut == null)
+ return;
+
+ var uberSheet = context.uberSheet;
+ uberSheet.EnableKeyword("COLOR_GRADING_HDR_3D");
+ uberSheet.properties.SetTexture(ShaderIDs.Lut3D, lut);
+ uberSheet.properties.SetVector(ShaderIDs.Lut3D_Params, new Vector2(1f / lut.width, lut.width - 1f));
+ uberSheet.properties.SetFloat(ShaderIDs.PostExposure, RuntimeUtilities.Exp2(settings.postExposure.value));
+ context.logLut = lut;
+ }
+
+ // HDR color pipeline is rendered to a 3D lut; it requires Texture3D & compute shaders
+ // support - Desktop / Consoles / Some high-end mobiles
+ // TODO: Use ShaderIDs for compute once the compatible APIs go in
+ void RenderHDRPipeline3D(PostProcessRenderContext context)
+ {
+ // Unfortunately because AnimationCurve doesn't implement GetHashCode and we don't have
+ // any reliable way to figure out if a curve data is different from another one we can't
+ // skip regenerating the Lut if nothing has changed. So it has to be done on every
+ // frame...
+ // It's not a very expensive operation anyway (we're talking about filling a 33x33x33
+ // Lut on the GPU) but every little thing helps, especially on mobile.
+ {
+ CheckInternalLogLut();
+
+ // Lut setup
+ var compute = context.resources.computeShaders.lut3DBaker;
+ int kernel = 0;
+
+ switch (settings.tonemapper.value)
+ {
+ case Tonemapper.None:
+ kernel = compute.FindKernel("KGenLut3D_NoTonemap");
+ break;
+ case Tonemapper.Neutral:
+ kernel = compute.FindKernel("KGenLut3D_NeutralTonemap");
+ break;
+ case Tonemapper.ACES:
+ kernel = compute.FindKernel("KGenLut3D_AcesTonemap");
+ break;
+ case Tonemapper.Custom:
+ kernel = compute.FindKernel("KGenLut3D_CustomTonemap");
+ break;
+ }
+
+ var cmd = context.command;
+ cmd.SetComputeTextureParam(compute, kernel, "_Output", m_InternalLogLut);
+ cmd.SetComputeVectorParam(compute, "_Size", new Vector4(k_Lut3DSize, 1f / (k_Lut3DSize - 1f), 0f, 0f));
+
+ var colorBalance = ColorUtilities.ComputeColorBalance(settings.temperature.value, settings.tint.value);
+ cmd.SetComputeVectorParam(compute, "_ColorBalance", colorBalance);
+ cmd.SetComputeVectorParam(compute, "_ColorFilter", settings.colorFilter.value);
+
+ float hue = settings.hueShift.value / 360f; // Remap to [-0.5;0.5]
+ float sat = settings.saturation.value / 100f + 1f; // Remap to [0;2]
+ float con = settings.contrast.value / 100f + 1f; // Remap to [0;2]
+ cmd.SetComputeVectorParam(compute, "_HueSatCon", new Vector4(hue, sat, con, 0f));
+
+ var channelMixerR = new Vector4(settings.mixerRedOutRedIn, settings.mixerRedOutGreenIn, settings.mixerRedOutBlueIn, 0f);
+ var channelMixerG = new Vector4(settings.mixerGreenOutRedIn, settings.mixerGreenOutGreenIn, settings.mixerGreenOutBlueIn, 0f);
+ var channelMixerB = new Vector4(settings.mixerBlueOutRedIn, settings.mixerBlueOutGreenIn, settings.mixerBlueOutBlueIn, 0f);
+ cmd.SetComputeVectorParam(compute, "_ChannelMixerRed", channelMixerR / 100f); // Remap to [-2;2]
+ cmd.SetComputeVectorParam(compute, "_ChannelMixerGreen", channelMixerG / 100f);
+ cmd.SetComputeVectorParam(compute, "_ChannelMixerBlue", channelMixerB / 100f);
+
+ var lift = ColorUtilities.ColorToLift(settings.lift.value * 0.2f);
+ var gain = ColorUtilities.ColorToGain(settings.gain.value * 0.8f);
+ var invgamma = ColorUtilities.ColorToInverseGamma(settings.gamma.value * 0.8f);
+ cmd.SetComputeVectorParam(compute, "_Lift", new Vector4(lift.x, lift.y, lift.z, 0f));
+ cmd.SetComputeVectorParam(compute, "_InvGamma", new Vector4(invgamma.x, invgamma.y, invgamma.z, 0f));
+ cmd.SetComputeVectorParam(compute, "_Gain", new Vector4(gain.x, gain.y, gain.z, 0f));
+
+ cmd.SetComputeTextureParam(compute, kernel, "_Curves", GetCurveTexture(true));
+
+ if (settings.tonemapper.value == Tonemapper.Custom)
+ {
+ m_HableCurve.Init(
+ settings.toneCurveToeStrength.value,
+ settings.toneCurveToeLength.value,
+ settings.toneCurveShoulderStrength.value,
+ settings.toneCurveShoulderLength.value,
+ settings.toneCurveShoulderAngle.value,
+ settings.toneCurveGamma.value
+ );
+
+ cmd.SetComputeVectorParam(compute, "_CustomToneCurve", m_HableCurve.uniforms.curve);
+ cmd.SetComputeVectorParam(compute, "_ToeSegmentA", m_HableCurve.uniforms.toeSegmentA);
+ cmd.SetComputeVectorParam(compute, "_ToeSegmentB", m_HableCurve.uniforms.toeSegmentB);
+ cmd.SetComputeVectorParam(compute, "_MidSegmentA", m_HableCurve.uniforms.midSegmentA);
+ cmd.SetComputeVectorParam(compute, "_MidSegmentB", m_HableCurve.uniforms.midSegmentB);
+ cmd.SetComputeVectorParam(compute, "_ShoSegmentA", m_HableCurve.uniforms.shoSegmentA);
+ cmd.SetComputeVectorParam(compute, "_ShoSegmentB", m_HableCurve.uniforms.shoSegmentB);
+ }
+
+ // Generate the lut
+ context.command.BeginSample("HdrColorGradingLut3D");
+ int groupSize = Mathf.CeilToInt(k_Lut3DSize / 4f);
+ cmd.DispatchCompute(compute, kernel, groupSize, groupSize, groupSize);
+ context.command.EndSample("HdrColorGradingLut3D");
+ }
+
+ var lut = m_InternalLogLut;
+ var uberSheet = context.uberSheet;
+ uberSheet.EnableKeyword("COLOR_GRADING_HDR_3D");
+ uberSheet.properties.SetTexture(ShaderIDs.Lut3D, lut);
+ uberSheet.properties.SetVector(ShaderIDs.Lut3D_Params, new Vector2(1f / lut.width, lut.width - 1f));
+ uberSheet.properties.SetFloat(ShaderIDs.PostExposure, RuntimeUtilities.Exp2(settings.postExposure.value));
+
+ context.logLut = lut;
+ }
+
+ // HDR color pipeline is rendered to a 2D strip lut (works on HDR platforms without compute
+ // and 3D texture support). Precision is sliiiiiiightly lower than when using a 3D texture
+ // LUT (33^3 -> 32^3) but most of the time it's imperceptible.
+ void RenderHDRPipeline2D(PostProcessRenderContext context)
+ {
+ // For the same reasons as in RenderHDRPipeline3D, regen LUT on every frame
+ {
+ CheckInternalStripLut();
+
+ // Lut setup
+ var lutSheet = context.propertySheets.Get(context.resources.shaders.lut2DBaker);
+ lutSheet.ClearKeywords();
+
+ lutSheet.properties.SetVector(ShaderIDs.Lut2D_Params, new Vector4(k_Lut2DSize, 0.5f / (k_Lut2DSize * k_Lut2DSize), 0.5f / k_Lut2DSize, k_Lut2DSize / (k_Lut2DSize - 1f)));
+
+ var colorBalance = ColorUtilities.ComputeColorBalance(settings.temperature.value, settings.tint.value);
+ lutSheet.properties.SetVector(ShaderIDs.ColorBalance, colorBalance);
+ lutSheet.properties.SetVector(ShaderIDs.ColorFilter, settings.colorFilter.value);
+
+ float hue = settings.hueShift.value / 360f; // Remap to [-0.5;0.5]
+ float sat = settings.saturation.value / 100f + 1f; // Remap to [0;2]
+ float con = settings.contrast.value / 100f + 1f; // Remap to [0;2]
+ lutSheet.properties.SetVector(ShaderIDs.HueSatCon, new Vector3(hue, sat, con));
+
+ var channelMixerR = new Vector3(settings.mixerRedOutRedIn, settings.mixerRedOutGreenIn, settings.mixerRedOutBlueIn);
+ var channelMixerG = new Vector3(settings.mixerGreenOutRedIn, settings.mixerGreenOutGreenIn, settings.mixerGreenOutBlueIn);
+ var channelMixerB = new Vector3(settings.mixerBlueOutRedIn, settings.mixerBlueOutGreenIn, settings.mixerBlueOutBlueIn);
+ lutSheet.properties.SetVector(ShaderIDs.ChannelMixerRed, channelMixerR / 100f); // Remap to [-2;2]
+ lutSheet.properties.SetVector(ShaderIDs.ChannelMixerGreen, channelMixerG / 100f);
+ lutSheet.properties.SetVector(ShaderIDs.ChannelMixerBlue, channelMixerB / 100f);
+
+ var lift = ColorUtilities.ColorToLift(settings.lift.value * 0.2f);
+ var gain = ColorUtilities.ColorToGain(settings.gain.value * 0.8f);
+ var invgamma = ColorUtilities.ColorToInverseGamma(settings.gamma.value * 0.8f);
+ lutSheet.properties.SetVector(ShaderIDs.Lift, lift);
+ lutSheet.properties.SetVector(ShaderIDs.InvGamma, invgamma);
+ lutSheet.properties.SetVector(ShaderIDs.Gain, gain);
+
+ lutSheet.properties.SetTexture(ShaderIDs.Curves, GetCurveTexture(true));
+
+ var tonemapper = settings.tonemapper.value;
+ if (tonemapper == Tonemapper.Custom)
+ {
+ lutSheet.EnableKeyword("TONEMAPPING_CUSTOM");
+
+ m_HableCurve.Init(
+ settings.toneCurveToeStrength.value,
+ settings.toneCurveToeLength.value,
+ settings.toneCurveShoulderStrength.value,
+ settings.toneCurveShoulderLength.value,
+ settings.toneCurveShoulderAngle.value,
+ settings.toneCurveGamma.value
+ );
+
+ lutSheet.properties.SetVector(ShaderIDs.CustomToneCurve, m_HableCurve.uniforms.curve);
+ lutSheet.properties.SetVector(ShaderIDs.ToeSegmentA, m_HableCurve.uniforms.toeSegmentA);
+ lutSheet.properties.SetVector(ShaderIDs.ToeSegmentB, m_HableCurve.uniforms.toeSegmentB);
+ lutSheet.properties.SetVector(ShaderIDs.MidSegmentA, m_HableCurve.uniforms.midSegmentA);
+ lutSheet.properties.SetVector(ShaderIDs.MidSegmentB, m_HableCurve.uniforms.midSegmentB);
+ lutSheet.properties.SetVector(ShaderIDs.ShoSegmentA, m_HableCurve.uniforms.shoSegmentA);
+ lutSheet.properties.SetVector(ShaderIDs.ShoSegmentB, m_HableCurve.uniforms.shoSegmentB);
+ }
+ else if (tonemapper == Tonemapper.ACES)
+ lutSheet.EnableKeyword("TONEMAPPING_ACES");
+ else if (tonemapper == Tonemapper.Neutral)
+ lutSheet.EnableKeyword("TONEMAPPING_NEUTRAL");
+
+ // Generate the lut
+ context.command.BeginSample("HdrColorGradingLut2D");
+ context.command.BlitFullscreenTriangle(BuiltinRenderTextureType.None, m_InternalLdrLut, lutSheet, (int)Pass.LutGenHDR2D);
+ context.command.EndSample("HdrColorGradingLut2D");
+ }
+
+ var lut = m_InternalLdrLut;
+ var uberSheet = context.uberSheet;
+ uberSheet.EnableKeyword("COLOR_GRADING_HDR_2D");
+ uberSheet.properties.SetVector(ShaderIDs.Lut2D_Params, new Vector3(1f / lut.width, 1f / lut.height, lut.height - 1f));
+ uberSheet.properties.SetTexture(ShaderIDs.Lut2D, lut);
+ uberSheet.properties.SetFloat(ShaderIDs.PostExposure, RuntimeUtilities.Exp2(settings.postExposure.value));
+ }
+
+ // LDR color pipeline is rendered to a 2D strip lut (works on every platform)
+ void RenderLDRPipeline2D(PostProcessRenderContext context)
+ {
+ // For the same reasons as in RenderHDRPipeline3D, regen LUT on every frame
+ {
+ CheckInternalStripLut();
+
+ // Lut setup
+ var lutSheet = context.propertySheets.Get(context.resources.shaders.lut2DBaker);
+ lutSheet.ClearKeywords();
+
+ lutSheet.properties.SetVector(ShaderIDs.Lut2D_Params, new Vector4(k_Lut2DSize, 0.5f / (k_Lut2DSize * k_Lut2DSize), 0.5f / k_Lut2DSize, k_Lut2DSize / (k_Lut2DSize - 1f)));
+
+ var colorBalance = ColorUtilities.ComputeColorBalance(settings.temperature.value, settings.tint.value);
+ lutSheet.properties.SetVector(ShaderIDs.ColorBalance, colorBalance);
+ lutSheet.properties.SetVector(ShaderIDs.ColorFilter, settings.colorFilter.value);
+
+ float hue = settings.hueShift.value / 360f; // Remap to [-0.5;0.5]
+ float sat = settings.saturation.value / 100f + 1f; // Remap to [0;2]
+ float con = settings.contrast.value / 100f + 1f; // Remap to [0;2]
+ lutSheet.properties.SetVector(ShaderIDs.HueSatCon, new Vector3(hue, sat, con));
+
+ var channelMixerR = new Vector3(settings.mixerRedOutRedIn, settings.mixerRedOutGreenIn, settings.mixerRedOutBlueIn);
+ var channelMixerG = new Vector3(settings.mixerGreenOutRedIn, settings.mixerGreenOutGreenIn, settings.mixerGreenOutBlueIn);
+ var channelMixerB = new Vector3(settings.mixerBlueOutRedIn, settings.mixerBlueOutGreenIn, settings.mixerBlueOutBlueIn);
+ lutSheet.properties.SetVector(ShaderIDs.ChannelMixerRed, channelMixerR / 100f); // Remap to [-2;2]
+ lutSheet.properties.SetVector(ShaderIDs.ChannelMixerGreen, channelMixerG / 100f);
+ lutSheet.properties.SetVector(ShaderIDs.ChannelMixerBlue, channelMixerB / 100f);
+
+ var lift = ColorUtilities.ColorToLift(settings.lift.value);
+ var gain = ColorUtilities.ColorToGain(settings.gain.value);
+ var invgamma = ColorUtilities.ColorToInverseGamma(settings.gamma.value);
+ lutSheet.properties.SetVector(ShaderIDs.Lift, lift);
+ lutSheet.properties.SetVector(ShaderIDs.InvGamma, invgamma);
+ lutSheet.properties.SetVector(ShaderIDs.Gain, gain);
+
+ lutSheet.properties.SetFloat(ShaderIDs.Brightness, (settings.brightness.value + 100f) / 100f);
+ lutSheet.properties.SetTexture(ShaderIDs.Curves, GetCurveTexture(false));
+
+ // Generate the lut
+ context.command.BeginSample("LdrColorGradingLut2D");
+
+ var userLut = settings.ldrLut.value;
+ if (userLut == null || userLut.width != userLut.height * userLut.height)
+ {
+ context.command.BlitFullscreenTriangle(BuiltinRenderTextureType.None, m_InternalLdrLut, lutSheet, (int)Pass.LutGenLDRFromScratch);
+ }
+ else
+ {
+ lutSheet.properties.SetVector(ShaderIDs.UserLut2D_Params, new Vector4(1f / userLut.width, 1f / userLut.height, userLut.height - 1f, settings.ldrLutContribution));
+ context.command.BlitFullscreenTriangle(userLut, m_InternalLdrLut, lutSheet, (int)Pass.LutGenLDR);
+ }
+
+ context.command.EndSample("LdrColorGradingLut2D");
+ }
+
+ var lut = m_InternalLdrLut;
+ var uberSheet = context.uberSheet;
+ uberSheet.EnableKeyword("COLOR_GRADING_LDR_2D");
+ uberSheet.properties.SetVector(ShaderIDs.Lut2D_Params, new Vector3(1f / lut.width, 1f / lut.height, lut.height - 1f));
+ uberSheet.properties.SetTexture(ShaderIDs.Lut2D, lut);
+ }
+
+ void CheckInternalLogLut()
+ {
+ // Check internal lut state, (re)create it if needed
+ if (m_InternalLogLut == null || !m_InternalLogLut.IsCreated())
+ {
+ RuntimeUtilities.Destroy(m_InternalLogLut);
+
+ var format = GetLutFormat();
+ m_InternalLogLut = new RenderTexture(k_Lut3DSize, k_Lut3DSize, 0, format, RenderTextureReadWrite.Linear)
+ {
+ name = "Color Grading Log Lut",
+ dimension = TextureDimension.Tex3D,
+ hideFlags = HideFlags.DontSave,
+ filterMode = FilterMode.Bilinear,
+ wrapMode = TextureWrapMode.Clamp,
+ anisoLevel = 0,
+ enableRandomWrite = true,
+ volumeDepth = k_Lut3DSize,
+ autoGenerateMips = false,
+ useMipMap = false
+ };
+ m_InternalLogLut.Create();
+ }
+ }
+
+ void CheckInternalStripLut()
+ {
+ // Check internal lut state, (re)create it if needed
+ if (m_InternalLdrLut == null || !m_InternalLdrLut.IsCreated())
+ {
+ RuntimeUtilities.Destroy(m_InternalLdrLut);
+
+ var format = GetLutFormat();
+ m_InternalLdrLut = new RenderTexture(k_Lut2DSize * k_Lut2DSize, k_Lut2DSize, 0, format, RenderTextureReadWrite.Linear)
+ {
+ name = "Color Grading Strip Lut",
+ hideFlags = HideFlags.DontSave,
+ filterMode = FilterMode.Bilinear,
+ wrapMode = TextureWrapMode.Clamp,
+ anisoLevel = 0,
+ autoGenerateMips = false,
+ useMipMap = false
+ };
+ m_InternalLdrLut.Create();
+ }
+ }
+
+ Texture2D GetCurveTexture(bool hdr)
+ {
+ if (m_GradingCurves == null)
+ {
+ var format = GetCurveFormat();
+ m_GradingCurves = new Texture2D(Spline.k_Precision, 2, format, false, true)
+ {
+ name = "Internal Curves Texture",
+ hideFlags = HideFlags.DontSave,
+ anisoLevel = 0,
+ wrapMode = TextureWrapMode.Clamp,
+ filterMode = FilterMode.Bilinear
+ };
+ }
+
+ var hueVsHueCurve = settings.hueVsHueCurve.value;
+ var hueVsSatCurve = settings.hueVsSatCurve.value;
+ var satVsSatCurve = settings.satVsSatCurve.value;
+ var lumVsSatCurve = settings.lumVsSatCurve.value;
+ var masterCurve = settings.masterCurve.value;
+ var redCurve = settings.redCurve.value;
+ var greenCurve = settings.greenCurve.value;
+ var blueCurve = settings.blueCurve.value;
+
+ var pixels = m_Pixels;
+
+ for (int i = 0; i < Spline.k_Precision; i++)
+ {
+ // Secondary/VS curves
+ float x = hueVsHueCurve.cachedData[i];
+ float y = hueVsSatCurve.cachedData[i];
+ float z = satVsSatCurve.cachedData[i];
+ float w = lumVsSatCurve.cachedData[i];
+ pixels[i] = new Color(x, y, z, w);
+
+ // YRGB
+ if (!hdr)
+ {
+ float m = masterCurve.cachedData[i];
+ float r = redCurve.cachedData[i];
+ float g = greenCurve.cachedData[i];
+ float b = blueCurve.cachedData[i];
+ pixels[i + Spline.k_Precision] = new Color(r, g, b, m);
+ }
+ }
+
+ m_GradingCurves.SetPixels(pixels);
+ m_GradingCurves.Apply(false, false);
+
+ return m_GradingCurves;
+ }
+
+ static bool IsRenderTextureFormatSupportedForLinearFiltering(RenderTextureFormat format)
+ {
+#if UNITY_2023_2_OR_NEWER
+ var gFormat = GraphicsFormatUtility.GetGraphicsFormat(format, RenderTextureReadWrite.Linear);
+ return SystemInfo.IsFormatSupported(gFormat, GraphicsFormatUsage.Linear);
+#elif UNITY_2019_1_OR_NEWER
+ var gFormat = GraphicsFormatUtility.GetGraphicsFormat(format, RenderTextureReadWrite.Linear);
+ return SystemInfo.IsFormatSupported(gFormat, FormatUsage.Linear);
+#else
+ // No good/fast way to test it on pre-2019.1
+ return format.IsSupported();
+#endif
+ }
+
+ static RenderTextureFormat GetLutFormat()
+ {
+ // Use ARGBHalf if possible, fallback on ARGB2101010 and ARGB32 otherwise
+ var format = RenderTextureFormat.ARGBHalf;
+
+ if (!IsRenderTextureFormatSupportedForLinearFiltering(format))
+ {
+ format = RenderTextureFormat.ARGB2101010;
+
+ // Note that using a log lut in ARGB32 is a *very* bad idea but we need it for
+ // compatibility reasons (else if a platform doesn't support one of the previous
+ // format it'll output a black screen, or worse will segfault on the user).
+ if (!IsRenderTextureFormatSupportedForLinearFiltering(format))
+ format = RenderTextureFormat.ARGB32;
+ }
+
+ return format;
+ }
+
+ static TextureFormat GetCurveFormat()
+ {
+ // Use RGBAHalf if possible, fallback on ARGB32 otherwise
+ var format = TextureFormat.RGBAHalf;
+
+ if (!SystemInfo.SupportsTextureFormat(format))
+ format = TextureFormat.ARGB32;
+
+ return format;
+ }
+
+ public override void Release()
+ {
+ RuntimeUtilities.Destroy(m_InternalLdrLut);
+ m_InternalLdrLut = null;
+
+ RuntimeUtilities.Destroy(m_InternalLogLut);
+ m_InternalLogLut = null;
+
+ RuntimeUtilities.Destroy(m_GradingCurves);
+ m_GradingCurves = null;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/ColorGrading.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Effects/ColorGrading.cs.meta
new file mode 100644
index 0000000..d5735f4
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/ColorGrading.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: adb84e30e02715445aeb9959894e3b4d
+timeCreated: 1493024209
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/DepthOfField.cs b/com.unity.postprocessing/PostProcessing/Runtime/Effects/DepthOfField.cs
new file mode 100644
index 0000000..0ecd9f7
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/DepthOfField.cs
@@ -0,0 +1,267 @@
+using System;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// Convolution kernel size for the Depth of Field effect.
+ ///
+ public enum KernelSize
+ {
+ ///
+ /// Small filter.
+ ///
+ Small,
+
+ ///
+ /// Medium filter.
+ ///
+ Medium,
+
+ ///
+ /// Large filter.
+ ///
+ Large,
+
+ ///
+ /// Very large filter.
+ ///
+ VeryLarge
+ }
+
+ ///
+ /// A volume parameter holding a value.
+ ///
+ [Serializable]
+ public sealed class KernelSizeParameter : ParameterOverride { }
+
+ ///
+ /// This class holds settings for the Depth of Field effect.
+ ///
+ [Serializable]
+ [PostProcess(typeof(DepthOfFieldRenderer), "Unity/Depth of Field", false)]
+ public sealed class DepthOfField : PostProcessEffectSettings
+ {
+ ///
+ /// The distance to the point of focus.
+ ///
+ [Min(0.1f), Tooltip("Distance to the point of focus.")]
+ public FloatParameter focusDistance = new FloatParameter { value = 10f };
+
+ ///
+ /// The ratio of the aperture (known as f-stop or f-number). The smaller the value is, the
+ /// shallower the depth of field is.
+ ///
+ [Range(0.05f, 32f), Tooltip("Ratio of aperture (known as f-stop or f-number). The smaller the value is, the shallower the depth of field is.")]
+ public FloatParameter aperture = new FloatParameter { value = 5.6f };
+
+ ///
+ /// The distance between the lens and the film. The larger the value is, the shallower the
+ /// depth of field is.
+ ///
+ [Range(1f, 300f), Tooltip("Distance between the lens and the film. The larger the value is, the shallower the depth of field is.")]
+ public FloatParameter focalLength = new FloatParameter { value = 50f };
+
+ ///
+ /// The convolution kernel size of the bokeh filter, which determines the maximum radius of
+ /// bokeh. It also affects the performance (the larger the kernel is, the longer the GPU
+ /// time is required).
+ ///
+ [DisplayName("Max Blur Size"), Tooltip("Convolution kernel size of the bokeh filter, which determines the maximum radius of bokeh. It also affects performances (the larger the kernel is, the longer the GPU time is required).")]
+ public KernelSizeParameter kernelSize = new KernelSizeParameter { value = KernelSize.Medium };
+
+ ///
+ /// Returns true if the effect is currently enabled and supported.
+ ///
+ /// The current post-processing render context
+ /// true if the effect is currently enabled and supported
+ public override bool IsEnabledAndSupported(PostProcessRenderContext context)
+ {
+ return enabled.value
+ && SystemInfo.graphicsShaderLevel >= 35;
+ }
+ }
+
+ [UnityEngine.Scripting.Preserve]
+ // TODO: Doesn't play nice with alpha propagation, see if it can be fixed without killing performances
+ internal sealed class DepthOfFieldRenderer : PostProcessEffectRenderer
+ {
+ enum Pass
+ {
+ CoCCalculation,
+ CoCTemporalFilter,
+ DownsampleAndPrefilter,
+ BokehSmallKernel,
+ BokehMediumKernel,
+ BokehLargeKernel,
+ BokehVeryLargeKernel,
+ PostFilter,
+ Combine,
+ DebugOverlay
+ }
+
+ // Ping-pong between two history textures as we can't read & write the same target in the
+ // same pass
+ const int k_NumEyes = 2;
+ const int k_NumCoCHistoryTextures = 2;
+ readonly RenderTexture[][] m_CoCHistoryTextures = new RenderTexture[k_NumEyes][];
+ int[] m_HistoryPingPong = new int[k_NumEyes];
+
+ // Height of the 35mm full-frame format (36mm x 24mm)
+ // TODO: Should be set by a physical camera
+ const float k_FilmHeight = 0.024f;
+
+ public DepthOfFieldRenderer()
+ {
+ for (int eye = 0; eye < k_NumEyes; eye++)
+ {
+ m_CoCHistoryTextures[eye] = new RenderTexture[k_NumCoCHistoryTextures];
+ m_HistoryPingPong[eye] = 0;
+ }
+ }
+
+ public override DepthTextureMode GetCameraFlags()
+ {
+ return DepthTextureMode.Depth;
+ }
+
+ RenderTextureFormat SelectFormat(RenderTextureFormat primary, RenderTextureFormat secondary)
+ {
+ if (primary.IsSupported())
+ return primary;
+
+ if (secondary.IsSupported())
+ return secondary;
+
+ return RenderTextureFormat.Default;
+ }
+
+ float CalculateMaxCoCRadius(int screenHeight)
+ {
+ // Estimate the allowable maximum radius of CoC from the kernel
+ // size (the equation below was empirically derived).
+ float radiusInPixels = (float)settings.kernelSize.value * 4f + 6f;
+
+ // Applying a 5% limit to the CoC radius to keep the size of
+ // TileMax/NeighborMax small enough.
+ return Mathf.Min(0.05f, radiusInPixels / screenHeight);
+ }
+
+ RenderTexture CheckHistory(int eye, int id, PostProcessRenderContext context, RenderTextureFormat format)
+ {
+ var rt = m_CoCHistoryTextures[eye][id];
+
+ if (m_ResetHistory || rt == null || !rt.IsCreated() || rt.width != context.width || rt.height != context.height)
+ {
+ RenderTexture.ReleaseTemporary(rt);
+
+ rt = context.GetScreenSpaceTemporaryRT(0, format, RenderTextureReadWrite.Linear);
+ rt.name = "CoC History, Eye: " + eye + ", ID: " + id;
+ rt.filterMode = FilterMode.Bilinear;
+ rt.Create();
+ m_CoCHistoryTextures[eye][id] = rt;
+ }
+
+ return rt;
+ }
+
+ public override void Render(PostProcessRenderContext context)
+ {
+ // The coc is stored in alpha so we need a 4 channels target. Note that using ARGB32
+ // will result in a very weak near-blur.
+ var colorFormat = context.camera.allowHDR ? RenderTextureFormat.ARGBHalf : RenderTextureFormat.ARGB32;
+ var cocFormat = SelectFormat(RenderTextureFormat.R8, RenderTextureFormat.RHalf);
+
+ // Material setup
+ float scaledFilmHeight = k_FilmHeight * (context.height / 1080f);
+ var f = settings.focalLength.value / 1000f;
+ var s1 = Mathf.Max(settings.focusDistance.value, f);
+ var aspect = (float)context.screenWidth / (float)context.screenHeight;
+ var coeff = f * f / (settings.aperture.value * (s1 - f) * scaledFilmHeight * 2f);
+ var maxCoC = CalculateMaxCoCRadius(context.screenHeight);
+
+ var sheet = context.propertySheets.Get(context.resources.shaders.depthOfField);
+ sheet.properties.Clear();
+ sheet.properties.SetFloat(ShaderIDs.Distance, s1);
+ sheet.properties.SetFloat(ShaderIDs.LensCoeff, coeff);
+ sheet.properties.SetFloat(ShaderIDs.MaxCoC, maxCoC);
+ sheet.properties.SetFloat(ShaderIDs.RcpMaxCoC, 1f / maxCoC);
+ sheet.properties.SetFloat(ShaderIDs.RcpAspect, 1f / aspect);
+
+ var cmd = context.command;
+ cmd.BeginSample("DepthOfField");
+
+ // CoC calculation pass
+ context.GetScreenSpaceTemporaryRT(cmd, ShaderIDs.CoCTex, 0, cocFormat, RenderTextureReadWrite.Linear);
+ cmd.BlitFullscreenTriangle(BuiltinRenderTextureType.None, ShaderIDs.CoCTex, sheet, (int)Pass.CoCCalculation);
+
+ // CoC temporal filter pass when TAA is enabled
+ if (context.IsTemporalAntialiasingActive())
+ {
+ float motionBlending = context.temporalAntialiasing.motionBlending;
+ float blend = m_ResetHistory ? 0f : motionBlending; // Handles first frame blending
+ var jitter = context.temporalAntialiasing.jitter;
+
+ sheet.properties.SetVector(ShaderIDs.TaaParams, new Vector3(jitter.x, jitter.y, blend));
+ }
+ else if (context.IsSuperResolutionActive())
+ {
+ var jitter = context.superResolution.jitter;
+ sheet.properties.SetVector(ShaderIDs.TaaParams, new Vector3(jitter.x, jitter.y, m_ResetHistory ? 0f : 0.85f));
+ }
+
+ if (context.IsTemporalAntialiasingActive() || context.IsSuperResolutionActive())
+ {
+ int pp = m_HistoryPingPong[context.xrActiveEye];
+ var historyRead = CheckHistory(context.xrActiveEye, ++pp % 2, context, cocFormat);
+ var historyWrite = CheckHistory(context.xrActiveEye, ++pp % 2, context, cocFormat);
+ m_HistoryPingPong[context.xrActiveEye] = ++pp % 2;
+
+ cmd.BlitFullscreenTriangle(historyRead, historyWrite, sheet, (int)Pass.CoCTemporalFilter);
+ cmd.ReleaseTemporaryRT(ShaderIDs.CoCTex);
+ cmd.SetGlobalTexture(ShaderIDs.CoCTex, historyWrite);
+ }
+
+ // Downsampling and prefiltering pass
+ context.GetScreenSpaceTemporaryRT(cmd, ShaderIDs.DepthOfFieldTex, 0, colorFormat, RenderTextureReadWrite.Default, FilterMode.Bilinear, context.width / 2, context.height / 2);
+ cmd.BlitFullscreenTriangle(context.source, ShaderIDs.DepthOfFieldTex, sheet, (int)Pass.DownsampleAndPrefilter);
+
+ // Bokeh simulation pass
+ context.GetScreenSpaceTemporaryRT(cmd, ShaderIDs.DepthOfFieldTemp, 0, colorFormat, RenderTextureReadWrite.Default, FilterMode.Bilinear, context.width / 2, context.height / 2);
+ cmd.BlitFullscreenTriangle(ShaderIDs.DepthOfFieldTex, ShaderIDs.DepthOfFieldTemp, sheet, (int)Pass.BokehSmallKernel + (int)settings.kernelSize.value);
+
+ // Postfilter pass
+ cmd.BlitFullscreenTriangle(ShaderIDs.DepthOfFieldTemp, ShaderIDs.DepthOfFieldTex, sheet, (int)Pass.PostFilter);
+ cmd.ReleaseTemporaryRT(ShaderIDs.DepthOfFieldTemp);
+
+ // Debug overlay pass
+ if (context.IsDebugOverlayEnabled(DebugOverlay.DepthOfField))
+ context.PushDebugOverlay(cmd, context.source, sheet, (int)Pass.DebugOverlay);
+
+ // Combine pass
+ cmd.BlitFullscreenTriangle(context.source, context.destination, sheet, (int)Pass.Combine);
+ cmd.ReleaseTemporaryRT(ShaderIDs.DepthOfFieldTex);
+
+ if (!context.IsTemporalAntialiasingActive() && !context.IsSuperResolutionActive())
+ cmd.ReleaseTemporaryRT(ShaderIDs.CoCTex);
+
+ cmd.EndSample("DepthOfField");
+
+ m_ResetHistory = false;
+ }
+
+ public override void Release()
+ {
+ for (int eye = 0; eye < k_NumEyes; eye++)
+ {
+ for (int i = 0; i < m_CoCHistoryTextures[eye].Length; i++)
+ {
+ RenderTexture.ReleaseTemporary(m_CoCHistoryTextures[eye][i]);
+ m_CoCHistoryTextures[eye][i] = null;
+ }
+ m_HistoryPingPong[eye] = 0;
+ }
+
+ ResetHistory();
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/DepthOfField.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Effects/DepthOfField.cs.meta
new file mode 100644
index 0000000..f77b54a
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/DepthOfField.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 556797029e73b2347956b6579e77e05b
+timeCreated: 1491828776
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/Dithering.cs b/com.unity.postprocessing/PostProcessing/Runtime/Effects/Dithering.cs
new file mode 100644
index 0000000..f4618fe
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/Dithering.cs
@@ -0,0 +1,42 @@
+using System;
+using UnityEngine.Assertions;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ [UnityEngine.Scripting.Preserve]
+ [Serializable]
+ internal sealed class Dithering
+ {
+ int m_NoiseTextureIndex = 0;
+ System.Random m_Random = new System.Random(1234);
+
+ internal void Render(PostProcessRenderContext context)
+ {
+ var blueNoise = context.resources.blueNoise64;
+ Assert.IsTrue(blueNoise != null && blueNoise.Length > 0);
+
+#if POSTFX_DEBUG_STATIC_DITHERING // Used by QA for automated testing
+ m_NoiseTextureIndex = 0;
+ float rndOffsetX = 0f;
+ float rndOffsetY = 0f;
+#else
+ if (++m_NoiseTextureIndex >= blueNoise.Length)
+ m_NoiseTextureIndex = 0;
+
+ float rndOffsetX = (float)m_Random.NextDouble();
+ float rndOffsetY = (float)m_Random.NextDouble();
+#endif
+
+ var noiseTex = blueNoise[m_NoiseTextureIndex];
+ var uberSheet = context.uberSheet;
+
+ uberSheet.properties.SetTexture(ShaderIDs.DitheringTex, noiseTex);
+ uberSheet.properties.SetVector(ShaderIDs.Dithering_Coords, new Vector4(
+ (float)context.screenWidth / (float)noiseTex.width,
+ (float)context.screenHeight / (float)noiseTex.height,
+ rndOffsetX,
+ rndOffsetY
+ ));
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/Dithering.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Effects/Dithering.cs.meta
new file mode 100644
index 0000000..952e482
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/Dithering.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 75066207954ccc44aa9d134af49040de
+timeCreated: 1490188285
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/FastApproximateAntialiasing.cs b/com.unity.postprocessing/PostProcessing/Runtime/Effects/FastApproximateAntialiasing.cs
new file mode 100644
index 0000000..640acdb
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/FastApproximateAntialiasing.cs
@@ -0,0 +1,28 @@
+using System;
+using UnityEngine.Serialization;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// This class holds settings for the Fast Approximate Anti-aliasing (FXAA) effect.
+ ///
+ [UnityEngine.Scripting.Preserve]
+ [Serializable]
+ public sealed class FastApproximateAntialiasing
+ {
+ ///
+ /// If true, it will use a slightly lower quality but faster variant of FXAA. Highly
+ /// recommended on mobile platforms.
+ ///
+ [FormerlySerializedAs("mobileOptimized")]
+ [Tooltip("Boost performances by lowering the effect quality. This setting is meant to be used on mobile and other low-end platforms but can also provide a nice performance boost on desktops and consoles.")]
+ public bool fastMode = false;
+
+ ///
+ /// Set this to true if you need to keep the alpha channel untouched. Else it will
+ /// use this channel to store internal data used to speed up and improve visual quality.
+ ///
+ [Tooltip("Keep alpha channel. This will slightly lower the effect quality but allows rendering against a transparent background.\nThis setting has no effect if the camera render target has no alpha channel.")]
+ public bool keepAlpha = false;
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/FastApproximateAntialiasing.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Effects/FastApproximateAntialiasing.cs.meta
new file mode 100644
index 0000000..00bef62
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/FastApproximateAntialiasing.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: efd3e892ff9d0b94c94e039ad5619e5d
+timeCreated: 1493489448
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/Fog.cs b/com.unity.postprocessing/PostProcessing/Runtime/Effects/Fog.cs
new file mode 100644
index 0000000..2d1e953
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/Fog.cs
@@ -0,0 +1,53 @@
+using System;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// This class holds settings for the Fog effect with the deferred rendering path.
+ ///
+ [UnityEngine.Scripting.Preserve]
+ [Serializable]
+ public sealed class Fog
+ {
+ ///
+ /// If true, enables the internal deferred fog pass. Actual fog settings should be
+ /// set in the Lighting panel.
+ ///
+ [Tooltip("Enables the internal deferred fog pass. Actual fog settings should be set in the Lighting panel.")]
+ public bool enabled = true;
+
+ ///
+ /// Should the fog affect the skybox?
+ ///
+ [Tooltip("Mark true for the fog to ignore the skybox")]
+ public bool excludeSkybox = true;
+
+ internal DepthTextureMode GetCameraFlags()
+ {
+ return DepthTextureMode.Depth;
+ }
+
+ internal bool IsEnabledAndSupported(PostProcessRenderContext context)
+ {
+ return enabled
+ && RenderSettings.fog
+ && !RuntimeUtilities.scriptableRenderPipelineActive
+ && context.resources.shaders.deferredFog
+ && context.resources.shaders.deferredFog.isSupported
+ && context.camera.actualRenderingPath == RenderingPath.DeferredShading; // In forward fog is already done at shader level
+ }
+
+ internal void Render(PostProcessRenderContext context)
+ {
+ var sheet = context.propertySheets.Get(context.resources.shaders.deferredFog);
+ sheet.ClearKeywords();
+
+ var fogColor = RuntimeUtilities.isLinearColorSpace ? RenderSettings.fogColor.linear : RenderSettings.fogColor;
+ sheet.properties.SetVector(ShaderIDs.FogColor, fogColor);
+ sheet.properties.SetVector(ShaderIDs.FogParams, new Vector3(RenderSettings.fogDensity, RenderSettings.fogStartDistance, RenderSettings.fogEndDistance));
+
+ var cmd = context.command;
+ cmd.BlitFullscreenTriangle(context.source, context.destination, sheet, excludeSkybox ? 1 : 0, false, null, true);
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/Fog.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Effects/Fog.cs.meta
new file mode 100644
index 0000000..45dbd91
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/Fog.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 62e2b920ea5fcaa4982e7fc50bf690a8
+timeCreated: 1498381577
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/Grain.cs b/com.unity.postprocessing/PostProcessing/Runtime/Effects/Grain.cs
new file mode 100644
index 0000000..edd6593
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/Grain.cs
@@ -0,0 +1,127 @@
+using System;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// This class holds settings for the Grain effect.
+ ///
+ [Serializable]
+ [PostProcess(typeof(GrainRenderer), "Unity/Grain")]
+ public sealed class Grain : PostProcessEffectSettings
+ {
+ ///
+ /// Set to true to render colored grain, false for grayscale grain.
+ ///
+ [Tooltip("Enable the use of colored grain.")]
+ public BoolParameter colored = new BoolParameter { value = true };
+
+ ///
+ /// The strength (or visibility) of the Grain effect on screen. Higher values mean more visible grain.
+ ///
+ [Range(0f, 1f), Tooltip("Grain strength. Higher values mean more visible grain.")]
+ public FloatParameter intensity = new FloatParameter { value = 0f };
+
+ ///
+ /// The size of grain particle on screen.
+ ///
+ [Range(0.3f, 3f), Tooltip("Grain particle size.")]
+ public FloatParameter size = new FloatParameter { value = 1f };
+
+ ///
+ /// Controls the noisiness response curve based on scene luminance. Lower values mean less noise in dark areas.
+ ///
+ [Range(0f, 1f), DisplayName("Luminance Contribution"), Tooltip("Controls the noise response curve based on scene luminance. Lower values mean less noise in dark areas.")]
+ public FloatParameter lumContrib = new FloatParameter { value = 0.8f };
+
+ ///
+ /// Returns true if the effect is currently enabled and supported.
+ ///
+ /// The current post-processing render context
+ /// true if the effect is currently enabled and supported
+ public override bool IsEnabledAndSupported(PostProcessRenderContext context)
+ {
+ return enabled.value
+ && intensity.value > 0f;
+ }
+ }
+
+#if POSTFX_DEBUG_STATIC_GRAIN
+#pragma warning disable 414
+#endif
+ [UnityEngine.Scripting.Preserve]
+ internal sealed class GrainRenderer : PostProcessEffectRenderer
+ {
+ RenderTexture m_GrainLookupRT;
+
+ const int k_SampleCount = 1024;
+ int m_SampleIndex;
+
+ public override void Render(PostProcessRenderContext context)
+ {
+#if POSTFX_DEBUG_STATIC_GRAIN
+ // Chosen by a fair dice roll
+ float time = 0.4f;
+ float rndOffsetX = 0f;
+ float rndOffsetY = 0f;
+#else
+ float time = Time.realtimeSinceStartup;
+ float rndOffsetX = HaltonSeq.Get(m_SampleIndex & 1023, 2);
+ float rndOffsetY = HaltonSeq.Get(m_SampleIndex & 1023, 3);
+
+ if (++m_SampleIndex >= k_SampleCount)
+ m_SampleIndex = 0;
+#endif
+
+ // Generate the grain lut for the current frame first
+ if (m_GrainLookupRT == null || !m_GrainLookupRT.IsCreated())
+ {
+ RuntimeUtilities.Destroy(m_GrainLookupRT);
+
+ m_GrainLookupRT = new RenderTexture(128, 128, 0, GetLookupFormat())
+ {
+ filterMode = FilterMode.Bilinear,
+ wrapMode = TextureWrapMode.Repeat,
+ anisoLevel = 0,
+ name = "Grain Lookup Texture"
+ };
+
+ m_GrainLookupRT.Create();
+ }
+
+ var sheet = context.propertySheets.Get(context.resources.shaders.grainBaker);
+ sheet.properties.Clear();
+ sheet.properties.SetFloat(ShaderIDs.Phase, time % 10f);
+ sheet.properties.SetVector(ShaderIDs.GrainNoiseParameters, new Vector3(12.9898f, 78.233f, 43758.5453f));
+
+ context.command.BeginSample("GrainLookup");
+ context.command.BlitFullscreenTriangle(BuiltinRenderTextureType.None, m_GrainLookupRT, sheet, settings.colored.value ? 1 : 0);
+ context.command.EndSample("GrainLookup");
+
+ // Send everything to the uber shader
+ var uberSheet = context.uberSheet;
+ uberSheet.EnableKeyword("GRAIN");
+ uberSheet.properties.SetTexture(ShaderIDs.GrainTex, m_GrainLookupRT);
+ uberSheet.properties.SetVector(ShaderIDs.Grain_Params1, new Vector2(settings.lumContrib.value, settings.intensity.value * 20f));
+ uberSheet.properties.SetVector(ShaderIDs.Grain_Params2, new Vector4((float)context.width / (float)m_GrainLookupRT.width / settings.size.value, (float)context.height / (float)m_GrainLookupRT.height / settings.size.value, rndOffsetX, rndOffsetY));
+ }
+
+ RenderTextureFormat GetLookupFormat()
+ {
+ if (RenderTextureFormat.ARGBHalf.IsSupported())
+ return RenderTextureFormat.ARGBHalf;
+
+ return RenderTextureFormat.ARGB32;
+ }
+
+ public override void Release()
+ {
+ RuntimeUtilities.Destroy(m_GrainLookupRT);
+ m_GrainLookupRT = null;
+ m_SampleIndex = 0;
+ }
+ }
+
+#if POSTFX_DEBUG_STATIC_GRAIN
+#pragma warning restore 414
+#endif
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/Grain.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Effects/Grain.cs.meta
new file mode 100644
index 0000000..c7c70fa
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/Grain.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: d65e486e4de6e5448a8fbb43dc8756a0
+timeCreated: 1491826543
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/LensDistortion.cs b/com.unity.postprocessing/PostProcessing/Runtime/Effects/LensDistortion.cs
new file mode 100644
index 0000000..421a97e
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/LensDistortion.cs
@@ -0,0 +1,82 @@
+using System;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// This class holds settings for the Lens Distortion effect.
+ ///
+ [Serializable]
+ [PostProcess(typeof(LensDistortionRenderer), "Unity/Lens Distortion")]
+ public sealed class LensDistortion : PostProcessEffectSettings
+ {
+ ///
+ /// The total amount of distortion to apply.
+ ///
+ [Range(-100f, 100f), Tooltip("Total distortion amount.")]
+ public FloatParameter intensity = new FloatParameter { value = 0f };
+
+ ///
+ /// Multiplies the intensity value on the x-axis. Setting this value to 0 will disable distortion on this axis.
+ ///
+ [Range(0f, 1f), DisplayName("X Multiplier"), Tooltip("Intensity multiplier on the x-axis. Set it to 0 to disable distortion on this axis.")]
+ public FloatParameter intensityX = new FloatParameter { value = 1f };
+
+ ///
+ /// Multiplies the intensity value on the y-axis. Setting this value to 0 will disable distortion on this axis.
+ ///
+ [Range(0f, 1f), DisplayName("Y Multiplier"), Tooltip("Intensity multiplier on the y-axis. Set it to 0 to disable distortion on this axis.")]
+ public FloatParameter intensityY = new FloatParameter { value = 1f };
+
+ ///
+ /// The center point for the distortion (x-axis).
+ ///
+ [Space]
+ [Range(-1f, 1f), Tooltip("Distortion center point (x-axis).")]
+ public FloatParameter centerX = new FloatParameter { value = 0f };
+
+ ///
+ /// The center point for the distortion (y-axis).
+ ///
+ [Range(-1f, 1f), Tooltip("Distortion center point (y-axis).")]
+ public FloatParameter centerY = new FloatParameter { value = 0f };
+
+ ///
+ /// A global screen scaling factor.
+ ///
+ [Space]
+ [Range(0.01f, 5f), Tooltip("Global screen scaling.")]
+ public FloatParameter scale = new FloatParameter { value = 1f };
+
+ ///
+ /// Returns true if the effect is currently enabled and supported.
+ ///
+ /// The current post-processing render context
+ /// true if the effect is currently enabled and supported
+ public override bool IsEnabledAndSupported(PostProcessRenderContext context)
+ {
+ return enabled.value
+ && !Mathf.Approximately(intensity, 0f)
+ && (intensityX > 0f || intensityY > 0f)
+ && !context.stereoActive;
+ }
+ }
+
+ [UnityEngine.Scripting.Preserve]
+ internal sealed class LensDistortionRenderer : PostProcessEffectRenderer
+ {
+ public override void Render(PostProcessRenderContext context)
+ {
+ var sheet = context.uberSheet;
+
+ float amount = 1.6f * Math.Max(Mathf.Abs(settings.intensity.value), 1f);
+ float theta = Mathf.Deg2Rad * Math.Min(160f, amount);
+ float sigma = 2f * Mathf.Tan(theta * 0.5f);
+ var p0 = new Vector4(settings.centerX.value, settings.centerY.value, Mathf.Max(settings.intensityX.value, 1e-4f), Mathf.Max(settings.intensityY.value, 1e-4f));
+ var p1 = new Vector4(settings.intensity.value >= 0f ? theta : 1f / theta, sigma, 1f / settings.scale.value, settings.intensity.value);
+
+ sheet.EnableKeyword("DISTORT");
+ sheet.properties.SetVector(ShaderIDs.Distortion_CenterScale, p0);
+ sheet.properties.SetVector(ShaderIDs.Distortion_Amount, p1);
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/LensDistortion.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Effects/LensDistortion.cs.meta
new file mode 100644
index 0000000..bb6b529
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/LensDistortion.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 9b77c5407dc277943b591ade9e6b18c5
+timeCreated: 1519737209
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/MotionBlur.cs b/com.unity.postprocessing/PostProcessing/Runtime/Effects/MotionBlur.cs
new file mode 100644
index 0000000..46cf8e8
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/MotionBlur.cs
@@ -0,0 +1,157 @@
+using System;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// This class holds settings for the Motion Blur effect.
+ ///
+ [Serializable]
+ [PostProcess(typeof(MotionBlurRenderer), "Unity/Motion Blur", false)]
+ public sealed class MotionBlur : PostProcessEffectSettings
+ {
+ ///
+ /// The angle of the rotary shutter. Larger values give longer exposure therefore a stronger
+ /// blur effect.
+ ///
+ [Range(0f, 360f), Tooltip("The angle of rotary shutter. Larger values give longer exposure.")]
+ public FloatParameter shutterAngle = new FloatParameter { value = 270f };
+
+ ///
+ /// The amount of sample points, which affects quality and performances.
+ ///
+ [Range(4, 32), Tooltip("The amount of sample points. This affects quality and performance.")]
+ public IntParameter sampleCount = new IntParameter { value = 10 };
+
+ ///
+ /// Returns true if the effect is currently enabled and supported.
+ ///
+ /// The current post-processing render context
+ /// true if the effect is currently enabled and supported
+ public override bool IsEnabledAndSupported(PostProcessRenderContext context)
+ {
+ return enabled.value
+ && shutterAngle.value > 0f
+#if UNITY_EDITOR
+ // Don't render motion blur preview when the editor is not playing as it can in some
+ // cases results in ugly artifacts (i.e. when resizing the game view).
+ && Application.isPlaying
+#endif
+ && SystemInfo.supportsMotionVectors
+ && RenderTextureFormat.RGHalf.IsSupported()
+ && !context.stereoActive;
+ }
+ }
+
+ [UnityEngine.Scripting.Preserve]
+ internal sealed class MotionBlurRenderer : PostProcessEffectRenderer
+ {
+ enum Pass
+ {
+ VelocitySetup,
+ TileMax1,
+ TileMax2,
+ TileMaxV,
+ NeighborMax,
+ Reconstruction
+ }
+
+ public override DepthTextureMode GetCameraFlags()
+ {
+ return DepthTextureMode.Depth | DepthTextureMode.MotionVectors;
+ }
+
+ private void CreateTemporaryRT(PostProcessRenderContext context, int nameID, int width, int height, RenderTextureFormat RTFormat)
+ {
+ var cmd = context.command;
+ var rtDesc = context.GetDescriptor(0, RTFormat, RenderTextureReadWrite.Linear);
+ rtDesc.width = width;
+ rtDesc.height = height;
+#if UNITY_2019_1_OR_NEWER
+ cmd.GetTemporaryRT(nameID, rtDesc, FilterMode.Point);
+#elif UNITY_2017_3_OR_NEWER
+ cmd.GetTemporaryRT(nameID, rtDesc.width, rtDesc.height, rtDesc.depthBufferBits, FilterMode.Point, rtDesc.colorFormat, RenderTextureReadWrite.Linear, rtDesc.msaaSamples, rtDesc.enableRandomWrite, rtDesc.memoryless, RuntimeUtilities.IsDynamicResolutionEnabled(context.camera));
+#else
+ cmd.GetTemporaryRT(nameID, rtDesc.width, rtDesc.height, rtDesc.depthBufferBits, FilterMode.Point, rtDesc.colorFormat, RenderTextureReadWrite.Linear, rtDesc.msaaSamples, rtDesc.enableRandomWrite, rtDesc.memoryless);
+#endif
+ }
+
+ public override void Render(PostProcessRenderContext context)
+ {
+ var cmd = context.command;
+
+ if (m_ResetHistory)
+ {
+ cmd.BlitFullscreenTriangle(context.source, context.destination);
+ m_ResetHistory = false;
+ return;
+ }
+
+ const float kMaxBlurRadius = 5f;
+ var vectorRTFormat = RenderTextureFormat.RGHalf;
+ var packedRTFormat = RenderTextureFormat.ARGB2101010.IsSupported()
+ ? RenderTextureFormat.ARGB2101010
+ : RenderTextureFormat.ARGB32;
+
+ var sheet = context.propertySheets.Get(context.resources.shaders.motionBlur);
+ cmd.BeginSample("MotionBlur");
+
+ // Calculate the maximum blur radius in pixels.
+ int maxBlurPixels = (int)(kMaxBlurRadius * context.height / 100);
+
+ // Calculate the TileMax size.
+ // It should be a multiple of 8 and larger than maxBlur.
+ int tileSize = ((maxBlurPixels - 1) / 8 + 1) * 8;
+
+ // Pass 1 - Velocity/depth packing
+ var velocityScale = settings.shutterAngle / 360f;
+ sheet.properties.SetFloat(ShaderIDs.VelocityScale, velocityScale);
+ sheet.properties.SetFloat(ShaderIDs.MaxBlurRadius, maxBlurPixels);
+ sheet.properties.SetFloat(ShaderIDs.RcpMaxBlurRadius, 1f / maxBlurPixels);
+
+ int vbuffer = ShaderIDs.VelocityTex;
+ CreateTemporaryRT(context, vbuffer, context.width, context.height, packedRTFormat);
+ cmd.BlitFullscreenTriangle(BuiltinRenderTextureType.None, vbuffer, sheet, (int)Pass.VelocitySetup);
+
+ // Pass 2 - First TileMax filter (1/2 downsize)
+ int tile2 = ShaderIDs.Tile2RT;
+ CreateTemporaryRT(context, tile2, context.width / 2, context.height / 2, vectorRTFormat);
+ cmd.BlitFullscreenTriangle(vbuffer, tile2, sheet, (int)Pass.TileMax1);
+
+ // Pass 3 - Second TileMax filter (1/2 downsize)
+ int tile4 = ShaderIDs.Tile4RT;
+ CreateTemporaryRT(context, tile4, context.width / 4, context.height / 4, vectorRTFormat);
+ cmd.BlitFullscreenTriangle(tile2, tile4, sheet, (int)Pass.TileMax2);
+ cmd.ReleaseTemporaryRT(tile2);
+
+ // Pass 4 - Third TileMax filter (1/2 downsize)
+ int tile8 = ShaderIDs.Tile8RT;
+ CreateTemporaryRT(context, tile8, context.width / 8, context.height / 8, vectorRTFormat);
+ cmd.BlitFullscreenTriangle(tile4, tile8, sheet, (int)Pass.TileMax2);
+ cmd.ReleaseTemporaryRT(tile4);
+
+ // Pass 5 - Fourth TileMax filter (reduce to tileSize)
+ var tileMaxOffs = (tileSize / 8f - 1f) * -0.5f * Vector2.one;
+ sheet.properties.SetVector(ShaderIDs.TileMaxOffs, tileMaxOffs);
+ sheet.properties.SetFloat(ShaderIDs.TileMaxLoop, (int)(tileSize / 8f));
+
+ int tile = ShaderIDs.TileVRT;
+ CreateTemporaryRT(context, tile, context.width / tileSize, context.height / tileSize, vectorRTFormat);
+ cmd.BlitFullscreenTriangle(tile8, tile, sheet, (int)Pass.TileMaxV);
+ cmd.ReleaseTemporaryRT(tile8);
+
+ // Pass 6 - NeighborMax filter
+ int neighborMax = ShaderIDs.NeighborMaxTex;
+ CreateTemporaryRT(context, neighborMax, context.width / tileSize, context.height / tileSize, vectorRTFormat);
+ cmd.BlitFullscreenTriangle(tile, neighborMax, sheet, (int)Pass.NeighborMax);
+ cmd.ReleaseTemporaryRT(tile);
+
+ // Pass 7 - Reconstruction pass
+ sheet.properties.SetFloat(ShaderIDs.LoopCount, Mathf.Clamp(settings.sampleCount / 2, 1, 64));
+ cmd.BlitFullscreenTriangle(context.source, context.destination, sheet, (int)Pass.Reconstruction);
+
+ cmd.ReleaseTemporaryRT(vbuffer);
+ cmd.ReleaseTemporaryRT(neighborMax);
+ cmd.EndSample("MotionBlur");
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/MotionBlur.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Effects/MotionBlur.cs.meta
new file mode 100644
index 0000000..c5ba8cd
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/MotionBlur.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: b94fcd11afffcb142908bfcb1e261fba
+timeCreated: 1491826543
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/MultiScaleVO.cs b/com.unity.postprocessing/PostProcessing/Runtime/Effects/MultiScaleVO.cs
new file mode 100644
index 0000000..a1af379
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/MultiScaleVO.cs
@@ -0,0 +1,567 @@
+using System;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ // Multi-scale volumetric obscurance
+ // TODO: Fix VR support
+
+ [UnityEngine.Scripting.Preserve]
+ [Serializable]
+ internal sealed class MultiScaleVO : IAmbientOcclusionMethod
+ {
+ internal enum MipLevel { Original, L1, L2, L3, L4, L5, L6 }
+
+ enum Pass
+ {
+ DepthCopy,
+ CompositionDeferred,
+ CompositionForward,
+ DebugOverlay
+ }
+
+ // The arrays below are reused between frames to reduce GC allocation.
+ readonly float[] m_SampleThickness =
+ {
+ Mathf.Sqrt(1f - 0.2f * 0.2f),
+ Mathf.Sqrt(1f - 0.4f * 0.4f),
+ Mathf.Sqrt(1f - 0.6f * 0.6f),
+ Mathf.Sqrt(1f - 0.8f * 0.8f),
+ Mathf.Sqrt(1f - 0.2f * 0.2f - 0.2f * 0.2f),
+ Mathf.Sqrt(1f - 0.2f * 0.2f - 0.4f * 0.4f),
+ Mathf.Sqrt(1f - 0.2f * 0.2f - 0.6f * 0.6f),
+ Mathf.Sqrt(1f - 0.2f * 0.2f - 0.8f * 0.8f),
+ Mathf.Sqrt(1f - 0.4f * 0.4f - 0.4f * 0.4f),
+ Mathf.Sqrt(1f - 0.4f * 0.4f - 0.6f * 0.6f),
+ Mathf.Sqrt(1f - 0.4f * 0.4f - 0.8f * 0.8f),
+ Mathf.Sqrt(1f - 0.6f * 0.6f - 0.6f * 0.6f)
+ };
+
+ readonly float[] m_InvThicknessTable = new float[12];
+ readonly float[] m_SampleWeightTable = new float[12];
+
+ readonly int[] m_Widths = new int[7];
+ readonly int[] m_Heights = new int[7];
+ // Scaled dimensions used with dynamic resolution
+ readonly int[] m_ScaledWidths = new int[7];
+ readonly int[] m_ScaledHeights = new int[7];
+
+ AmbientOcclusion m_Settings;
+ PropertySheet m_PropertySheet;
+ PostProcessResources m_Resources;
+
+ // Can't use a temporary because we need to share it between cmdbuffers - also fixes a weird
+ // command buffer warning
+ RenderTexture m_AmbientOnlyAO;
+
+ readonly RenderTargetIdentifier[] m_MRT =
+ {
+ BuiltinRenderTextureType.GBuffer0, // Albedo, Occ
+ BuiltinRenderTextureType.CameraTarget // Ambient
+ };
+
+ public MultiScaleVO(AmbientOcclusion settings)
+ {
+ m_Settings = settings;
+ }
+
+ public DepthTextureMode GetCameraFlags()
+ {
+ return DepthTextureMode.Depth;
+ }
+
+ // Special case for AO [because SRPs], please don't do this in other effects, it's bad
+ // practice in this framework
+ public void SetResources(PostProcessResources resources)
+ {
+ m_Resources = resources;
+ }
+
+ void Alloc(CommandBuffer cmd, int id, MipLevel size, RenderTextureFormat format, bool uav, bool dynamicScale)
+ {
+ int sizeId = (int)size;
+ cmd.GetTemporaryRT(id, new RenderTextureDescriptor
+ {
+#if UNITY_2019_4_OR_NEWER
+ width = m_Widths[sizeId],
+ height = m_Heights[sizeId],
+#else
+ width = m_ScaledWidths[sizeId],
+ height = m_ScaledHeights[sizeId],
+#endif
+ colorFormat = format,
+ depthBufferBits = 0,
+ volumeDepth = 1,
+ autoGenerateMips = false,
+ msaaSamples = 1,
+#if UNITY_2019_2_OR_NEWER
+ mipCount = 1,
+#endif
+#if UNITY_2019_4_OR_NEWER
+ useDynamicScale = dynamicScale,
+#endif
+ enableRandomWrite = uav,
+ dimension = TextureDimension.Tex2D,
+ sRGB = false
+ }, FilterMode.Point);
+ }
+
+ void AllocArray(CommandBuffer cmd, int id, MipLevel size, RenderTextureFormat format, bool uav, bool dynamicScale)
+ {
+ int sizeId = (int)size;
+ cmd.GetTemporaryRT(id, new RenderTextureDescriptor
+ {
+#if UNITY_2019_4_OR_NEWER
+ width = m_Widths[sizeId],
+ height = m_Heights[sizeId],
+#else
+ width = m_ScaledWidths[sizeId],
+ height = m_ScaledHeights[sizeId],
+#endif
+ colorFormat = format,
+ depthBufferBits = 0,
+ volumeDepth = 16,
+ autoGenerateMips = false,
+ msaaSamples = 1,
+#if UNITY_2019_2_OR_NEWER
+ mipCount = 1,
+#endif
+#if UNITY_2019_4_OR_NEWER
+ useDynamicScale = dynamicScale,
+#endif
+ enableRandomWrite = uav,
+ dimension = TextureDimension.Tex2DArray,
+ sRGB = false
+ }, FilterMode.Point);
+ }
+
+ void Release(CommandBuffer cmd, int id)
+ {
+ cmd.ReleaseTemporaryRT(id);
+ }
+
+ // Calculate values in _ZBuferParams (built-in shader variable)
+ // We can't use _ZBufferParams in compute shaders, so this function is
+ // used to give the values in it to compute shaders.
+ Vector4 CalculateZBufferParams(Camera camera)
+ {
+ float fpn = camera.farClipPlane / camera.nearClipPlane;
+
+ if (SystemInfo.usesReversedZBuffer)
+ return new Vector4(fpn - 1f, 1f, 0f, 0f);
+
+ return new Vector4(1f - fpn, fpn, 0f, 0f);
+ }
+
+ float CalculateTanHalfFovHeight(Camera camera)
+ {
+ return 1f / camera.projectionMatrix[0, 0];
+ }
+
+ Vector2 GetSize(MipLevel mip)
+ {
+ return new Vector2(m_ScaledWidths[(int)mip], m_ScaledHeights[(int)mip]);
+ }
+
+ Vector3 GetSizeArray(MipLevel mip)
+ {
+ return new Vector3(m_ScaledWidths[(int)mip], m_ScaledHeights[(int)mip], 16);
+ }
+
+ public void GenerateAOMap(CommandBuffer cmd, Camera camera, RenderTargetIdentifier destination, RenderTargetIdentifier? depthMap, bool invert, bool isMSAA)
+ {
+ // Base size
+ m_Widths[0] = m_ScaledWidths[0] = camera.pixelWidth * (RuntimeUtilities.isSinglePassStereoEnabled ? 2 : 1);
+ m_Heights[0] = m_ScaledHeights[0] = camera.pixelHeight;
+#if UNITY_2017_3_OR_NEWER
+ m_ScaledWidths[0] = camera.scaledPixelWidth * (RuntimeUtilities.isSinglePassStereoEnabled ? 2 : 1);
+ m_ScaledHeights[0] = camera.scaledPixelHeight;
+#endif
+ float widthScalingFactor = ScalableBufferManager.widthScaleFactor;
+ float heightScalingFactor = ScalableBufferManager.heightScaleFactor;
+ // L1 -> L6 sizes
+ for (int i = 1; i < 7; i++)
+ {
+ int div = 1 << i;
+ m_Widths[i] = (m_Widths[0] + (div - 1)) / div;
+ m_Heights[i] = (m_Heights[0] + (div - 1)) / div;
+ m_ScaledWidths[i] = Mathf.CeilToInt(m_Widths[i] * widthScalingFactor);
+ m_ScaledHeights[i] = Mathf.CeilToInt(m_Heights[i] * heightScalingFactor);
+ }
+
+ // Allocate temporary textures
+ PushAllocCommands(cmd, isMSAA, camera);
+
+ // Render logic
+ PushDownsampleCommands(cmd, camera, depthMap, isMSAA);
+
+ float tanHalfFovH = CalculateTanHalfFovHeight(camera);
+ PushRenderCommands(cmd, ShaderIDs.TiledDepth1, ShaderIDs.Occlusion1, GetSizeArray(MipLevel.L3), tanHalfFovH, isMSAA);
+ PushRenderCommands(cmd, ShaderIDs.TiledDepth2, ShaderIDs.Occlusion2, GetSizeArray(MipLevel.L4), tanHalfFovH, isMSAA);
+ PushRenderCommands(cmd, ShaderIDs.TiledDepth3, ShaderIDs.Occlusion3, GetSizeArray(MipLevel.L5), tanHalfFovH, isMSAA);
+ PushRenderCommands(cmd, ShaderIDs.TiledDepth4, ShaderIDs.Occlusion4, GetSizeArray(MipLevel.L6), tanHalfFovH, isMSAA);
+
+ PushUpsampleCommands(cmd, ShaderIDs.LowDepth4, ShaderIDs.Occlusion4, ShaderIDs.LowDepth3, ShaderIDs.Occlusion3, ShaderIDs.Combined3, GetSize(MipLevel.L4), GetSize(MipLevel.L3), isMSAA);
+ PushUpsampleCommands(cmd, ShaderIDs.LowDepth3, ShaderIDs.Combined3, ShaderIDs.LowDepth2, ShaderIDs.Occlusion2, ShaderIDs.Combined2, GetSize(MipLevel.L3), GetSize(MipLevel.L2), isMSAA);
+ PushUpsampleCommands(cmd, ShaderIDs.LowDepth2, ShaderIDs.Combined2, ShaderIDs.LowDepth1, ShaderIDs.Occlusion1, ShaderIDs.Combined1, GetSize(MipLevel.L2), GetSize(MipLevel.L1), isMSAA);
+ PushUpsampleCommands(cmd, ShaderIDs.LowDepth1, ShaderIDs.Combined1, ShaderIDs.LinearDepth, null, destination, GetSize(MipLevel.L1), GetSize(MipLevel.Original), isMSAA, invert);
+
+ // Cleanup
+ PushReleaseCommands(cmd);
+ }
+
+ void PushAllocCommands(CommandBuffer cmd, bool isMSAA, Camera camera)
+ {
+ bool dynamicResolutionEnabled = RuntimeUtilities.IsDynamicResolutionEnabled(camera);
+ if (isMSAA)
+ {
+ Alloc(cmd, ShaderIDs.LinearDepth, MipLevel.Original, RenderTextureFormat.RGHalf, true, dynamicResolutionEnabled);
+
+ Alloc(cmd, ShaderIDs.LowDepth1, MipLevel.L1, RenderTextureFormat.RGFloat, true, dynamicResolutionEnabled);
+ Alloc(cmd, ShaderIDs.LowDepth2, MipLevel.L2, RenderTextureFormat.RGFloat, true, dynamicResolutionEnabled);
+ Alloc(cmd, ShaderIDs.LowDepth3, MipLevel.L3, RenderTextureFormat.RGFloat, true, dynamicResolutionEnabled);
+ Alloc(cmd, ShaderIDs.LowDepth4, MipLevel.L4, RenderTextureFormat.RGFloat, true, dynamicResolutionEnabled);
+
+ AllocArray(cmd, ShaderIDs.TiledDepth1, MipLevel.L3, RenderTextureFormat.RGHalf, true, dynamicResolutionEnabled);
+ AllocArray(cmd, ShaderIDs.TiledDepth2, MipLevel.L4, RenderTextureFormat.RGHalf, true, dynamicResolutionEnabled);
+ AllocArray(cmd, ShaderIDs.TiledDepth3, MipLevel.L5, RenderTextureFormat.RGHalf, true, dynamicResolutionEnabled);
+ AllocArray(cmd, ShaderIDs.TiledDepth4, MipLevel.L6, RenderTextureFormat.RGHalf, true, dynamicResolutionEnabled);
+
+ Alloc(cmd, ShaderIDs.Occlusion1, MipLevel.L1, RenderTextureFormat.RG16, true, dynamicResolutionEnabled);
+ Alloc(cmd, ShaderIDs.Occlusion2, MipLevel.L2, RenderTextureFormat.RG16, true, dynamicResolutionEnabled);
+ Alloc(cmd, ShaderIDs.Occlusion3, MipLevel.L3, RenderTextureFormat.RG16, true, dynamicResolutionEnabled);
+ Alloc(cmd, ShaderIDs.Occlusion4, MipLevel.L4, RenderTextureFormat.RG16, true, dynamicResolutionEnabled);
+
+ Alloc(cmd, ShaderIDs.Combined1, MipLevel.L1, RenderTextureFormat.RG16, true, dynamicResolutionEnabled);
+ Alloc(cmd, ShaderIDs.Combined2, MipLevel.L2, RenderTextureFormat.RG16, true, dynamicResolutionEnabled);
+ Alloc(cmd, ShaderIDs.Combined3, MipLevel.L3, RenderTextureFormat.RG16, true, dynamicResolutionEnabled);
+ }
+ else
+ {
+ Alloc(cmd, ShaderIDs.LinearDepth, MipLevel.Original, RenderTextureFormat.RHalf, true, dynamicResolutionEnabled);
+
+ Alloc(cmd, ShaderIDs.LowDepth1, MipLevel.L1, RenderTextureFormat.RFloat, true, dynamicResolutionEnabled);
+ Alloc(cmd, ShaderIDs.LowDepth2, MipLevel.L2, RenderTextureFormat.RFloat, true, dynamicResolutionEnabled);
+ Alloc(cmd, ShaderIDs.LowDepth3, MipLevel.L3, RenderTextureFormat.RFloat, true, dynamicResolutionEnabled);
+ Alloc(cmd, ShaderIDs.LowDepth4, MipLevel.L4, RenderTextureFormat.RFloat, true, dynamicResolutionEnabled);
+
+ AllocArray(cmd, ShaderIDs.TiledDepth1, MipLevel.L3, RenderTextureFormat.RHalf, true, dynamicResolutionEnabled);
+ AllocArray(cmd, ShaderIDs.TiledDepth2, MipLevel.L4, RenderTextureFormat.RHalf, true, dynamicResolutionEnabled);
+ AllocArray(cmd, ShaderIDs.TiledDepth3, MipLevel.L5, RenderTextureFormat.RHalf, true, dynamicResolutionEnabled);
+ AllocArray(cmd, ShaderIDs.TiledDepth4, MipLevel.L6, RenderTextureFormat.RHalf, true, dynamicResolutionEnabled);
+
+ Alloc(cmd, ShaderIDs.Occlusion1, MipLevel.L1, RenderTextureFormat.R8, true, dynamicResolutionEnabled);
+ Alloc(cmd, ShaderIDs.Occlusion2, MipLevel.L2, RenderTextureFormat.R8, true, dynamicResolutionEnabled);
+ Alloc(cmd, ShaderIDs.Occlusion3, MipLevel.L3, RenderTextureFormat.R8, true, dynamicResolutionEnabled);
+ Alloc(cmd, ShaderIDs.Occlusion4, MipLevel.L4, RenderTextureFormat.R8, true, dynamicResolutionEnabled);
+
+ Alloc(cmd, ShaderIDs.Combined1, MipLevel.L1, RenderTextureFormat.R8, true, dynamicResolutionEnabled);
+ Alloc(cmd, ShaderIDs.Combined2, MipLevel.L2, RenderTextureFormat.R8, true, dynamicResolutionEnabled);
+ Alloc(cmd, ShaderIDs.Combined3, MipLevel.L3, RenderTextureFormat.R8, true, dynamicResolutionEnabled);
+ }
+ }
+
+ void PushDownsampleCommands(CommandBuffer cmd, Camera camera, RenderTargetIdentifier? depthMap, bool isMSAA)
+ {
+ RenderTargetIdentifier depthMapId;
+ bool needDepthMapRelease = false;
+
+ if (depthMap != null)
+ {
+ depthMapId = depthMap.Value;
+ }
+ else
+ {
+ // Make a copy of the depth texture, or reuse the resolved depth
+ // buffer (it's only available in some specific situations).
+ if (!RuntimeUtilities.IsResolvedDepthAvailable(camera))
+ {
+ Alloc(cmd, ShaderIDs.DepthCopy, MipLevel.Original, RenderTextureFormat.RFloat, false, RuntimeUtilities.IsDynamicResolutionEnabled(camera));
+ depthMapId = new RenderTargetIdentifier(ShaderIDs.DepthCopy);
+ cmd.BlitFullscreenTriangle(BuiltinRenderTextureType.None, depthMapId, m_PropertySheet, (int)Pass.DepthCopy);
+ needDepthMapRelease = true;
+ }
+ else
+ {
+ depthMapId = BuiltinRenderTextureType.ResolvedDepth;
+ }
+ }
+
+ // 1st downsampling pass.
+ var cs = m_Resources.computeShaders.multiScaleAODownsample1;
+ int kernel = cs.FindKernel(isMSAA ? "MultiScaleVODownsample1_MSAA" : "MultiScaleVODownsample1");
+
+ cmd.SetComputeTextureParam(cs, kernel, "LinearZ", ShaderIDs.LinearDepth);
+ cmd.SetComputeTextureParam(cs, kernel, "DS2x", ShaderIDs.LowDepth1);
+ cmd.SetComputeTextureParam(cs, kernel, "DS4x", ShaderIDs.LowDepth2);
+ cmd.SetComputeTextureParam(cs, kernel, "DS2xAtlas", ShaderIDs.TiledDepth1);
+ cmd.SetComputeTextureParam(cs, kernel, "DS4xAtlas", ShaderIDs.TiledDepth2);
+ cmd.SetComputeVectorParam(cs, "ZBufferParams", CalculateZBufferParams(camera));
+ cmd.SetComputeTextureParam(cs, kernel, "Depth", depthMapId);
+
+ cmd.DispatchCompute(cs, kernel, m_ScaledWidths[(int)MipLevel.L4], m_ScaledHeights[(int)MipLevel.L4], 1);
+
+ if (needDepthMapRelease)
+ Release(cmd, ShaderIDs.DepthCopy);
+
+ // 2nd downsampling pass.
+ cs = m_Resources.computeShaders.multiScaleAODownsample2;
+ kernel = isMSAA ? cs.FindKernel("MultiScaleVODownsample2_MSAA") : cs.FindKernel("MultiScaleVODownsample2");
+
+ cmd.SetComputeTextureParam(cs, kernel, "DS4x", ShaderIDs.LowDepth2);
+ cmd.SetComputeTextureParam(cs, kernel, "DS8x", ShaderIDs.LowDepth3);
+ cmd.SetComputeTextureParam(cs, kernel, "DS16x", ShaderIDs.LowDepth4);
+ cmd.SetComputeTextureParam(cs, kernel, "DS8xAtlas", ShaderIDs.TiledDepth3);
+ cmd.SetComputeTextureParam(cs, kernel, "DS16xAtlas", ShaderIDs.TiledDepth4);
+
+ cmd.DispatchCompute(cs, kernel, m_ScaledWidths[(int)MipLevel.L6], m_ScaledHeights[(int)MipLevel.L6], 1);
+ }
+
+ void PushRenderCommands(CommandBuffer cmd, int source, int destination, Vector3 sourceSize, float tanHalfFovH, bool isMSAA)
+ {
+ // Here we compute multipliers that convert the center depth value into (the reciprocal
+ // of) sphere thicknesses at each sample location. This assumes a maximum sample radius
+ // of 5 units, but since a sphere has no thickness at its extent, we don't need to
+ // sample that far out. Only samples whole integer offsets with distance less than 25
+ // are used. This means that there is no sample at (3, 4) because its distance is
+ // exactly 25 (and has a thickness of 0.)
+
+ // The shaders are set up to sample a circular region within a 5-pixel radius.
+ const float kScreenspaceDiameter = 10f;
+
+ // SphereDiameter = CenterDepth * ThicknessMultiplier. This will compute the thickness
+ // of a sphere centered at a specific depth. The ellipsoid scale can stretch a sphere
+ // into an ellipsoid, which changes the characteristics of the AO.
+ // TanHalfFovH: Radius of sphere in depth units if its center lies at Z = 1
+ // ScreenspaceDiameter: Diameter of sample sphere in pixel units
+ // ScreenspaceDiameter / BufferWidth: Ratio of the screen width that the sphere actually covers
+ float thicknessMultiplier = 2f * tanHalfFovH * kScreenspaceDiameter / sourceSize.x;
+ if (RuntimeUtilities.isSinglePassStereoEnabled)
+ thicknessMultiplier *= 2f;
+
+ // This will transform a depth value from [0, thickness] to [0, 1].
+ float inverseRangeFactor = 1f / thicknessMultiplier;
+
+ // The thicknesses are smaller for all off-center samples of the sphere. Compute
+ // thicknesses relative to the center sample.
+ for (int i = 0; i < 12; i++)
+ m_InvThicknessTable[i] = inverseRangeFactor / m_SampleThickness[i];
+
+ // These are the weights that are multiplied against the samples because not all samples
+ // are equally important. The farther the sample is from the center location, the less
+ // they matter. We use the thickness of the sphere to determine the weight. The scalars
+ // in front are the number of samples with this weight because we sum the samples
+ // together before multiplying by the weight, so as an aggregate all of those samples
+ // matter more. After generating this table, the weights are normalized.
+ m_SampleWeightTable[0] = 4 * m_SampleThickness[0]; // Axial
+ m_SampleWeightTable[1] = 4 * m_SampleThickness[1]; // Axial
+ m_SampleWeightTable[2] = 4 * m_SampleThickness[2]; // Axial
+ m_SampleWeightTable[3] = 4 * m_SampleThickness[3]; // Axial
+ m_SampleWeightTable[4] = 4 * m_SampleThickness[4]; // Diagonal
+ m_SampleWeightTable[5] = 8 * m_SampleThickness[5]; // L-shaped
+ m_SampleWeightTable[6] = 8 * m_SampleThickness[6]; // L-shaped
+ m_SampleWeightTable[7] = 8 * m_SampleThickness[7]; // L-shaped
+ m_SampleWeightTable[8] = 4 * m_SampleThickness[8]; // Diagonal
+ m_SampleWeightTable[9] = 8 * m_SampleThickness[9]; // L-shaped
+ m_SampleWeightTable[10] = 8 * m_SampleThickness[10]; // L-shaped
+ m_SampleWeightTable[11] = 4 * m_SampleThickness[11]; // Diagonal
+
+ // Zero out the unused samples.
+ // FIXME: should we support SAMPLE_EXHAUSTIVELY mode?
+ m_SampleWeightTable[0] = 0;
+ m_SampleWeightTable[2] = 0;
+ m_SampleWeightTable[5] = 0;
+ m_SampleWeightTable[7] = 0;
+ m_SampleWeightTable[9] = 0;
+
+ // Normalize the weights by dividing by the sum of all weights
+ var totalWeight = 0f;
+
+ foreach (float w in m_SampleWeightTable)
+ totalWeight += w;
+
+ for (int i = 0; i < m_SampleWeightTable.Length; i++)
+ m_SampleWeightTable[i] /= totalWeight;
+
+ // Set the arguments for the render kernel.
+ var cs = m_Resources.computeShaders.multiScaleAORender;
+ int kernel = isMSAA ? cs.FindKernel("MultiScaleVORender_MSAA_interleaved") : cs.FindKernel("MultiScaleVORender_interleaved");
+
+ cmd.SetComputeFloatParams(cs, "gInvThicknessTable", m_InvThicknessTable);
+ cmd.SetComputeFloatParams(cs, "gSampleWeightTable", m_SampleWeightTable);
+ cmd.SetComputeVectorParam(cs, "gInvSliceDimension", new Vector2(1f / sourceSize.x, 1f / sourceSize.y));
+ cmd.SetComputeVectorParam(cs, "AdditionalParams", new Vector3(-1f / m_Settings.thicknessModifier.value, m_Settings.intensity.value, m_Settings.zBias.value));
+ cmd.SetComputeTextureParam(cs, kernel, "DepthTex", source);
+ cmd.SetComputeTextureParam(cs, kernel, "Occlusion", destination);
+
+ // Calculate the thread group count and add a dispatch command with them.
+ uint xsize, ysize, zsize;
+ cs.GetKernelThreadGroupSizes(kernel, out xsize, out ysize, out zsize);
+
+ cmd.DispatchCompute(
+ cs, kernel,
+ ((int)sourceSize.x + (int)xsize - 1) / (int)xsize,
+ ((int)sourceSize.y + (int)ysize - 1) / (int)ysize,
+ ((int)sourceSize.z + (int)zsize - 1) / (int)zsize
+ );
+ }
+
+ void PushUpsampleCommands(CommandBuffer cmd, int lowResDepth, int interleavedAO, int highResDepth, int? highResAO, RenderTargetIdentifier dest, Vector3 lowResDepthSize, Vector2 highResDepthSize, bool isMSAA, bool invert = false)
+ {
+ var cs = m_Resources.computeShaders.multiScaleAOUpsample;
+ int kernel = 0;
+ if (!isMSAA)
+ {
+ kernel = cs.FindKernel(highResAO == null ? invert
+ ? "MultiScaleVOUpSample_invert"
+ : "MultiScaleVOUpSample"
+ : "MultiScaleVOUpSample_blendout");
+ }
+ else
+ {
+ kernel = cs.FindKernel(highResAO == null ? invert
+ ? "MultiScaleVOUpSample_MSAA_invert"
+ : "MultiScaleVOUpSample_MSAA"
+ : "MultiScaleVOUpSample_MSAA_blendout");
+ }
+
+
+ float stepSize = 1920f / lowResDepthSize.x;
+ float bTolerance = 1f - Mathf.Pow(10f, m_Settings.blurTolerance.value) * stepSize;
+ bTolerance *= bTolerance;
+ float uTolerance = Mathf.Pow(10f, m_Settings.upsampleTolerance.value);
+ float noiseFilterWeight = 1f / (Mathf.Pow(10f, m_Settings.noiseFilterTolerance.value) + uTolerance);
+
+ cmd.SetComputeVectorParam(cs, "InvLowResolution", new Vector2(1f / lowResDepthSize.x, 1f / lowResDepthSize.y));
+ cmd.SetComputeVectorParam(cs, "InvHighResolution", new Vector2(1f / highResDepthSize.x, 1f / highResDepthSize.y));
+ cmd.SetComputeVectorParam(cs, "AdditionalParams", new Vector4(noiseFilterWeight, stepSize, bTolerance, uTolerance));
+
+ cmd.SetComputeTextureParam(cs, kernel, "LoResDB", lowResDepth);
+ cmd.SetComputeTextureParam(cs, kernel, "HiResDB", highResDepth);
+ cmd.SetComputeTextureParam(cs, kernel, "LoResAO1", interleavedAO);
+
+ if (highResAO != null)
+ cmd.SetComputeTextureParam(cs, kernel, "HiResAO", highResAO.Value);
+
+ cmd.SetComputeTextureParam(cs, kernel, "AoResult", dest);
+
+ int xcount = ((int)highResDepthSize.x + 17) / 16;
+ int ycount = ((int)highResDepthSize.y + 17) / 16;
+ cmd.DispatchCompute(cs, kernel, xcount, ycount, 1);
+ }
+
+ void PushReleaseCommands(CommandBuffer cmd)
+ {
+ Release(cmd, ShaderIDs.LinearDepth);
+
+ Release(cmd, ShaderIDs.LowDepth1);
+ Release(cmd, ShaderIDs.LowDepth2);
+ Release(cmd, ShaderIDs.LowDepth3);
+ Release(cmd, ShaderIDs.LowDepth4);
+
+ Release(cmd, ShaderIDs.TiledDepth1);
+ Release(cmd, ShaderIDs.TiledDepth2);
+ Release(cmd, ShaderIDs.TiledDepth3);
+ Release(cmd, ShaderIDs.TiledDepth4);
+
+ Release(cmd, ShaderIDs.Occlusion1);
+ Release(cmd, ShaderIDs.Occlusion2);
+ Release(cmd, ShaderIDs.Occlusion3);
+ Release(cmd, ShaderIDs.Occlusion4);
+
+ Release(cmd, ShaderIDs.Combined1);
+ Release(cmd, ShaderIDs.Combined2);
+ Release(cmd, ShaderIDs.Combined3);
+ }
+
+ void PreparePropertySheet(PostProcessRenderContext context)
+ {
+ var sheet = context.propertySheets.Get(m_Resources.shaders.multiScaleAO);
+ sheet.ClearKeywords();
+ sheet.properties.SetVector(ShaderIDs.AOColor, Color.white - m_Settings.color.value);
+ m_PropertySheet = sheet;
+ }
+
+ void CheckAOTexture(PostProcessRenderContext context)
+ {
+ bool AOUpdateNeeded = m_AmbientOnlyAO == null || !m_AmbientOnlyAO.IsCreated() || m_AmbientOnlyAO.width != context.width || m_AmbientOnlyAO.height != context.height;
+#if UNITY_2017_3_OR_NEWER
+ bool dynamicResolutionEnabled = RuntimeUtilities.IsDynamicResolutionEnabled(context.camera);
+ AOUpdateNeeded = AOUpdateNeeded || m_AmbientOnlyAO.useDynamicScale != dynamicResolutionEnabled;
+#endif
+ if (AOUpdateNeeded)
+ {
+ RuntimeUtilities.Destroy(m_AmbientOnlyAO);
+
+ m_AmbientOnlyAO = new RenderTexture(context.width, context.height, 0, RenderTextureFormat.R8, RenderTextureReadWrite.Linear)
+ {
+ hideFlags = HideFlags.DontSave,
+ filterMode = FilterMode.Point,
+ enableRandomWrite = true,
+#if UNITY_2017_3_OR_NEWER
+ useDynamicScale = dynamicResolutionEnabled
+#endif
+ };
+ m_AmbientOnlyAO.Create();
+ }
+ }
+
+ void PushDebug(PostProcessRenderContext context)
+ {
+ if (context.IsDebugOverlayEnabled(DebugOverlay.AmbientOcclusion))
+ context.PushDebugOverlay(context.command, m_AmbientOnlyAO, m_PropertySheet, (int)Pass.DebugOverlay);
+ }
+
+ public void RenderAfterOpaque(PostProcessRenderContext context)
+ {
+ var cmd = context.command;
+ cmd.BeginSample("Ambient Occlusion");
+ SetResources(context.resources);
+ PreparePropertySheet(context);
+ CheckAOTexture(context);
+
+ // In Forward mode, fog is applied at the object level in the grometry pass so we need
+ // to apply it to AO as well or it'll drawn on top of the fog effect.
+ if (context.camera.actualRenderingPath == RenderingPath.Forward && RenderSettings.fog)
+ {
+ m_PropertySheet.EnableKeyword("APPLY_FORWARD_FOG");
+ m_PropertySheet.properties.SetVector(
+ ShaderIDs.FogParams,
+ new Vector3(RenderSettings.fogDensity, RenderSettings.fogStartDistance, RenderSettings.fogEndDistance)
+ );
+ }
+
+ GenerateAOMap(cmd, context.camera, m_AmbientOnlyAO, null, false, false);
+ PushDebug(context);
+ cmd.SetGlobalTexture(ShaderIDs.MSVOcclusionTexture, m_AmbientOnlyAO);
+ cmd.BlitFullscreenTriangle(BuiltinRenderTextureType.None, BuiltinRenderTextureType.CameraTarget, m_PropertySheet, (int)Pass.CompositionForward, RenderBufferLoadAction.Load);
+ cmd.EndSample("Ambient Occlusion");
+ }
+
+ public void RenderAmbientOnly(PostProcessRenderContext context)
+ {
+ var cmd = context.command;
+ cmd.BeginSample("Ambient Occlusion Render");
+ SetResources(context.resources);
+ PreparePropertySheet(context);
+ CheckAOTexture(context);
+ GenerateAOMap(cmd, context.camera, m_AmbientOnlyAO, null, false, false);
+ PushDebug(context);
+ cmd.EndSample("Ambient Occlusion Render");
+ }
+
+ public void CompositeAmbientOnly(PostProcessRenderContext context)
+ {
+ var cmd = context.command;
+ cmd.BeginSample("Ambient Occlusion Composite");
+ cmd.SetGlobalTexture(ShaderIDs.MSVOcclusionTexture, m_AmbientOnlyAO);
+ cmd.BlitFullscreenTriangle(BuiltinRenderTextureType.None, m_MRT, BuiltinRenderTextureType.CameraTarget, m_PropertySheet, (int)Pass.CompositionDeferred);
+ cmd.EndSample("Ambient Occlusion Composite");
+ }
+
+ public void Release()
+ {
+ RuntimeUtilities.Destroy(m_AmbientOnlyAO);
+ m_AmbientOnlyAO = null;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/MultiScaleVO.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Effects/MultiScaleVO.cs.meta
new file mode 100644
index 0000000..f7f7f95
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/MultiScaleVO.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: f59da4cf1b7dee244bc37fa6add23b00
+timeCreated: 1503308000
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/ScalableAO.cs b/com.unity.postprocessing/PostProcessing/Runtime/Effects/ScalableAO.cs
new file mode 100644
index 0000000..9842b73
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/ScalableAO.cs
@@ -0,0 +1,166 @@
+using System;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ // Scalable ambient obscurance
+ [UnityEngine.Scripting.Preserve]
+ [Serializable]
+ internal sealed class ScalableAO : IAmbientOcclusionMethod
+ {
+ RenderTexture m_Result;
+ PropertySheet m_PropertySheet;
+ AmbientOcclusion m_Settings;
+
+ readonly RenderTargetIdentifier[] m_MRT =
+ {
+ BuiltinRenderTextureType.GBuffer0, // Albedo, Occ
+ BuiltinRenderTextureType.CameraTarget // Ambient
+ };
+
+ readonly int[] m_SampleCount = { 4, 6, 10, 8, 12 };
+
+ enum Pass
+ {
+ OcclusionEstimationForward,
+ OcclusionEstimationDeferred,
+ HorizontalBlurForward,
+ HorizontalBlurDeferred,
+ VerticalBlur,
+ CompositionForward,
+ CompositionDeferred,
+ DebugOverlay
+ }
+
+ public ScalableAO(AmbientOcclusion settings)
+ {
+ m_Settings = settings;
+ }
+
+ public DepthTextureMode GetCameraFlags()
+ {
+ return DepthTextureMode.Depth | DepthTextureMode.DepthNormals;
+ }
+
+ void DoLazyInitialization(PostProcessRenderContext context)
+ {
+ m_PropertySheet = context.propertySheets.Get(context.resources.shaders.scalableAO);
+
+ bool reset = false;
+
+ if (m_Result == null || !m_Result.IsCreated())
+ {
+ // Initial allocation
+ m_Result = context.GetScreenSpaceTemporaryRT(0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
+ m_Result.hideFlags = HideFlags.DontSave;
+ m_Result.filterMode = FilterMode.Bilinear;
+
+ reset = true;
+ }
+ else if (m_Result.width != context.width || m_Result.height != context.height)
+ {
+ // Release and reallocate
+ m_Result.Release();
+ m_Result.width = context.width;
+ m_Result.height = context.height;
+ reset = true;
+ }
+
+ if (reset)
+ m_Result.Create();
+ }
+
+ void Render(PostProcessRenderContext context, CommandBuffer cmd, int occlusionSource)
+ {
+ DoLazyInitialization(context);
+ m_Settings.radius.value = Mathf.Max(m_Settings.radius.value, 1e-4f);
+
+ // Material setup
+ // Always use a quater-res AO buffer unless High/Ultra quality is set.
+ bool downsampling = (int)m_Settings.quality.value < (int)AmbientOcclusionQuality.High;
+ float px = m_Settings.intensity.value;
+ float py = m_Settings.radius.value;
+ float pz = downsampling ? 0.5f : 1f;
+ float pw = m_SampleCount[(int)m_Settings.quality.value];
+
+ var sheet = m_PropertySheet;
+ sheet.ClearKeywords();
+ sheet.properties.SetVector(ShaderIDs.AOParams, new Vector4(px, py, pz, pw));
+ sheet.properties.SetVector(ShaderIDs.AOColor, Color.white - m_Settings.color.value);
+
+ // In forward fog is applied at the object level in the grometry pass so we need to
+ // apply it to AO as well or it'll drawn on top of the fog effect.
+ // Not needed in Deferred.
+ if (context.camera.actualRenderingPath == RenderingPath.Forward && RenderSettings.fog)
+ {
+ sheet.EnableKeyword("APPLY_FORWARD_FOG");
+ sheet.properties.SetVector(
+ ShaderIDs.FogParams,
+ new Vector3(RenderSettings.fogDensity, RenderSettings.fogStartDistance, RenderSettings.fogEndDistance)
+ );
+ }
+
+ // Texture setup
+ int ts = downsampling ? 2 : 1;
+ const RenderTextureFormat kFormat = RenderTextureFormat.ARGB32;
+ const RenderTextureReadWrite kRWMode = RenderTextureReadWrite.Linear;
+ const FilterMode kFilter = FilterMode.Bilinear;
+
+ // AO buffer
+ var rtMask = ShaderIDs.OcclusionTexture1;
+ int scaledWidth = context.width / ts;
+ int scaledHeight = context.height / ts;
+ context.GetScreenSpaceTemporaryRT(cmd, rtMask, 0, kFormat, kRWMode, kFilter, scaledWidth, scaledHeight);
+
+ // AO estimation
+ cmd.BlitFullscreenTriangle(BuiltinRenderTextureType.None, rtMask, sheet, (int)Pass.OcclusionEstimationForward + occlusionSource);
+
+ // Blur buffer
+ var rtBlur = ShaderIDs.OcclusionTexture2;
+ context.GetScreenSpaceTemporaryRT(cmd, rtBlur, 0, kFormat, kRWMode, kFilter);
+
+ // Separable blur (horizontal pass)
+ cmd.BlitFullscreenTriangle(rtMask, rtBlur, sheet, (int)Pass.HorizontalBlurForward + occlusionSource);
+ cmd.ReleaseTemporaryRT(rtMask);
+
+ // Separable blur (vertical pass)
+ cmd.BlitFullscreenTriangle(rtBlur, m_Result, sheet, (int)Pass.VerticalBlur);
+ cmd.ReleaseTemporaryRT(rtBlur);
+
+ if (context.IsDebugOverlayEnabled(DebugOverlay.AmbientOcclusion))
+ context.PushDebugOverlay(cmd, m_Result, sheet, (int)Pass.DebugOverlay);
+ }
+
+ public void RenderAfterOpaque(PostProcessRenderContext context)
+ {
+ var cmd = context.command;
+ cmd.BeginSample("Ambient Occlusion");
+ Render(context, cmd, 0);
+ cmd.SetGlobalTexture(ShaderIDs.SAOcclusionTexture, m_Result);
+ cmd.BlitFullscreenTriangle(BuiltinRenderTextureType.None, BuiltinRenderTextureType.CameraTarget, m_PropertySheet, (int)Pass.CompositionForward, RenderBufferLoadAction.Load);
+ cmd.EndSample("Ambient Occlusion");
+ }
+
+ public void RenderAmbientOnly(PostProcessRenderContext context)
+ {
+ var cmd = context.command;
+ cmd.BeginSample("Ambient Occlusion Render");
+ Render(context, cmd, 1);
+ cmd.EndSample("Ambient Occlusion Render");
+ }
+
+ public void CompositeAmbientOnly(PostProcessRenderContext context)
+ {
+ var cmd = context.command;
+ cmd.BeginSample("Ambient Occlusion Composite");
+ cmd.SetGlobalTexture(ShaderIDs.SAOcclusionTexture, m_Result);
+ cmd.BlitFullscreenTriangle(BuiltinRenderTextureType.None, m_MRT, BuiltinRenderTextureType.CameraTarget, m_PropertySheet, (int)Pass.CompositionDeferred);
+ cmd.EndSample("Ambient Occlusion Composite");
+ }
+
+ public void Release()
+ {
+ RuntimeUtilities.Destroy(m_Result);
+ m_Result = null;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/ScalableAO.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Effects/ScalableAO.cs.meta
new file mode 100644
index 0000000..41a662c
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/ScalableAO.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: c564cc69bd8582a48b2e0a2090d28361
+timeCreated: 1503307993
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/ScreenSpaceReflections.cs b/com.unity.postprocessing/PostProcessing/Runtime/Effects/ScreenSpaceReflections.cs
new file mode 100644
index 0000000..354710b
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/ScreenSpaceReflections.cs
@@ -0,0 +1,343 @@
+using System;
+using UnityEngine.Assertions;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// Screen-space Reflections quality presets.
+ ///
+ public enum ScreenSpaceReflectionPreset
+ {
+ ///
+ /// Lowest quality.
+ ///
+ Lower,
+
+ ///
+ /// Low quality.
+ ///
+ Low,
+
+ ///
+ /// Medium quality.
+ ///
+ Medium,
+
+ ///
+ /// High quality.
+ ///
+ High,
+
+ ///
+ /// Higher quality.
+ ///
+ Higher,
+
+ ///
+ /// Ultra quality.
+ ///
+ Ultra,
+
+ ///
+ /// Overkill (as in: don't use) quality.
+ ///
+ Overkill,
+
+ ///
+ /// Custom, tweakable quality settings.
+ ///
+ Custom
+ }
+
+ ///
+ /// Screen-space Reflections buffer sizes.
+ ///
+ public enum ScreenSpaceReflectionResolution
+ {
+ ///
+ /// Downsampled buffer. Faster but lower quality.
+ ///
+ Downsampled,
+
+ ///
+ /// Full-sized buffer. Slower but higher quality.
+ ///
+ FullSize,
+
+ ///
+ /// Supersampled buffer. Very slow but much higher quality.
+ ///
+ Supersampled
+ }
+
+ ///
+ /// A volume parameter holding a value.
+ ///
+ [Serializable]
+ public sealed class ScreenSpaceReflectionPresetParameter : ParameterOverride { }
+
+ ///
+ /// A volume parameter holding a value.
+ ///
+ [Serializable]
+ public sealed class ScreenSpaceReflectionResolutionParameter : ParameterOverride { }
+
+ ///
+ /// This class holds settings for the Screen-space Reflections effect.
+ ///
+ [Serializable]
+ [PostProcess(typeof(ScreenSpaceReflectionsRenderer), "Unity/Screen-space reflections")]
+ public sealed class ScreenSpaceReflections : PostProcessEffectSettings
+ {
+ ///
+ /// The quality preset to use for rendering. Use
+ /// to tweak settings.
+ ///
+ [Tooltip("Choose a quality preset, or use \"Custom\" to create your own custom preset. Don't use a preset higher than \"Medium\" if you desire good performance on consoles.")]
+ public ScreenSpaceReflectionPresetParameter preset = new ScreenSpaceReflectionPresetParameter { value = ScreenSpaceReflectionPreset.Medium };
+
+ ///
+ /// The maximum number of steps in the raymarching pass. Higher values mean more reflections.
+ ///
+ [Range(0, 256), Tooltip("Maximum number of steps in the raymarching pass. Higher values mean more reflections.")]
+ public IntParameter maximumIterationCount = new IntParameter { value = 16 };
+
+ ///
+ /// Changes the size of the internal buffer. Downsample it to maximize performances or
+ /// supersample it to get slow but higher quality results.
+ ///
+ [Tooltip("Changes the size of the SSR buffer. Downsample it to maximize performances or supersample it for higher quality results with reduced performance.")]
+ public ScreenSpaceReflectionResolutionParameter resolution = new ScreenSpaceReflectionResolutionParameter { value = ScreenSpaceReflectionResolution.Downsampled };
+
+ ///
+ /// The ray thickness. Lower values are more expensive but allow the effect to detect
+ /// smaller details.
+ ///
+ [Range(1f, 64f), Tooltip("Ray thickness. Lower values are more expensive but allow the effect to detect smaller details.")]
+ public FloatParameter thickness = new FloatParameter { value = 8f };
+
+ ///
+ /// The maximum distance to traverse in the scene after which it will stop drawing
+ /// reflections.
+ ///
+ [Tooltip("Maximum distance to traverse after which it will stop drawing reflections.")]
+ public FloatParameter maximumMarchDistance = new FloatParameter { value = 100f };
+
+ ///
+ /// Fades reflections close to the near plane. This is useful to hide common artifacts.
+ ///
+ [Range(0f, 1f), Tooltip("Fades reflections close to the near planes.")]
+ public FloatParameter distanceFade = new FloatParameter { value = 0.5f };
+
+ ///
+ /// Fades reflections close to the screen edges.
+ ///
+ [Range(0f, 1f), Tooltip("Fades reflections close to the screen edges.")]
+ public FloatParameter vignette = new FloatParameter { value = 0.5f };
+
+ ///
+ /// Returns true if the effect is currently enabled and supported.
+ ///
+ /// The current post-processing render context
+ /// true if the effect is currently enabled and supported
+ public override bool IsEnabledAndSupported(PostProcessRenderContext context)
+ {
+ return enabled
+ && context.camera.actualRenderingPath == RenderingPath.DeferredShading
+ && SystemInfo.supportsMotionVectors
+ && SystemInfo.supportsComputeShaders
+ && SystemInfo.copyTextureSupport > CopyTextureSupport.None
+ && context.resources.shaders.screenSpaceReflections
+ && context.resources.shaders.screenSpaceReflections.isSupported
+ && context.resources.computeShaders.gaussianDownsample;
+ }
+ }
+
+ [UnityEngine.Scripting.Preserve]
+ internal sealed class ScreenSpaceReflectionsRenderer : PostProcessEffectRenderer
+ {
+ RenderTexture m_Resolve;
+ RenderTexture m_History;
+ int[] m_MipIDs;
+
+ class QualityPreset
+ {
+ public int maximumIterationCount;
+ public float thickness;
+ public ScreenSpaceReflectionResolution downsampling;
+ }
+
+ readonly QualityPreset[] m_Presets =
+ {
+ new QualityPreset { maximumIterationCount = 10, thickness = 32, downsampling = ScreenSpaceReflectionResolution.Downsampled }, // Lower
+ new QualityPreset { maximumIterationCount = 16, thickness = 32, downsampling = ScreenSpaceReflectionResolution.Downsampled }, // Low
+ new QualityPreset { maximumIterationCount = 32, thickness = 16, downsampling = ScreenSpaceReflectionResolution.Downsampled }, // Medium
+ new QualityPreset { maximumIterationCount = 48, thickness = 8, downsampling = ScreenSpaceReflectionResolution.Downsampled }, // High
+ new QualityPreset { maximumIterationCount = 16, thickness = 32, downsampling = ScreenSpaceReflectionResolution.FullSize }, // Higher
+ new QualityPreset { maximumIterationCount = 48, thickness = 16, downsampling = ScreenSpaceReflectionResolution.FullSize }, // Ultra
+ new QualityPreset { maximumIterationCount = 128, thickness = 12, downsampling = ScreenSpaceReflectionResolution.Supersampled }, // Overkill
+ };
+
+ enum Pass
+ {
+ Test,
+ Resolve,
+ Reproject,
+ Composite
+ }
+
+ public override DepthTextureMode GetCameraFlags()
+ {
+ return DepthTextureMode.Depth | DepthTextureMode.MotionVectors;
+ }
+
+ internal void CheckRT(ref RenderTexture rt, int width, int height, FilterMode filterMode, bool useMipMap)
+ {
+ if (rt == null || !rt.IsCreated() || rt.width != width || rt.height != height)
+ {
+ if (rt != null)
+ {
+ rt.Release();
+ RuntimeUtilities.Destroy(rt);
+ }
+
+ rt = new RenderTexture(width, height, 0, RuntimeUtilities.defaultHDRRenderTextureFormat)
+ {
+ filterMode = filterMode,
+ useMipMap = useMipMap,
+ autoGenerateMips = false,
+ hideFlags = HideFlags.HideAndDontSave
+ };
+
+ rt.Create();
+ }
+ }
+
+ public override void Render(PostProcessRenderContext context)
+ {
+ var cmd = context.command;
+ cmd.BeginSample("Screen-space Reflections");
+
+ // Get quality settings
+ if (settings.preset.value != ScreenSpaceReflectionPreset.Custom)
+ {
+ int id = (int)settings.preset.value;
+ settings.maximumIterationCount.value = m_Presets[id].maximumIterationCount;
+ settings.thickness.value = m_Presets[id].thickness;
+ settings.resolution.value = m_Presets[id].downsampling;
+ }
+
+ settings.maximumMarchDistance.value = Mathf.Max(0f, settings.maximumMarchDistance.value);
+
+ // Square POT target
+ int size = Mathf.ClosestPowerOfTwo(Mathf.Min(context.width, context.height));
+
+ if (settings.resolution.value == ScreenSpaceReflectionResolution.Downsampled)
+ size >>= 1;
+ else if (settings.resolution.value == ScreenSpaceReflectionResolution.Supersampled)
+ size <<= 1;
+
+ // The gaussian pyramid compute works in blocks of 8x8 so make sure the last lod has a
+ // minimum size of 8x8
+ const int kMaxLods = 12;
+ int lodCount = Mathf.FloorToInt(Mathf.Log(size, 2f) - 3f);
+ lodCount = Mathf.Min(lodCount, kMaxLods);
+
+ CheckRT(ref m_Resolve, size, size, FilterMode.Trilinear, true);
+
+ var noiseTex = context.resources.blueNoise256[0];
+ var sheet = context.propertySheets.Get(context.resources.shaders.screenSpaceReflections);
+ sheet.properties.SetTexture(ShaderIDs.Noise, noiseTex);
+
+ var screenSpaceProjectionMatrix = new Matrix4x4();
+ screenSpaceProjectionMatrix.SetRow(0, new Vector4(size * 0.5f, 0f, 0f, size * 0.5f));
+ screenSpaceProjectionMatrix.SetRow(1, new Vector4(0f, size * 0.5f, 0f, size * 0.5f));
+ screenSpaceProjectionMatrix.SetRow(2, new Vector4(0f, 0f, 1f, 0f));
+ screenSpaceProjectionMatrix.SetRow(3, new Vector4(0f, 0f, 0f, 1f));
+
+ var projectionMatrix = GL.GetGPUProjectionMatrix(context.camera.projectionMatrix, false);
+ screenSpaceProjectionMatrix *= projectionMatrix;
+
+ sheet.properties.SetMatrix(ShaderIDs.ViewMatrix, context.camera.worldToCameraMatrix);
+ sheet.properties.SetMatrix(ShaderIDs.InverseViewMatrix, context.camera.worldToCameraMatrix.inverse);
+ sheet.properties.SetMatrix(ShaderIDs.ScreenSpaceProjectionMatrix, screenSpaceProjectionMatrix);
+ sheet.properties.SetVector(ShaderIDs.Params, new Vector4((float)settings.vignette.value, settings.distanceFade.value, settings.maximumMarchDistance.value, lodCount));
+ sheet.properties.SetVector(ShaderIDs.Params2, new Vector4((float)context.width / (float)context.height, (float)size / (float)noiseTex.width, settings.thickness.value, settings.maximumIterationCount.value));
+
+ cmd.GetTemporaryRT(ShaderIDs.Test, size, size, 0, FilterMode.Point, context.sourceFormat);
+ cmd.BlitFullscreenTriangle(context.source, ShaderIDs.Test, sheet, (int)Pass.Test);
+
+ if (context.isSceneView)
+ {
+ cmd.BlitFullscreenTriangle(context.source, m_Resolve, sheet, (int)Pass.Resolve);
+ }
+ else
+ {
+ CheckRT(ref m_History, size, size, FilterMode.Bilinear, false);
+
+ if (m_ResetHistory)
+ {
+ context.command.BlitFullscreenTriangle(context.source, m_History);
+ m_ResetHistory = false;
+ }
+
+ cmd.GetTemporaryRT(ShaderIDs.SSRResolveTemp, size, size, 0, FilterMode.Bilinear, context.sourceFormat);
+ cmd.BlitFullscreenTriangle(context.source, ShaderIDs.SSRResolveTemp, sheet, (int)Pass.Resolve);
+
+ sheet.properties.SetTexture(ShaderIDs.History, m_History);
+ cmd.BlitFullscreenTriangle(ShaderIDs.SSRResolveTemp, m_Resolve, sheet, (int)Pass.Reproject);
+
+ cmd.CopyTexture(m_Resolve, 0, 0, m_History, 0, 0);
+
+ cmd.ReleaseTemporaryRT(ShaderIDs.SSRResolveTemp);
+ }
+
+ cmd.ReleaseTemporaryRT(ShaderIDs.Test);
+
+ // Pre-cache mipmaps ids
+ if (m_MipIDs == null || m_MipIDs.Length == 0)
+ {
+ m_MipIDs = new int[kMaxLods];
+
+ for (int i = 0; i < kMaxLods; i++)
+ m_MipIDs[i] = Shader.PropertyToID("_SSRGaussianMip" + i);
+ }
+
+ var compute = context.resources.computeShaders.gaussianDownsample;
+ int kernel = compute.FindKernel("KMain");
+ var mipFormat = RuntimeUtilities.defaultHDRRenderTextureFormat;
+
+ var last = new RenderTargetIdentifier(m_Resolve);
+
+ for (int i = 0; i < lodCount; i++)
+ {
+ size >>= 1;
+ Assert.IsTrue(size > 0);
+
+ cmd.GetTemporaryRT(m_MipIDs[i], size, size, 0, FilterMode.Bilinear, mipFormat, RenderTextureReadWrite.Default, 1, true);
+ cmd.SetComputeTextureParam(compute, kernel, "_Source", last);
+ cmd.SetComputeTextureParam(compute, kernel, "_Result", m_MipIDs[i]);
+ cmd.SetComputeVectorParam(compute, "_Size", new Vector4(size, size, 1f / size, 1f / size));
+ cmd.DispatchCompute(compute, kernel, size / 8, size / 8, 1);
+ cmd.CopyTexture(m_MipIDs[i], 0, 0, m_Resolve, 0, i + 1);
+
+ last = m_MipIDs[i];
+ }
+
+ for (int i = 0; i < lodCount; i++)
+ cmd.ReleaseTemporaryRT(m_MipIDs[i]);
+
+ sheet.properties.SetTexture(ShaderIDs.Resolve, m_Resolve);
+ cmd.BlitFullscreenTriangle(context.source, context.destination, sheet, (int)Pass.Composite, preserveDepth: true);
+ cmd.EndSample("Screen-space Reflections");
+ }
+
+ public override void Release()
+ {
+ RuntimeUtilities.Destroy(m_Resolve);
+ RuntimeUtilities.Destroy(m_History);
+ m_Resolve = null;
+ m_History = null;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/ScreenSpaceReflections.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Effects/ScreenSpaceReflections.cs.meta
new file mode 100644
index 0000000..521f001
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/ScreenSpaceReflections.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 7a34fa72bd4185749832024e9c8010bf
+timeCreated: 1503573119
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/SubpixelMorphologicalAntialiasing.cs b/com.unity.postprocessing/PostProcessing/Runtime/Effects/SubpixelMorphologicalAntialiasing.cs
new file mode 100644
index 0000000..bf29cec
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/SubpixelMorphologicalAntialiasing.cs
@@ -0,0 +1,84 @@
+using System;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// This class holds settings for the Subpixel Morphological Anti-aliasing (SMAA) effect.
+ ///
+ [UnityEngine.Scripting.Preserve]
+ [Serializable]
+ public sealed class SubpixelMorphologicalAntialiasing
+ {
+ enum Pass
+ {
+ EdgeDetection = 0,
+ BlendWeights = 3,
+ NeighborhoodBlending = 6
+ }
+
+ ///
+ /// Quality presets.
+ ///
+ public enum Quality
+ {
+ ///
+ /// Low quality.
+ ///
+ Low = 0,
+
+ ///
+ /// Medium quality.
+ ///
+ Medium = 1,
+
+ ///
+ /// High quality.
+ ///
+ High = 2
+ }
+
+ ///
+ /// The quality preset to use for the anti-aliasing filter.
+ ///
+ [Tooltip("Lower quality is faster at the expense of visual quality (Low = ~60%, Medium = ~80%).")]
+ public Quality quality = Quality.High;
+
+ ///
+ /// Checks if the effect is supported on the target platform.
+ ///
+ /// true if the anti-aliasing filter is supported, false otherwise
+ public bool IsSupported()
+ {
+ return !RuntimeUtilities.isSinglePassStereoEnabled;
+ }
+
+ internal void Render(PostProcessRenderContext context)
+ {
+ var sheet = context.propertySheets.Get(context.resources.shaders.subpixelMorphologicalAntialiasing);
+ sheet.properties.SetTexture("_AreaTex", context.resources.smaaLuts.area);
+ sheet.properties.SetTexture("_SearchTex", context.resources.smaaLuts.search);
+
+ var cmd = context.command;
+ cmd.BeginSample("SubpixelMorphologicalAntialiasing");
+
+#if UNITY_2017_3_OR_NEWER
+ bool dynamicResolutionEnabled = RuntimeUtilities.IsDynamicResolutionEnabled(context.camera);
+ cmd.GetTemporaryRT(ShaderIDs.SMAA_Flip, context.width, context.height, 0, FilterMode.Bilinear, context.sourceFormat, RenderTextureReadWrite.Linear, 1, false, RenderTextureMemoryless.None, dynamicResolutionEnabled);
+ cmd.GetTemporaryRT(ShaderIDs.SMAA_Flop, context.width, context.height, 0, FilterMode.Bilinear, context.sourceFormat, RenderTextureReadWrite.Linear, 1, false, RenderTextureMemoryless.None, dynamicResolutionEnabled);
+#else
+ cmd.GetTemporaryRT(ShaderIDs.SMAA_Flip, context.width, context.height, 0, FilterMode.Bilinear, context.sourceFormat, RenderTextureReadWrite.Linear, 1, false);
+ cmd.GetTemporaryRT(ShaderIDs.SMAA_Flop, context.width, context.height, 0, FilterMode.Bilinear, context.sourceFormat, RenderTextureReadWrite.Linear, 1, false);
+#endif
+
+ cmd.BlitFullscreenTriangle(context.source, ShaderIDs.SMAA_Flip, sheet, (int)Pass.EdgeDetection + (int)quality, true);
+ cmd.BlitFullscreenTriangle(ShaderIDs.SMAA_Flip, ShaderIDs.SMAA_Flop, sheet, (int)Pass.BlendWeights + (int)quality);
+ cmd.SetGlobalTexture("_BlendTex", ShaderIDs.SMAA_Flop);
+ cmd.BlitFullscreenTriangle(context.source, context.destination, sheet, (int)Pass.NeighborhoodBlending);
+
+ cmd.ReleaseTemporaryRT(ShaderIDs.SMAA_Flip);
+ cmd.ReleaseTemporaryRT(ShaderIDs.SMAA_Flop);
+
+ cmd.EndSample("SubpixelMorphologicalAntialiasing");
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/SubpixelMorphologicalAntialiasing.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Effects/SubpixelMorphologicalAntialiasing.cs.meta
new file mode 100644
index 0000000..709478c
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/SubpixelMorphologicalAntialiasing.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: f3b0ecb61e2f1e54ebd4572178bfd8b1
+timeCreated: 1497735449
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/SuperResolution.cs b/com.unity.postprocessing/PostProcessing/Runtime/Effects/SuperResolution.cs
new file mode 100644
index 0000000..b9c653c
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/SuperResolution.cs
@@ -0,0 +1,350 @@
+// Copyright (c) 2023 Nico de Poel
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.Experimental.Rendering;
+using FidelityFX;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ [UnityEngine.Scripting.Preserve]
+ [Serializable]
+ public class SuperResolution
+ {
+ public Func callbacksFactory { get; set; } = (context) => new Callbacks(context.resources);
+
+ [Tooltip("Standard scaling ratio presets.")]
+ public Fsr2.QualityMode qualityMode = Fsr2.QualityMode.Quality;
+
+ [Tooltip("Apply RCAS sharpening to the image after upscaling.")]
+ public bool performSharpenPass = true;
+ [Tooltip("Strength of the sharpening effect.")]
+ [Range(0, 1)] public float sharpness = 0.8f;
+
+ [Tooltip("Allow the use of half precision compute operations, potentially improving performance if the platform supports it.")]
+ public bool enableFP16 = false;
+
+ [Tooltip("Choose where to get the exposure value from. Use auto-exposure from either FSR2 or Unity, provide a manual exposure texture, or use a default value.")]
+ public ExposureSource exposureSource = ExposureSource.Auto;
+ [Tooltip("Value by which the input signal will be divided, to get back to the original signal produced by the game.")]
+ public float preExposure = 1.0f;
+ [Tooltip("Optional 1x1 texture containing the exposure value for the current frame.")]
+ public Texture exposure = null;
+
+ public enum ExposureSource
+ {
+ Default,
+ Auto,
+ Unity,
+ Manual,
+ }
+
+ [Tooltip("Optional texture to control the influence of the current frame on the reconstructed output. If unset, either an auto-generated or a default cleared reactive mask will be used.")]
+ public Texture reactiveMask = null;
+ [Tooltip("Optional texture for marking areas of specialist rendering which should be accounted for during the upscaling process. If unset, a default cleared mask will be used.")]
+ public Texture transparencyAndCompositionMask = null;
+ [Tooltip("Automatically generate a reactive mask based on the difference between opaque-only render output and the final render output including alpha transparencies.")]
+ public bool autoGenerateReactiveMask = true;
+ [Tooltip("Parameters to control the process of auto-generating a reactive mask.")]
+ public GenerateReactiveParameters generateReactiveParameters = new GenerateReactiveParameters();
+
+ [Serializable]
+ public class GenerateReactiveParameters
+ {
+ [Tooltip("A value to scale the output")]
+ [Range(0, 2)] public float scale = 0.5f;
+ [Tooltip("A threshold value to generate a binary reactive mask")]
+ [Range(0, 1)] public float cutoffThreshold = 0.2f;
+ [Tooltip("A value to set for the binary reactive mask")]
+ [Range(0, 1)] public float binaryValue = 0.9f;
+ [Tooltip("Flags to determine how to generate the reactive mask")]
+ public Fsr2.GenerateReactiveFlags flags = Fsr2.GenerateReactiveFlags.ApplyTonemap | Fsr2.GenerateReactiveFlags.ApplyThreshold | Fsr2.GenerateReactiveFlags.UseComponentsMax;
+ }
+
+ [Tooltip("(Experimental) Automatically generate and use Reactive mask and Transparency & composition mask internally.")]
+ public bool autoGenerateTransparencyAndComposition = false;
+ [Tooltip("Parameters to control the process of auto-generating transparency and composition masks.")]
+ public GenerateTcrParameters generateTransparencyAndCompositionParameters = new GenerateTcrParameters();
+
+ [Serializable]
+ public class GenerateTcrParameters
+ {
+ [Tooltip("Setting this value too small will cause visual instability. Larger values can cause ghosting.")]
+ [Range(0, 1)] public float autoTcThreshold = 0.05f;
+ [Tooltip("Smaller values will increase stability at hard edges of translucent objects.")]
+ [Range(0, 2)] public float autoTcScale = 1.0f;
+ [Tooltip("Larger values result in more reactive pixels.")]
+ [Range(0, 10)] public float autoReactiveScale = 5.0f;
+ [Tooltip("Maximum value reactivity can reach.")]
+ [Range(0, 1)] public float autoReactiveMax = 0.9f;
+ }
+
+ public Vector2 jitter { get; private set; }
+ public Vector2Int renderSize => _renderSize;
+ public Vector2Int displaySize => _displaySize;
+ public RenderTargetIdentifier colorOpaqueOnly { get; set; }
+
+ private Fsr2Context _fsrContext;
+ private Vector2Int _renderSize;
+ private Vector2Int _displaySize;
+ private bool _resetHistory;
+
+ private IFsr2Callbacks _callbacks;
+ private float _appliedBiasOffset;
+
+ private readonly Fsr2.DispatchDescription _dispatchDescription = new Fsr2.DispatchDescription();
+ private readonly Fsr2.GenerateReactiveDescription _genReactiveDescription = new Fsr2.GenerateReactiveDescription();
+
+ private Fsr2.QualityMode _prevQualityMode;
+ private ExposureSource _prevExposureSource;
+ private Vector2Int _prevDisplaySize;
+
+ private Rect _originalRect;
+
+ public bool IsSupported()
+ {
+ return SystemInfo.supportsComputeShaders && SystemInfo.supportsMotionVectors;
+ }
+
+ public DepthTextureMode GetCameraFlags()
+ {
+ return DepthTextureMode.Depth | DepthTextureMode.MotionVectors;
+ }
+
+ public void Release()
+ {
+ DestroyFsrContext();
+ }
+
+ public void ResetHistory()
+ {
+ _resetHistory = true;
+ }
+
+ public void ConfigureJitteredProjectionMatrix(PostProcessRenderContext context)
+ {
+ ApplyJitter(context.camera);
+ }
+
+ public void ConfigureCameraViewport(PostProcessRenderContext context)
+ {
+ var camera = context.camera;
+ _originalRect = camera.rect;
+
+ // Determine the desired rendering and display resolutions
+ _displaySize = new Vector2Int(camera.pixelWidth, camera.pixelHeight);
+ Fsr2.GetRenderResolutionFromQualityMode(out int renderWidth, out int renderHeight, _displaySize.x, _displaySize.y, qualityMode);
+ _renderSize = new Vector2Int(renderWidth, renderHeight);
+
+ // Render to a smaller portion of the screen by manipulating the camera's viewport rect
+ camera.aspect = (_displaySize.x * _originalRect.width) / (_displaySize.y * _originalRect.height);
+ camera.rect = new Rect(0, 0, _originalRect.width * _renderSize.x / _displaySize.x, _originalRect.height * _renderSize.y / _displaySize.y);
+ }
+
+ public void ResetCameraViewport(PostProcessRenderContext context)
+ {
+ context.camera.rect = _originalRect;
+ }
+
+ public void Render(PostProcessRenderContext context)
+ {
+ var cmd = context.command;
+ cmd.BeginSample("FSR2");
+
+ // Monitor for any resolution changes and recreate the FSR2 context if necessary
+ // We can't create an FSR2 context without info from the post-processing context, so delay the initial setup until here
+ if (_fsrContext == null || _displaySize.x != _prevDisplaySize.x || _displaySize.y != _prevDisplaySize.y || qualityMode != _prevQualityMode || exposureSource != _prevExposureSource)
+ {
+ DestroyFsrContext();
+ CreateFsrContext(context);
+ }
+
+ cmd.SetGlobalTexture(Fsr2ShaderIDs.SrvInputColor, context.source);
+ cmd.SetGlobalTexture(Fsr2ShaderIDs.SrvInputDepth, BuiltinRenderTextureType.CameraTarget, RenderTextureSubElement.Depth);
+ cmd.SetGlobalTexture(Fsr2ShaderIDs.SrvInputMotionVectors, BuiltinRenderTextureType.MotionVectors);
+
+ SetupDispatchDescription(context);
+
+ if (autoGenerateReactiveMask)
+ {
+ SetupAutoReactiveDescription(context);
+
+ cmd.GetTemporaryRT(Fsr2ShaderIDs.UavAutoReactive, _renderSize.x, _renderSize.y, 0, default, GraphicsFormat.R8_UNorm, 1, true);
+ _fsrContext.GenerateReactiveMask(_genReactiveDescription, cmd);
+ _dispatchDescription.Reactive = Fsr2ShaderIDs.UavAutoReactive;
+ }
+
+ _fsrContext.Dispatch(_dispatchDescription, cmd);
+
+ cmd.EndSample("FSR2");
+
+ _resetHistory = false;
+ }
+
+ private void CreateFsrContext(PostProcessRenderContext context)
+ {
+ _prevQualityMode = qualityMode;
+ _prevExposureSource = exposureSource;
+ _prevDisplaySize = _displaySize;
+
+ // Initialize FSR2 context
+ Fsr2.InitializationFlags flags = 0;
+ if (context.camera.allowHDR) flags |= Fsr2.InitializationFlags.EnableHighDynamicRange;
+ if (enableFP16) flags |= Fsr2.InitializationFlags.EnableFP16Usage;
+ if (exposureSource == ExposureSource.Auto) flags |= Fsr2.InitializationFlags.EnableAutoExposure;
+
+ _callbacks = callbacksFactory(context);
+ _fsrContext = Fsr2.CreateContext(_displaySize, _renderSize, _callbacks, flags);
+
+ // Apply a mipmap bias so that textures retain their sharpness
+ float biasOffset = Fsr2.GetMipmapBiasOffset(_renderSize.x, _displaySize.x);
+ if (!float.IsNaN(biasOffset) && !float.IsInfinity(biasOffset))
+ {
+ _callbacks.ApplyMipmapBias(biasOffset);
+ _appliedBiasOffset = biasOffset;
+ }
+ else
+ {
+ _appliedBiasOffset = 0f;
+ }
+ }
+
+ private void DestroyFsrContext()
+ {
+ if (_fsrContext != null)
+ {
+ _fsrContext.Destroy();
+ _fsrContext = null;
+ }
+
+ // Undo the current mipmap bias offset
+ if (!float.IsNaN(_appliedBiasOffset) && !float.IsInfinity(_appliedBiasOffset) && _appliedBiasOffset != 0f)
+ {
+ _callbacks.ApplyMipmapBias(-_appliedBiasOffset);
+ _appliedBiasOffset = 0f;
+ }
+ }
+
+ private void ApplyJitter(Camera camera)
+ {
+ // Perform custom jittering of the camera's projection matrix according to FSR2's recipe
+ int jitterPhaseCount = Fsr2.GetJitterPhaseCount(_renderSize.x, _displaySize.x);
+ Fsr2.GetJitterOffset(out float jitterX, out float jitterY, Time.frameCount, jitterPhaseCount);
+
+ _dispatchDescription.JitterOffset = new Vector2(jitterX, jitterY);
+
+ jitterX = 2.0f * jitterX / _renderSize.x;
+ jitterY = 2.0f * jitterY / _renderSize.y;
+
+ var jitterTranslationMatrix = Matrix4x4.Translate(new Vector3(jitterX, jitterY, 0));
+ camera.nonJitteredProjectionMatrix = camera.projectionMatrix;
+ camera.projectionMatrix = jitterTranslationMatrix * camera.nonJitteredProjectionMatrix;
+ camera.useJitteredProjectionMatrixForTransparentRendering = false;
+
+ jitter = new Vector2(jitterX, jitterY);
+ }
+
+ private void SetupDispatchDescription(PostProcessRenderContext context)
+ {
+ var camera = context.camera;
+
+ // Set up the main FSR2 dispatch parameters
+ // The input textures are left blank here, as they get bound directly through SetGlobalTexture elsewhere in this source file
+ _dispatchDescription.Color = null;
+ _dispatchDescription.Depth = null;
+ _dispatchDescription.MotionVectors = null;
+ _dispatchDescription.Exposure = null;
+ _dispatchDescription.Reactive = null;
+ _dispatchDescription.TransparencyAndComposition = null;
+
+ if (exposureSource == ExposureSource.Manual && exposure != null) _dispatchDescription.Exposure = exposure;
+ if (exposureSource == ExposureSource.Unity) _dispatchDescription.Exposure = context.autoExposureTexture;
+ if (reactiveMask != null) _dispatchDescription.Reactive = reactiveMask;
+ if (transparencyAndCompositionMask != null) _dispatchDescription.TransparencyAndComposition = transparencyAndCompositionMask;
+
+ _dispatchDescription.Output = context.destination;
+ _dispatchDescription.PreExposure = preExposure;
+ _dispatchDescription.EnableSharpening = performSharpenPass;
+ _dispatchDescription.Sharpness = sharpness;
+ _dispatchDescription.MotionVectorScale.x = -_renderSize.x;
+ _dispatchDescription.MotionVectorScale.y = -_renderSize.y;
+ _dispatchDescription.RenderSize = _renderSize;
+ _dispatchDescription.InputResourceSize = _renderSize; // TODO: this may need to be maxRenderSize to support dynamic resolution
+ _dispatchDescription.FrameTimeDelta = Time.unscaledDeltaTime;
+ _dispatchDescription.CameraNear = camera.nearClipPlane;
+ _dispatchDescription.CameraFar = camera.farClipPlane;
+ _dispatchDescription.CameraFovAngleVertical = camera.fieldOfView * Mathf.Deg2Rad;
+ _dispatchDescription.ViewSpaceToMetersFactor = 1.0f; // 1 unit is 1 meter in Unity
+ _dispatchDescription.Reset = _resetHistory;
+
+ // Set up the parameters for the optional experimental auto-TCR feature
+ _dispatchDescription.EnableAutoReactive = autoGenerateTransparencyAndComposition;
+ if (autoGenerateTransparencyAndComposition)
+ {
+ _dispatchDescription.ColorOpaqueOnly = colorOpaqueOnly;
+ _dispatchDescription.AutoTcThreshold = generateTransparencyAndCompositionParameters.autoTcThreshold;
+ _dispatchDescription.AutoTcScale = generateTransparencyAndCompositionParameters.autoTcScale;
+ _dispatchDescription.AutoReactiveScale = generateTransparencyAndCompositionParameters.autoReactiveScale;
+ _dispatchDescription.AutoReactiveMax = generateTransparencyAndCompositionParameters.autoReactiveMax;
+ }
+
+ if (SystemInfo.usesReversedZBuffer)
+ {
+ // Swap the near and far clip plane distances as FSR2 expects this when using inverted depth
+ (_dispatchDescription.CameraNear, _dispatchDescription.CameraFar) = (_dispatchDescription.CameraFar, _dispatchDescription.CameraNear);
+ }
+ }
+
+ private void SetupAutoReactiveDescription(PostProcessRenderContext context)
+ {
+ // Set up the parameters to auto-generate a reactive mask
+ _genReactiveDescription.ColorOpaqueOnly = colorOpaqueOnly;
+ _genReactiveDescription.ColorPreUpscale = null;
+ _genReactiveDescription.OutReactive = null;
+ _genReactiveDescription.RenderSize = _renderSize;
+ _genReactiveDescription.Scale = generateReactiveParameters.scale;
+ _genReactiveDescription.CutoffThreshold = generateReactiveParameters.cutoffThreshold;
+ _genReactiveDescription.BinaryValue = generateReactiveParameters.binaryValue;
+ _genReactiveDescription.Flags = generateReactiveParameters.flags;
+ }
+
+ private class Callbacks : Fsr2CallbacksBase
+ {
+ private readonly PostProcessResources _resources;
+
+ public Callbacks(PostProcessResources resources)
+ {
+ _resources = resources;
+ }
+
+ public override ComputeShader LoadComputeShader(string name)
+ {
+ return _resources.computeShaders.FindComputeShader(name);
+ }
+
+ public override void UnloadComputeShader(ComputeShader shader)
+ {
+ }
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/SuperResolution.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Effects/SuperResolution.cs.meta
new file mode 100644
index 0000000..979fe66
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/SuperResolution.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 804fb4cfea0948247a52576cc4a79609
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/TemporalAntialiasing.cs b/com.unity.postprocessing/PostProcessing/Runtime/Effects/TemporalAntialiasing.cs
new file mode 100644
index 0000000..2b9b5bd
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/TemporalAntialiasing.cs
@@ -0,0 +1,293 @@
+using System;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// This class holds settings for the Temporal Anti-aliasing (TAA) effect.
+ ///
+ [UnityEngine.Scripting.Preserve]
+ [Serializable]
+ public sealed class TemporalAntialiasing
+ {
+ ///
+ /// The diameter (in texels) inside which jitter samples are spread. Smaller values result
+ /// in crisper but more aliased output, while larger values result in more stable but
+ /// blurrier output.
+ ///
+ [Tooltip("The diameter (in texels) inside which jitter samples are spread. Smaller values result in crisper but more aliased output, while larger values result in more stable, but blurrier, output.")]
+ [Range(0.1f, 1f)]
+ public float jitterSpread = 0.75f;
+
+ ///
+ /// Controls the amount of sharpening applied to the color buffer. High values may introduce
+ /// dark-border artifacts.
+ ///
+ [Tooltip("Controls the amount of sharpening applied to the color buffer. High values may introduce dark-border artifacts.")]
+ [Range(0f, 3f)]
+ public float sharpness = 0.25f;
+
+ ///
+ /// The blend coefficient for a stationary fragment. Controls the percentage of history
+ /// sample blended into the final color.
+ ///
+ [Tooltip("The blend coefficient for a stationary fragment. Controls the percentage of history sample blended into the final color.")]
+ [Range(0f, 0.99f)]
+ public float stationaryBlending = 0.95f;
+
+ ///
+ /// The blend coefficient for a fragment with significant motion. Controls the percentage of
+ /// history sample blended into the final color.
+ ///
+ [Tooltip("The blend coefficient for a fragment with significant motion. Controls the percentage of history sample blended into the final color.")]
+ [Range(0f, 0.99f)]
+ public float motionBlending = 0.85f;
+
+ ///
+ /// Sets a custom function that will be called to generate the jittered projection matrice.
+ ///
+ public Func jitteredMatrixFunc;
+
+ ///
+ /// The current jitter amount
+ ///
+ public Vector2 jitter { get; private set; }
+
+ enum Pass
+ {
+ SolverDilate,
+ SolverNoDilate
+ }
+
+ readonly RenderTargetIdentifier[] m_Mrt = new RenderTargetIdentifier[2];
+ bool m_ResetHistory = true;
+
+ const int k_SampleCount = 8;
+
+ ///
+ /// The current sample index.
+ ///
+ public int sampleIndex { get; private set; }
+
+ // Ping-pong between two history textures as we can't read & write the same target in the
+ // same pass
+ const int k_NumEyes = 2;
+ const int k_NumHistoryTextures = 2;
+ readonly RenderTexture[][] m_HistoryTextures = new RenderTexture[k_NumEyes][];
+
+ readonly int[] m_HistoryPingPong = new int[k_NumEyes];
+
+ ///
+ /// Returns true if the effect is currently enabled and supported.
+ ///
+ /// true if the effect is currently enabled and supported
+ public bool IsSupported()
+ {
+ return SystemInfo.supportedRenderTargetCount >= 2
+ && SystemInfo.supportsMotionVectors
+#if !UNITY_2017_3_OR_NEWER
+ && !RuntimeUtilities.isVREnabled
+#endif
+#if !UNITY_2023_1_OR_NEWER
+ && SystemInfo.graphicsDeviceType != GraphicsDeviceType.OpenGLES2;
+#else
+ ;
+#endif
+ }
+
+ internal DepthTextureMode GetCameraFlags()
+ {
+ return DepthTextureMode.Depth | DepthTextureMode.MotionVectors;
+ }
+
+ internal void ResetHistory()
+ {
+ m_ResetHistory = true;
+ }
+
+ Vector2 GenerateRandomOffset()
+ {
+ // The variance between 0 and the actual halton sequence values reveals noticeable instability
+ // in Unity's shadow maps, so we avoid index 0.
+ var offset = new Vector2(
+ HaltonSeq.Get((sampleIndex & 1023) + 1, 2) - 0.5f,
+ HaltonSeq.Get((sampleIndex & 1023) + 1, 3) - 0.5f
+ );
+
+ if (++sampleIndex >= k_SampleCount)
+ sampleIndex = 0;
+
+ return offset;
+ }
+
+ ///
+ /// Generates a jittered projection matrix for a given camera.
+ ///
+ /// The camera to get a jittered projection matrix for.
+ /// A jittered projection matrix.
+ public Matrix4x4 GetJitteredProjectionMatrix(Camera camera)
+ {
+ Matrix4x4 cameraProj;
+ jitter = GenerateRandomOffset();
+ jitter *= jitterSpread;
+
+ if (jitteredMatrixFunc != null)
+ {
+ cameraProj = jitteredMatrixFunc(camera, jitter);
+ }
+ else
+ {
+ cameraProj = camera.orthographic
+ ? RuntimeUtilities.GetJitteredOrthographicProjectionMatrix(camera, jitter)
+ : RuntimeUtilities.GetJitteredPerspectiveProjectionMatrix(camera, jitter);
+ }
+
+ jitter = new Vector2(jitter.x / camera.pixelWidth, jitter.y / camera.pixelHeight);
+ return cameraProj;
+ }
+
+ ///
+ /// Prepares the jittered and non jittered projection matrices.
+ ///
+ /// The current post-processing context.
+ public void ConfigureJitteredProjectionMatrix(PostProcessRenderContext context)
+ {
+ var camera = context.camera;
+ camera.nonJitteredProjectionMatrix = camera.projectionMatrix;
+ camera.projectionMatrix = GetJitteredProjectionMatrix(camera);
+ camera.useJitteredProjectionMatrixForTransparentRendering = false;
+ }
+
+ ///
+ /// Prepares the jittered and non jittered projection matrices for stereo rendering.
+ ///
+ /// The current post-processing context.
+ // TODO: We'll probably need to isolate most of this for SRPs
+ public void ConfigureStereoJitteredProjectionMatrices(PostProcessRenderContext context)
+ {
+#if UNITY_2017_3_OR_NEWER
+ var camera = context.camera;
+ jitter = GenerateRandomOffset();
+ jitter *= jitterSpread;
+
+ for (var eye = Camera.StereoscopicEye.Left; eye <= Camera.StereoscopicEye.Right; eye++)
+ {
+ // This saves off the device generated projection matrices as non-jittered
+ context.camera.CopyStereoDeviceProjectionMatrixToNonJittered(eye);
+ var originalProj = context.camera.GetStereoNonJitteredProjectionMatrix(eye);
+
+ // Currently no support for custom jitter func, as VR devices would need to provide
+ // original projection matrix as input along with jitter
+ var jitteredMatrix = RuntimeUtilities.GenerateJitteredProjectionMatrixFromOriginal(context, originalProj, jitter);
+ context.camera.SetStereoProjectionMatrix(eye, jitteredMatrix);
+ }
+
+ // jitter has to be scaled for the actual eye texture size, not just the intermediate texture size
+ // which could be double-wide in certain stereo rendering scenarios
+ jitter = new Vector2(jitter.x / context.screenWidth, jitter.y / context.screenHeight);
+ camera.useJitteredProjectionMatrixForTransparentRendering = false;
+#endif
+ }
+
+ void GenerateHistoryName(RenderTexture rt, int id, PostProcessRenderContext context)
+ {
+ rt.name = "Temporal Anti-aliasing History id #" + id;
+
+ if (context.stereoActive)
+ rt.name += " for eye " + context.xrActiveEye;
+ }
+
+ RenderTexture CheckHistory(int id, PostProcessRenderContext context)
+ {
+ int activeEye = context.xrActiveEye;
+
+ if (m_HistoryTextures[activeEye] == null)
+ m_HistoryTextures[activeEye] = new RenderTexture[k_NumHistoryTextures];
+
+ var rt = m_HistoryTextures[activeEye][id];
+
+ if (m_ResetHistory || rt == null || !rt.IsCreated())
+ {
+ RenderTexture.ReleaseTemporary(rt);
+
+ rt = context.GetScreenSpaceTemporaryRT(0, context.sourceFormat);
+ GenerateHistoryName(rt, id, context);
+
+ rt.filterMode = FilterMode.Bilinear;
+ m_HistoryTextures[activeEye][id] = rt;
+
+ context.command.BlitFullscreenTriangle(context.source, rt);
+ }
+ else if (rt.width != context.width || rt.height != context.height)
+ {
+ // On size change, simply copy the old history to the new one. This looks better
+ // than completely discarding the history and seeing a few aliased frames.
+ var rt2 = context.GetScreenSpaceTemporaryRT(0, context.sourceFormat);
+ GenerateHistoryName(rt2, id, context);
+
+ rt2.filterMode = FilterMode.Bilinear;
+ m_HistoryTextures[activeEye][id] = rt2;
+
+ context.command.BlitFullscreenTriangle(rt, rt2);
+ RenderTexture.ReleaseTemporary(rt);
+ }
+
+ return m_HistoryTextures[activeEye][id];
+ }
+
+ internal void Render(PostProcessRenderContext context)
+ {
+ var sheet = context.propertySheets.Get(context.resources.shaders.temporalAntialiasing);
+
+ var cmd = context.command;
+ cmd.BeginSample("TemporalAntialiasing");
+
+ int pp = m_HistoryPingPong[context.xrActiveEye];
+ var historyRead = CheckHistory(++pp % 2, context);
+ var historyWrite = CheckHistory(++pp % 2, context);
+ m_HistoryPingPong[context.xrActiveEye] = ++pp % 2;
+
+ const float kMotionAmplification = 100f * 60f;
+ sheet.properties.SetVector(ShaderIDs.Jitter, jitter);
+ sheet.properties.SetFloat(ShaderIDs.Sharpness, sharpness);
+ sheet.properties.SetVector(ShaderIDs.FinalBlendParameters, new Vector4(stationaryBlending, motionBlending, kMotionAmplification, 0f));
+ sheet.properties.SetTexture(ShaderIDs.HistoryTex, historyRead);
+
+ // TODO: Account for different possible RenderViewportScale value from previous frame...
+
+ int pass = context.camera.orthographic ? (int)Pass.SolverNoDilate : (int)Pass.SolverDilate;
+ m_Mrt[0] = context.destination;
+ m_Mrt[1] = historyWrite;
+
+ cmd.BlitFullscreenTriangle(context.source, m_Mrt, context.source, sheet, pass);
+ cmd.EndSample("TemporalAntialiasing");
+
+ m_ResetHistory = false;
+ }
+
+ internal void Release()
+ {
+ if (m_HistoryTextures != null)
+ {
+ for (int i = 0; i < m_HistoryTextures.Length; i++)
+ {
+ if (m_HistoryTextures[i] == null)
+ continue;
+
+ for (int j = 0; j < m_HistoryTextures[i].Length; j++)
+ {
+ RenderTexture.ReleaseTemporary(m_HistoryTextures[i][j]);
+ m_HistoryTextures[i][j] = null;
+ }
+
+ m_HistoryTextures[i] = null;
+ }
+ }
+
+ sampleIndex = 0;
+ m_HistoryPingPong[0] = 0;
+ m_HistoryPingPong[1] = 0;
+
+ ResetHistory();
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/TemporalAntialiasing.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Effects/TemporalAntialiasing.cs.meta
new file mode 100644
index 0000000..9b76b52
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/TemporalAntialiasing.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 5a7fc26078c70a6469392d9775f433be
+timeCreated: 1490188293
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/Vignette.cs b/com.unity.postprocessing/PostProcessing/Runtime/Effects/Vignette.cs
new file mode 100644
index 0000000..48e5c78
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/Vignette.cs
@@ -0,0 +1,125 @@
+using System;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// A list of available render modes for the Vignette effect.
+ ///
+ public enum VignetteMode
+ {
+ ///
+ /// This mode offers parametric controls for the position, shape and intensity of the Vignette.
+ ///
+ Classic,
+
+ ///
+ /// This mode multiplies a custom texture mask over the screen to create a Vignette effect.
+ ///
+ Masked
+ }
+
+ ///
+ /// A volume parameter holding a value.
+ ///
+ [Serializable]
+ public sealed class VignetteModeParameter : ParameterOverride { }
+
+ ///
+ /// This class holds settings for the Vignette effect.
+ ///
+ [Serializable]
+ [PostProcess(typeof(VignetteRenderer), "Unity/Vignette")]
+ public sealed class Vignette : PostProcessEffectSettings
+ {
+ ///
+ /// Use the \"Classic\" mode for parametric controls. Use the \"Masked\" mode to use your own texture mask.
+ ///
+ [Tooltip("Use the \"Classic\" mode for parametric controls. Use the \"Masked\" mode to use your own texture mask.")]
+ public VignetteModeParameter mode = new VignetteModeParameter { value = VignetteMode.Classic };
+
+ ///
+ /// The color to use to tint the vignette.
+ ///
+ [Tooltip("Vignette color.")]
+ public ColorParameter color = new ColorParameter { value = new Color(0f, 0f, 0f, 1f) };
+
+ ///
+ /// Sets the vignette center point (screen center is [0.5,0.5]).
+ ///
+ [Tooltip("Sets the vignette center point (screen center is [0.5, 0.5]).")]
+ public Vector2Parameter center = new Vector2Parameter { value = new Vector2(0.5f, 0.5f) };
+
+ ///
+ /// The amount of vignetting on screen.
+ ///
+ [Range(0f, 1f), Tooltip("Amount of vignetting on screen.")]
+ public FloatParameter intensity = new FloatParameter { value = 0f };
+
+ ///
+ /// The smoothness of the vignette borders.
+ ///
+ [Range(0.01f, 1f), Tooltip("Smoothness of the vignette borders.")]
+ public FloatParameter smoothness = new FloatParameter { value = 0.2f };
+
+ ///
+ /// Lower values will make a square-ish vignette.
+ ///
+ [Range(0f, 1f), Tooltip("Lower values will make a square-ish vignette.")]
+ public FloatParameter roundness = new FloatParameter { value = 1f };
+
+ ///
+ /// Should the vignette be perfectly round or be dependent on the current aspect ratio?
+ ///
+ [Tooltip("Set to true to mark the vignette to be perfectly round. False will make its shape dependent on the current aspect ratio.")]
+ public BoolParameter rounded = new BoolParameter { value = false };
+
+ ///
+ /// A black and white mask to use as a vignette.
+ ///
+ [Tooltip("A black and white mask to use as a vignette.")]
+ public TextureParameter mask = new TextureParameter { value = null };
+
+ ///
+ /// Mask opacity.
+ ///
+ [Range(0f, 1f), Tooltip("Mask opacity.")]
+ public FloatParameter opacity = new FloatParameter { value = 1f };
+
+ ///
+ /// Returns true if the effect is currently enabled and supported.
+ ///
+ /// The current post-processing render context
+ /// true if the effect is currently enabled and supported
+ public override bool IsEnabledAndSupported(PostProcessRenderContext context)
+ {
+ return enabled.value
+ && ((mode.value == VignetteMode.Classic && intensity.value > 0f)
+ || (mode.value == VignetteMode.Masked && opacity.value > 0f && mask.value != null));
+ }
+ }
+
+ [UnityEngine.Scripting.Preserve]
+ internal sealed class VignetteRenderer : PostProcessEffectRenderer
+ {
+ public override void Render(PostProcessRenderContext context)
+ {
+ var sheet = context.uberSheet;
+ sheet.EnableKeyword("VIGNETTE");
+ sheet.properties.SetColor(ShaderIDs.Vignette_Color, settings.color.value);
+
+ if (settings.mode == VignetteMode.Classic)
+ {
+ sheet.properties.SetFloat(ShaderIDs.Vignette_Mode, 0f);
+ sheet.properties.SetVector(ShaderIDs.Vignette_Center, settings.center.value);
+ float roundness = (1f - settings.roundness.value) * 6f + settings.roundness.value;
+ sheet.properties.SetVector(ShaderIDs.Vignette_Settings, new Vector4(settings.intensity.value * 3f, settings.smoothness.value * 5f, roundness, settings.rounded.value ? 1f : 0f));
+ }
+ else // Masked
+ {
+ sheet.properties.SetFloat(ShaderIDs.Vignette_Mode, 1f);
+ sheet.properties.SetTexture(ShaderIDs.Vignette_Mask, settings.mask.value);
+ sheet.properties.SetFloat(ShaderIDs.Vignette_Opacity, Mathf.Clamp01(settings.opacity.value));
+ }
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Effects/Vignette.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Effects/Vignette.cs.meta
new file mode 100644
index 0000000..f2f06ce
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Effects/Vignette.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 40b924e2dad56384a8df2a1e111bb675
+timeCreated: 1491826542
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/FSR2.meta b/com.unity.postprocessing/PostProcessing/Runtime/FSR2.meta
new file mode 100644
index 0000000..1579387
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/FSR2.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 9e2d87f36f288024cb500a20acaae11e
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2.cs b/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2.cs
new file mode 100644
index 0000000..772cfc3
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2.cs
@@ -0,0 +1,289 @@
+// Copyright (c) 2023 Nico de Poel
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Runtime.InteropServices;
+using UnityEngine;
+using UnityEngine.Rendering;
+
+namespace FidelityFX
+{
+ ///
+ /// A collection of helper functions and data structures required by the FSR2 process.
+ ///
+ public static class Fsr2
+ {
+ ///
+ /// Creates a new FSR2 context with standard parameters that are appropriate for the current platform.
+ ///
+ public static Fsr2Context CreateContext(Vector2Int displaySize, Vector2Int maxRenderSize, IFsr2Callbacks callbacks, InitializationFlags flags = 0)
+ {
+ if (SystemInfo.usesReversedZBuffer)
+ flags |= InitializationFlags.EnableDepthInverted;
+ else
+ flags &= ~InitializationFlags.EnableDepthInverted;
+
+#if UNITY_EDITOR || DEVELOPMENT_BUILD
+ flags |= InitializationFlags.EnableDebugChecking;
+#endif
+
+ Debug.Log($"Setting up FSR2 with render size: {maxRenderSize.x}x{maxRenderSize.y}, display size: {displaySize.x}x{displaySize.y}, flags: {flags}");
+
+ var contextDescription = new ContextDescription
+ {
+ Flags = flags,
+ DisplaySize = displaySize,
+ MaxRenderSize = maxRenderSize,
+ Callbacks = callbacks,
+ };
+
+ var context = new Fsr2Context();
+ context.Create(contextDescription);
+ return context;
+ }
+
+ public static float GetUpscaleRatioFromQualityMode(QualityMode qualityMode)
+ {
+ switch (qualityMode)
+ {
+ case QualityMode.UltraQuality:
+ return 1.2f;
+ case QualityMode.Quality:
+ return 1.5f;
+ case QualityMode.Balanced:
+ return 1.7f;
+ case QualityMode.Performance:
+ return 2.0f;
+ case QualityMode.UltraPerformance:
+ return 3.0f;
+ default:
+ return 1.0f;
+ }
+ }
+
+ public static void GetRenderResolutionFromQualityMode(
+ out int renderWidth, out int renderHeight,
+ int displayWidth, int displayHeight, QualityMode qualityMode)
+ {
+ float ratio = GetUpscaleRatioFromQualityMode(qualityMode);
+ renderWidth = Mathf.RoundToInt(displayWidth / ratio);
+ renderHeight = Mathf.RoundToInt(displayHeight / ratio);
+ }
+
+ public static float GetMipmapBiasOffset(int renderWidth, int displayWidth)
+ {
+ return Mathf.Log((float)renderWidth / displayWidth, 2.0f) - 1.0f;
+ }
+
+ public static int GetJitterPhaseCount(int renderWidth, int displayWidth)
+ {
+ const float basePhaseCount = 8.0f;
+ int jitterPhaseCount = (int)(basePhaseCount * Mathf.Pow((float)displayWidth / renderWidth, 2.0f));
+ return jitterPhaseCount;
+ }
+
+ public static void GetJitterOffset(out float outX, out float outY, int index, int phaseCount)
+ {
+ outX = Halton((index % phaseCount) + 1, 2) - 0.5f;
+ outY = Halton((index % phaseCount) + 1, 3) - 0.5f;
+ }
+
+ // Calculate halton number for index and base.
+ private static float Halton(int index, int @base)
+ {
+ float f = 1.0f, result = 0.0f;
+
+ for (int currentIndex = index; currentIndex > 0;) {
+
+ f /= @base;
+ result += f * (currentIndex % @base);
+ currentIndex = (int)Mathf.Floor((float)currentIndex / @base);
+ }
+
+ return result;
+ }
+
+ public static float Lanczos2(float value)
+ {
+ return Mathf.Abs(value) < Mathf.Epsilon ? 1.0f : Mathf.Sin(Mathf.PI * value) / (Mathf.PI * value) * (Mathf.Sin(0.5f * Mathf.PI * value) / (0.5f * Mathf.PI * value));
+ }
+
+ public enum QualityMode
+ {
+ UltraQuality = 0,
+ Quality = 1,
+ Balanced = 2,
+ Performance = 3,
+ UltraPerformance = 4,
+ }
+
+ [Flags]
+ public enum InitializationFlags
+ {
+ EnableHighDynamicRange = 1 << 0,
+ EnableDisplayResolutionMotionVectors = 1 << 1,
+ EnableMotionVectorsJitterCancellation = 1 << 2,
+ EnableDepthInverted = 1 << 3,
+ EnableDepthInfinite = 1 << 4,
+ EnableAutoExposure = 1 << 5,
+ EnableDynamicResolution = 1 << 6,
+ EnableFP16Usage = 1 << 7,
+ EnableDebugChecking = 1 << 8,
+ }
+
+ public struct ContextDescription
+ {
+ public InitializationFlags Flags;
+ public Vector2Int MaxRenderSize;
+ public Vector2Int DisplaySize;
+ public IFsr2Callbacks Callbacks;
+ }
+
+ ///
+ /// The input and output resources are all optional. If they are null, the Fsr2Context won't try to bind them to any shaders.
+ /// This allows for customized and more efficient resource management outside of Fsr2Context, tailored to the specific scenario.
+ ///
+ public class DispatchDescription
+ {
+ public RenderTargetIdentifier? Color;
+ public RenderTargetIdentifier? Depth;
+ public RenderTargetIdentifier? MotionVectors;
+ public RenderTargetIdentifier? Exposure;
+ public RenderTargetIdentifier? Reactive;
+ public RenderTargetIdentifier? TransparencyAndComposition;
+ public RenderTargetIdentifier? Output;
+ public Vector2 JitterOffset;
+ public Vector2 MotionVectorScale;
+ public Vector2Int RenderSize;
+ public Vector2Int InputResourceSize;
+ public bool EnableSharpening;
+ public float Sharpness;
+ public float FrameTimeDelta; // in seconds
+ public float PreExposure;
+ public bool Reset;
+ public float CameraNear;
+ public float CameraFar;
+ public float CameraFovAngleVertical;
+ public float ViewSpaceToMetersFactor;
+
+ // EXPERIMENTAL reactive mask generation parameters
+ public bool EnableAutoReactive;
+ public RenderTargetIdentifier? ColorOpaqueOnly;
+ public float AutoTcThreshold = 0.05f;
+ public float AutoTcScale = 1.0f;
+ public float AutoReactiveScale = 5.0f;
+ public float AutoReactiveMax = 0.9f;
+ }
+
+ ///
+ /// The default values for Scale, CutoffThreshold, BinaryValue and Flags were taken from the FSR2 demo project.
+ ///
+ public class GenerateReactiveDescription
+ {
+ public RenderTargetIdentifier? ColorOpaqueOnly;
+ public RenderTargetIdentifier? ColorPreUpscale;
+ public RenderTargetIdentifier? OutReactive;
+ public Vector2Int RenderSize;
+ public float Scale = 0.5f;
+ public float CutoffThreshold = 0.2f;
+ public float BinaryValue = 0.9f;
+ public GenerateReactiveFlags Flags = GenerateReactiveFlags.ApplyTonemap | GenerateReactiveFlags.ApplyThreshold | GenerateReactiveFlags.UseComponentsMax;
+ }
+
+ [Flags]
+ public enum GenerateReactiveFlags
+ {
+ ApplyTonemap = 1 << 0,
+ ApplyInverseTonemap = 1 << 1,
+ ApplyThreshold = 1 << 2,
+ UseComponentsMax = 1 << 3,
+ }
+
+ [Serializable, StructLayout(LayoutKind.Sequential)]
+ internal struct Fsr2Constants
+ {
+ public Vector2Int renderSize;
+ public Vector2Int maxRenderSize;
+ public Vector2Int displaySize;
+ public Vector2Int inputColorResourceDimensions;
+ public Vector2Int lumaMipDimensions;
+ public int lumaMipLevelToUse;
+ public int frameIndex;
+
+ public Vector4 deviceToViewDepth;
+ public Vector2 jitterOffset;
+ public Vector2 motionVectorScale;
+ public Vector2 downscaleFactor;
+ public Vector2 motionVectorJitterCancellation;
+ public float preExposure;
+ public float previousFramePreExposure;
+ public float tanHalfFOV;
+ public float jitterPhaseCount;
+ public float deltaTime;
+ public float dynamicResChangeFactor;
+ public float viewSpaceToMetersFactor;
+
+ public int dummy;
+ }
+
+ [Serializable, StructLayout(LayoutKind.Sequential)]
+ internal struct SpdConstants
+ {
+ public uint mips;
+ public uint numWorkGroups;
+ public uint workGroupOffsetX, workGroupOffsetY;
+ public uint renderSizeX, renderSizeY;
+ }
+
+ [Serializable, StructLayout(LayoutKind.Sequential)]
+ internal struct GenerateReactiveConstants
+ {
+ public float scale;
+ public float threshold;
+ public float binaryValue;
+ public uint flags;
+ }
+
+ [Serializable, StructLayout(LayoutKind.Sequential)]
+ internal struct GenerateReactiveConstants2
+ {
+ public float autoTcThreshold;
+ public float autoTcScale;
+ public float autoReactiveScale;
+ public float autoReactiveMax;
+ }
+
+ [Serializable, StructLayout(LayoutKind.Sequential)]
+ internal struct RcasConstants
+ {
+ public RcasConstants(uint sharpness, uint halfSharp)
+ {
+ this.sharpness = sharpness;
+ this.halfSharp = halfSharp;
+ dummy0 = dummy1 = 0;
+ }
+
+ public readonly uint sharpness;
+ public readonly uint halfSharp;
+ public readonly uint dummy0;
+ public readonly uint dummy1;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2.cs.meta
new file mode 100644
index 0000000..10fe120
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 742d52dc87714f0d93f3b59719859dff
+timeCreated: 1673441954
\ No newline at end of file
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2Callbacks.cs b/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2Callbacks.cs
new file mode 100644
index 0000000..cc384f9
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2Callbacks.cs
@@ -0,0 +1,85 @@
+// Copyright (c) 2023 Nico de Poel
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using UnityEngine;
+
+namespace FidelityFX
+{
+ ///
+ /// A collection of callbacks required by the FSR2 process.
+ /// This allows some customization by the game dev on how to integrate FSR2 into their own game setup.
+ ///
+ public interface IFsr2Callbacks
+ {
+ Shader LoadShader(string name);
+ void UnloadShader(Shader shader);
+ ComputeShader LoadComputeShader(string name);
+ void UnloadComputeShader(ComputeShader shader);
+
+ ///
+ /// Apply a mipmap bias to in-game textures to prevent them from becoming blurry as the internal rendering resolution lowers.
+ /// This will need to be customized on a per-game basis, as there is no clear universal way to determine what are "in-game" textures.
+ /// The default implementation will simply apply a mipmap bias to all 2D textures, which will include things like UI textures and which might miss things like terrain texture arrays.
+ ///
+ /// Depending on how your game organizes its assets, you will want to create a filter that more specifically selects the textures that need to have this mipmap bias applied.
+ /// You may also want to store the bias offset value and apply it to any assets that are loaded in on demand.
+ ///
+ void ApplyMipmapBias(float biasOffset);
+ }
+
+ ///
+ /// Default implementation of IFsr2Callbacks using simple Resources calls.
+ /// These are fine for testing but a proper game will want to extend and override these methods.
+ ///
+ public class Fsr2CallbacksBase: IFsr2Callbacks
+ {
+ protected float CurrentBiasOffset = 0;
+
+ public virtual Shader LoadShader(string name)
+ {
+ return Resources.Load(name);
+ }
+
+ public virtual void UnloadShader(Shader shader)
+ {
+ Resources.UnloadAsset(shader);
+ }
+
+ public virtual ComputeShader LoadComputeShader(string name)
+ {
+ return Resources.Load(name);
+ }
+
+ public virtual void UnloadComputeShader(ComputeShader shader)
+ {
+ Resources.UnloadAsset(shader);
+ }
+
+ public virtual void ApplyMipmapBias(float biasOffset)
+ {
+ CurrentBiasOffset += biasOffset;
+
+ foreach (var texture in Resources.FindObjectsOfTypeAll())
+ {
+ texture.mipMapBias += biasOffset;
+ }
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2Callbacks.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2Callbacks.cs.meta
new file mode 100644
index 0000000..abc4d96
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2Callbacks.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 5906deeb6ec2854449bf33db2e71a046
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2Context.cs b/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2Context.cs
new file mode 100644
index 0000000..c8b17c1
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2Context.cs
@@ -0,0 +1,607 @@
+// Copyright (c) 2023 Nico de Poel
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using UnityEngine;
+using UnityEngine.Rendering;
+
+namespace FidelityFX
+{
+ ///
+ /// This class loosely matches the FfxFsr2Context struct from the original FSR2 codebase.
+ /// It manages the various resources and compute passes required by the FSR2 process.
+ /// Note that this class does not know anything about Unity render pipelines; all it knows is CommandBuffers and RenderTargetIdentifiers.
+ /// This should make it suitable for integration with any of the available Unity render pipelines.
+ ///
+ public class Fsr2Context
+ {
+ private const int MaxQueuedFrames = 16;
+
+ private Fsr2.ContextDescription _contextDescription;
+ private CommandBuffer _commandBuffer;
+
+ private Fsr2Pipeline _depthClipPipeline;
+ private Fsr2Pipeline _reconstructPreviousDepthPipeline;
+ private Fsr2Pipeline _lockPipeline;
+ private Fsr2Pipeline _accumulatePipeline;
+ private Fsr2Pipeline _rcasPipeline;
+ private Fsr2Pipeline _computeLuminancePyramidPipeline;
+ private Fsr2Pipeline _generateReactivePipeline;
+ private Fsr2Pipeline _tcrAutogeneratePipeline;
+
+ private readonly Fsr2Resources _resources = new Fsr2Resources();
+
+ private ComputeBuffer _fsr2ConstantsBuffer;
+ private readonly Fsr2.Fsr2Constants[] _fsr2ConstantsArray = { new Fsr2.Fsr2Constants() };
+ private ref Fsr2.Fsr2Constants Constants => ref _fsr2ConstantsArray[0];
+
+ private ComputeBuffer _spdConstantsBuffer;
+ private readonly Fsr2.SpdConstants[] _spdConstantsArray = { new Fsr2.SpdConstants() };
+ private ref Fsr2.SpdConstants SpdConsts => ref _spdConstantsArray[0];
+
+ private ComputeBuffer _rcasConstantsBuffer;
+ private readonly Fsr2.RcasConstants[] _rcasConstantsArray = new Fsr2.RcasConstants[1];
+ private ref Fsr2.RcasConstants RcasConsts => ref _rcasConstantsArray[0];
+
+ private ComputeBuffer _generateReactiveConstantsBuffer;
+ private readonly Fsr2.GenerateReactiveConstants[] _generateReactiveConstantsArray = { new Fsr2.GenerateReactiveConstants() };
+ private ref Fsr2.GenerateReactiveConstants GenReactiveConsts => ref _generateReactiveConstantsArray[0];
+
+ private ComputeBuffer _tcrAutogenerateConstantsBuffer;
+ private readonly Fsr2.GenerateReactiveConstants2[] _tcrAutogenerateConstantsArray = { new Fsr2.GenerateReactiveConstants2() };
+ private ref Fsr2.GenerateReactiveConstants2 TcrAutoGenConsts => ref _tcrAutogenerateConstantsArray[0];
+
+ private bool _firstExecution;
+ private Vector2 _previousJitterOffset;
+ private int _resourceFrameIndex;
+
+ public void Create(Fsr2.ContextDescription contextDescription)
+ {
+ _contextDescription = contextDescription;
+ _commandBuffer = new CommandBuffer { name = "FSR2" };
+
+ _fsr2ConstantsBuffer = CreateConstantBuffer();
+ _spdConstantsBuffer = CreateConstantBuffer();
+ _rcasConstantsBuffer = CreateConstantBuffer();
+ _generateReactiveConstantsBuffer = CreateConstantBuffer();
+ _tcrAutogenerateConstantsBuffer = CreateConstantBuffer();
+
+ // Set defaults
+ _firstExecution = true;
+ _resourceFrameIndex = 0;
+
+ Constants.displaySize = _contextDescription.DisplaySize;
+
+ _resources.Create(_contextDescription);
+ CreatePipelines();
+ }
+
+ private void CreatePipelines()
+ {
+ _computeLuminancePyramidPipeline = new Fsr2ComputeLuminancePyramidPipeline(_contextDescription, _resources, _fsr2ConstantsBuffer, _spdConstantsBuffer);
+ _reconstructPreviousDepthPipeline = new Fsr2ReconstructPreviousDepthPipeline(_contextDescription, _resources, _fsr2ConstantsBuffer);
+ _depthClipPipeline = new Fsr2DepthClipPipeline(_contextDescription, _resources, _fsr2ConstantsBuffer);
+ _lockPipeline = new Fsr2LockPipeline(_contextDescription, _resources, _fsr2ConstantsBuffer);
+ _accumulatePipeline = new Fsr2AccumulatePipeline(_contextDescription, _resources, _fsr2ConstantsBuffer);
+ _rcasPipeline = new Fsr2RcasPipeline(_contextDescription, _resources, _fsr2ConstantsBuffer, _rcasConstantsBuffer);
+ _generateReactivePipeline = new Fsr2GenerateReactivePipeline(_contextDescription, _resources, _generateReactiveConstantsBuffer);
+ _tcrAutogeneratePipeline = new Fsr2TcrAutogeneratePipeline(_contextDescription, _resources, _fsr2ConstantsBuffer, _tcrAutogenerateConstantsBuffer);
+ }
+
+ public void Destroy()
+ {
+ DestroyPipeline(ref _tcrAutogeneratePipeline);
+ DestroyPipeline(ref _generateReactivePipeline);
+ DestroyPipeline(ref _computeLuminancePyramidPipeline);
+ DestroyPipeline(ref _rcasPipeline);
+ DestroyPipeline(ref _accumulatePipeline);
+ DestroyPipeline(ref _lockPipeline);
+ DestroyPipeline(ref _reconstructPreviousDepthPipeline);
+ DestroyPipeline(ref _depthClipPipeline);
+
+ _resources.Destroy();
+
+ DestroyConstantBuffer(ref _tcrAutogenerateConstantsBuffer);
+ DestroyConstantBuffer(ref _generateReactiveConstantsBuffer);
+ DestroyConstantBuffer(ref _rcasConstantsBuffer);
+ DestroyConstantBuffer(ref _spdConstantsBuffer);
+ DestroyConstantBuffer(ref _fsr2ConstantsBuffer);
+
+ _commandBuffer.Dispose();
+ _commandBuffer = null;
+ }
+
+ public void Dispatch(Fsr2.DispatchDescription dispatchParams)
+ {
+ _commandBuffer.Clear();
+ Dispatch(dispatchParams, _commandBuffer);
+ Graphics.ExecuteCommandBuffer(_commandBuffer);
+ }
+
+ public void Dispatch(Fsr2.DispatchDescription dispatchParams, CommandBuffer commandBuffer)
+ {
+ if ((_contextDescription.Flags & Fsr2.InitializationFlags.EnableDebugChecking) != 0)
+ {
+ DebugCheckDispatch(dispatchParams);
+ }
+
+ if (_firstExecution)
+ {
+ commandBuffer.SetRenderTarget(_resources.LockStatus[0]);
+ commandBuffer.ClearRenderTarget(false, true, Color.clear);
+ commandBuffer.SetRenderTarget(_resources.LockStatus[1]);
+ commandBuffer.ClearRenderTarget(false, true, Color.clear);
+
+ // Reset atomic counter to 0
+ commandBuffer.SetRenderTarget(_resources.SpdAtomicCounter);
+ commandBuffer.ClearRenderTarget(false, true, Color.clear);
+ }
+
+ int frameIndex = _resourceFrameIndex % 2;
+ bool resetAccumulation = dispatchParams.Reset || _firstExecution;
+ _firstExecution = false;
+
+ // If auto exposure is enabled use the auto exposure SRV, otherwise what the app sends
+ if ((_contextDescription.Flags & Fsr2.InitializationFlags.EnableAutoExposure) != 0)
+ dispatchParams.Exposure = _resources.AutoExposure;
+ else if (dispatchParams.Exposure == null)
+ dispatchParams.Exposure = _resources.DefaultExposure;
+
+ if (dispatchParams.EnableAutoReactive)
+ {
+ // Create the auto-TCR resources only when we need them
+ if (_resources.AutoReactive == null)
+ _resources.CreateTcrAutogenResources(_contextDescription);
+
+ if (resetAccumulation)
+ commandBuffer.Blit(_resources.PrevPreAlpha[frameIndex ^ 1], dispatchParams.ColorOpaqueOnly ?? Fsr2ShaderIDs.SrvOpaqueOnly);
+ }
+ else if (_resources.AutoReactive != null)
+ {
+ // Destroy the auto-TCR resources if we don't use the feature
+ _resources.DestroyTcrAutogenResources();
+ }
+
+ if (dispatchParams.Reactive == null) dispatchParams.Reactive = _resources.DefaultReactive;
+ if (dispatchParams.TransparencyAndComposition == null) dispatchParams.TransparencyAndComposition = _resources.DefaultReactive;
+ Fsr2Resources.CreateAliasableResources(commandBuffer, _contextDescription, dispatchParams);
+
+ SetupConstants(dispatchParams, resetAccumulation);
+
+ // Reactive mask bias
+ const int threadGroupWorkRegionDim = 8;
+ int dispatchSrcX = (Constants.renderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
+ int dispatchSrcY = (Constants.renderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
+ int dispatchDstX = (_contextDescription.DisplaySize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
+ int dispatchDstY = (_contextDescription.DisplaySize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
+
+ // Clear reconstructed depth for max depth store
+ if (resetAccumulation)
+ {
+ commandBuffer.SetRenderTarget(_resources.LockStatus[frameIndex ^ 1]);
+ commandBuffer.ClearRenderTarget(false, true, Color.clear);
+
+ commandBuffer.SetRenderTarget(_resources.InternalUpscaled[frameIndex ^ 1]);
+ commandBuffer.ClearRenderTarget(false, true, Color.clear);
+
+ commandBuffer.SetRenderTarget(_resources.SceneLuminance);
+ commandBuffer.ClearRenderTarget(false, true, Color.clear);
+
+ // Auto exposure always used to track luma changes in locking logic
+ commandBuffer.SetRenderTarget(_resources.AutoExposure);
+ commandBuffer.ClearRenderTarget(false, true, new Color(-1f, 1e8f, 0f, 0f));
+ }
+
+ // Auto exposure
+ SetupSpdConstants(dispatchParams, out var dispatchThreadGroupCount);
+
+ // Initialize constant buffers data
+ _fsr2ConstantsBuffer.SetData(_fsr2ConstantsArray);
+ _spdConstantsBuffer.SetData(_spdConstantsArray);
+
+ // Auto reactive
+ if (dispatchParams.EnableAutoReactive)
+ {
+ GenerateTransparencyCompositionReactive(dispatchParams, commandBuffer, frameIndex);
+ dispatchParams.Reactive = _resources.AutoReactive;
+ dispatchParams.TransparencyAndComposition = _resources.AutoComposition;
+ }
+
+ // Compute luminance pyramid
+ _computeLuminancePyramidPipeline.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchThreadGroupCount.x, dispatchThreadGroupCount.y);
+
+ // Reconstruct previous depth
+ _reconstructPreviousDepthPipeline.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchSrcX, dispatchSrcY);
+
+ // Depth clip
+ _depthClipPipeline.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchSrcX, dispatchSrcY);
+
+ // Create locks
+ _lockPipeline.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchSrcX, dispatchSrcY);
+
+ // Accumulate
+ _accumulatePipeline.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchDstX, dispatchDstY);
+
+ if (dispatchParams.EnableSharpening)
+ {
+ // Compute the constants
+ SetupRcasConstants(dispatchParams);
+ _rcasConstantsBuffer.SetData(_rcasConstantsArray);
+
+ // Dispatch RCAS
+ const int threadGroupWorkRegionDimRcas = 16;
+ int threadGroupsX = (Screen.width + threadGroupWorkRegionDimRcas - 1) / threadGroupWorkRegionDimRcas;
+ int threadGroupsY = (Screen.height + threadGroupWorkRegionDimRcas - 1) / threadGroupWorkRegionDimRcas;
+ _rcasPipeline.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, threadGroupsX, threadGroupsY);
+ }
+
+ _resourceFrameIndex = (_resourceFrameIndex + 1) % MaxQueuedFrames;
+
+ Fsr2Resources.DestroyAliasableResources(commandBuffer);
+ }
+
+ public void GenerateReactiveMask(Fsr2.GenerateReactiveDescription dispatchParams)
+ {
+ _commandBuffer.Clear();
+ GenerateReactiveMask(dispatchParams, _commandBuffer);
+ Graphics.ExecuteCommandBuffer(_commandBuffer);
+ }
+
+ public void GenerateReactiveMask(Fsr2.GenerateReactiveDescription dispatchParams, CommandBuffer commandBuffer)
+ {
+ const int threadGroupWorkRegionDim = 8;
+ int dispatchSrcX = (dispatchParams.RenderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
+ int dispatchSrcY = (dispatchParams.RenderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
+
+ GenReactiveConsts.scale = dispatchParams.Scale;
+ GenReactiveConsts.threshold = dispatchParams.CutoffThreshold;
+ GenReactiveConsts.binaryValue = dispatchParams.BinaryValue;
+ GenReactiveConsts.flags = (uint)dispatchParams.Flags;
+ _generateReactiveConstantsBuffer.SetData(_generateReactiveConstantsArray);
+
+ ((Fsr2GenerateReactivePipeline)_generateReactivePipeline).ScheduleDispatch(commandBuffer, dispatchParams, dispatchSrcX, dispatchSrcY);
+ }
+
+ private void GenerateTransparencyCompositionReactive(Fsr2.DispatchDescription dispatchParams, CommandBuffer commandBuffer, int frameIndex)
+ {
+ const int threadGroupWorkRegionDim = 8;
+ int dispatchSrcX = (dispatchParams.RenderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
+ int dispatchSrcY = (dispatchParams.RenderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
+
+ TcrAutoGenConsts.autoTcThreshold = dispatchParams.AutoTcThreshold;
+ TcrAutoGenConsts.autoTcScale = dispatchParams.AutoTcScale;
+ TcrAutoGenConsts.autoReactiveScale = dispatchParams.AutoReactiveScale;
+ TcrAutoGenConsts.autoReactiveMax = dispatchParams.AutoReactiveMax;
+ _tcrAutogenerateConstantsBuffer.SetData(_tcrAutogenerateConstantsArray);
+
+ _tcrAutogeneratePipeline.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchSrcX, dispatchSrcY);
+ }
+
+ private void SetupConstants(Fsr2.DispatchDescription dispatchParams, bool resetAccumulation)
+ {
+ ref Fsr2.Fsr2Constants constants = ref Constants;
+
+ constants.jitterOffset = dispatchParams.JitterOffset;
+ constants.renderSize = dispatchParams.RenderSize;
+ constants.maxRenderSize = _contextDescription.MaxRenderSize;
+ constants.inputColorResourceDimensions = dispatchParams.InputResourceSize;
+
+ // Compute the horizontal FOV for the shader from the vertical one
+ float aspectRatio = (float)dispatchParams.RenderSize.x / dispatchParams.RenderSize.y;
+ float cameraAngleHorizontal = Mathf.Atan(Mathf.Tan(dispatchParams.CameraFovAngleVertical / 2.0f) * aspectRatio) * 2.0f;
+ constants.tanHalfFOV = Mathf.Tan(cameraAngleHorizontal * 0.5f);
+ constants.viewSpaceToMetersFactor = (dispatchParams.ViewSpaceToMetersFactor > 0.0f) ? dispatchParams.ViewSpaceToMetersFactor : 1.0f;
+
+ // Compute params to enable device depth to view space depth computation in shader
+ constants.deviceToViewDepth = SetupDeviceDepthToViewSpaceDepthParams(dispatchParams);
+
+ // To be updated if resource is larger than the actual image size
+ constants.downscaleFactor = new Vector2((float)constants.renderSize.x / _contextDescription.DisplaySize.x, (float)constants.renderSize.y / _contextDescription.DisplaySize.y);
+ constants.previousFramePreExposure = constants.preExposure;
+ constants.preExposure = (dispatchParams.PreExposure != 0) ? dispatchParams.PreExposure : 1.0f;
+
+ // Motion vector data
+ Vector2Int motionVectorsTargetSize = (_contextDescription.Flags & Fsr2.InitializationFlags.EnableDisplayResolutionMotionVectors) != 0 ? constants.displaySize : constants.renderSize;
+ constants.motionVectorScale = dispatchParams.MotionVectorScale / motionVectorsTargetSize;
+
+ // Compute jitter cancellation
+ if ((_contextDescription.Flags & Fsr2.InitializationFlags.EnableMotionVectorsJitterCancellation) != 0)
+ {
+ constants.motionVectorJitterCancellation = (_previousJitterOffset - constants.jitterOffset) / motionVectorsTargetSize;
+ _previousJitterOffset = constants.jitterOffset;
+ }
+
+ int jitterPhaseCount = Fsr2.GetJitterPhaseCount(dispatchParams.RenderSize.x, _contextDescription.DisplaySize.x);
+ if (resetAccumulation || constants.jitterPhaseCount == 0)
+ {
+ constants.jitterPhaseCount = jitterPhaseCount;
+ }
+ else
+ {
+ int jitterPhaseCountDelta = (int)(jitterPhaseCount - constants.jitterPhaseCount);
+ if (jitterPhaseCountDelta > 0)
+ constants.jitterPhaseCount++;
+ else if (jitterPhaseCountDelta < 0)
+ constants.jitterPhaseCount--;
+ }
+
+ // Convert delta time to seconds and clamp to [0, 1]
+ constants.deltaTime = Mathf.Clamp01(dispatchParams.FrameTimeDelta);
+
+ if (resetAccumulation)
+ constants.frameIndex = 0;
+ else
+ constants.frameIndex++;
+
+ // Shading change usage of the SPD mip levels
+ constants.lumaMipLevelToUse = Fsr2Pipeline.ShadingChangeMipLevel;
+
+ float mipDiv = 2 << constants.lumaMipLevelToUse;
+ constants.lumaMipDimensions.x = (int)(constants.maxRenderSize.x / mipDiv);
+ constants.lumaMipDimensions.y = (int)(constants.maxRenderSize.y / mipDiv);
+ }
+
+ private Vector4 SetupDeviceDepthToViewSpaceDepthParams(Fsr2.DispatchDescription dispatchParams)
+ {
+ bool inverted = (_contextDescription.Flags & Fsr2.InitializationFlags.EnableDepthInverted) != 0;
+ bool infinite = (_contextDescription.Flags & Fsr2.InitializationFlags.EnableDepthInfinite) != 0;
+
+ // make sure it has no impact if near and far plane values are swapped in dispatch params
+ // the flags "inverted" and "infinite" will decide what transform to use
+ float min = Mathf.Min(dispatchParams.CameraNear, dispatchParams.CameraFar);
+ float max = Mathf.Max(dispatchParams.CameraNear, dispatchParams.CameraFar);
+
+ if (inverted)
+ {
+ (min, max) = (max, min);
+ }
+
+ float q = max / (min - max);
+ float d = -1.0f;
+
+ Vector4 matrixElemC = new Vector4(q, -1.0f - Mathf.Epsilon, q, 0.0f + Mathf.Epsilon);
+ Vector4 matrixElemE = new Vector4(q * min, -min - Mathf.Epsilon, q * min, max);
+
+ // Revert x and y coords
+ float aspect = (float)dispatchParams.RenderSize.x / dispatchParams.RenderSize.y;
+ float cotHalfFovY = Mathf.Cos(0.5f * dispatchParams.CameraFovAngleVertical) / Mathf.Sin(0.5f * dispatchParams.CameraFovAngleVertical);
+
+ int matrixIndex = (inverted ? 2 : 0) + (infinite ? 1 : 0);
+ return new Vector4(
+ d * matrixElemC[matrixIndex],
+ matrixElemE[matrixIndex],
+ aspect / cotHalfFovY,
+ 1.0f / cotHalfFovY);
+ }
+
+ private void SetupRcasConstants(Fsr2.DispatchDescription dispatchParams)
+ {
+ int sharpnessIndex = Mathf.RoundToInt(Mathf.Clamp01(dispatchParams.Sharpness) * (RcasConfigs.Count - 1));
+ RcasConsts = RcasConfigs[sharpnessIndex];
+ }
+
+ private void SetupSpdConstants(Fsr2.DispatchDescription dispatchParams, out Vector2Int dispatchThreadGroupCount)
+ {
+ RectInt rectInfo = new RectInt(0, 0, dispatchParams.RenderSize.x, dispatchParams.RenderSize.y);
+ SpdSetup(rectInfo, out dispatchThreadGroupCount, out var workGroupOffset, out var numWorkGroupsAndMips);
+
+ // Downsample
+ ref Fsr2.SpdConstants spdConstants = ref SpdConsts;
+ spdConstants.numWorkGroups = (uint)numWorkGroupsAndMips.x;
+ spdConstants.mips = (uint)numWorkGroupsAndMips.y;
+ spdConstants.workGroupOffsetX = (uint)workGroupOffset.x;
+ spdConstants.workGroupOffsetY = (uint)workGroupOffset.y;
+ spdConstants.renderSizeX = (uint)dispatchParams.RenderSize.x;
+ spdConstants.renderSizeY = (uint)dispatchParams.RenderSize.y;
+ }
+
+ private static void SpdSetup(RectInt rectInfo, out Vector2Int dispatchThreadGroupCount, out Vector2Int workGroupOffset, out Vector2Int numWorkGroupsAndMips, int mips = -1)
+ {
+ workGroupOffset = new Vector2Int(rectInfo.x / 64, rectInfo.y / 64);
+
+ int endIndexX = (rectInfo.x + rectInfo.width - 1) / 64;
+ int endIndexY = (rectInfo.y + rectInfo.height - 1) / 64;
+
+ dispatchThreadGroupCount = new Vector2Int(endIndexX + 1 - workGroupOffset.x, endIndexY + 1 - workGroupOffset.y);
+
+ numWorkGroupsAndMips = new Vector2Int(dispatchThreadGroupCount.x * dispatchThreadGroupCount.y, mips);
+ if (mips < 0)
+ {
+ float resolution = Math.Max(rectInfo.width, rectInfo.height);
+ numWorkGroupsAndMips.y = Math.Min(Mathf.FloorToInt(Mathf.Log(resolution, 2.0f)), 12);
+ }
+ }
+
+ private void DebugCheckDispatch(Fsr2.DispatchDescription dispatchParams)
+ {
+ // Global texture binding may be queued as part of the command list, which is why we check these after running the process at least once
+ if (!_firstExecution && !dispatchParams.Reset)
+ {
+ if (!dispatchParams.Color.HasValue && Shader.GetGlobalTexture(Fsr2ShaderIDs.SrvInputColor) == null)
+ {
+ Debug.LogError("Color resource is null");
+ }
+
+ if (!dispatchParams.Depth.HasValue && Shader.GetGlobalTexture(Fsr2ShaderIDs.SrvInputDepth) == null)
+ {
+ Debug.LogError("Depth resource is null");
+ }
+
+ if (!dispatchParams.MotionVectors.HasValue && Shader.GetGlobalTexture(Fsr2ShaderIDs.SrvInputMotionVectors) == null)
+ {
+ Debug.LogError("MotionVectors resource is null");
+ }
+
+ if (!dispatchParams.Output.HasValue && Shader.GetGlobalTexture(Fsr2ShaderIDs.UavUpscaledOutput) == null)
+ {
+ Debug.LogError("Output resource is null");
+ }
+ }
+
+ if (dispatchParams.Exposure.HasValue && (_contextDescription.Flags & Fsr2.InitializationFlags.EnableAutoExposure) != 0)
+ {
+ Debug.LogWarning("Exposure resource provided, however auto exposure flag is present");
+ }
+
+ if (Mathf.Abs(dispatchParams.JitterOffset.x) > 1.0f || Mathf.Abs(dispatchParams.JitterOffset.y) > 1.0f)
+ {
+ Debug.LogWarning("JitterOffset contains value outside of expected range [-1.0, 1.0]");
+ }
+
+ if (dispatchParams.MotionVectorScale.x > _contextDescription.MaxRenderSize.x || dispatchParams.MotionVectorScale.y > _contextDescription.MaxRenderSize.y)
+ {
+ Debug.LogWarning("MotionVectorScale contains scale value greater than MaxRenderSize");
+ }
+
+ if (dispatchParams.MotionVectorScale.x == 0.0f || dispatchParams.MotionVectorScale.y == 0.0f)
+ {
+ Debug.LogWarning("MotionVectorScale contains zero scale value");
+ }
+
+ if (dispatchParams.RenderSize.x > _contextDescription.MaxRenderSize.x || dispatchParams.RenderSize.y > _contextDescription.MaxRenderSize.y)
+ {
+ Debug.LogWarning("RenderSize is greater than context MaxRenderSize");
+ }
+
+ if (dispatchParams.RenderSize.x == 0 || dispatchParams.RenderSize.y == 0)
+ {
+ Debug.LogWarning("RenderSize contains zero dimension");
+ }
+
+ if (dispatchParams.FrameTimeDelta > 1.0f)
+ {
+ Debug.LogWarning("FrameTimeDelta is greater than 1.0f - this value should be seconds (~0.0166 for 60fps)");
+ }
+
+ if (dispatchParams.PreExposure == 0.0f)
+ {
+ Debug.LogError("PreExposure provided as 0.0f which is invalid");
+ }
+
+ bool infiniteDepth = (_contextDescription.Flags & Fsr2.InitializationFlags.EnableDepthInfinite) != 0;
+ bool inverseDepth = (_contextDescription.Flags & Fsr2.InitializationFlags.EnableDepthInverted) != 0;
+
+ if (inverseDepth)
+ {
+ if (dispatchParams.CameraNear < dispatchParams.CameraFar)
+ {
+ Debug.LogWarning("EnableDepthInverted flag is present yet CameraNear is less than CameraFar");
+ }
+
+ if (infiniteDepth)
+ {
+ if (dispatchParams.CameraNear < float.MaxValue)
+ {
+ Debug.LogWarning("EnableDepthInfinite and EnableDepthInverted present, yet CameraNear != float.MaxValue");
+ }
+ }
+
+ if (dispatchParams.CameraFar < 0.075f)
+ {
+ Debug.LogWarning("EnableDepthInverted present, CameraFar value is very low which may result in depth separation artefacting");
+ }
+ }
+ else
+ {
+ if (dispatchParams.CameraNear > dispatchParams.CameraFar)
+ {
+ Debug.LogWarning("CameraNear is greater than CameraFar in non-inverted-depth context");
+ }
+
+ if (infiniteDepth)
+ {
+ if (dispatchParams.CameraFar < float.MaxValue)
+ {
+ Debug.LogWarning("EnableDepthInfinite present, yet CameraFar != float.MaxValue");
+ }
+ }
+
+ if (dispatchParams.CameraNear < 0.075f)
+ {
+ Debug.LogWarning("CameraNear value is very low which may result in depth separation artefacting");
+ }
+ }
+
+ if (dispatchParams.CameraFovAngleVertical <= 0.0f)
+ {
+ Debug.LogError("CameraFovAngleVertical is 0.0f - this value should be > 0.0f");
+ }
+
+ if (dispatchParams.CameraFovAngleVertical > Mathf.PI)
+ {
+ Debug.LogError("CameraFovAngleVertical is greater than 180 degrees/PI");
+ }
+ }
+
+ ///
+ /// The FSR2 C++ codebase uses floats bitwise converted to ints to pass sharpness parameters to the RCAS shader.
+ /// This is not possible in C# without enabling unsafe code compilation, so to avoid that we instead use a table of precomputed values.
+ ///
+ private static readonly List RcasConfigs = new List()
+ {
+ new Fsr2.RcasConstants(1048576000u, 872428544u),
+ new Fsr2.RcasConstants(1049178080u, 877212745u),
+ new Fsr2.RcasConstants(1049823372u, 882390168u),
+ new Fsr2.RcasConstants(1050514979u, 887895276u),
+ new Fsr2.RcasConstants(1051256227u, 893859143u),
+ new Fsr2.RcasConstants(1052050675u, 900216232u),
+ new Fsr2.RcasConstants(1052902144u, 907032080u),
+ new Fsr2.RcasConstants(1053814727u, 914306687u),
+ new Fsr2.RcasConstants(1054792807u, 922105590u),
+ new Fsr2.RcasConstants(1055841087u, 930494326u),
+ new Fsr2.RcasConstants(1056964608u, 939538432u),
+ new Fsr2.RcasConstants(1057566688u, 944322633u),
+ new Fsr2.RcasConstants(1058211980u, 949500056u),
+ new Fsr2.RcasConstants(1058903587u, 955005164u),
+ new Fsr2.RcasConstants(1059644835u, 960969031u),
+ new Fsr2.RcasConstants(1060439283u, 967326120u),
+ new Fsr2.RcasConstants(1061290752u, 974141968u),
+ new Fsr2.RcasConstants(1062203335u, 981416575u),
+ new Fsr2.RcasConstants(1063181415u, 989215478u),
+ new Fsr2.RcasConstants(1064229695u, 997604214u),
+ new Fsr2.RcasConstants(1065353216u, 1006648320),
+ };
+
+ private static ComputeBuffer CreateConstantBuffer() where TConstants: struct
+ {
+ return new ComputeBuffer(1, Marshal.SizeOf(), ComputeBufferType.Constant);
+ }
+
+ private static void DestroyConstantBuffer(ref ComputeBuffer bufferRef)
+ {
+ if (bufferRef == null)
+ return;
+
+ bufferRef.Release();
+ bufferRef = null;
+ }
+
+ private static void DestroyPipeline(ref Fsr2Pipeline pipeline)
+ {
+ if (pipeline == null)
+ return;
+
+ pipeline.Dispose();
+ pipeline = null;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2Context.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2Context.cs.meta
new file mode 100644
index 0000000..ed50468
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2Context.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 2f00ea267c3443d88bbd0e9dd7c08b4a
+timeCreated: 1673442225
\ No newline at end of file
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2Pipeline.cs b/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2Pipeline.cs
new file mode 100644
index 0000000..5b963f0
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2Pipeline.cs
@@ -0,0 +1,403 @@
+// Copyright (c) 2023 Nico de Poel
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Runtime.InteropServices;
+using UnityEngine;
+using UnityEngine.Rendering;
+
+namespace FidelityFX
+{
+ ///
+ /// Base class for all of the compute passes that make up the FSR2 process.
+ /// This loosely matches the FfxPipelineState struct from the original FSR2 codebase, wrapped in an object-oriented blanket.
+ /// These classes are responsible for loading compute shaders, managing temporary resources, binding resources to shader kernels and dispatching said shaders.
+ ///
+ internal abstract class Fsr2Pipeline: IDisposable
+ {
+ internal const int ShadingChangeMipLevel = 4; // This matches the FFX_FSR2_SHADING_CHANGE_MIP_LEVEL define
+
+ protected readonly Fsr2.ContextDescription ContextDescription;
+ protected readonly Fsr2Resources Resources;
+ protected readonly ComputeBuffer Constants;
+
+ protected ComputeShader ComputeShader;
+ protected int KernelIndex;
+
+ protected virtual bool AllowFP16 => true;
+
+ protected Fsr2Pipeline(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants)
+ {
+ ContextDescription = contextDescription;
+ Resources = resources;
+ Constants = constants;
+ }
+
+ public virtual void Dispose()
+ {
+ UnloadComputeShader();
+ }
+
+ public abstract void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY);
+
+ protected void LoadComputeShader(string name)
+ {
+ LoadComputeShader(name, ContextDescription.Flags, ref ComputeShader, out KernelIndex);
+ }
+
+ private void LoadComputeShader(string name, Fsr2.InitializationFlags flags, ref ComputeShader shaderRef, out int kernelIndex)
+ {
+ if (shaderRef == null)
+ {
+ shaderRef = ContextDescription.Callbacks.LoadComputeShader(name);
+ if (shaderRef == null)
+ throw new MissingReferenceException($"Shader '{name}' could not be loaded! Please ensure it is included in the project correctly.");
+ }
+
+ kernelIndex = shaderRef.FindKernel("CS");
+
+ bool useLut = false;
+#if UNITY_2022_1_OR_NEWER // This will also work in 2020.3.43+ and 2021.3.14+
+ if (SystemInfo.computeSubGroupSize == 64)
+ {
+ useLut = true;
+ }
+#endif
+
+ // Allow 16-bit floating point as a configuration option, except on passes that explicitly disable it
+ bool supportedFP16 = ((flags & Fsr2.InitializationFlags.EnableFP16Usage) != 0 && AllowFP16);
+
+ // This matches the permutation rules from the CreatePipeline* functions
+ if ((flags & Fsr2.InitializationFlags.EnableHighDynamicRange) != 0) shaderRef.EnableKeyword("FFX_FSR2_OPTION_HDR_COLOR_INPUT");
+ if ((flags & Fsr2.InitializationFlags.EnableDisplayResolutionMotionVectors) == 0) shaderRef.EnableKeyword("FFX_FSR2_OPTION_LOW_RESOLUTION_MOTION_VECTORS");
+ if ((flags & Fsr2.InitializationFlags.EnableMotionVectorsJitterCancellation) != 0) shaderRef.EnableKeyword("FFX_FSR2_OPTION_JITTERED_MOTION_VECTORS");
+ if ((flags & Fsr2.InitializationFlags.EnableDepthInverted) != 0) shaderRef.EnableKeyword("FFX_FSR2_OPTION_INVERTED_DEPTH");
+ if (useLut) shaderRef.EnableKeyword("FFX_FSR2_OPTION_REPROJECT_USE_LANCZOS_TYPE");
+ if (supportedFP16) shaderRef.EnableKeyword("FFX_HALF");
+
+ // Inform the shader which render pipeline we're currently using
+ var pipeline = GraphicsSettings.currentRenderPipeline;
+ if (pipeline != null && pipeline.GetType().Name.Contains("HDRenderPipeline"))
+ {
+ shaderRef.EnableKeyword("UNITY_FSR2_HDRP");
+ }
+ }
+
+ private void UnloadComputeShader()
+ {
+ UnloadComputeShader(ref ComputeShader);
+ }
+
+ private void UnloadComputeShader(ref ComputeShader shaderRef)
+ {
+ if (shaderRef == null)
+ return;
+
+ ContextDescription.Callbacks.UnloadComputeShader(shaderRef);
+ shaderRef = null;
+ }
+ }
+
+ internal class Fsr2ComputeLuminancePyramidPipeline : Fsr2Pipeline
+ {
+ private readonly ComputeBuffer _spdConstants;
+
+ public Fsr2ComputeLuminancePyramidPipeline(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants, ComputeBuffer spdConstants)
+ : base(contextDescription, resources, constants)
+ {
+ _spdConstants = spdConstants;
+
+ LoadComputeShader("FSR2/ffx_fsr2_compute_luminance_pyramid_pass");
+ }
+
+ public override void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
+ {
+ if (dispatchParams.Color.HasValue)
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputColor, dispatchParams.Color.Value, 0, RenderTextureSubElement.Color);
+
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavSpdAtomicCount, Resources.SpdAtomicCounter);
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavExposureMipLumaChange, Resources.SceneLuminance, ShadingChangeMipLevel);
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavExposureMip5, Resources.SceneLuminance, 5);
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavAutoExposure, Resources.AutoExposure);
+
+ commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants, 0, Marshal.SizeOf());
+ commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbSpd, _spdConstants, 0, Marshal.SizeOf());
+
+ commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
+ }
+ }
+
+ internal class Fsr2ReconstructPreviousDepthPipeline : Fsr2Pipeline
+ {
+ public Fsr2ReconstructPreviousDepthPipeline(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants)
+ : base(contextDescription, resources, constants)
+ {
+ LoadComputeShader("FSR2/ffx_fsr2_reconstruct_previous_depth_pass");
+ }
+
+ public override void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
+ {
+ if (dispatchParams.Color.HasValue)
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputColor, dispatchParams.Color.Value, 0, RenderTextureSubElement.Color);
+
+ if (dispatchParams.Depth.HasValue)
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputDepth, dispatchParams.Depth.Value, 0, RenderTextureSubElement.Depth);
+
+ if (dispatchParams.MotionVectors.HasValue)
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputMotionVectors, dispatchParams.MotionVectors.Value);
+
+ if (dispatchParams.Exposure.HasValue)
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputExposure, dispatchParams.Exposure.Value);
+
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavDilatedMotionVectors, Resources.DilatedMotionVectors[frameIndex]);
+
+ commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants, 0, Marshal.SizeOf());
+
+ commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
+ }
+ }
+
+ internal class Fsr2DepthClipPipeline : Fsr2Pipeline
+ {
+ public Fsr2DepthClipPipeline(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants)
+ : base(contextDescription, resources, constants)
+ {
+ LoadComputeShader("FSR2/ffx_fsr2_depth_clip_pass");
+ }
+
+ public override void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
+ {
+ if (dispatchParams.Color.HasValue)
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputColor, dispatchParams.Color.Value, 0, RenderTextureSubElement.Color);
+
+ if (dispatchParams.Depth.HasValue)
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputDepth, dispatchParams.Depth.Value, 0, RenderTextureSubElement.Depth);
+
+ if (dispatchParams.MotionVectors.HasValue)
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputMotionVectors, dispatchParams.MotionVectors.Value);
+
+ if (dispatchParams.Exposure.HasValue)
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputExposure, dispatchParams.Exposure.Value);
+
+ if (dispatchParams.Reactive.HasValue)
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvReactiveMask, dispatchParams.Reactive.Value);
+
+ if (dispatchParams.TransparencyAndComposition.HasValue)
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvTransparencyAndCompositionMask, dispatchParams.TransparencyAndComposition.Value);
+
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvReconstructedPrevNearestDepth, Fsr2ShaderIDs.UavReconstructedPrevNearestDepth);
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedMotionVectors[frameIndex]);
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvDilatedDepth, Fsr2ShaderIDs.UavDilatedDepth);
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvPrevDilatedMotionVectors, Resources.DilatedMotionVectors[frameIndex ^ 1]);
+
+ commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants, 0, Marshal.SizeOf());
+
+ commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
+ }
+ }
+
+ internal class Fsr2LockPipeline : Fsr2Pipeline
+ {
+ public Fsr2LockPipeline(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants)
+ : base(contextDescription, resources, constants)
+ {
+ LoadComputeShader("FSR2/ffx_fsr2_lock_pass");
+ }
+
+ public override void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
+ {
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvLockInputLuma, Fsr2ShaderIDs.UavLockInputLuma);
+ commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants, 0, Marshal.SizeOf());
+
+ commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
+ }
+ }
+
+ internal class Fsr2AccumulatePipeline : Fsr2Pipeline
+ {
+ private const string SharpeningKeyword = "FFX_FSR2_OPTION_APPLY_SHARPENING";
+
+ // Workaround: Disable FP16 path for the accumulate pass on NVIDIA due to reduced occupancy and high VRAM throughput.
+ protected override bool AllowFP16 => SystemInfo.graphicsDeviceVendorID != 0x10DE;
+
+#if UNITY_2021_2_OR_NEWER
+ private readonly LocalKeyword _sharpeningKeyword;
+#endif
+
+ public Fsr2AccumulatePipeline(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants)
+ : base(contextDescription, resources, constants)
+ {
+ LoadComputeShader("FSR2/ffx_fsr2_accumulate_pass");
+#if UNITY_2021_2_OR_NEWER
+ _sharpeningKeyword = new LocalKeyword(ComputeShader, SharpeningKeyword);
+#endif
+ }
+
+ public override void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
+ {
+#if UNITY_2021_2_OR_NEWER
+ if (dispatchParams.EnableSharpening)
+ commandBuffer.EnableKeyword(ComputeShader, _sharpeningKeyword);
+ else
+ commandBuffer.DisableKeyword(ComputeShader, _sharpeningKeyword);
+#else
+ if (dispatchParams.EnableSharpening)
+ commandBuffer.EnableShaderKeyword(SharpeningKeyword);
+ else
+ commandBuffer.DisableShaderKeyword(SharpeningKeyword);
+#endif
+
+ if ((ContextDescription.Flags & Fsr2.InitializationFlags.EnableDisplayResolutionMotionVectors) == 0)
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedMotionVectors[frameIndex]);
+ else if (dispatchParams.MotionVectors.HasValue)
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputMotionVectors, dispatchParams.MotionVectors.Value);
+
+ if (dispatchParams.Exposure.HasValue)
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputExposure, dispatchParams.Exposure.Value);
+
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvDilatedReactiveMasks, Fsr2ShaderIDs.UavDilatedReactiveMasks);
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInternalUpscaled, Resources.InternalUpscaled[frameIndex ^ 1]);
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvLockStatus, Resources.LockStatus[frameIndex ^ 1]);
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvPreparedInputColor, Fsr2ShaderIDs.UavPreparedInputColor);
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvLanczosLut, Resources.LanczosLut);
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvUpscaleMaximumBiasLut, Resources.MaximumBiasLut);
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvSceneLuminanceMips, Resources.SceneLuminance);
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvAutoExposure, Resources.AutoExposure);
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvLumaHistory, Resources.LumaHistory[frameIndex ^ 1]);
+
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavInternalUpscaled, Resources.InternalUpscaled[frameIndex]);
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavLockStatus, Resources.LockStatus[frameIndex]);
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavLumaHistory, Resources.LumaHistory[frameIndex]);
+
+ if (dispatchParams.Output.HasValue)
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavUpscaledOutput, dispatchParams.Output.Value);
+
+ commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants, 0, Marshal.SizeOf());
+
+ commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
+ }
+ }
+
+ internal class Fsr2RcasPipeline : Fsr2Pipeline
+ {
+ private readonly ComputeBuffer _rcasConstants;
+
+ public Fsr2RcasPipeline(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants, ComputeBuffer rcasConstants)
+ : base(contextDescription, resources, constants)
+ {
+ _rcasConstants = rcasConstants;
+
+ LoadComputeShader("FSR2/ffx_fsr2_rcas_pass");
+ }
+
+ public override void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
+ {
+ if (dispatchParams.Exposure.HasValue)
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputExposure, dispatchParams.Exposure.Value);
+
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvRcasInput, Resources.InternalUpscaled[frameIndex]);
+
+ if (dispatchParams.Output.HasValue)
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavUpscaledOutput, dispatchParams.Output.Value);
+
+ commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants, 0, Marshal.SizeOf());
+ commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbRcas, _rcasConstants, 0, Marshal.SizeOf());
+
+ commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
+ }
+ }
+
+ internal class Fsr2GenerateReactivePipeline : Fsr2Pipeline
+ {
+ private readonly ComputeBuffer _generateReactiveConstants;
+
+ public Fsr2GenerateReactivePipeline(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer generateReactiveConstants)
+ : base(contextDescription, resources, null)
+ {
+ _generateReactiveConstants = generateReactiveConstants;
+
+ LoadComputeShader("FSR2/ffx_fsr2_autogen_reactive_pass");
+ }
+
+ public override void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
+ {
+ }
+
+ public void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.GenerateReactiveDescription dispatchParams, int dispatchX, int dispatchY)
+ {
+ if (dispatchParams.ColorOpaqueOnly.HasValue)
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvOpaqueOnly, dispatchParams.ColorOpaqueOnly.Value, 0, RenderTextureSubElement.Color);
+
+ if (dispatchParams.ColorPreUpscale.HasValue)
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputColor, dispatchParams.ColorPreUpscale.Value, 0, RenderTextureSubElement.Color);
+
+ if (dispatchParams.OutReactive.HasValue)
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavAutoReactive, dispatchParams.OutReactive.Value);
+
+ commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbGenReactive, _generateReactiveConstants, 0, Marshal.SizeOf());
+
+ commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
+ }
+ }
+
+ internal class Fsr2TcrAutogeneratePipeline : Fsr2Pipeline
+ {
+ private readonly ComputeBuffer _tcrAutogenerateConstants;
+
+ public Fsr2TcrAutogeneratePipeline(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants, ComputeBuffer tcrAutogenerateConstants)
+ : base(contextDescription, resources, constants)
+ {
+ _tcrAutogenerateConstants = tcrAutogenerateConstants;
+
+ LoadComputeShader("FSR2/ffx_fsr2_tcr_autogen_pass");
+ }
+
+ public override void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
+ {
+ if (dispatchParams.ColorOpaqueOnly.HasValue)
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvOpaqueOnly, dispatchParams.ColorOpaqueOnly.Value, 0, RenderTextureSubElement.Color);
+
+ if (dispatchParams.Color.HasValue)
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputColor, dispatchParams.Color.Value, 0, RenderTextureSubElement.Color);
+
+ if (dispatchParams.MotionVectors.HasValue)
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputMotionVectors, dispatchParams.MotionVectors.Value);
+
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvPrevColorPreAlpha, Resources.PrevPreAlpha[frameIndex ^ 1]);
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvPrevColorPostAlpha, Resources.PrevPostAlpha[frameIndex ^ 1]);
+
+ if (dispatchParams.Reactive.HasValue)
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvReactiveMask, dispatchParams.Reactive.Value);
+
+ if (dispatchParams.TransparencyAndComposition.HasValue)
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvTransparencyAndCompositionMask, dispatchParams.TransparencyAndComposition.Value);
+
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavAutoReactive, Resources.AutoReactive);
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavAutoComposition, Resources.AutoComposition);
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavPrevColorPreAlpha, Resources.PrevPreAlpha[frameIndex]);
+ commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavPrevColorPostAlpha, Resources.PrevPostAlpha[frameIndex]);
+
+ commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants, 0, Marshal.SizeOf());
+ commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbGenReactive, _tcrAutogenerateConstants, 0, Marshal.SizeOf());
+
+ commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2Pipeline.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2Pipeline.cs.meta
new file mode 100644
index 0000000..06ce7e4
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2Pipeline.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 14234aed75ce454183019d2e20a44d24
+timeCreated: 1676885169
\ No newline at end of file
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2Resources.cs b/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2Resources.cs
new file mode 100644
index 0000000..a3e8e27
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2Resources.cs
@@ -0,0 +1,251 @@
+// Copyright (c) 2023 Nico de Poel
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using UnityEngine;
+using UnityEngine.Experimental.Rendering;
+using UnityEngine.Rendering;
+
+namespace FidelityFX
+{
+ ///
+ /// Helper class for bundling and managing persistent resources required by the FSR2 process.
+ /// This includes lookup tables, default fallback resources and double-buffered resources that get swapped between frames.
+ ///
+ internal class Fsr2Resources
+ {
+ public Texture2D DefaultExposure;
+ public Texture2D DefaultReactive;
+ public Texture2D LanczosLut;
+ public Texture2D MaximumBiasLut;
+ public RenderTexture SpdAtomicCounter;
+ public RenderTexture AutoExposure;
+ public RenderTexture SceneLuminance;
+ public RenderTexture AutoReactive;
+ public RenderTexture AutoComposition;
+ public readonly RenderTexture[] DilatedMotionVectors = new RenderTexture[2];
+ public readonly RenderTexture[] LockStatus = new RenderTexture[2];
+ public readonly RenderTexture[] InternalUpscaled = new RenderTexture[2];
+ public readonly RenderTexture[] LumaHistory = new RenderTexture[2];
+ public readonly RenderTexture[] PrevPreAlpha = new RenderTexture[2];
+ public readonly RenderTexture[] PrevPostAlpha = new RenderTexture[2];
+
+ public void Create(Fsr2.ContextDescription contextDescription)
+ {
+ // Generate the data for the LUT
+ const int lanczos2LutWidth = 128;
+ float[] lanczos2Weights = new float[lanczos2LutWidth];
+ for (int currentLanczosWidthIndex = 0; currentLanczosWidthIndex < lanczos2LutWidth; ++currentLanczosWidthIndex)
+ {
+ float x = 2.0f * currentLanczosWidthIndex / (lanczos2LutWidth - 1);
+ float y = Fsr2.Lanczos2(x);
+ lanczos2Weights[currentLanczosWidthIndex] = y;
+ }
+
+ float[] maximumBias = new float[MaximumBiasTextureWidth * MaximumBiasTextureHeight];
+ for (int i = 0; i < maximumBias.Length; ++i)
+ {
+ maximumBias[i] = MaximumBias[i] / 2.0f;
+ }
+
+ // Resource FSR2_LanczosLutData: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R16_SNORM, FFX_RESOURCE_FLAGS_NONE
+ // R16_SNorm textures are not supported by Unity on most platforms, strangely enough. So instead we use R32_SFloat and upload pre-normalized float data.
+ LanczosLut = new Texture2D(lanczos2LutWidth, 1, GraphicsFormat.R32_SFloat, TextureCreationFlags.None) { name = "FSR2_LanczosLutData" };
+ LanczosLut.SetPixelData(lanczos2Weights, 0);
+ LanczosLut.Apply();
+
+ // Resource FSR2_MaximumUpsampleBias: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R16_SNORM, FFX_RESOURCE_FLAGS_NONE
+ MaximumBiasLut = new Texture2D(MaximumBiasTextureWidth, MaximumBiasTextureHeight, GraphicsFormat.R32_SFloat, TextureCreationFlags.None) { name = "FSR2_MaximumUpsampleBias" };
+ MaximumBiasLut.SetPixelData(maximumBias, 0);
+ MaximumBiasLut.Apply();
+
+ // Resource FSR2_DefaultExposure: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R32G32_FLOAT, FFX_RESOURCE_FLAGS_NONE
+ DefaultExposure = new Texture2D(1, 1, GraphicsFormat.R32G32_SFloat, TextureCreationFlags.None) { name = "FSR2_DefaultExposure" };
+ DefaultExposure.SetPixel(0, 0, Color.clear);
+ DefaultExposure.Apply();
+
+ // Resource FSR2_DefaultReactivityMask: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE
+ DefaultReactive = new Texture2D(1, 1, GraphicsFormat.R8_UNorm, TextureCreationFlags.None) { name = "FSR2_DefaultReactivityMask" };
+ DefaultReactive.SetPixel(0, 0, Color.clear);
+ DefaultReactive.Apply();
+
+ // Resource FSR2_SpdAtomicCounter: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32_UINT, FFX_RESOURCE_FLAGS_ALIASABLE
+ // Despite what the original FSR2 codebase says, this resource really isn't aliasable. Resetting this counter to 0 every frame breaks auto-exposure on MacOS Metal.
+ SpdAtomicCounter = new RenderTexture(1, 1, 0, GraphicsFormat.R32_UInt) { name = "FSR2_SpdAtomicCounter", enableRandomWrite = true };
+ SpdAtomicCounter.Create();
+
+ // Resource FSR2_AutoExposure: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32G32_FLOAT, FFX_RESOURCE_FLAGS_NONE
+ AutoExposure = new RenderTexture(1, 1, 0, GraphicsFormat.R32G32_SFloat) { name = "FSR2_AutoExposure", enableRandomWrite = true };
+ AutoExposure.Create();
+
+ // Resource FSR2_ExposureMips: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16_FLOAT, FFX_RESOURCE_FLAGS_ALIASABLE
+ // This is a rather special case: it's an aliasable resource, but because we require a mipmap chain and bind specific mip levels per shader, we can't easily use temporary RTs for this.
+ int w = contextDescription.MaxRenderSize.x / 2, h = contextDescription.MaxRenderSize.y / 2;
+ int mipCount = 1 + Mathf.FloorToInt(Mathf.Log(Math.Max(w, h), 2.0f));
+ SceneLuminance = new RenderTexture(w, h, 0, GraphicsFormat.R16_SFloat, mipCount) { name = "FSR2_ExposureMips", enableRandomWrite = true, useMipMap = true, autoGenerateMips = false };
+ SceneLuminance.Create();
+
+ // Resources FSR2_InternalDilatedVelocity1/2: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16G16_FLOAT, FFX_RESOURCE_FLAGS_NONE
+ CreateDoubleBufferedResource(DilatedMotionVectors, "FSR2_InternalDilatedVelocity", contextDescription.MaxRenderSize, GraphicsFormat.R16G16_SFloat);
+
+ // Resources FSR2_LockStatus1/2: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16G16_FLOAT, FFX_RESOURCE_FLAGS_NONE
+ CreateDoubleBufferedResource(LockStatus, "FSR2_LockStatus", contextDescription.DisplaySize, GraphicsFormat.R16G16_SFloat);
+
+ // Resources FSR2_InternalUpscaled1/2: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16G16B16A16_FLOAT, FFX_RESOURCE_FLAGS_NONE
+ CreateDoubleBufferedResource(InternalUpscaled, "FSR2_InternalUpscaled", contextDescription.DisplaySize, GraphicsFormat.R16G16B16A16_SFloat);
+
+ // Resources FSR2_LumaHistory1/2: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8G8B8A8_UNORM, FFX_RESOURCE_FLAGS_NONE
+ CreateDoubleBufferedResource(LumaHistory, "FSR2_LumaHistory", contextDescription.DisplaySize, GraphicsFormat.R8G8B8A8_UNorm);
+ }
+
+ public void CreateTcrAutogenResources(Fsr2.ContextDescription contextDescription)
+ {
+ // Resource FSR2_AutoReactive: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE
+ AutoReactive = new RenderTexture(contextDescription.MaxRenderSize.x, contextDescription.MaxRenderSize.y, 0, GraphicsFormat.R8_UNorm) { name = "FSR2_AutoReactive", enableRandomWrite = true };
+ AutoReactive.Create();
+
+ // Resource FSR2_AutoComposition: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE
+ AutoComposition = new RenderTexture(contextDescription.MaxRenderSize.x, contextDescription.MaxRenderSize.y, 0, GraphicsFormat.R8_UNorm) { name = "FSR2_AutoComposition", enableRandomWrite = true };
+ AutoComposition.Create();
+
+ // Resources FSR2_PrevPreAlpha0/1: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R11G11B10_FLOAT, FFX_RESOURCE_FLAGS_NONE
+ CreateDoubleBufferedResource(PrevPreAlpha, "FSR2_PrevPreAlpha", contextDescription.MaxRenderSize, GraphicsFormat.B10G11R11_UFloatPack32);
+
+ // Resources FSR2_PrevPostAlpha0/1: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R11G11B10_FLOAT, FFX_RESOURCE_FLAGS_NONE
+ CreateDoubleBufferedResource(PrevPostAlpha, "FSR2_PrevPostAlpha", contextDescription.MaxRenderSize, GraphicsFormat.B10G11R11_UFloatPack32);
+ }
+
+ // Set up shared aliasable resources, i.e. temporary render textures
+ // These do not need to persist between frames, but they do need to be available between passes
+ public static void CreateAliasableResources(CommandBuffer commandBuffer, Fsr2.ContextDescription contextDescription, Fsr2.DispatchDescription dispatchParams)
+ {
+ Vector2Int displaySize = contextDescription.DisplaySize;
+ Vector2Int maxRenderSize = contextDescription.MaxRenderSize;
+
+ // FSR2_ReconstructedPrevNearestDepth: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32_UINT, FFX_RESOURCE_FLAGS_ALIASABLE
+ commandBuffer.GetTemporaryRT(Fsr2ShaderIDs.UavReconstructedPrevNearestDepth, maxRenderSize.x, maxRenderSize.y, 0, default, GraphicsFormat.R32_UInt, 1, true);
+
+ // FSR2_DilatedDepth: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32_FLOAT, FFX_RESOURCE_FLAGS_ALIASABLE
+ commandBuffer.GetTemporaryRT(Fsr2ShaderIDs.UavDilatedDepth, maxRenderSize.x, maxRenderSize.y, 0, default, GraphicsFormat.R32_SFloat, 1, true);
+
+ // FSR2_LockInputLuma: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16_FLOAT, FFX_RESOURCE_FLAGS_ALIASABLE
+ commandBuffer.GetTemporaryRT(Fsr2ShaderIDs.UavLockInputLuma, maxRenderSize.x, maxRenderSize.y, 0, default, GraphicsFormat.R16_SFloat, 1, true);
+
+ // FSR2_DilatedReactiveMasks: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8G8_UNORM, FFX_RESOURCE_FLAGS_ALIASABLE
+ commandBuffer.GetTemporaryRT(Fsr2ShaderIDs.UavDilatedReactiveMasks, maxRenderSize.x, maxRenderSize.y, 0, default, GraphicsFormat.R8G8_UNorm, 1, true);
+
+ // FSR2_PreparedInputColor: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16G16B16A16_FLOAT, FFX_RESOURCE_FLAGS_ALIASABLE
+ commandBuffer.GetTemporaryRT(Fsr2ShaderIDs.UavPreparedInputColor, maxRenderSize.x, maxRenderSize.y, 0, default, GraphicsFormat.R16G16B16A16_SFloat, 1, true);
+
+ // FSR2_NewLocks: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_ALIASABLE
+ commandBuffer.GetTemporaryRT(Fsr2ShaderIDs.UavNewLocks, displaySize.x, displaySize.y, 0, default, GraphicsFormat.R8_UNorm, 1, true);
+ }
+
+ public static void DestroyAliasableResources(CommandBuffer commandBuffer)
+ {
+ // Release all of the aliasable resources used this frame
+ commandBuffer.ReleaseTemporaryRT(Fsr2ShaderIDs.UavReconstructedPrevNearestDepth);
+ commandBuffer.ReleaseTemporaryRT(Fsr2ShaderIDs.UavDilatedDepth);
+ commandBuffer.ReleaseTemporaryRT(Fsr2ShaderIDs.UavLockInputLuma);
+ commandBuffer.ReleaseTemporaryRT(Fsr2ShaderIDs.UavDilatedReactiveMasks);
+ commandBuffer.ReleaseTemporaryRT(Fsr2ShaderIDs.UavPreparedInputColor);
+ commandBuffer.ReleaseTemporaryRT(Fsr2ShaderIDs.UavNewLocks);
+ }
+
+ private static void CreateDoubleBufferedResource(RenderTexture[] resource, string name, Vector2Int size, GraphicsFormat format)
+ {
+ for (int i = 0; i < 2; ++i)
+ {
+ resource[i] = new RenderTexture(size.x, size.y, 0, format) { name = name + (i + 1), enableRandomWrite = true };
+ resource[i].Create();
+ }
+ }
+
+ public void Destroy()
+ {
+ DestroyTcrAutogenResources();
+
+ DestroyResource(LumaHistory);
+ DestroyResource(InternalUpscaled);
+ DestroyResource(LockStatus);
+ DestroyResource(DilatedMotionVectors);
+ DestroyResource(ref SceneLuminance);
+ DestroyResource(ref AutoExposure);
+ DestroyResource(ref DefaultReactive);
+ DestroyResource(ref DefaultExposure);
+ DestroyResource(ref MaximumBiasLut);
+ DestroyResource(ref LanczosLut);
+ }
+
+ public void DestroyTcrAutogenResources()
+ {
+ DestroyResource(PrevPostAlpha);
+ DestroyResource(PrevPreAlpha);
+ DestroyResource(ref AutoComposition);
+ DestroyResource(ref AutoReactive);
+ }
+
+ private static void DestroyResource(ref Texture2D resource)
+ {
+ if (resource == null)
+ return;
+
+ UnityEngine.Object.Destroy(resource);
+ resource = null;
+ }
+
+ private static void DestroyResource(ref RenderTexture resource)
+ {
+ if (resource == null)
+ return;
+
+ resource.Release();
+ resource = null;
+ }
+
+ private static void DestroyResource(RenderTexture[] resource)
+ {
+ for (int i = 0; i < resource.Length; ++i)
+ DestroyResource(ref resource[i]);
+ }
+
+ private const int MaximumBiasTextureWidth = 16;
+ private const int MaximumBiasTextureHeight = 16;
+ private static readonly float[] MaximumBias =
+ {
+ 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.876f, 1.809f, 1.772f, 1.753f, 1.748f,
+ 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.869f, 1.801f, 1.764f, 1.745f, 1.739f,
+ 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.976f, 1.841f, 1.774f, 1.737f, 1.716f, 1.71f,
+ 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.914f, 1.784f, 1.716f, 1.673f, 1.649f, 1.641f,
+ 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.793f, 1.676f, 1.604f, 1.562f, 1.54f, 1.533f,
+ 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.802f, 1.619f, 1.536f, 1.492f, 1.467f, 1.454f, 1.449f,
+ 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.812f, 1.575f, 1.496f, 1.456f, 1.432f, 1.416f, 1.408f, 1.405f,
+ 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.555f, 1.479f, 1.438f, 1.413f, 1.398f, 1.387f, 1.381f, 1.379f,
+ 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.812f, 1.555f, 1.474f, 1.43f, 1.404f, 1.387f, 1.376f, 1.368f, 1.363f, 1.362f,
+ 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.802f, 1.575f, 1.479f, 1.43f, 1.401f, 1.382f, 1.369f, 1.36f, 1.354f, 1.351f, 1.35f,
+ 2.0f, 2.0f, 1.976f, 1.914f, 1.793f, 1.619f, 1.496f, 1.438f, 1.404f, 1.382f, 1.367f, 1.357f, 1.349f, 1.344f, 1.341f, 1.34f,
+ 1.876f, 1.869f, 1.841f, 1.784f, 1.676f, 1.536f, 1.456f, 1.413f, 1.387f, 1.369f, 1.357f, 1.347f, 1.341f, 1.336f, 1.333f, 1.332f,
+ 1.809f, 1.801f, 1.774f, 1.716f, 1.604f, 1.492f, 1.432f, 1.398f, 1.376f, 1.36f, 1.349f, 1.341f, 1.335f, 1.33f, 1.328f, 1.327f,
+ 1.772f, 1.764f, 1.737f, 1.673f, 1.562f, 1.467f, 1.416f, 1.387f, 1.368f, 1.354f, 1.344f, 1.336f, 1.33f, 1.326f, 1.323f, 1.323f,
+ 1.753f, 1.745f, 1.716f, 1.649f, 1.54f, 1.454f, 1.408f, 1.381f, 1.363f, 1.351f, 1.341f, 1.333f, 1.328f, 1.323f, 1.321f, 1.32f,
+ 1.748f, 1.739f, 1.71f, 1.641f, 1.533f, 1.449f, 1.405f, 1.379f, 1.362f, 1.35f, 1.34f, 1.332f, 1.327f, 1.323f, 1.32f, 1.319f,
+ };
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2Resources.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2Resources.cs.meta
new file mode 100644
index 0000000..0e993b4
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2Resources.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 22ad49193f244ab4a36d0a1512f3015f
+timeCreated: 1677236102
\ No newline at end of file
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2ShaderIDs.cs b/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2ShaderIDs.cs
new file mode 100644
index 0000000..b07c967
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2ShaderIDs.cs
@@ -0,0 +1,80 @@
+// Copyright (c) 2023 Nico de Poel
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using UnityEngine;
+
+namespace FidelityFX
+{
+ internal static class Fsr2ShaderIDs
+ {
+ // Shader resource views, i.e. read-only bindings
+ internal static readonly int SrvInputColor = Shader.PropertyToID("r_input_color_jittered");
+ internal static readonly int SrvOpaqueOnly = Shader.PropertyToID("r_input_opaque_only");
+ internal static readonly int SrvInputMotionVectors = Shader.PropertyToID("r_input_motion_vectors");
+ internal static readonly int SrvInputDepth = Shader.PropertyToID("r_input_depth");
+ internal static readonly int SrvInputExposure = Shader.PropertyToID("r_input_exposure");
+ internal static readonly int SrvAutoExposure = Shader.PropertyToID("r_auto_exposure");
+ internal static readonly int SrvReactiveMask = Shader.PropertyToID("r_reactive_mask");
+ internal static readonly int SrvTransparencyAndCompositionMask = Shader.PropertyToID("r_transparency_and_composition_mask");
+ internal static readonly int SrvReconstructedPrevNearestDepth = Shader.PropertyToID("r_reconstructed_previous_nearest_depth");
+ internal static readonly int SrvDilatedMotionVectors = Shader.PropertyToID("r_dilated_motion_vectors");
+ internal static readonly int SrvPrevDilatedMotionVectors = Shader.PropertyToID("r_previous_dilated_motion_vectors");
+ internal static readonly int SrvDilatedDepth = Shader.PropertyToID("r_dilatedDepth");
+ internal static readonly int SrvInternalUpscaled = Shader.PropertyToID("r_internal_upscaled_color");
+ internal static readonly int SrvLockStatus = Shader.PropertyToID("r_lock_status");
+ internal static readonly int SrvLockInputLuma = Shader.PropertyToID("r_lock_input_luma");
+ internal static readonly int SrvPreparedInputColor = Shader.PropertyToID("r_prepared_input_color");
+ internal static readonly int SrvLumaHistory = Shader.PropertyToID("r_luma_history");
+ internal static readonly int SrvRcasInput = Shader.PropertyToID("r_rcas_input");
+ internal static readonly int SrvLanczosLut = Shader.PropertyToID("r_lanczos_lut");
+ internal static readonly int SrvSceneLuminanceMips = Shader.PropertyToID("r_imgMips");
+ internal static readonly int SrvUpscaleMaximumBiasLut = Shader.PropertyToID("r_upsample_maximum_bias_lut");
+ internal static readonly int SrvDilatedReactiveMasks = Shader.PropertyToID("r_dilated_reactive_masks");
+ internal static readonly int SrvPrevColorPreAlpha = Shader.PropertyToID("r_input_prev_color_pre_alpha");
+ internal static readonly int SrvPrevColorPostAlpha = Shader.PropertyToID("r_input_prev_color_post_alpha");
+
+ // Unordered access views, i.e. random read/write bindings
+ internal static readonly int UavReconstructedPrevNearestDepth = Shader.PropertyToID("rw_reconstructed_previous_nearest_depth");
+ internal static readonly int UavDilatedMotionVectors = Shader.PropertyToID("rw_dilated_motion_vectors");
+ internal static readonly int UavDilatedDepth = Shader.PropertyToID("rw_dilatedDepth");
+ internal static readonly int UavInternalUpscaled = Shader.PropertyToID("rw_internal_upscaled_color");
+ internal static readonly int UavLockStatus = Shader.PropertyToID("rw_lock_status");
+ internal static readonly int UavLockInputLuma = Shader.PropertyToID("rw_lock_input_luma");
+ internal static readonly int UavNewLocks = Shader.PropertyToID("rw_new_locks");
+ internal static readonly int UavPreparedInputColor = Shader.PropertyToID("rw_prepared_input_color");
+ internal static readonly int UavLumaHistory = Shader.PropertyToID("rw_luma_history");
+ internal static readonly int UavUpscaledOutput = Shader.PropertyToID("rw_upscaled_output");
+ internal static readonly int UavExposureMipLumaChange = Shader.PropertyToID("rw_img_mip_shading_change");
+ internal static readonly int UavExposureMip5 = Shader.PropertyToID("rw_img_mip_5");
+ internal static readonly int UavDilatedReactiveMasks = Shader.PropertyToID("rw_dilated_reactive_masks");
+ internal static readonly int UavAutoExposure = Shader.PropertyToID("rw_auto_exposure");
+ internal static readonly int UavSpdAtomicCount = Shader.PropertyToID("rw_spd_global_atomic");
+ internal static readonly int UavAutoReactive = Shader.PropertyToID("rw_output_autoreactive");
+ internal static readonly int UavAutoComposition = Shader.PropertyToID("rw_output_autocomposition");
+ internal static readonly int UavPrevColorPreAlpha = Shader.PropertyToID("rw_output_prev_color_pre_alpha");
+ internal static readonly int UavPrevColorPostAlpha = Shader.PropertyToID("rw_output_prev_color_post_alpha");
+
+ // Constant buffer bindings
+ internal static readonly int CbFsr2 = Shader.PropertyToID("cbFSR2");
+ internal static readonly int CbSpd = Shader.PropertyToID("cbSPD");
+ internal static readonly int CbRcas = Shader.PropertyToID("cbRCAS");
+ internal static readonly int CbGenReactive = Shader.PropertyToID("cbGenerateReactive");
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2ShaderIDs.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2ShaderIDs.cs.meta
new file mode 100644
index 0000000..ef83135
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/FSR2/Fsr2ShaderIDs.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: ad1eca9398174f6c85d8bc01d10993df
+timeCreated: 1679060863
\ No newline at end of file
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Monitors.meta b/com.unity.postprocessing/PostProcessing/Runtime/Monitors.meta
new file mode 100644
index 0000000..d288f89
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Monitors.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 0a243807ad889ae44bf63a9bcdc984af
+folderAsset: yes
+timeCreated: 1499676298
+licenseType: Pro
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Monitors/HistogramMonitor.cs b/com.unity.postprocessing/PostProcessing/Runtime/Monitors/HistogramMonitor.cs
new file mode 100644
index 0000000..fef48f9
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Monitors/HistogramMonitor.cs
@@ -0,0 +1,120 @@
+using System;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// This class holds settings for the Histogram monitor.
+ ///
+ [Serializable]
+ public sealed class HistogramMonitor : Monitor
+ {
+ ///
+ /// Displayable channels.
+ ///
+ public enum Channel
+ {
+ ///
+ /// The red channel.
+ ///
+ Red,
+
+ ///
+ /// The green channel.
+ ///
+ Green,
+
+ ///
+ /// The blue channel.
+ ///
+ Blue,
+
+ ///
+ /// The master (luminance) channel.
+ ///
+ Master
+ }
+
+ ///
+ /// The width of the rendered histogram.
+ ///
+ public int width = 512;
+
+ ///
+ /// The height of the rendered histogram.
+ ///
+ public int height = 256;
+
+ ///
+ /// The channel to render.
+ ///
+ public Channel channel = Channel.Master;
+
+ ComputeBuffer m_Data;
+ const int k_NumBins = 256;
+ const int k_ThreadGroupSizeX = 16;
+ const int k_ThreadGroupSizeY = 16;
+
+ internal override void OnDisable()
+ {
+ base.OnDisable();
+
+ if (m_Data != null)
+ m_Data.Release();
+
+ m_Data = null;
+ }
+
+ internal override bool NeedsHalfRes()
+ {
+ return true;
+ }
+
+ internal override bool ShaderResourcesAvailable(PostProcessRenderContext context)
+ {
+ return context.resources.computeShaders.gammaHistogram;
+ }
+
+ internal override void Render(PostProcessRenderContext context)
+ {
+ CheckOutput(width, height);
+
+ if (m_Data == null)
+ m_Data = new ComputeBuffer(k_NumBins, sizeof(uint));
+
+ var compute = context.resources.computeShaders.gammaHistogram;
+ var cmd = context.command;
+ cmd.BeginSample("GammaHistogram");
+
+ // Clear the buffer on every frame as we use it to accumulate values on every frame
+ int kernel = compute.FindKernel("KHistogramClear");
+ cmd.SetComputeBufferParam(compute, kernel, "_HistogramBuffer", m_Data);
+ cmd.DispatchCompute(compute, kernel, Mathf.CeilToInt(k_NumBins / (float)k_ThreadGroupSizeX), 1, 1);
+
+ // Gather all pixels and fill in our histogram
+ kernel = compute.FindKernel("KHistogramGather");
+ var parameters = new Vector4(
+ context.width / 2,
+ context.height / 2,
+ RuntimeUtilities.isLinearColorSpace ? 1 : 0,
+ (int)channel
+ );
+
+ cmd.SetComputeVectorParam(compute, "_Params", parameters);
+ cmd.SetComputeTextureParam(compute, kernel, "_Source", ShaderIDs.HalfResFinalCopy);
+ cmd.SetComputeBufferParam(compute, kernel, "_HistogramBuffer", m_Data);
+ cmd.DispatchCompute(compute, kernel,
+ Mathf.CeilToInt(parameters.x / k_ThreadGroupSizeX),
+ Mathf.CeilToInt(parameters.y / k_ThreadGroupSizeY),
+ 1
+ );
+
+ // Generate the histogram texture
+ var sheet = context.propertySheets.Get(context.resources.shaders.gammaHistogram);
+ sheet.properties.SetVector(ShaderIDs.Params, new Vector4(width, height, 0f, 0f));
+ sheet.properties.SetBuffer(ShaderIDs.HistogramBuffer, m_Data);
+ cmd.BlitFullscreenTriangle(BuiltinRenderTextureType.None, output, sheet, 0);
+
+ cmd.EndSample("GammaHistogram");
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Monitors/HistogramMonitor.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Monitors/HistogramMonitor.cs.meta
new file mode 100644
index 0000000..dd9a92e
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Monitors/HistogramMonitor.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: cce62646e6d421c41b0aa1c300fcd0fe
+timeCreated: 1499676418
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Monitors/LightMeterMonitor.cs b/com.unity.postprocessing/PostProcessing/Runtime/Monitors/LightMeterMonitor.cs
new file mode 100644
index 0000000..b2b43ab
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Monitors/LightMeterMonitor.cs
@@ -0,0 +1,83 @@
+using System;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// This class holds settings for the Light Meter monitor.
+ ///
+ [Serializable]
+ public sealed class LightMeterMonitor : Monitor
+ {
+ ///
+ /// The width of the rendered light meter.
+ ///
+ public int width = 512;
+
+ ///
+ /// The height of the rendered light meter.
+ ///
+ public int height = 256;
+
+ ///
+ /// Should we display grading and tonemapping curves on top?
+ ///
+ ///
+ /// This only works when is active.
+ ///
+ public bool showCurves = true;
+
+ internal override bool ShaderResourcesAvailable(PostProcessRenderContext context)
+ {
+ return context.resources.shaders.lightMeter && context.resources.shaders.lightMeter.isSupported;
+ }
+
+ internal override void Render(PostProcessRenderContext context)
+ {
+ CheckOutput(width, height);
+
+ var histogram = context.logHistogram;
+
+ var sheet = context.propertySheets.Get(context.resources.shaders.lightMeter);
+ sheet.ClearKeywords();
+ sheet.properties.SetBuffer(ShaderIDs.HistogramBuffer, histogram.data);
+
+ var scaleOffsetRes = histogram.GetHistogramScaleOffsetRes(context);
+ scaleOffsetRes.z = 1f / width;
+ scaleOffsetRes.w = 1f / height;
+
+ sheet.properties.SetVector(ShaderIDs.ScaleOffsetRes, scaleOffsetRes);
+
+ if (context.logLut != null && showCurves)
+ {
+ sheet.EnableKeyword("COLOR_GRADING_HDR");
+ sheet.properties.SetTexture(ShaderIDs.Lut3D, context.logLut);
+ }
+
+ var autoExpo = context.autoExposure;
+ if (autoExpo != null)
+ {
+ // Make sure filtering values are correct to avoid apocalyptic consequences
+ float lowPercent = autoExpo.filtering.value.x;
+ float highPercent = autoExpo.filtering.value.y;
+ const float kMinDelta = 1e-2f;
+ highPercent = Mathf.Clamp(highPercent, 1f + kMinDelta, 99f);
+ lowPercent = Mathf.Clamp(lowPercent, 1f, highPercent - kMinDelta);
+
+ var parameters = new Vector4(
+ lowPercent * 0.01f,
+ highPercent * 0.01f,
+ RuntimeUtilities.Exp2(autoExpo.minLuminance.value),
+ RuntimeUtilities.Exp2(autoExpo.maxLuminance.value)
+ );
+
+ sheet.EnableKeyword("AUTO_EXPOSURE");
+ sheet.properties.SetVector(ShaderIDs.Params, parameters);
+ }
+
+ var cmd = context.command;
+ cmd.BeginSample("LightMeter");
+ cmd.BlitFullscreenTriangle(BuiltinRenderTextureType.None, output, sheet, 0);
+ cmd.EndSample("LightMeter");
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Monitors/LightMeterMonitor.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Monitors/LightMeterMonitor.cs.meta
new file mode 100644
index 0000000..96a3a25
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Monitors/LightMeterMonitor.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 322fbe1dae0fe4a4e9645768b3944aae
+timeCreated: 1499676398
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Monitors/Monitor.cs b/com.unity.postprocessing/PostProcessing/Runtime/Monitors/Monitor.cs
new file mode 100644
index 0000000..4cb3ad9
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Monitors/Monitor.cs
@@ -0,0 +1,92 @@
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// Debug monitor types.
+ ///
+ public enum MonitorType
+ {
+ ///
+ /// Light meter.
+ ///
+ LightMeter,
+
+ ///
+ /// Gamma histogram.
+ ///
+ Histogram,
+
+ ///
+ /// Waveform.
+ ///
+ Waveform,
+
+ ///
+ /// YUV vectorscope.
+ ///
+ Vectorscope
+ }
+
+ ///
+ /// The base class for all debug monitors.
+ ///
+ public abstract class Monitor
+ {
+ ///
+ /// The target texture to render this monitor to.
+ ///
+ public RenderTexture output { get; protected set; }
+
+ internal bool requested = false;
+
+ ///
+ /// Checks if a monitor is supported and should be rendered.
+ ///
+ /// The current post-processing context.
+ /// true if supported and enabled, false otherwise.
+ public bool IsRequestedAndSupported(PostProcessRenderContext context)
+ {
+ return requested
+ && SystemInfo.supportsComputeShaders
+ && !RuntimeUtilities.isAndroidOpenGL
+ && ShaderResourcesAvailable(context);
+ }
+
+ internal abstract bool ShaderResourcesAvailable(PostProcessRenderContext context);
+
+ internal virtual bool NeedsHalfRes()
+ {
+ return false;
+ }
+
+ ///
+ /// Validates the output texture.
+ ///
+ /// The output width.
+ /// The output height.
+ protected void CheckOutput(int width, int height)
+ {
+ if (output == null || !output.IsCreated() || output.width != width || output.height != height)
+ {
+ RuntimeUtilities.Destroy(output);
+ output = new RenderTexture(width, height, 0, RenderTextureFormat.ARGB32)
+ {
+ anisoLevel = 0,
+ filterMode = FilterMode.Bilinear,
+ wrapMode = TextureWrapMode.Clamp,
+ useMipMap = false
+ };
+ }
+ }
+
+ internal virtual void OnEnable()
+ {
+ }
+
+ internal virtual void OnDisable()
+ {
+ RuntimeUtilities.Destroy(output);
+ }
+
+ internal abstract void Render(PostProcessRenderContext context);
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Monitors/Monitor.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Monitors/Monitor.cs.meta
new file mode 100644
index 0000000..6313025
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Monitors/Monitor.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 5d05ae29f423ce241b6cddfe46280b4c
+timeCreated: 1499676521
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Monitors/VectorscopeMonitor.cs b/com.unity.postprocessing/PostProcessing/Runtime/Monitors/VectorscopeMonitor.cs
new file mode 100644
index 0000000..70c3129
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Monitors/VectorscopeMonitor.cs
@@ -0,0 +1,99 @@
+using System;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// This class holds settings for the Vectorscope monitor.
+ ///
+ [Serializable]
+ public sealed class VectorscopeMonitor : Monitor
+ {
+ ///
+ /// The width and height of the rendered vectorscope.
+ ///
+ public int size = 256;
+
+ ///
+ /// The exposure multiplier applied to the vectorscope values.
+ ///
+ public float exposure = 0.12f;
+
+ ComputeBuffer m_Data;
+ const int k_ThreadGroupSizeX = 16;
+ const int k_ThreadGroupSizeY = 16;
+
+ internal override void OnDisable()
+ {
+ base.OnDisable();
+
+ if (m_Data != null)
+ m_Data.Release();
+
+ m_Data = null;
+ }
+
+ internal override bool NeedsHalfRes()
+ {
+ return true;
+ }
+
+ internal override bool ShaderResourcesAvailable(PostProcessRenderContext context)
+ {
+ return context.resources.computeShaders.vectorscope;
+ }
+
+ internal override void Render(PostProcessRenderContext context)
+ {
+ CheckOutput(size, size);
+ exposure = Mathf.Max(0f, exposure);
+
+ int count = size * size;
+ if (m_Data == null)
+ m_Data = new ComputeBuffer(count, sizeof(uint));
+ else if (m_Data.count != count)
+ {
+ m_Data.Release();
+ m_Data = new ComputeBuffer(count, sizeof(uint));
+ }
+
+ var compute = context.resources.computeShaders.vectorscope;
+ var cmd = context.command;
+ cmd.BeginSample("Vectorscope");
+
+ var parameters = new Vector4(
+ context.width / 2,
+ context.height / 2,
+ size,
+ RuntimeUtilities.isLinearColorSpace ? 1 : 0
+ );
+
+ // Clear the buffer on every frame as we use it to accumulate values on every frame
+ int kernel = compute.FindKernel("KVectorscopeClear");
+ cmd.SetComputeBufferParam(compute, kernel, "_VectorscopeBuffer", m_Data);
+ cmd.SetComputeVectorParam(compute, "_Params", parameters);
+ cmd.DispatchCompute(compute, kernel,
+ Mathf.CeilToInt(size / (float)k_ThreadGroupSizeX),
+ Mathf.CeilToInt(size / (float)k_ThreadGroupSizeY),
+ 1
+ );
+
+ // Gather all pixels and fill in our histogram
+ kernel = compute.FindKernel("KVectorscopeGather");
+ cmd.SetComputeBufferParam(compute, kernel, "_VectorscopeBuffer", m_Data);
+ cmd.SetComputeTextureParam(compute, kernel, "_Source", ShaderIDs.HalfResFinalCopy);
+ cmd.DispatchCompute(compute, kernel,
+ Mathf.CeilToInt(parameters.x / k_ThreadGroupSizeX),
+ Mathf.CeilToInt(parameters.y / k_ThreadGroupSizeY),
+ 1
+ );
+
+ // Generate the histogram texture
+ var sheet = context.propertySheets.Get(context.resources.shaders.vectorscope);
+ sheet.properties.SetVector(ShaderIDs.Params, new Vector4(size, size, exposure, 0f));
+ sheet.properties.SetBuffer(ShaderIDs.VectorscopeBuffer, m_Data);
+ cmd.BlitFullscreenTriangle(BuiltinRenderTextureType.None, output, sheet, 0);
+
+ cmd.EndSample("Vectorscope");
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Monitors/VectorscopeMonitor.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Monitors/VectorscopeMonitor.cs.meta
new file mode 100644
index 0000000..5b15b30
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Monitors/VectorscopeMonitor.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 279b45d82a92b4d4fa0b30d03486fa68
+timeCreated: 1499676436
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Monitors/WaveformMonitor.cs b/com.unity.postprocessing/PostProcessing/Runtime/Monitors/WaveformMonitor.cs
new file mode 100644
index 0000000..7917ae1
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Monitors/WaveformMonitor.cs
@@ -0,0 +1,111 @@
+using System;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// This class holds settings for the Waveform monitor.
+ ///
+ [Serializable]
+ public sealed class WaveformMonitor : Monitor
+ {
+ ///
+ /// The exposure multiplier applied to the waveform values.
+ ///
+ public float exposure = 0.12f;
+
+ ///
+ /// The height of the rendered waveform.
+ ///
+ ///
+ /// Waveforms display localized values so the width is dynamic and depends on the current
+ /// aspect ratio.
+ ///
+ public int height = 256;
+
+ ComputeBuffer m_Data;
+
+ const int k_ThreadGroupSize = 256;
+ const int k_ThreadGroupSizeX = 16;
+ const int k_ThreadGroupSizeY = 16;
+
+ internal override void OnDisable()
+ {
+ base.OnDisable();
+
+ if (m_Data != null)
+ m_Data.Release();
+
+ m_Data = null;
+ }
+
+ internal override bool NeedsHalfRes()
+ {
+ return true;
+ }
+
+ internal override bool ShaderResourcesAvailable(PostProcessRenderContext context)
+ {
+ return context.resources.computeShaders.waveform;
+ }
+
+ internal override void Render(PostProcessRenderContext context)
+ {
+ // Waveform show localized data, so width depends on the aspect ratio
+ float ratio = (context.width / 2f) / (context.height / 2f);
+ int width = Mathf.FloorToInt(height * ratio);
+
+ CheckOutput(width, height);
+ exposure = Mathf.Max(0f, exposure);
+
+ int count = width * height;
+ if (m_Data == null)
+ {
+ m_Data = new ComputeBuffer(count, sizeof(uint) << 2);
+ }
+ else if (m_Data.count < count)
+ {
+ m_Data.Release();
+ m_Data = new ComputeBuffer(count, sizeof(uint) << 2);
+ }
+
+ var compute = context.resources.computeShaders.waveform;
+ var cmd = context.command;
+ cmd.BeginSample("Waveform");
+
+ var parameters = new Vector4(
+ width,
+ height,
+ RuntimeUtilities.isLinearColorSpace ? 1 : 0,
+ 0f
+ );
+
+ // Clear the buffer on every frame
+ int kernel = compute.FindKernel("KWaveformClear");
+ cmd.SetComputeBufferParam(compute, kernel, "_WaveformBuffer", m_Data);
+ cmd.SetComputeVectorParam(compute, "_Params", parameters);
+ cmd.DispatchCompute(compute, kernel, Mathf.CeilToInt(width / (float)k_ThreadGroupSizeX), Mathf.CeilToInt(height / (float)k_ThreadGroupSizeY), 1);
+
+ // For performance reasons, especially on consoles, we'll just downscale the source
+ // again to reduce VMEM stalls. Eventually the whole algorithm needs to be rewritten as
+ // it's currently pretty naive.
+ cmd.GetTemporaryRT(ShaderIDs.WaveformSource, width, height, 0, FilterMode.Bilinear, context.sourceFormat);
+ cmd.BlitFullscreenTriangle(ShaderIDs.HalfResFinalCopy, ShaderIDs.WaveformSource);
+
+ // Gather all pixels and fill in our waveform
+ kernel = compute.FindKernel("KWaveformGather");
+ cmd.SetComputeBufferParam(compute, kernel, "_WaveformBuffer", m_Data);
+ cmd.SetComputeTextureParam(compute, kernel, "_Source", ShaderIDs.WaveformSource);
+ cmd.SetComputeVectorParam(compute, "_Params", parameters);
+ cmd.DispatchCompute(compute, kernel, width, Mathf.CeilToInt(height / (float)k_ThreadGroupSize), 1);
+ cmd.ReleaseTemporaryRT(ShaderIDs.WaveformSource);
+
+ // Generate the waveform texture
+ var sheet = context.propertySheets.Get(context.resources.shaders.waveform);
+ sheet.properties.SetVector(ShaderIDs.Params, new Vector4(width, height, exposure, 0f));
+ sheet.properties.SetBuffer(ShaderIDs.WaveformBuffer, m_Data);
+ cmd.BlitFullscreenTriangle(BuiltinRenderTextureType.None, output, sheet, 0);
+
+ cmd.EndSample("Waveform");
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Monitors/WaveformMonitor.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Monitors/WaveformMonitor.cs.meta
new file mode 100644
index 0000000..a5f61be
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Monitors/WaveformMonitor.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: d579562c49280d84cb532cd67d19da5d
+timeCreated: 1499676423
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/ParameterOverride.cs b/com.unity.postprocessing/PostProcessing/Runtime/ParameterOverride.cs
new file mode 100644
index 0000000..6a3558a
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/ParameterOverride.cs
@@ -0,0 +1,633 @@
+using System;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// The base abstract class for all parameter override types.
+ ///
+ ///
+ public abstract class ParameterOverride
+ {
+ ///
+ /// The override state of this parameter.
+ ///
+ public bool overrideState;
+
+ internal abstract void Interp(ParameterOverride from, ParameterOverride to, float t);
+
+ ///
+ /// Returns the computed hash code for this parameter.
+ ///
+ /// A computed hash code
+ public abstract int GetHash();
+
+ ///
+ /// Casts and returns the value stored in this parameter.
+ ///
+ /// The type to cast to
+ /// The value stored in this parameter
+ public T GetValue()
+ {
+ return ((ParameterOverride)this).value;
+ }
+
+ ///
+ /// This method is called right after the parent has
+ /// been initialized. This is used in case you need to access fields or properties that
+ /// can't be accessed in the constructor of a
+ /// (ParameterOverride objects are generally declared and initialized in a
+ /// ).
+ ///
+ ///
+ protected internal virtual void OnEnable()
+ {
+ }
+
+ ///
+ /// This method is called right before the parent
+ /// gets de-initialized.
+ ///
+ ///
+ protected internal virtual void OnDisable()
+ {
+ }
+
+ internal abstract void SetValue(ParameterOverride parameter);
+ }
+
+ ///
+ /// The base typed class for all parameter override types.
+ ///
+ /// The type of value to store in this ParameterOverride
+ ///
+ /// Due to limitations with the serialization system in Unity you shouldn't use this class
+ /// directly. Use one of the pre-flatten types (like or make your
+ /// own by extending this class.
+ ///
+ ///
+ /// This sample code shows how to make a custom parameter holding a float.
+ ///
+ /// [Serializable]
+ /// public sealed class FloatParameter : ParameterOverride<float>
+ /// {
+ /// public override void Interp(float from, float to, float t)
+ /// {
+ /// value = from + (to - from) * t;
+ /// }
+ /// }
+ ///
+ ///
+ [Serializable]
+ public class ParameterOverride : ParameterOverride
+ {
+ ///
+ /// The value stored in this parameter.
+ ///
+ public T value;
+
+ ///
+ /// Creates a ParameterOverride with a default and
+ /// set to false.
+ ///
+ public ParameterOverride()
+ : this(default(T), false)
+ {
+ }
+
+ ///
+ /// Creates a ParameterOverride with a given value and
+ /// set to false.
+ ///
+ /// The value to set this parameter to
+ public ParameterOverride(T value)
+ : this(value, false)
+ {
+ }
+
+ ///
+ /// Creates a ParameterOverride with a given value and override state.
+ ///
+ /// The value to set this parameter to
+ /// The override state for this value
+ public ParameterOverride(T value, bool overrideState)
+ {
+ this.value = value;
+ this.overrideState = overrideState;
+ }
+
+ internal override void Interp(ParameterOverride from, ParameterOverride to, float t)
+ {
+ // Note: this isn't completely safe but it'll do fine
+ Interp(from.GetValue(), to.GetValue(), t);
+ }
+
+ ///
+ /// Interpolates between two values given an interpolation factor .
+ ///
+ /// The value to interpolate from
+ /// The value to interpolate to
+ /// An interpolation factor (generally in range [0,1])
+ ///
+ /// By default this method does a "snap" interpolation, meaning it will return the value
+ /// if is higher than 0,
+ /// otherwise.
+ ///
+ public virtual void Interp(T from, T to, float t)
+ {
+ // Returns `to` if `dt > 0` by default so we don't have to write overrides for bools and
+ // enumerations.
+ value = t > 0f ? to : from;
+ }
+
+ ///
+ /// Sets the value for this parameter to and mark the override state
+ /// to true.
+ ///
+ ///
+ public void Override(T x)
+ {
+ overrideState = true;
+ value = x;
+ }
+
+ internal override void SetValue(ParameterOverride parameter)
+ {
+ value = parameter.GetValue();
+ }
+
+ ///
+ /// Returns the computed hash code for this parameter.
+ ///
+ /// A computed hash code
+ public override int GetHash()
+ {
+ unchecked
+ {
+ int hash = 17;
+ hash = hash * 23 + overrideState.GetHashCode();
+ hash = hash * 23 + value.GetHashCode();
+ return hash;
+ }
+ }
+
+ ///
+ /// Implicit conversion between and its value type.
+ ///
+ /// The parameter to implicitly cast
+ /// A value of type .
+ public static implicit operator T(ParameterOverride prop)
+ {
+ return prop.value;
+ }
+ }
+
+ // Bypassing the limited unity serialization system...
+
+ ///
+ /// A that holds a float value.
+ ///
+ ///
+ /// The interpolation method for this parameter is the same as .
+ ///
+ [Serializable]
+ public sealed class FloatParameter : ParameterOverride
+ {
+ ///
+ /// Interpolates between two values given an interpolation factor .
+ ///
+ /// The value to interpolate from
+ /// The value to interpolate to
+ /// An interpolation factor (generally in range [0,1])
+ ///
+ /// By default this method does a "snap" interpolation, meaning it will return the value
+ /// if is higher than 0,
+ /// otherwise.
+ ///
+ public override void Interp(float from, float to, float t)
+ {
+ value = from + (to - from) * t;
+ }
+ }
+
+ ///
+ /// A that holds a int value.
+ ///
+ ///
+ /// The interpolation method for this parameter is the same as
+ /// casted to int.
+ ///
+ [Serializable]
+ public sealed class IntParameter : ParameterOverride
+ {
+ ///
+ /// Interpolates between two values given an interpolation factor .
+ ///
+ /// The value to interpolate from
+ /// The value to interpolate to
+ /// An interpolation factor (generally in range [0,1])
+ ///
+ /// By default this method does a "snap" interpolation, meaning it will return the value
+ /// if is higher than 0,
+ /// otherwise.
+ ///
+ public override void Interp(int from, int to, float t)
+ {
+ // Int snapping interpolation. Don't use this for enums as they don't necessarily have
+ // contiguous values. Use the default interpolator instead (same as bool).
+ value = (int)(from + (to - from) * t);
+ }
+ }
+
+ ///
+ /// A that holds a bool value.
+ ///
+ [Serializable]
+ public sealed class BoolParameter : ParameterOverride { }
+
+ ///
+ /// A that holds a value.
+ ///
+ ///
+ /// The interpolation method for this parameter is the same as
+ /// for each channel.
+ ///
+ [Serializable]
+ public sealed class ColorParameter : ParameterOverride
+ {
+ ///
+ /// Interpolates between two values given an interpolation factor .
+ ///
+ /// The value to interpolate from
+ /// The value to interpolate to
+ /// An interpolation factor (generally in range [0,1])
+ ///
+ /// By default this method does a "snap" interpolation, meaning it will return the value
+ /// if is higher than 0,
+ /// otherwise.
+ ///
+ public override void Interp(Color from, Color to, float t)
+ {
+ // Lerping color values is a sensitive subject... We looked into lerping colors using
+ // HSV and LCH but they have some downsides that make them not work correctly in all
+ // situations, so we stick with RGB lerping for now, at least its behavior is
+ // predictable despite looking desaturated when `t ~= 0.5` and it's faster anyway.
+ value.r = from.r + (to.r - from.r) * t;
+ value.g = from.g + (to.g - from.g) * t;
+ value.b = from.b + (to.b - from.b) * t;
+ value.a = from.a + (to.a - from.a) * t;
+ }
+
+ ///
+ /// Implicit conversion between and a .
+ ///
+ /// The parameter to implicitly cast
+ /// A Vector4.
+ public static implicit operator Vector4(ColorParameter prop)
+ {
+ return prop.value;
+ }
+ }
+
+ ///
+ /// A that holds a value.
+ ///
+ ///
+ /// The interpolation method for this parameter is the same as
+ /// for each axis.
+ ///
+ [Serializable]
+ public sealed class Vector2Parameter : ParameterOverride
+ {
+ ///
+ /// Interpolates between two values given an interpolation factor .
+ ///
+ /// The value to interpolate from
+ /// The value to interpolate to
+ /// An interpolation factor (generally in range [0,1])
+ ///
+ /// By default this method does a "snap" interpolation, meaning it will return the value
+ /// if is higher than 0,
+ /// otherwise.
+ ///
+ public override void Interp(Vector2 from, Vector2 to, float t)
+ {
+ value.x = from.x + (to.x - from.x) * t;
+ value.y = from.y + (to.y - from.y) * t;
+ }
+
+ ///
+ /// Implicit conversion between and a .
+ ///
+ /// The parameter to implicitly cast
+ /// A Vector3.
+ public static implicit operator Vector3(Vector2Parameter prop)
+ {
+ return prop.value;
+ }
+
+ ///
+ /// Implicit conversion between and a .
+ ///
+ /// The parameter to implicitly cast
+ /// A Vector4.
+ public static implicit operator Vector4(Vector2Parameter prop)
+ {
+ return prop.value;
+ }
+ }
+
+ ///
+ /// A that holds a value.
+ ///
+ ///
+ /// The interpolation method for this parameter is the same as
+ /// for each axis.
+ ///
+ [Serializable]
+ public sealed class Vector3Parameter : ParameterOverride
+ {
+ ///
+ /// Interpolates between two values given an interpolation factor .
+ ///
+ /// The value to interpolate from
+ /// The value to interpolate to
+ /// An interpolation factor (generally in range [0,1])
+ ///
+ /// By default this method does a "snap" interpolation, meaning it will return the value
+ /// if is higher than 0,
+ /// otherwise.
+ ///
+ public override void Interp(Vector3 from, Vector3 to, float t)
+ {
+ value.x = from.x + (to.x - from.x) * t;
+ value.y = from.y + (to.y - from.y) * t;
+ value.z = from.z + (to.z - from.z) * t;
+ }
+
+ ///
+ /// Implicit conversion between and a .
+ ///
+ /// The parameter to implicitly cast
+ /// A Vector2.
+ public static implicit operator Vector2(Vector3Parameter prop)
+ {
+ return prop.value;
+ }
+
+ ///
+ /// Implicit conversion between and a .
+ ///
+ /// The parameter to implicitly cast
+ /// A Vector4.
+ public static implicit operator Vector4(Vector3Parameter prop)
+ {
+ return prop.value;
+ }
+ }
+
+ ///
+ /// A that holds a value.
+ ///
+ ///
+ /// The interpolation method for this parameter is the same as
+ /// for each axis.
+ ///
+ [Serializable]
+ public sealed class Vector4Parameter : ParameterOverride
+ {
+ ///
+ /// Interpolates between two values given an interpolation factor .
+ ///
+ /// The value to interpolate from
+ /// The value to interpolate to
+ /// An interpolation factor (generally in range [0,1])
+ ///
+ /// By default this method does a "snap" interpolation, meaning it will return the value
+ /// if is higher than 0,
+ /// otherwise.
+ ///
+ public override void Interp(Vector4 from, Vector4 to, float t)
+ {
+ value.x = from.x + (to.x - from.x) * t;
+ value.y = from.y + (to.y - from.y) * t;
+ value.z = from.z + (to.z - from.z) * t;
+ value.w = from.w + (to.w - from.w) * t;
+ }
+
+ ///
+ /// Implicit conversion between and a .
+ ///
+ /// The parameter to implicitly cast
+ /// A Vector2.
+ public static implicit operator Vector2(Vector4Parameter prop)
+ {
+ return prop.value;
+ }
+
+ ///
+ /// Implicit conversion between and a .
+ ///
+ /// The parameter to implicitly cast
+ /// A Vector3.
+ public static implicit operator Vector3(Vector4Parameter prop)
+ {
+ return prop.value;
+ }
+ }
+
+ ///
+ /// A that holds a value.
+ ///
+ ///
+ /// The interpolation method for this parameter is the same as
+ /// for each point on the curve.
+ ///
+ [Serializable]
+ public sealed class SplineParameter : ParameterOverride
+ {
+ ///
+ /// This method is called right after the parent has
+ /// been initialized. This is used in case you need to access fields or properties that
+ /// can't be accessed in the constructor of a
+ /// (ParameterOverride objects are generally declared and initialized in a
+ /// ).
+ ///
+ ///
+ protected internal override void OnEnable()
+ {
+ if (value != null)
+ value.Cache(int.MinValue);
+ }
+
+ internal override void SetValue(ParameterOverride parameter)
+ {
+ base.SetValue(parameter);
+
+ if (value != null)
+ value.Cache(Time.renderedFrameCount);
+ }
+
+ ///
+ /// Interpolates between two values given an interpolation factor .
+ ///
+ /// The value to interpolate from
+ /// The value to interpolate to
+ /// An interpolation factor (generally in range [0,1])
+ ///
+ /// By default this method does a "snap" interpolation, meaning it will return the value
+ /// if is higher than 0,
+ /// otherwise.
+ ///
+ public override void Interp(Spline from, Spline to, float t)
+ {
+ if (from == null || to == null)
+ {
+ base.Interp(from, to, t);
+ return;
+ }
+
+ int frameCount = Time.renderedFrameCount;
+ from.Cache(frameCount);
+ to.Cache(frameCount);
+
+ for (int i = 0; i < Spline.k_Precision; i++)
+ {
+ float a = from.cachedData[i];
+ float b = to.cachedData[i];
+ value.cachedData[i] = a + (b - a) * t;
+ }
+ }
+ }
+
+ ///
+ /// A set of default textures to use as default values for .
+ ///
+ public enum TextureParameterDefault
+ {
+ ///
+ /// No texture, or null.
+ ///
+ None,
+
+ ///
+ /// A black texture.
+ ///
+ Black,
+
+ ///
+ /// A white texture.
+ ///
+ White,
+
+ ///
+ /// A transparent texture.
+ ///
+ Transparent,
+
+ ///
+ /// A 2D lookup table in strip format with width = height * height.
+ ///
+ Lut2D
+ }
+
+ ///
+ /// A that holds a value.
+ ///
+ ///
+ /// Texture interpolation is done using a classic linear interpolation method.
+ ///
+ [Serializable]
+ public sealed class TextureParameter : ParameterOverride
+ {
+ /// The default state & type for the texture.
+ public TextureParameterDefault defaultState = TextureParameterDefault.Black;
+
+ ///
+ /// Interpolates between two values given an interpolation factor .
+ ///
+ /// The value to interpolate from
+ /// The value to interpolate to
+ /// An interpolation factor (generally in range [0,1])
+ ///
+ /// By default this method does a "snap" interpolation, meaning it will return the value
+ /// if is higher than 0,
+ /// otherwise.
+ ///
+ public override void Interp(Texture from, Texture to, float t)
+ {
+ // Both are null, do nothing
+ if (from == null && to == null)
+ {
+ value = null;
+ return;
+ }
+
+ // Both aren't null we're ready to blend
+ if (from != null && to != null)
+ {
+ value = TextureLerper.instance.Lerp(from, to, t);
+ return;
+ }
+
+ // One of them is null, blend to/from a default value is applicable
+ {
+ if (defaultState == TextureParameterDefault.Lut2D)
+ {
+ int size = from != null ? from.height : to.height;
+ Texture defaultTexture = RuntimeUtilities.GetLutStrip(size);
+
+ if (from == null) from = defaultTexture;
+ if (to == null) to = defaultTexture;
+ }
+
+ Color tgtColor;
+
+ switch (defaultState)
+ {
+ case TextureParameterDefault.Black:
+ tgtColor = Color.black;
+ break;
+ case TextureParameterDefault.White:
+ tgtColor = Color.white;
+ break;
+ case TextureParameterDefault.Transparent:
+ tgtColor = Color.clear;
+ break;
+ case TextureParameterDefault.Lut2D:
+ {
+ // Find the current lut size
+ int size = from != null ? from.height : to.height;
+ Texture defaultTexture = RuntimeUtilities.GetLutStrip(size);
+ if (from == null) from = defaultTexture;
+ if (to == null) to = defaultTexture;
+
+ // Fail safe in case the lut size is incorrect
+ if (from.width != to.width || from.height != to.height)
+ {
+ value = null;
+ return;
+ }
+
+ value = TextureLerper.instance.Lerp(from, to, t);
+ // All done, return
+ return;
+ }
+ default:
+ // defaultState is none, so just interpolate the base and return
+ base.Interp(from, to, t);
+ return;
+ }
+ // If we made it this far, tgtColor contains the color we'll be lerping into (or out of)
+ if (from == null)
+ {
+ // color -> texture lerp, invert ratio
+ value = TextureLerper.instance.Lerp(to, tgtColor, 1f - t);
+ }
+ else
+ {
+ value = TextureLerper.instance.Lerp(from, tgtColor, t);
+ }
+ }
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/ParameterOverride.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/ParameterOverride.cs.meta
new file mode 100644
index 0000000..00e09d6
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/ParameterOverride.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: bc5d8aaf03e613843a0ecaff18e0dfbd
+timeCreated: 1487257630
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/PostProcessBundle.cs b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessBundle.cs
new file mode 100644
index 0000000..c06b991
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessBundle.cs
@@ -0,0 +1,77 @@
+using System;
+using UnityEngine.Assertions;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// A tuple-like class that holds reference to an effect settings and its associated attribute
+ /// and renderer.
+ ///
+ public sealed class PostProcessBundle
+ {
+ ///
+ /// The attribute set on the effect.
+ ///
+ public PostProcessAttribute attribute { get; private set; }
+
+ ///
+ /// The settings for the effect.
+ ///
+ public PostProcessEffectSettings settings { get; private set; }
+
+ internal PostProcessEffectRenderer renderer
+ {
+ get
+ {
+ if (m_Renderer == null)
+ {
+ Assert.IsNotNull(attribute.renderer);
+ var rendererType = attribute.renderer;
+ m_Renderer = (PostProcessEffectRenderer)Activator.CreateInstance(rendererType);
+ m_Renderer.SetSettings(settings);
+ m_Renderer.Init();
+ }
+
+ return m_Renderer;
+ }
+ }
+
+ PostProcessEffectRenderer m_Renderer;
+
+ internal PostProcessBundle(PostProcessEffectSettings settings)
+ {
+ // If settings is null, it means that at some point a null element has been added to
+ // the volume effect list or there was a deserialization error and a reference to
+ // the settings scriptableobject was lost
+ Assert.IsNotNull(settings);
+ this.settings = settings;
+ attribute = settings.GetType().GetAttribute();
+ }
+
+ internal void Release()
+ {
+ if (m_Renderer != null)
+ m_Renderer.Release();
+
+ RuntimeUtilities.Destroy(settings);
+ }
+
+ internal void ResetHistory()
+ {
+ if (m_Renderer != null)
+ m_Renderer.ResetHistory();
+ }
+
+ internal T CastSettings()
+ where T : PostProcessEffectSettings
+ {
+ return (T)settings;
+ }
+
+ internal T CastRenderer()
+ where T : PostProcessEffectRenderer
+ {
+ return (T)renderer;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/PostProcessBundle.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessBundle.cs.meta
new file mode 100644
index 0000000..b22a4a6
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessBundle.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 79092fbfc2fc7394aa0754682e3089f7
+timeCreated: 1493281307
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/PostProcessDebug.cs b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessDebug.cs
new file mode 100644
index 0000000..c63f333
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessDebug.cs
@@ -0,0 +1,160 @@
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// This component holds a set of debugging utilities related to post-processing.
+ ///
+ ///
+ /// These utilities can be used at runtime to debug on device.
+ ///
+#if UNITY_2018_3_OR_NEWER
+ [ExecuteAlways]
+#else
+ [ExecuteInEditMode]
+#endif
+ [AddComponentMenu("Rendering/Post-process Debug", 1002)]
+ public sealed class PostProcessDebug : MonoBehaviour
+ {
+ ///
+ /// A reference to a to debug.
+ ///
+ public PostProcessLayer postProcessLayer;
+ PostProcessLayer m_PreviousPostProcessLayer;
+
+ ///
+ /// Holds settings for the light meter.
+ ///
+ public bool lightMeter;
+
+ ///
+ /// Holds settings for the histogram.
+ ///
+ public bool histogram;
+
+ ///
+ /// Holds settings for the waveform.
+ ///
+ public bool waveform;
+
+ ///
+ /// Holds settings for the vectorscope.
+ ///
+ public bool vectorscope;
+
+ ///
+ /// The currently set overlay.
+ ///
+ public DebugOverlay debugOverlay = DebugOverlay.None;
+
+ Camera m_CurrentCamera;
+ CommandBuffer m_CmdAfterEverything;
+
+ void OnEnable()
+ {
+ m_CmdAfterEverything = new CommandBuffer { name = "Post-processing Debug Overlay" };
+
+#if UNITY_EDITOR
+ // Update is only called on object change when ExecuteInEditMode is set, but we need it
+ // to execute on every frame no matter what when not in play mode, so we'll use the
+ // editor update loop instead...
+ UnityEditor.EditorApplication.update += UpdateStates;
+#endif
+ }
+
+ void OnDisable()
+ {
+#if UNITY_EDITOR
+ UnityEditor.EditorApplication.update -= UpdateStates;
+#endif
+
+ if (m_CurrentCamera != null)
+ m_CurrentCamera.RemoveCommandBuffer(CameraEvent.AfterImageEffects, m_CmdAfterEverything);
+
+ m_CurrentCamera = null;
+ m_PreviousPostProcessLayer = null;
+ }
+
+#if !UNITY_EDITOR
+ void Update()
+ {
+ UpdateStates();
+ }
+
+#endif
+
+ void Reset()
+ {
+ postProcessLayer = GetComponent();
+ }
+
+ void UpdateStates()
+ {
+ if (m_PreviousPostProcessLayer != postProcessLayer)
+ {
+ // Remove cmdbuffer from previously set camera
+ if (m_CurrentCamera != null)
+ {
+ m_CurrentCamera.RemoveCommandBuffer(CameraEvent.AfterImageEffects, m_CmdAfterEverything);
+ m_CurrentCamera = null;
+ }
+
+ m_PreviousPostProcessLayer = postProcessLayer;
+
+ // Add cmdbuffer to the currently set camera
+ if (postProcessLayer != null)
+ {
+ m_CurrentCamera = postProcessLayer.GetComponent();
+ m_CurrentCamera.AddCommandBuffer(CameraEvent.AfterImageEffects, m_CmdAfterEverything);
+ }
+ }
+
+ if (postProcessLayer == null || !postProcessLayer.enabled)
+ return;
+
+ // Monitors
+ if (lightMeter) postProcessLayer.debugLayer.RequestMonitorPass(MonitorType.LightMeter);
+ if (histogram) postProcessLayer.debugLayer.RequestMonitorPass(MonitorType.Histogram);
+ if (waveform) postProcessLayer.debugLayer.RequestMonitorPass(MonitorType.Waveform);
+ if (vectorscope) postProcessLayer.debugLayer.RequestMonitorPass(MonitorType.Vectorscope);
+
+ // Overlay
+ postProcessLayer.debugLayer.RequestDebugOverlay(debugOverlay);
+ }
+
+ void OnPostRender()
+ {
+ m_CmdAfterEverything.Clear();
+
+ if (postProcessLayer == null || !postProcessLayer.enabled || !postProcessLayer.debugLayer.debugOverlayActive)
+ return;
+
+ m_CmdAfterEverything.Blit(postProcessLayer.debugLayer.debugOverlayTarget, BuiltinRenderTextureType.CameraTarget);
+ }
+
+ void OnGUI()
+ {
+ if (postProcessLayer == null || !postProcessLayer.enabled)
+ return;
+
+ // Some SRPs don't unbind render targets and leave them as-is
+ RenderTexture.active = null;
+
+ var rect = new Rect(5, 5, 0, 0);
+ var debugLayer = postProcessLayer.debugLayer;
+ DrawMonitor(ref rect, debugLayer.lightMeter, lightMeter);
+ DrawMonitor(ref rect, debugLayer.histogram, histogram);
+ DrawMonitor(ref rect, debugLayer.waveform, waveform);
+ DrawMonitor(ref rect, debugLayer.vectorscope, vectorscope);
+ }
+
+ void DrawMonitor(ref Rect rect, Monitor monitor, bool enabled)
+ {
+ if (!enabled || monitor.output == null)
+ return;
+
+ rect.width = monitor.output.width;
+ rect.height = monitor.output.height;
+ GUI.DrawTexture(rect, monitor.output);
+ rect.x += monitor.output.width + 5f;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/PostProcessDebug.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessDebug.cs.meta
new file mode 100644
index 0000000..83ea241
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessDebug.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: c520d478f3d2445429bd7ac9c92b03a3
+timeCreated: 1499764102
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {fileID: 2800000, guid: 5f51e0b22aa8cb84b9f422576ce87ff9, type: 3}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/PostProcessDebugLayer.cs b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessDebugLayer.cs
new file mode 100644
index 0000000..6264dd9
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessDebugLayer.cs
@@ -0,0 +1,368 @@
+using System;
+using System.Collections.Generic;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// A list of debug overlays.
+ ///
+ public enum DebugOverlay
+ {
+ ///
+ /// No overlay.
+ ///
+ None,
+
+ ///
+ /// Displays the depth buffer.
+ ///
+ Depth,
+
+ ///
+ /// Displays the screen-space normals buffer.
+ ///
+ Normals,
+
+ ///
+ /// Displays the screen-space motion vectors.
+ ///
+ MotionVectors,
+
+ ///
+ /// Dims the screen and displays NaN and Inf pixels with a bright pink color.
+ ///
+ NANTracker,
+
+ ///
+ /// A color blindness simulator.
+ ///
+ ColorBlindnessSimulation,
+
+ ///
+ /// A menu item separator for the inspector. Do not use.
+ ///
+ _,
+
+ ///
+ /// Displays the raw ambient occlusion map.
+ ///
+ AmbientOcclusion,
+
+ ///
+ /// Displays the bloom buffer.
+ ///
+ BloomBuffer,
+
+ ///
+ /// Displays the thresholded buffer used to generate bloom.
+ ///
+ BloomThreshold,
+
+ ///
+ /// Displays depth of field helpers.
+ ///
+ DepthOfField
+ }
+
+ ///
+ /// A list of color blindness types.
+ ///
+ public enum ColorBlindnessType
+ {
+ ///
+ /// Deuteranopia (red-green color blindness).
+ ///
+ Deuteranopia,
+
+ ///
+ /// Protanopia (red-green color blindness).
+ ///
+ Protanopia,
+
+ ///
+ /// Tritanopia (blue-yellow color blindness).
+ ///
+ Tritanopia
+ }
+
+ ///
+ /// This class centralizes rendering commands for debug modes.
+ ///
+ [Serializable]
+ public sealed class PostProcessDebugLayer
+ {
+ ///
+ /// Light meter renderer.
+ ///
+ public LightMeterMonitor lightMeter;
+
+ ///
+ /// Histogram renderer.
+ ///
+ public HistogramMonitor histogram;
+
+ ///
+ /// Waveform renderer.
+ ///
+ public WaveformMonitor waveform;
+
+ ///
+ /// Vectorscope monitor.
+ ///
+ public VectorscopeMonitor vectorscope;
+
+ Dictionary m_Monitors;
+
+ // Current frame size
+ int frameWidth;
+ int frameHeight;
+
+ ///
+ /// The render target used to render debug overlays in.
+ ///
+ public RenderTexture debugOverlayTarget { get; private set; }
+
+ ///
+ /// Returns true if the frame that was just drawn had an active debug overlay.
+ ///
+ public bool debugOverlayActive { get; private set; }
+
+ ///
+ /// The debug overlay requested for the current frame. It is reset to None once the
+ /// frame has finished rendering.
+ ///
+ public DebugOverlay debugOverlay { get; private set; }
+
+ ///
+ /// Debug overlay settings wrapper.
+ ///
+ [Serializable]
+ public class OverlaySettings
+ {
+ ///
+ /// Should we remap depth to a linear range?
+ ///
+ public bool linearDepth = false;
+
+ ///
+ /// The intensity of motion vector colors.
+ ///
+ [Range(0f, 16f)]
+ public float motionColorIntensity = 4f;
+
+ ///
+ /// The size of the motion vector grid.
+ ///
+ [Range(4, 128)]
+ public int motionGridSize = 64;
+
+ ///
+ /// The color blindness type to simulate.
+ ///
+ public ColorBlindnessType colorBlindnessType = ColorBlindnessType.Deuteranopia;
+
+ ///
+ /// The strength of the selected color blindness type.
+ ///
+ [Range(0f, 1f)]
+ public float colorBlindnessStrength = 1f;
+ }
+
+ ///
+ /// Debug overlay settings.
+ ///
+ public OverlaySettings overlaySettings;
+
+ internal void OnEnable()
+ {
+ RuntimeUtilities.CreateIfNull(ref lightMeter);
+ RuntimeUtilities.CreateIfNull(ref histogram);
+ RuntimeUtilities.CreateIfNull(ref waveform);
+ RuntimeUtilities.CreateIfNull(ref vectorscope);
+ RuntimeUtilities.CreateIfNull(ref overlaySettings);
+
+ m_Monitors = new Dictionary
+ {
+ { MonitorType.LightMeter, lightMeter },
+ { MonitorType.Histogram, histogram },
+ { MonitorType.Waveform, waveform },
+ { MonitorType.Vectorscope, vectorscope }
+ };
+
+ foreach (var kvp in m_Monitors)
+ kvp.Value.OnEnable();
+ }
+
+ internal void OnDisable()
+ {
+ foreach (var kvp in m_Monitors)
+ kvp.Value.OnDisable();
+
+ DestroyDebugOverlayTarget();
+ }
+
+ void DestroyDebugOverlayTarget()
+ {
+ RuntimeUtilities.Destroy(debugOverlayTarget);
+ debugOverlayTarget = null;
+ }
+
+ ///
+ /// Requests the drawing of a monitor for the current frame.
+ ///
+ /// The monitor to request
+ public void RequestMonitorPass(MonitorType monitor)
+ {
+ m_Monitors[monitor].requested = true;
+ }
+
+ ///
+ /// Requests the drawing of a debug overlay for the current frame.
+ ///
+ /// The debug overlay to request
+ public void RequestDebugOverlay(DebugOverlay mode)
+ {
+ debugOverlay = mode;
+ }
+
+ // Sets the current frame size - used to make sure the debug overlay target is always the
+ // correct size - mostly useful in the editor as the user can easily resize the gameview.
+ internal void SetFrameSize(int width, int height)
+ {
+ frameWidth = width;
+ frameHeight = height;
+ debugOverlayActive = false;
+ }
+
+ ///
+ /// Blit a source render target to the debug overlay target.
+ ///
+ /// The command buffer to send render commands to
+ /// The source target
+ /// The property sheet to use for the blit
+ /// The pass to use for the property sheet
+ public void PushDebugOverlay(CommandBuffer cmd, RenderTargetIdentifier source, PropertySheet sheet, int pass)
+ {
+ if (debugOverlayTarget == null || !debugOverlayTarget.IsCreated() || debugOverlayTarget.width != frameWidth || debugOverlayTarget.height != frameHeight)
+ {
+ RuntimeUtilities.Destroy(debugOverlayTarget);
+
+ debugOverlayTarget = new RenderTexture(frameWidth, frameHeight, 0, RenderTextureFormat.ARGB32)
+ {
+ name = "Debug Overlay Target",
+ anisoLevel = 1,
+ filterMode = FilterMode.Bilinear,
+ wrapMode = TextureWrapMode.Clamp,
+ hideFlags = HideFlags.HideAndDontSave
+ };
+ debugOverlayTarget.Create();
+ }
+
+ cmd.BlitFullscreenTriangle(source, debugOverlayTarget, sheet, pass);
+ debugOverlayActive = true;
+ }
+
+ internal DepthTextureMode GetCameraFlags()
+ {
+ if (debugOverlay == DebugOverlay.Depth)
+ return DepthTextureMode.Depth;
+
+ if (debugOverlay == DebugOverlay.Normals)
+ return DepthTextureMode.DepthNormals;
+
+ if (debugOverlay == DebugOverlay.MotionVectors)
+ return DepthTextureMode.MotionVectors | DepthTextureMode.Depth;
+
+ return DepthTextureMode.None;
+ }
+
+ internal void RenderMonitors(PostProcessRenderContext context)
+ {
+ // Monitors
+ bool anyActive = false;
+ bool needsHalfRes = false;
+
+ foreach (var kvp in m_Monitors)
+ {
+ bool active = kvp.Value.IsRequestedAndSupported(context);
+ anyActive |= active;
+ needsHalfRes |= active && kvp.Value.NeedsHalfRes();
+ }
+
+ if (!anyActive)
+ return;
+
+ var cmd = context.command;
+ cmd.BeginSample("Monitors");
+
+ if (needsHalfRes)
+ {
+ cmd.GetTemporaryRT(ShaderIDs.HalfResFinalCopy, context.width / 2, context.height / 2, 0, FilterMode.Bilinear, context.sourceFormat);
+ cmd.Blit(context.destination, ShaderIDs.HalfResFinalCopy);
+ }
+
+ foreach (var kvp in m_Monitors)
+ {
+ var monitor = kvp.Value;
+
+ if (monitor.requested)
+ monitor.Render(context);
+ }
+
+ if (needsHalfRes)
+ cmd.ReleaseTemporaryRT(ShaderIDs.HalfResFinalCopy);
+
+ cmd.EndSample("Monitors");
+ }
+
+ internal void RenderSpecialOverlays(PostProcessRenderContext context)
+ {
+ if (debugOverlay == DebugOverlay.Depth)
+ {
+ var sheet = context.propertySheets.Get(context.resources.shaders.debugOverlays);
+ sheet.properties.SetVector(ShaderIDs.Params, new Vector4(overlaySettings.linearDepth ? 1f : 0f, 0f, 0f, 0f));
+ PushDebugOverlay(context.command, BuiltinRenderTextureType.None, sheet, 0);
+ }
+ else if (debugOverlay == DebugOverlay.Normals)
+ {
+ var sheet = context.propertySheets.Get(context.resources.shaders.debugOverlays);
+ sheet.ClearKeywords();
+
+#if !UNITY_2022_1_OR_NEWER
+ if (context.camera.actualRenderingPath == RenderingPath.DeferredLighting)
+ sheet.EnableKeyword("SOURCE_GBUFFER");
+#endif
+
+ PushDebugOverlay(context.command, BuiltinRenderTextureType.None, sheet, 1);
+ }
+ else if (debugOverlay == DebugOverlay.MotionVectors)
+ {
+ var sheet = context.propertySheets.Get(context.resources.shaders.debugOverlays);
+ sheet.properties.SetVector(ShaderIDs.Params, new Vector4(overlaySettings.motionColorIntensity, overlaySettings.motionGridSize, 0f, 0f));
+ PushDebugOverlay(context.command, context.source, sheet, 2);
+ }
+ else if (debugOverlay == DebugOverlay.NANTracker)
+ {
+ var sheet = context.propertySheets.Get(context.resources.shaders.debugOverlays);
+ PushDebugOverlay(context.command, context.source, sheet, 3);
+ }
+ else if (debugOverlay == DebugOverlay.ColorBlindnessSimulation)
+ {
+ var sheet = context.propertySheets.Get(context.resources.shaders.debugOverlays);
+ sheet.properties.SetVector(ShaderIDs.Params, new Vector4(overlaySettings.colorBlindnessStrength, 0f, 0f, 0f));
+ PushDebugOverlay(context.command, context.source, sheet, 4 + (int)overlaySettings.colorBlindnessType);
+ }
+ }
+
+ internal void EndFrame()
+ {
+ foreach (var kvp in m_Monitors)
+ kvp.Value.requested = false;
+
+ if (!debugOverlayActive)
+ DestroyDebugOverlayTarget();
+
+ debugOverlay = DebugOverlay.None;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/PostProcessDebugLayer.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessDebugLayer.cs.meta
new file mode 100644
index 0000000..4d04343
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessDebugLayer.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 314a03e1d67d9fb4b85926a765017e02
+timeCreated: 1499676807
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/PostProcessEffectRenderer.cs b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessEffectRenderer.cs
new file mode 100644
index 0000000..9a5b293
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessEffectRenderer.cs
@@ -0,0 +1,78 @@
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// The base abstract class for all effect renderer types. If you're writing your own effect you
+ /// should rather use .
+ ///
+ ///
+ public abstract class PostProcessEffectRenderer
+ {
+ ///
+ /// This member is set to true when is
+ /// called by the user to reset temporal effects and other history-based effects.
+ ///
+ protected bool m_ResetHistory = true;
+
+ ///
+ /// Called when the renderer is created and its associated settings have been set.
+ ///
+ ///
+ public virtual void Init()
+ {
+ }
+
+ ///
+ /// Override this method if your renderer needs access to any of the buffers defined in
+ /// .
+ ///
+ /// The currently set depth texture modes
+ ///
+ public virtual DepthTextureMode GetCameraFlags()
+ {
+ return DepthTextureMode.None;
+ }
+
+ ///
+ /// Resets the history state for this renderer. This is automatically called when
+ /// is called by the user.
+ ///
+ public virtual void ResetHistory()
+ {
+ m_ResetHistory = true;
+ }
+
+ ///
+ /// Override this method to release any resource allocated by your renderer.
+ ///
+ public virtual void Release()
+ {
+ ResetHistory();
+ }
+
+ ///
+ /// The render method called by when the effect is rendered.
+ ///
+ /// A context object
+ public abstract void Render(PostProcessRenderContext context);
+
+ internal abstract void SetSettings(PostProcessEffectSettings settings);
+ }
+
+ ///
+ /// The base abstract class for all effect renderer types.
+ ///
+ /// The associated type of settings for this renderer
+ public abstract class PostProcessEffectRenderer : PostProcessEffectRenderer
+ where T : PostProcessEffectSettings
+ {
+ ///
+ /// The current state of the effect settings associated with this renderer.
+ ///
+ public T settings { get; internal set; }
+
+ internal override void SetSettings(PostProcessEffectSettings settings)
+ {
+ this.settings = (T)settings;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/PostProcessEffectRenderer.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessEffectRenderer.cs.meta
new file mode 100644
index 0000000..cc41dbd
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessEffectRenderer.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 5cfe6169b379ff84eb9796502a1a144d
+timeCreated: 1488642315
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/PostProcessEffectSettings.cs b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessEffectSettings.cs
new file mode 100644
index 0000000..bc68c03
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessEffectSettings.cs
@@ -0,0 +1,121 @@
+using System;
+using System.Collections.ObjectModel;
+using System.Reflection;
+using System.Linq;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// The base class for all post-processing effect settings. Any
+ /// members found in this class will be automatically handled and interpolated by the volume
+ /// framework.
+ ///
+ ///
+ ///
+ /// [Serializable]
+ /// [PostProcess(typeof(ExampleRenderer), "Custom/ExampleEffect")]
+ /// public sealed class ExampleEffect : PostProcessEffectSettings
+ /// {
+ /// [Range(0f, 1f), Tooltip("Effect intensity.")]
+ /// public FloatParameter intensity = new FloatParameter { value = 0f };
+ ///
+ /// public override bool IsEnabledAndSupported(PostProcessRenderContext context)
+ /// {
+ /// return enabled.value
+ /// && intensity.value > 0f; // Only render the effect if intensity is greater than 0
+ /// }
+ /// }
+ ///
+ ///
+ [Serializable]
+ public class PostProcessEffectSettings : ScriptableObject
+ {
+ ///
+ /// The active state of the set of parameter defined in this class.
+ ///
+ ///
+ public bool active = true;
+
+ ///
+ /// The true state of the effect override in the stack. Setting this to false will
+ /// disable rendering for this effect assuming a volume with a higher priority doesn't
+ /// override it to true.
+ ///
+ public BoolParameter enabled = new BoolParameter { overrideState = true, value = false };
+
+ internal ReadOnlyCollection parameters;
+
+ void OnEnable()
+ {
+ // Automatically grab all fields of type ParameterOverride for this instance
+ parameters = GetType()
+ .GetFields(BindingFlags.Public | BindingFlags.Instance)
+ .Where(t => t.FieldType.IsSubclassOf(typeof(ParameterOverride)))
+ .OrderBy(t => t.MetadataToken) // Guaranteed order
+ .Select(t => (ParameterOverride)t.GetValue(this))
+ .ToList()
+ .AsReadOnly();
+
+ foreach (var parameter in parameters)
+ parameter.OnEnable();
+ }
+
+ void OnDisable()
+ {
+ if (parameters == null)
+ return;
+
+ foreach (var parameter in parameters)
+ parameter.OnDisable();
+ }
+
+ ///
+ /// Sets all the overrides for this effect to a given value.
+ ///
+ /// The value to set the override states to
+ /// If false, the field will also
+ /// be set to the given value.
+ public void SetAllOverridesTo(bool state, bool excludeEnabled = true)
+ {
+ foreach (var prop in parameters)
+ {
+ if (excludeEnabled && prop == enabled)
+ continue;
+
+ prop.overrideState = state;
+ }
+ }
+
+ ///
+ /// Returns true if the effect is currently enabled and supported.
+ ///
+ /// The current post-processing render context
+ /// true if the effect is currently enabled and supported
+ public virtual bool IsEnabledAndSupported(PostProcessRenderContext context)
+ {
+ return enabled.value;
+ }
+
+ ///
+ /// Returns the computed hash code for this parameter.
+ ///
+ /// A computed hash code
+ public int GetHash()
+ {
+ // Custom hashing function used to compare the state of settings (it's not meant to be
+ // unique but to be a quick way to check if two setting sets have the same state or not).
+ // Hash collision rate should be pretty low.
+ unchecked
+ {
+ //return parameters.Aggregate(17, (i, p) => i * 23 + p.GetHash());
+
+ int hash = 17;
+
+ foreach (var p in parameters)
+ hash = hash * 23 + p.GetHash();
+
+ return hash;
+ }
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/PostProcessEffectSettings.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessEffectSettings.cs.meta
new file mode 100644
index 0000000..4e2b545
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessEffectSettings.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 2df5c9d441da8704c8eab449a2f79d85
+timeCreated: 1487259888
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/PostProcessEvent.cs b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessEvent.cs
new file mode 100644
index 0000000..beb55b3
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessEvent.cs
@@ -0,0 +1,51 @@
+using System.Collections.Generic;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// Injection points for custom effects.
+ ///
+ public enum PostProcessEvent
+ {
+ ///
+ /// Effects at this injection points will execute before transparent objects are rendered.
+ /// These effects will be rendered at the internal render resolution.
+ ///
+ BeforeTransparent = 0,
+
+ ///
+ /// Effects at this injection point will execute before upscaling and temporal anti-aliasing.
+ /// These effects will be rendered at the internal render resolution.
+ ///
+ BeforeUpscaling = 1,
+
+ ///
+ /// Effects at this injection points will execute after temporal anti-aliasing and before
+ /// builtin effects are rendered.
+ /// These effects will be rendered at the display resolution.
+ ///
+ BeforeStack = 2,
+
+ ///
+ /// Effects at this injection points will execute after builtin effects have been rendered
+ /// and before the final pass that does FXAA and applies dithering.
+ /// These effects will be rendered at the display resolution.
+ ///
+ AfterStack = 3,
+ }
+
+ // Box free comparer for our `PostProcessEvent` enum, else the runtime will box the type when
+ // used as a key in a dictionary, thus leading to garbage generation... *sigh*
+ internal struct PostProcessEventComparer : IEqualityComparer
+ {
+ public bool Equals(PostProcessEvent x, PostProcessEvent y)
+ {
+ return x == y;
+ }
+
+ public int GetHashCode(PostProcessEvent obj)
+ {
+ return (int)obj;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/PostProcessEvent.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessEvent.cs.meta
new file mode 100644
index 0000000..f2fdd0b
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessEvent.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: e4732e1210a3d39459db8b431f866659
+timeCreated: 1492527856
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/PostProcessLayer.cs b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessLayer.cs
new file mode 100644
index 0000000..7bc836b
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessLayer.cs
@@ -0,0 +1,1561 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine.Assertions;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+#if (ENABLE_VR_MODULE && ENABLE_VR)
+ using XRSettings = UnityEngine.XR.XRSettings;
+#endif
+
+ ///
+ /// This is the component responsible for rendering post-processing effects. It must be put on
+ /// every camera you want post-processing to be applied to.
+ ///
+#if UNITY_2018_3_OR_NEWER
+ [ExecuteAlways]
+#else
+ [ExecuteInEditMode]
+#endif
+ [DisallowMultipleComponent, ImageEffectAllowedInSceneView]
+ [AddComponentMenu("Rendering/Post-process Layer", 1000)]
+ [RequireComponent(typeof(Camera))]
+ public sealed class PostProcessLayer : MonoBehaviour
+ {
+ ///
+ /// Builtin anti-aliasing methods.
+ ///
+ public enum Antialiasing
+ {
+ ///
+ /// No anti-aliasing.
+ ///
+ None,
+
+ ///
+ /// Fast Approximate Anti-aliasing (FXAA). Fast but low quality.
+ ///
+ FastApproximateAntialiasing,
+
+ ///
+ /// Subpixel Morphological Anti-aliasing (SMAA). Slower but higher quality than FXAA.
+ ///
+ SubpixelMorphologicalAntialiasing,
+
+ ///
+ /// Temporal Anti-aliasing (TAA). As fast as SMAA but generally higher quality. Because
+ /// of it's temporal nature, it can introduce ghosting artifacts on fast moving objects
+ /// in highly contrasted areas.
+ ///
+ TemporalAntialiasing,
+
+ ///
+ /// FidelityFX Super Resolution 2 (FSR2).
+ ///
+ SuperResolution,
+ }
+
+ ///
+ /// This is transform that will be drive the volume blending feature. In some cases you may
+ /// want to use a transform other than the camera, e.g. for a top down game you'll want the
+ /// player character to drive the blending instead of the actual camera transform.
+ /// Setting this field to null will disable local volumes for this layer (global ones
+ /// will still work).
+ ///
+ public Transform volumeTrigger;
+
+ ///
+ /// A mask of layers to consider for volume blending. It allows you to do volume filtering
+ /// and is especially useful to optimize volume traversal. You should always have your
+ /// volumes in dedicated layers instead of the default one for best performances.
+ ///
+ public LayerMask volumeLayer;
+
+ ///
+ /// If true, it will kill any invalid / NaN pixel and replace it with a black color
+ /// before post-processing is applied. It's generally a good idea to keep this enabled to
+ /// avoid post-processing artifacts cause by broken data in the scene.
+ ///
+ public bool stopNaNPropagation = true;
+
+ ///
+ /// If true, it will render straight to the backbuffer and save the final blit done
+ /// by the engine. This has less overhead and will improve performance on lower-end platforms
+ /// (like mobiles) but breaks compatibility with legacy image effect that use OnRenderImage.
+ ///
+ public bool finalBlitToCameraTarget = false;
+
+ ///
+ /// The anti-aliasing method to use for this camera. By default it's set to None.
+ ///
+ public Antialiasing antialiasingMode = Antialiasing.None;
+
+ ///
+ /// Temporal Anti-aliasing settings for this camera.
+ ///
+ public TemporalAntialiasing temporalAntialiasing;
+
+ ///
+ /// FSR2 upscaling & anti-aliasing settings for this camera.
+ ///
+ public SuperResolution superResolution;
+
+ ///
+ /// Subpixel Morphological Anti-aliasing settings for this camera.
+ ///
+ public SubpixelMorphologicalAntialiasing subpixelMorphologicalAntialiasing;
+
+ ///
+ /// Fast Approximate Anti-aliasing settings for this camera.
+ ///
+ public FastApproximateAntialiasing fastApproximateAntialiasing;
+
+ ///
+ /// Fog settings for this camera.
+ ///
+ public Fog fog;
+
+ Dithering dithering;
+
+ ///
+ /// The debug layer is reponsible for rendering debugging information on the screen. It will
+ /// only be used if this layer is referenced in a component.
+ ///
+ ///
+ public PostProcessDebugLayer debugLayer;
+
+ [SerializeField]
+ PostProcessResources m_Resources;
+
+ // Some juggling needed to track down reference to the resource asset when loaded from asset
+ // bundle (guid conflict)
+ [NonSerialized]
+ PostProcessResources m_OldResources;
+
+ // UI states
+ [UnityEngine.Scripting.Preserve]
+ [SerializeField]
+ bool m_ShowToolkit;
+
+ [UnityEngine.Scripting.Preserve]
+ [SerializeField]
+ bool m_ShowCustomSorter;
+
+ ///
+ /// If true, it will stop applying post-processing effects just before color grading
+ /// is applied. This is used internally to export to EXR without color grading.
+ ///
+ public bool breakBeforeColorGrading = false;
+
+ // Pre-ordered custom user effects
+ // These are automatically populated and made to work properly with the serialization
+ // system AND the editor. Modify at your own risk.
+
+ ///
+ /// A wrapper around bundles to allow their serialization in lists.
+ ///
+ [Serializable]
+ public sealed class SerializedBundleRef
+ {
+ ///
+ /// The assembly qualified name used for serialization as we can't serialize the types
+ /// themselves.
+ ///
+ public string assemblyQualifiedName; // We only need this at init time anyway so it's fine
+
+ ///
+ /// A reference to the bundle itself.
+ ///
+ public PostProcessBundle bundle; // Not serialized, is set/reset when deserialization kicks in
+ }
+
+ [SerializeField]
+ List m_BeforeTransparentBundles;
+
+ [SerializeField]
+ List m_BeforeUpscalingBundles;
+
+ [SerializeField]
+ List m_BeforeStackBundles;
+
+ [SerializeField]
+ List m_AfterStackBundles;
+
+ ///
+ /// Pre-ordered effects mapped to available injection points.
+ ///
+ public Dictionary> sortedBundles { get; private set; }
+
+ ///
+ /// The current flags set on the camera for the built-in render pipeline.
+ ///
+ public DepthTextureMode cameraDepthFlags { get; private set; }
+
+ // We need to keep track of bundle initialization because for some obscure reason, on
+ // assembly reload a MonoBehavior's Editor OnEnable will be called BEFORE the MonoBehavior's
+ // own OnEnable... So we'll use it to pre-init bundles if the layer inspector is opened and
+ // the component hasn't been enabled yet.
+
+ ///
+ /// Returns true if the bundles have been initialized properly.
+ ///
+ public bool haveBundlesBeenInited { get; private set; }
+
+ // Settings/Renderer bundles mapped to settings types
+ Dictionary m_Bundles;
+
+ PropertySheetFactory m_PropertySheetFactory;
+ CommandBuffer m_LegacyCmdBufferBeforeReflections;
+ CommandBuffer m_LegacyCmdBufferBeforeLighting;
+ CommandBuffer m_LegacyCmdBufferOpaque;
+ CommandBuffer m_LegacyCmdBuffer;
+ Camera m_Camera;
+ PostProcessRenderContext m_CurrentContext;
+ LogHistogram m_LogHistogram;
+
+ RenderTexture m_opaqueOnly;
+ RenderTexture m_upscaledOutput;
+ RenderTexture m_originalTargetTexture;
+
+ bool m_SettingsUpdateNeeded = true;
+ bool m_IsRenderingInSceneView = false;
+
+ TargetPool m_TargetPool;
+
+ bool m_NaNKilled = false;
+
+ // Recycled list - used to reduce GC stress when gathering active effects in a bundle list
+ // on each frame
+ readonly List m_ActiveEffects = new List();
+ readonly List m_Targets = new List();
+
+ void OnEnable()
+ {
+ Init(null);
+
+ if (!haveBundlesBeenInited)
+ InitBundles();
+
+ m_LogHistogram = new LogHistogram();
+ m_PropertySheetFactory = new PropertySheetFactory();
+ m_TargetPool = new TargetPool();
+
+ debugLayer.OnEnable();
+
+ if (RuntimeUtilities.scriptableRenderPipelineActive)
+ return;
+
+ InitLegacy();
+ }
+
+ void InitLegacy()
+ {
+ m_LegacyCmdBufferBeforeReflections = new CommandBuffer { name = "Deferred Ambient Occlusion" };
+ m_LegacyCmdBufferBeforeLighting = new CommandBuffer { name = "Deferred Ambient Occlusion" };
+ m_LegacyCmdBufferOpaque = new CommandBuffer { name = "Opaque Only Post-processing" };
+ m_LegacyCmdBuffer = new CommandBuffer { name = "Post-processing" };
+
+ m_Camera = GetComponent();
+
+#if !UNITY_2019_1_OR_NEWER // OnRenderImage (below) implies forceIntoRenderTexture
+ m_Camera.forceIntoRenderTexture = true; // Needed when running Forward / LDR / No MSAA
+#endif
+
+ m_Camera.AddCommandBuffer(CameraEvent.BeforeReflections, m_LegacyCmdBufferBeforeReflections);
+ m_Camera.AddCommandBuffer(CameraEvent.BeforeLighting, m_LegacyCmdBufferBeforeLighting);
+ m_Camera.AddCommandBuffer(CameraEvent.BeforeImageEffectsOpaque, m_LegacyCmdBufferOpaque);
+ m_Camera.AddCommandBuffer(CameraEvent.BeforeImageEffects, m_LegacyCmdBuffer);
+
+ // Internal context used if no SRP is set
+ m_CurrentContext = new PostProcessRenderContext();
+ }
+
+#if UNITY_2019_1_OR_NEWER
+ bool DynamicResolutionAllowsFinalBlitToCameraTarget()
+ {
+ return (!RuntimeUtilities.IsDynamicResolutionEnabled(m_Camera) || (ScalableBufferManager.heightScaleFactor == 1.0 && ScalableBufferManager.widthScaleFactor == 1.0));
+ }
+
+#endif
+
+#if UNITY_2019_1_OR_NEWER
+ // We always use a CommandBuffer to blit to the final render target
+ // OnRenderImage is used only to avoid the automatic blit from the RenderTexture of Camera.forceIntoRenderTexture to the actual target
+ [ImageEffectUsesCommandBuffer]
+ void OnRenderImage(RenderTexture src, RenderTexture dst)
+ {
+ if (m_opaqueOnly != null)
+ {
+ RenderTexture.ReleaseTemporary(m_opaqueOnly);
+ m_opaqueOnly = null;
+ }
+
+ if (!finalBlitToCameraTarget && m_CurrentContext.IsSuperResolutionActive())
+ {
+ // Set the camera back to its original parameters, so we can output at full display resolution
+ superResolution.ResetCameraViewport(m_CurrentContext);
+
+ // Blit the upscaled image to the backbuffer
+ if (m_originalTargetTexture != null)
+ {
+ Graphics.Blit(m_upscaledOutput, m_originalTargetTexture);
+ RenderTexture.active = dst;
+
+ // Put the original target texture back at the end of the frame
+ m_Camera.targetTexture = m_originalTargetTexture;
+ m_originalTargetTexture = null;
+ }
+ else
+ {
+ Graphics.Blit(m_upscaledOutput, dst);
+ }
+
+ RenderTexture.ReleaseTemporary(m_upscaledOutput);
+ m_upscaledOutput = null;
+ return;
+ }
+
+ if (finalBlitToCameraTarget && !m_CurrentContext.stereoActive && DynamicResolutionAllowsFinalBlitToCameraTarget())
+ RenderTexture.active = dst; // silence warning
+ else
+ Graphics.Blit(src, dst);
+ }
+
+#endif
+
+ ///
+ /// Initializes this layer. If you create the layer via scripting you should always call
+ /// this method.
+ ///
+ /// A reference to the resource asset
+ public void Init(PostProcessResources resources)
+ {
+ if (resources != null) m_Resources = resources;
+
+ RuntimeUtilities.CreateIfNull(ref temporalAntialiasing);
+ RuntimeUtilities.CreateIfNull(ref superResolution);
+ RuntimeUtilities.CreateIfNull(ref subpixelMorphologicalAntialiasing);
+ RuntimeUtilities.CreateIfNull(ref fastApproximateAntialiasing);
+ RuntimeUtilities.CreateIfNull(ref dithering);
+ RuntimeUtilities.CreateIfNull(ref fog);
+ RuntimeUtilities.CreateIfNull(ref debugLayer);
+ }
+
+ ///
+ /// Initializes all the effect bundles. This is called automatically by the framework.
+ ///
+ public void InitBundles()
+ {
+ if (haveBundlesBeenInited)
+ return;
+
+ // Create these lists only once, the serialization system will take over after that
+ RuntimeUtilities.CreateIfNull(ref m_BeforeTransparentBundles);
+ RuntimeUtilities.CreateIfNull(ref m_BeforeUpscalingBundles);
+ RuntimeUtilities.CreateIfNull(ref m_BeforeStackBundles);
+ RuntimeUtilities.CreateIfNull(ref m_AfterStackBundles);
+
+ // Create a bundle for each effect type
+ m_Bundles = new Dictionary();
+
+ foreach (var type in PostProcessManager.instance.settingsTypes.Keys)
+ {
+ var settings = (PostProcessEffectSettings)ScriptableObject.CreateInstance(type);
+ var bundle = new PostProcessBundle(settings);
+ m_Bundles.Add(type, bundle);
+ }
+
+ // Update sorted lists with newly added or removed effects in the assemblies
+ UpdateBundleSortList(m_BeforeTransparentBundles, PostProcessEvent.BeforeTransparent);
+ UpdateBundleSortList(m_BeforeUpscalingBundles, PostProcessEvent.BeforeUpscaling);
+ UpdateBundleSortList(m_BeforeStackBundles, PostProcessEvent.BeforeStack);
+ UpdateBundleSortList(m_AfterStackBundles, PostProcessEvent.AfterStack);
+
+ // Push all sorted lists in a dictionary for easier access
+ sortedBundles = new Dictionary>(new PostProcessEventComparer())
+ {
+ { PostProcessEvent.BeforeTransparent, m_BeforeTransparentBundles },
+ { PostProcessEvent.BeforeUpscaling, m_BeforeUpscalingBundles },
+ { PostProcessEvent.BeforeStack, m_BeforeStackBundles },
+ { PostProcessEvent.AfterStack, m_AfterStackBundles }
+ };
+
+ // Done
+ haveBundlesBeenInited = true;
+ }
+
+ void UpdateBundleSortList(List sortedList, PostProcessEvent evt)
+ {
+ // First get all effects associated with the injection point
+ var effects = m_Bundles.Where(kvp => kvp.Value.attribute.eventType == evt && !kvp.Value.attribute.builtinEffect)
+ .Select(kvp => kvp.Value)
+ .ToList();
+
+ // Remove types that don't exist anymore
+ sortedList.RemoveAll(x =>
+ {
+ string searchStr = x.assemblyQualifiedName;
+ return !effects.Exists(b => b.settings.GetType().AssemblyQualifiedName == searchStr);
+ });
+
+ // Add new ones
+ foreach (var effect in effects)
+ {
+ string typeName = effect.settings.GetType().AssemblyQualifiedName;
+
+ if (!sortedList.Exists(b => b.assemblyQualifiedName == typeName))
+ {
+ var sbr = new SerializedBundleRef { assemblyQualifiedName = typeName };
+ sortedList.Add(sbr);
+ }
+ }
+
+ // Link internal references
+ foreach (var effect in sortedList)
+ {
+ string typeName = effect.assemblyQualifiedName;
+ var bundle = effects.Find(b => b.settings.GetType().AssemblyQualifiedName == typeName);
+ effect.bundle = bundle;
+ }
+ }
+
+ void OnDisable()
+ {
+ // Have to check for null camera in case the user is doing back'n'forth between SRP and
+ // legacy
+ if (m_Camera != null)
+ {
+ if (m_LegacyCmdBufferBeforeReflections != null)
+ m_Camera.RemoveCommandBuffer(CameraEvent.BeforeReflections, m_LegacyCmdBufferBeforeReflections);
+ if (m_LegacyCmdBufferBeforeLighting != null)
+ m_Camera.RemoveCommandBuffer(CameraEvent.BeforeLighting, m_LegacyCmdBufferBeforeLighting);
+ if (m_LegacyCmdBufferOpaque != null)
+ m_Camera.RemoveCommandBuffer(CameraEvent.BeforeImageEffectsOpaque, m_LegacyCmdBufferOpaque);
+ if (m_LegacyCmdBuffer != null)
+ m_Camera.RemoveCommandBuffer(CameraEvent.BeforeImageEffects, m_LegacyCmdBuffer);
+ }
+
+ temporalAntialiasing.Release();
+ superResolution.Release();
+ m_LogHistogram.Release();
+
+ foreach (var bundle in m_Bundles.Values)
+ bundle.Release();
+
+ m_Bundles.Clear();
+ m_PropertySheetFactory.Release();
+
+ if (debugLayer != null)
+ debugLayer.OnDisable();
+
+ // Might be an issue if several layers are blending in the same frame...
+ TextureLerper.instance.Clear();
+
+ haveBundlesBeenInited = false;
+ }
+
+ // Called everytime the user resets the component from the inspector and more importantly
+ // the first time it's added to a GameObject. As we don't have added/removed event for
+ // components, this will do fine
+ void Reset()
+ {
+ volumeTrigger = transform;
+ }
+
+ void LateUpdate()
+ {
+ // Temporarily take control of the camera's target texture, so that the upscaled output doesn't get clipped
+ if (m_Camera.targetTexture != null && m_CurrentContext.IsSuperResolutionActive())
+ {
+ m_originalTargetTexture = m_Camera.targetTexture;
+ m_Camera.targetTexture = null;
+ }
+ }
+
+ void OnPreCull()
+ {
+ // Unused in scriptable render pipelines
+ if (RuntimeUtilities.scriptableRenderPipelineActive)
+ return;
+
+ if (m_Camera == null || m_CurrentContext == null)
+ InitLegacy();
+
+ // Postprocessing does tweak load/store actions when it uses render targets.
+ // But when using builtin render pipeline, Camera will silently apply viewport when setting render target,
+ // meaning that Postprocessing might think that it is rendering to fullscreen RT
+ // and use LoadAction.DontCare freely, which will ruin the RT if we are using viewport.
+ // It should actually check for having tiled architecture but this is not exposed to script,
+ // so we are checking for mobile as a good substitute
+#if UNITY_2019_3_OR_NEWER
+ if (SystemInfo.usesLoadStoreActions)
+#else
+ if (Application.isMobilePlatform)
+#endif
+ {
+ Rect r = m_Camera.rect;
+ if (Mathf.Abs(r.x) > 1e-6f || Mathf.Abs(r.y) > 1e-6f || Mathf.Abs(1.0f - r.width) > 1e-6f || Mathf.Abs(1.0f - r.height) > 1e-6f)
+ {
+ Debug.LogWarning("When used with builtin render pipeline, Postprocessing package expects to be used on a fullscreen Camera.\nPlease note that using Camera viewport may result in visual artefacts or some things not working.", m_Camera);
+ }
+ }
+
+ // Resets the projection matrix from previous frame in case TAA was enabled.
+ // We also need to force reset the non-jittered projection matrix here as it's not done
+ // when ResetProjectionMatrix() is called and will break transparent rendering if TAA
+ // is switched off and the FOV or any other camera property changes.
+ if (m_CurrentContext.IsTemporalAntialiasingActive() || m_CurrentContext.IsSuperResolutionActive())
+ {
+#if UNITY_2018_2_OR_NEWER
+ if (!m_Camera.usePhysicalProperties)
+#endif
+ {
+ m_Camera.ResetProjectionMatrix();
+ m_Camera.nonJitteredProjectionMatrix = m_Camera.projectionMatrix;
+#if (ENABLE_VR_MODULE && ENABLE_VR)
+ if (m_Camera.stereoEnabled)
+ {
+ m_Camera.ResetStereoProjectionMatrices();
+ if (m_Camera.stereoActiveEye == Camera.MonoOrStereoscopicEye.Right)
+ {
+ m_Camera.CopyStereoDeviceProjectionMatrixToNonJittered(Camera.StereoscopicEye.Right);
+ m_Camera.projectionMatrix = m_Camera.GetStereoNonJitteredProjectionMatrix(Camera.StereoscopicEye.Right);
+ m_Camera.nonJitteredProjectionMatrix = m_Camera.projectionMatrix;
+ m_Camera.SetStereoProjectionMatrix(Camera.StereoscopicEye.Right, m_Camera.GetStereoProjectionMatrix(Camera.StereoscopicEye.Right));
+ }
+ else if (m_Camera.stereoActiveEye == Camera.MonoOrStereoscopicEye.Left || m_Camera.stereoActiveEye == Camera.MonoOrStereoscopicEye.Mono)
+ {
+ m_Camera.CopyStereoDeviceProjectionMatrixToNonJittered(Camera.StereoscopicEye.Left); // device to unjittered
+ m_Camera.projectionMatrix = m_Camera.GetStereoNonJitteredProjectionMatrix(Camera.StereoscopicEye.Left);
+ m_Camera.nonJitteredProjectionMatrix = m_Camera.projectionMatrix;
+ m_Camera.SetStereoProjectionMatrix(Camera.StereoscopicEye.Left, m_Camera.GetStereoProjectionMatrix(Camera.StereoscopicEye.Left));
+ }
+ }
+#endif
+ }
+ }
+
+#if (ENABLE_VR_MODULE && ENABLE_VR)
+ if (m_Camera.stereoEnabled)
+ {
+ Shader.SetGlobalFloat(ShaderIDs.RenderViewportScaleFactor, XRSettings.renderViewportScale);
+ }
+ else
+#endif
+ {
+ Shader.SetGlobalFloat(ShaderIDs.RenderViewportScaleFactor, 1.0f);
+ }
+
+ BuildCommandBuffers();
+ }
+
+ void OnPreRender()
+ {
+ // Unused in scriptable render pipelines
+ // Only needed for multi-pass stereo right eye
+ if (RuntimeUtilities.scriptableRenderPipelineActive ||
+ (m_Camera.stereoActiveEye != Camera.MonoOrStereoscopicEye.Right))
+ return;
+
+ BuildCommandBuffers();
+ }
+
+ static bool RequiresInitialBlit(Camera camera, PostProcessRenderContext context)
+ {
+ // [ImageEffectUsesCommandBuffer] is currently broken, FIXME
+ return true;
+
+ /*
+#if UNITY_2019_1_OR_NEWER
+ if (camera.allowMSAA) // this shouldn't be necessary, but until re-tested on older Unity versions just do the blits
+ return true;
+ if (RuntimeUtilities.scriptableRenderPipelineActive) // Should never be called from SRP
+ return true;
+
+ return false;
+#else
+ return true;
+#endif
+ */
+ }
+
+ void UpdateSrcDstForOpaqueOnly(ref int src, ref int dst, PostProcessRenderContext context, RenderTargetIdentifier cameraTarget, int opaqueOnlyEffectsRemaining)
+ {
+ if (src > -1)
+ context.command.ReleaseTemporaryRT(src);
+
+ context.source = context.destination;
+ src = dst;
+
+ if (opaqueOnlyEffectsRemaining == 1)
+ {
+ context.destination = cameraTarget;
+ }
+ else
+ {
+ dst = m_TargetPool.Get();
+ context.destination = dst;
+ context.GetScreenSpaceTemporaryRT(context.command, dst, 0, context.sourceFormat);
+ }
+ }
+
+ void BuildCommandBuffers()
+ {
+ var context = m_CurrentContext;
+ var sourceFormat = m_Camera.targetTexture ? m_Camera.targetTexture.format : (m_Camera.allowHDR ? RuntimeUtilities.defaultHDRRenderTextureFormat : RenderTextureFormat.Default);
+
+ if (!RuntimeUtilities.isFloatingPointFormat(sourceFormat))
+ m_NaNKilled = true;
+
+ context.Reset();
+ context.camera = m_Camera;
+ context.sourceFormat = sourceFormat;
+
+ // TODO: Investigate retaining command buffers on XR multi-pass right eye
+ m_LegacyCmdBufferBeforeReflections.Clear();
+ m_LegacyCmdBufferBeforeLighting.Clear();
+ m_LegacyCmdBufferOpaque.Clear();
+ m_LegacyCmdBuffer.Clear();
+
+ SetupContext(context);
+
+ // Modify internal rendering resolution for both the camera and the pre-upscaling post-processing effects
+ if (context.IsSuperResolutionActive())
+ {
+ superResolution.ConfigureCameraViewport(context);
+ context.SetRenderSize(superResolution.renderSize);
+ }
+ else
+ {
+ // Ensure all of FSR2's resources are released when it's not in use
+ superResolution.Release();
+ }
+
+ context.command = m_LegacyCmdBufferOpaque;
+ TextureLerper.instance.BeginFrame(context);
+ UpdateVolumeSystem(context.camera, context.command);
+
+ // Lighting & opaque-only effects
+ var aoBundle = GetBundle();
+ var aoSettings = aoBundle.CastSettings();
+ var aoRenderer = aoBundle.CastRenderer();
+
+ bool aoSupported = aoSettings.IsEnabledAndSupported(context);
+ bool aoAmbientOnly = aoRenderer.IsAmbientOnly(context);
+ bool isAmbientOcclusionDeferred = aoSupported && aoAmbientOnly;
+ bool isAmbientOcclusionOpaque = aoSupported && !aoAmbientOnly;
+
+ var ssrBundle = GetBundle();
+ var ssrSettings = ssrBundle.settings;
+ var ssrRenderer = ssrBundle.renderer;
+ bool isScreenSpaceReflectionsActive = ssrSettings.IsEnabledAndSupported(context);
+
+#if UNITY_2019_1_OR_NEWER
+ if (context.stereoActive)
+ context.UpdateSinglePassStereoState(context.IsTemporalAntialiasingActive() || context.IsSuperResolutionActive(), aoSupported, isScreenSpaceReflectionsActive);
+#endif
+ // Ambient-only AO is a special case and has to be done in separate command buffers
+ if (isAmbientOcclusionDeferred)
+ {
+ var ao = aoRenderer.Get();
+
+ // Render as soon as possible - should be done async in SRPs when available
+ context.command = m_LegacyCmdBufferBeforeReflections;
+ ao.RenderAmbientOnly(context);
+
+ // Composite with GBuffer right before the lighting pass
+ context.command = m_LegacyCmdBufferBeforeLighting;
+ ao.CompositeAmbientOnly(context);
+ }
+ else if (isAmbientOcclusionOpaque)
+ {
+ context.command = m_LegacyCmdBufferOpaque;
+ aoRenderer.Get().RenderAfterOpaque(context);
+ }
+
+ bool fsrRequiresOpaque = context.IsSuperResolutionActive() && (superResolution.autoGenerateReactiveMask || superResolution.autoGenerateTransparencyAndComposition);
+
+ bool isFogActive = fog.IsEnabledAndSupported(context);
+ bool hasCustomOpaqueOnlyEffects = HasOpaqueOnlyEffects(context);
+ int opaqueOnlyEffects = 0;
+ opaqueOnlyEffects += fsrRequiresOpaque ? 1 : 0;
+ opaqueOnlyEffects += isScreenSpaceReflectionsActive ? 1 : 0;
+ opaqueOnlyEffects += isFogActive ? 1 : 0;
+ opaqueOnlyEffects += hasCustomOpaqueOnlyEffects ? 1 : 0;
+
+ // This works on right eye because it is resolved/populated at runtime
+ var cameraTarget = new RenderTargetIdentifier(BuiltinRenderTextureType.CameraTarget);
+
+ if (opaqueOnlyEffects > 0)
+ {
+ var cmd = m_LegacyCmdBufferOpaque;
+ context.command = cmd;
+ context.source = cameraTarget;
+ context.destination = cameraTarget;
+ int srcTarget = -1;
+ int dstTarget = -1;
+
+ UpdateSrcDstForOpaqueOnly(ref srcTarget, ref dstTarget, context, cameraTarget, opaqueOnlyEffects + 1); // + 1 for blit
+
+ if (RequiresInitialBlit(m_Camera, context) || opaqueOnlyEffects == 1)
+ {
+ cmd.BuiltinBlit(context.source, context.destination, RuntimeUtilities.copyStdMaterial, stopNaNPropagation ? 1 : 0);
+ UpdateSrcDstForOpaqueOnly(ref srcTarget, ref dstTarget, context, cameraTarget, opaqueOnlyEffects);
+ }
+
+ if (fsrRequiresOpaque)
+ {
+ m_opaqueOnly = context.GetScreenSpaceTemporaryRT();
+ cmd.BuiltinBlit(context.source, m_opaqueOnly);
+ opaqueOnlyEffects--;
+ }
+
+ if (isScreenSpaceReflectionsActive)
+ {
+ ssrRenderer.RenderOrLog(context);
+ opaqueOnlyEffects--;
+ UpdateSrcDstForOpaqueOnly(ref srcTarget, ref dstTarget, context, cameraTarget, opaqueOnlyEffects);
+ }
+
+ if (isFogActive)
+ {
+ fog.Render(context);
+ opaqueOnlyEffects--;
+ UpdateSrcDstForOpaqueOnly(ref srcTarget, ref dstTarget, context, cameraTarget, opaqueOnlyEffects);
+ }
+
+ if (hasCustomOpaqueOnlyEffects)
+ RenderOpaqueOnly(context);
+
+ cmd.ReleaseTemporaryRT(srcTarget);
+ }
+
+ // Post-transparency stack
+ int tempRt = -1;
+ bool forceNanKillPass = (!m_NaNKilled && stopNaNPropagation && RuntimeUtilities.isFloatingPointFormat(sourceFormat));
+ bool vrSinglePassInstancingEnabled = context.stereoActive && context.numberOfEyes > 1 && context.stereoRenderingMode == PostProcessRenderContext.StereoRenderingMode.SinglePassInstanced;
+ if (!vrSinglePassInstancingEnabled && (RequiresInitialBlit(m_Camera, context) || forceNanKillPass))
+ {
+ int width = context.width;
+#if UNITY_2019_1_OR_NEWER && ENABLE_VR_MODULE && ENABLE_VR
+ var xrDesc = XRSettings.eyeTextureDesc;
+ if (context.stereoActive && context.stereoRenderingMode == PostProcessRenderContext.StereoRenderingMode.SinglePass)
+ width = xrDesc.width;
+#endif
+ tempRt = m_TargetPool.Get();
+ context.GetScreenSpaceTemporaryRT(m_LegacyCmdBuffer, tempRt, 0, sourceFormat, RenderTextureReadWrite.sRGB, FilterMode.Bilinear, width);
+ m_LegacyCmdBuffer.BuiltinBlit(cameraTarget, tempRt, RuntimeUtilities.copyStdMaterial, stopNaNPropagation ? 1 : 0);
+ if (!m_NaNKilled)
+ m_NaNKilled = stopNaNPropagation;
+
+ context.source = tempRt;
+ }
+ else
+ {
+ context.source = cameraTarget;
+ }
+
+ context.destination = cameraTarget;
+
+ if (!finalBlitToCameraTarget && m_CurrentContext.IsSuperResolutionActive())
+ {
+ var displaySize = superResolution.displaySize;
+ m_upscaledOutput = context.GetScreenSpaceTemporaryRT(widthOverride: displaySize.x, heightOverride: displaySize.y);
+ context.destination = m_upscaledOutput;
+ }
+
+#if UNITY_2019_1_OR_NEWER
+ if (finalBlitToCameraTarget && !m_CurrentContext.stereoActive && !RuntimeUtilities.scriptableRenderPipelineActive && DynamicResolutionAllowsFinalBlitToCameraTarget())
+ {
+ if (m_Camera.targetTexture)
+ {
+ context.destination = m_Camera.targetTexture.colorBuffer;
+ }
+ else
+ {
+ context.flip = true;
+ context.destination = Display.main.colorBuffer;
+ }
+ }
+#endif
+
+ context.command = m_LegacyCmdBuffer;
+
+ Render(context);
+
+ if (tempRt > -1)
+ m_LegacyCmdBuffer.ReleaseTemporaryRT(tempRt);
+ }
+
+ void OnPostRender()
+ {
+ // Unused in scriptable render pipelines
+ if (RuntimeUtilities.scriptableRenderPipelineActive)
+ return;
+
+ // Set the camera back to its original parameters, so we can output at full display resolution
+ if (finalBlitToCameraTarget && m_CurrentContext.IsSuperResolutionActive())
+ {
+ superResolution.ResetCameraViewport(m_CurrentContext);
+ }
+
+ if (m_CurrentContext.IsTemporalAntialiasingActive() || m_CurrentContext.IsSuperResolutionActive())
+ {
+#if UNITY_2018_2_OR_NEWER
+ // TAA calls SetProjectionMatrix so if the camera projection mode was physical, it gets set to explicit. So we set it back to physical.
+ if (m_CurrentContext.physicalCamera)
+ m_Camera.usePhysicalProperties = true;
+ else
+#endif
+ {
+ // The camera must be reset on precull and post render to avoid issues with alpha when toggling TAA.
+ m_Camera.ResetProjectionMatrix();
+#if (ENABLE_VR_MODULE && ENABLE_VR)
+ if (m_CurrentContext.stereoActive)
+ {
+ if (RuntimeUtilities.isSinglePassStereoEnabled || m_Camera.stereoActiveEye == Camera.MonoOrStereoscopicEye.Right)
+ {
+ m_Camera.ResetStereoProjectionMatrices();
+ // copy the left eye onto the projection matrix so that we're using the correct projection matrix after calling m_Camera.ResetProjectionMatrix(); above.
+ if (XRSettings.stereoRenderingMode == XRSettings.StereoRenderingMode.MultiPass)
+ m_Camera.projectionMatrix = m_Camera.GetStereoProjectionMatrix(Camera.StereoscopicEye.Left);
+ }
+ }
+#endif
+ }
+ }
+ }
+
+ ///
+ /// Grabs the bundle for the given effect type.
+ ///
+ /// An effect type.
+ /// The bundle for the effect of type
+ public PostProcessBundle GetBundle()
+ where T : PostProcessEffectSettings
+ {
+ return GetBundle(typeof(T));
+ }
+
+ ///
+ /// Grabs the bundle for the given effect type.
+ ///
+ /// An effect type.
+ /// The bundle for the effect of type
+ public PostProcessBundle GetBundle(Type settingsType)
+ {
+ Assert.IsTrue(m_Bundles.ContainsKey(settingsType), "Invalid type");
+ return m_Bundles[settingsType];
+ }
+
+ ///
+ /// Gets the current settings for a given effect.
+ ///
+ /// The type of effect to look for
+ /// The current state of an effect
+ public T GetSettings()
+ where T : PostProcessEffectSettings
+ {
+ return GetBundle().CastSettings();
+ }
+
+ ///
+ /// Utility method to bake a multi-scale volumetric obscurance map for the current camera.
+ /// This will only work if ambient occlusion is active in the scene.
+ ///
+ /// The command buffer to use for rendering steps
+ /// The camera to render ambient occlusion for
+ /// The destination render target
+ /// The depth map to use. If null, it will use the depth map
+ /// from the given camera
+ /// Should the result be inverted?
+ /// Should use MSAA?
+ public void BakeMSVOMap(CommandBuffer cmd, Camera camera, RenderTargetIdentifier destination, RenderTargetIdentifier? depthMap, bool invert, bool isMSAA = false)
+ {
+ var bundle = GetBundle();
+ var renderer = bundle.CastRenderer().GetMultiScaleVO();
+ renderer.SetResources(m_Resources);
+ renderer.GenerateAOMap(cmd, camera, destination, depthMap, invert, isMSAA);
+ }
+
+ internal void OverrideSettings(List baseSettings, float interpFactor)
+ {
+ // Go through all settings & overriden parameters for the given volume and lerp values
+ foreach (var settings in baseSettings)
+ {
+ if (!settings.active)
+ continue;
+
+ var target = GetBundle(settings.GetType()).settings;
+ int count = settings.parameters.Count;
+
+ for (int i = 0; i < count; i++)
+ {
+ var toParam = settings.parameters[i];
+ if (toParam.overrideState)
+ {
+ var fromParam = target.parameters[i];
+ fromParam.Interp(fromParam, toParam, interpFactor);
+ }
+ }
+ }
+ }
+
+ // In the legacy render loop you have to explicitely set flags on camera to tell that you
+ // need depth, depth+normals or motion vectors... This won't have any effect with most
+ // scriptable render pipelines.
+ void SetLegacyCameraFlags(PostProcessRenderContext context)
+ {
+ var flags = DepthTextureMode.None;
+
+ foreach (var bundle in m_Bundles)
+ {
+ if (bundle.Value.settings.IsEnabledAndSupported(context))
+ flags |= bundle.Value.renderer.GetCameraFlags();
+ }
+
+ // Special case for AA & lighting effects
+ if (context.IsTemporalAntialiasingActive())
+ flags |= temporalAntialiasing.GetCameraFlags();
+
+ if (context.IsSuperResolutionActive())
+ flags |= superResolution.GetCameraFlags();
+
+ if (fog.IsEnabledAndSupported(context))
+ flags |= fog.GetCameraFlags();
+
+ if (debugLayer.debugOverlay != DebugOverlay.None)
+ flags |= debugLayer.GetCameraFlags();
+
+ context.camera.depthTextureMode |= flags;
+ cameraDepthFlags = flags;
+ }
+
+ ///
+ /// This method should be called whenever you need to reset any temporal effect, e.g. when
+ /// doing camera cuts.
+ ///
+ public void ResetHistory()
+ {
+ foreach (var bundle in m_Bundles)
+ bundle.Value.ResetHistory();
+
+ temporalAntialiasing.ResetHistory();
+ superResolution.ResetHistory();
+ }
+
+ ///
+ /// Checks if this layer has any active opaque-only effect.
+ ///
+ /// The current render context
+ /// true if opaque-only effects are active, false otherwise
+ public bool HasOpaqueOnlyEffects(PostProcessRenderContext context)
+ {
+ return HasActiveEffects(PostProcessEvent.BeforeTransparent, context);
+ }
+
+ ///
+ /// Checks if this layer has any active effect at the given injection point.
+ ///
+ /// The injection point to look for
+ /// The current render context
+ /// true if any effect at the given injection point is active, false
+ /// otherwise
+ public bool HasActiveEffects(PostProcessEvent evt, PostProcessRenderContext context)
+ {
+ var list = sortedBundles[evt];
+
+ foreach (var item in list)
+ {
+ bool enabledAndSupported = item.bundle.settings.IsEnabledAndSupported(context);
+
+ if (context.isSceneView)
+ {
+ if (item.bundle.attribute.allowInSceneView && enabledAndSupported)
+ return true;
+ }
+ else if (enabledAndSupported)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ void SetupContext(PostProcessRenderContext context)
+ {
+ // Juggling required when a scene with post processing is loaded from an asset bundle
+ // See #1148230
+ // Additional !RuntimeUtilities.isValidResources() to fix #1262826
+ // The static member s_Resources is unset by addressable. The code is ill formed as it
+ // is not made to handle multiple scene.
+ if (m_OldResources != m_Resources || !RuntimeUtilities.isValidResources())
+ {
+ RuntimeUtilities.UpdateResources(m_Resources);
+ m_OldResources = m_Resources;
+ }
+
+ m_IsRenderingInSceneView = context.camera.cameraType == CameraType.SceneView;
+ context.isSceneView = m_IsRenderingInSceneView;
+ context.resources = m_Resources;
+ context.propertySheets = m_PropertySheetFactory;
+ context.debugLayer = debugLayer;
+ context.antialiasing = antialiasingMode;
+ context.temporalAntialiasing = temporalAntialiasing;
+ context.superResolution = superResolution;
+ context.logHistogram = m_LogHistogram;
+
+#if UNITY_2018_2_OR_NEWER
+ context.physicalCamera = context.camera.usePhysicalProperties;
+#endif
+
+ SetLegacyCameraFlags(context);
+
+ // Prepare debug overlay
+ debugLayer.SetFrameSize(context.width, context.height);
+
+ // Unsafe to keep this around but we need it for OnGUI events for debug views
+ // Will be removed eventually
+ m_CurrentContext = context;
+ }
+
+ ///
+ /// Updates the state of the volume system. This should be called before any other
+ /// post-processing method when running in a scriptable render pipeline. You don't need to
+ /// call this method when running in one of the builtin pipelines.
+ ///
+ /// The currently rendering camera.
+ /// A command buffer to fill.
+ public void UpdateVolumeSystem(Camera cam, CommandBuffer cmd)
+ {
+ if (m_SettingsUpdateNeeded)
+ {
+ cmd.BeginSample("VolumeBlending");
+ PostProcessManager.instance.UpdateSettings(this, cam);
+ cmd.EndSample("VolumeBlending");
+ m_TargetPool.Reset();
+
+ // TODO: fix me once VR support is in SRP
+ // Needed in SRP so that _RenderViewportScaleFactor isn't 0
+ if (RuntimeUtilities.scriptableRenderPipelineActive)
+ Shader.SetGlobalFloat(ShaderIDs.RenderViewportScaleFactor, 1f);
+ }
+
+ m_SettingsUpdateNeeded = false;
+ }
+
+ ///
+ /// Renders effects in the bucket. You
+ /// should call before calling this method as it won't
+ /// automatically blit source into destination if no opaque-only effect is active.
+ ///
+ /// The current post-processing context.
+ public void RenderOpaqueOnly(PostProcessRenderContext context)
+ {
+ if (RuntimeUtilities.scriptableRenderPipelineActive)
+ SetupContext(context);
+
+ TextureLerper.instance.BeginFrame(context);
+
+ // Update & override layer settings first (volume blending), will only be done once per
+ // frame, either here or in Render() if there isn't any opaque-only effect to render.
+ // TODO: should be removed, keeping this here for older SRPs
+ UpdateVolumeSystem(context.camera, context.command);
+
+ RenderList(sortedBundles[PostProcessEvent.BeforeTransparent], context, "OpaqueOnly");
+ }
+
+ ///
+ /// Renders all effects not in the bucket.
+ ///
+ /// The current post-processing context.
+ public void Render(PostProcessRenderContext context)
+ {
+ if (RuntimeUtilities.scriptableRenderPipelineActive)
+ SetupContext(context);
+
+ TextureLerper.instance.BeginFrame(context);
+ var cmd = context.command;
+
+ // Update & override layer settings first (volume blending) if the opaque only pass
+ // hasn't been called this frame.
+ // TODO: should be removed, keeping this here for older SRPs
+ UpdateVolumeSystem(context.camera, context.command);
+
+ // Do a NaN killing pass if needed
+ int lastTarget = -1;
+ RenderTargetIdentifier cameraTexture = context.source;
+
+#if UNITY_2019_1_OR_NEWER
+ if (context.stereoActive && context.numberOfEyes > 1 && context.stereoRenderingMode == PostProcessRenderContext.StereoRenderingMode.SinglePass)
+ {
+ cmd.SetSinglePassStereo(SinglePassStereoMode.None);
+ cmd.DisableShaderKeyword("UNITY_SINGLE_PASS_STEREO");
+ }
+#endif
+
+ for (int eye = 0; eye < context.numberOfEyes; eye++)
+ {
+ bool preparedStereoSource = false;
+
+ if (stopNaNPropagation && !m_NaNKilled)
+ {
+ lastTarget = m_TargetPool.Get();
+ context.GetScreenSpaceTemporaryRT(cmd, lastTarget, 0, context.sourceFormat);
+ if (context.stereoActive && context.numberOfEyes > 1)
+ {
+ if (context.stereoRenderingMode == PostProcessRenderContext.StereoRenderingMode.SinglePassInstanced)
+ {
+ cmd.BlitFullscreenTriangleFromTexArray(context.source, lastTarget, RuntimeUtilities.copyFromTexArraySheet, 1, false, eye);
+ preparedStereoSource = true;
+ }
+ else if (context.stereoRenderingMode == PostProcessRenderContext.StereoRenderingMode.SinglePass)
+ {
+ cmd.BlitFullscreenTriangleFromDoubleWide(context.source, lastTarget, RuntimeUtilities.copyStdFromDoubleWideMaterial, 1, eye);
+ preparedStereoSource = true;
+ }
+ }
+ else
+ cmd.BlitFullscreenTriangle(context.source, lastTarget, RuntimeUtilities.copySheet, 1);
+ context.source = lastTarget;
+ m_NaNKilled = true;
+ }
+
+ if (!preparedStereoSource && context.numberOfEyes > 1)
+ {
+ lastTarget = m_TargetPool.Get();
+ context.GetScreenSpaceTemporaryRT(cmd, lastTarget, 0, context.sourceFormat);
+ if (context.stereoActive)
+ {
+ if (context.stereoRenderingMode == PostProcessRenderContext.StereoRenderingMode.SinglePassInstanced)
+ {
+ cmd.BlitFullscreenTriangleFromTexArray(context.source, lastTarget, RuntimeUtilities.copyFromTexArraySheet, 1, false, eye);
+ preparedStereoSource = true;
+ }
+ else if (context.stereoRenderingMode == PostProcessRenderContext.StereoRenderingMode.SinglePass)
+ {
+ cmd.BlitFullscreenTriangleFromDoubleWide(context.source, lastTarget, RuntimeUtilities.copyStdFromDoubleWideMaterial, stopNaNPropagation ? 1 : 0, eye);
+ preparedStereoSource = true;
+ }
+ }
+ context.source = lastTarget;
+ }
+
+ // Right before upscaling & temporal anti-aliasing
+ if (HasActiveEffects(PostProcessEvent.BeforeUpscaling, context))
+ lastTarget = RenderInjectionPoint(PostProcessEvent.BeforeUpscaling, context, "BeforeUpscaling", lastTarget);
+
+ // Do temporal anti-aliasing first
+ if (context.IsTemporalAntialiasingActive())
+ {
+ if (!RuntimeUtilities.scriptableRenderPipelineActive)
+ {
+ if (context.stereoActive)
+ {
+ // We only need to configure all of this once for stereo, during OnPreCull
+ if (context.camera.stereoActiveEye != Camera.MonoOrStereoscopicEye.Right)
+ temporalAntialiasing.ConfigureStereoJitteredProjectionMatrices(context);
+ }
+ else
+ {
+ temporalAntialiasing.ConfigureJitteredProjectionMatrix(context);
+ }
+ }
+
+ var taaTarget = m_TargetPool.Get();
+ var finalDestination = context.destination;
+ context.GetScreenSpaceTemporaryRT(cmd, taaTarget, 0, context.sourceFormat);
+ context.destination = taaTarget;
+ temporalAntialiasing.Render(context);
+ context.source = taaTarget;
+ context.destination = finalDestination;
+
+ if (lastTarget > -1)
+ cmd.ReleaseTemporaryRT(lastTarget);
+
+ lastTarget = taaTarget;
+ }
+ else if (context.IsSuperResolutionActive())
+ {
+ superResolution.ConfigureJitteredProjectionMatrix(context);
+
+ // Set the upscaler's output to full display resolution, as well as for all following post-processing effects
+ context.SetRenderSize(superResolution.displaySize);
+
+ var fsrTarget = m_TargetPool.Get();
+ var finalDestination = context.destination;
+ context.GetScreenSpaceTemporaryRT(cmd, fsrTarget, 0, context.sourceFormat, enableRandomWrite: true);
+ context.destination = fsrTarget;
+ superResolution.colorOpaqueOnly = m_opaqueOnly;
+ superResolution.Render(context);
+ context.source = fsrTarget;
+ context.destination = finalDestination;
+
+ if (lastTarget > -1)
+ cmd.ReleaseTemporaryRT(lastTarget);
+
+ lastTarget = fsrTarget;
+ }
+
+ bool hasBeforeStackEffects = HasActiveEffects(PostProcessEvent.BeforeStack, context);
+ bool hasAfterStackEffects = HasActiveEffects(PostProcessEvent.AfterStack, context) && !breakBeforeColorGrading;
+ bool needsFinalPass = (hasAfterStackEffects
+ || (antialiasingMode == Antialiasing.FastApproximateAntialiasing) || (antialiasingMode == Antialiasing.SubpixelMorphologicalAntialiasing && subpixelMorphologicalAntialiasing.IsSupported()))
+ && !breakBeforeColorGrading;
+
+ // Right before the builtin stack
+ if (hasBeforeStackEffects)
+ lastTarget = RenderInjectionPoint(PostProcessEvent.BeforeStack, context, "BeforeStack", lastTarget);
+
+ // Builtin stack
+ lastTarget = RenderBuiltins(context, !needsFinalPass, lastTarget, eye);
+
+ // After the builtin stack but before the final pass (before FXAA & Dithering)
+ if (hasAfterStackEffects)
+ lastTarget = RenderInjectionPoint(PostProcessEvent.AfterStack, context, "AfterStack", lastTarget);
+
+ // And close with the final pass
+ if (needsFinalPass)
+ RenderFinalPass(context, lastTarget, eye);
+
+ if (context.stereoActive)
+ context.source = cameraTexture;
+ }
+
+#if UNITY_2019_1_OR_NEWER
+ if (context.stereoActive && context.numberOfEyes > 1 && context.stereoRenderingMode == PostProcessRenderContext.StereoRenderingMode.SinglePass)
+ {
+ cmd.SetSinglePassStereo(SinglePassStereoMode.SideBySide);
+ cmd.EnableShaderKeyword("UNITY_SINGLE_PASS_STEREO");
+ }
+#endif
+
+ // Render debug monitors & overlay if requested
+ debugLayer.RenderSpecialOverlays(context);
+ debugLayer.RenderMonitors(context);
+
+ // End frame cleanup
+ TextureLerper.instance.EndFrame();
+ debugLayer.EndFrame();
+ m_SettingsUpdateNeeded = true;
+ m_NaNKilled = false;
+ }
+
+ int RenderInjectionPoint(PostProcessEvent evt, PostProcessRenderContext context, string marker, int releaseTargetAfterUse = -1)
+ {
+ int tempTarget = m_TargetPool.Get();
+ var finalDestination = context.destination;
+
+ var cmd = context.command;
+ context.GetScreenSpaceTemporaryRT(cmd, tempTarget, 0, context.sourceFormat);
+ context.destination = tempTarget;
+ RenderList(sortedBundles[evt], context, marker);
+ context.source = tempTarget;
+ context.destination = finalDestination;
+
+ if (releaseTargetAfterUse > -1)
+ cmd.ReleaseTemporaryRT(releaseTargetAfterUse);
+
+ return tempTarget;
+ }
+
+ void RenderList(List list, PostProcessRenderContext context, string marker)
+ {
+ var cmd = context.command;
+ cmd.BeginSample(marker);
+
+ // First gather active effects - we need this to manage render targets more efficiently
+ m_ActiveEffects.Clear();
+ for (int i = 0; i < list.Count; i++)
+ {
+ var effect = list[i].bundle;
+ if (effect.settings.IsEnabledAndSupported(context))
+ {
+ if (!context.isSceneView || (context.isSceneView && effect.attribute.allowInSceneView))
+ m_ActiveEffects.Add(effect.renderer);
+ }
+ }
+
+ int count = m_ActiveEffects.Count;
+
+ // If there's only one active effect, we can simply execute it and skip the rest
+ if (count == 1)
+ {
+ m_ActiveEffects[0].RenderOrLog(context);
+ }
+ else
+ {
+ // Else create the target chain
+ m_Targets.Clear();
+ m_Targets.Add(context.source); // First target is always source
+
+ int tempTarget1 = m_TargetPool.Get();
+ int tempTarget2 = m_TargetPool.Get();
+
+ for (int i = 0; i < count - 1; i++)
+ m_Targets.Add(i % 2 == 0 ? tempTarget1 : tempTarget2);
+
+ m_Targets.Add(context.destination); // Last target is always destination
+
+ // Render
+ context.GetScreenSpaceTemporaryRT(cmd, tempTarget1, 0, context.sourceFormat);
+ if (count > 2)
+ context.GetScreenSpaceTemporaryRT(cmd, tempTarget2, 0, context.sourceFormat);
+
+ for (int i = 0; i < count; i++)
+ {
+ context.source = m_Targets[i];
+ context.destination = m_Targets[i + 1];
+ m_ActiveEffects[i].RenderOrLog(context);
+ }
+
+ cmd.ReleaseTemporaryRT(tempTarget1);
+ if (count > 2)
+ cmd.ReleaseTemporaryRT(tempTarget2);
+ }
+
+ cmd.EndSample(marker);
+ }
+
+ void ApplyFlip(PostProcessRenderContext context, MaterialPropertyBlock properties)
+ {
+ if (context.flip && !context.isSceneView)
+ properties.SetVector(ShaderIDs.UVTransform, new Vector4(1.0f, 1.0f, 0.0f, 0.0f));
+ else
+ ApplyDefaultFlip(properties);
+ }
+
+ void ApplyDefaultFlip(MaterialPropertyBlock properties)
+ {
+ properties.SetVector(ShaderIDs.UVTransform, SystemInfo.graphicsUVStartsAtTop ? new Vector4(1.0f, -1.0f, 0.0f, 1.0f) : new Vector4(1.0f, 1.0f, 0.0f, 0.0f));
+ }
+
+ int RenderBuiltins(PostProcessRenderContext context, bool isFinalPass, int releaseTargetAfterUse = -1, int eye = -1)
+ {
+ var uberSheet = context.propertySheets.Get(context.resources.shaders.uber);
+ uberSheet.ClearKeywords();
+ uberSheet.properties.Clear();
+ context.uberSheet = uberSheet;
+ context.autoExposureTexture = RuntimeUtilities.whiteTexture;
+ context.bloomBufferNameID = -1;
+
+ if (isFinalPass && context.stereoActive && context.stereoRenderingMode == PostProcessRenderContext.StereoRenderingMode.SinglePassInstanced)
+ uberSheet.EnableKeyword("STEREO_INSTANCING_ENABLED");
+
+ var cmd = context.command;
+ cmd.BeginSample("BuiltinStack");
+
+ int tempTarget = -1;
+ var finalDestination = context.destination;
+
+ if (!isFinalPass)
+ {
+ // Render to an intermediate target as this won't be the final pass
+ tempTarget = m_TargetPool.Get();
+ context.GetScreenSpaceTemporaryRT(cmd, tempTarget, 0, context.sourceFormat);
+ context.destination = tempTarget;
+
+ // Handle FXAA's keep alpha mode
+ if (antialiasingMode == Antialiasing.FastApproximateAntialiasing && !fastApproximateAntialiasing.keepAlpha && RuntimeUtilities.hasAlpha(context.sourceFormat))
+ uberSheet.properties.SetFloat(ShaderIDs.LumaInAlpha, 1f);
+ }
+
+ // Depth of field final combination pass used to be done in Uber which led to artifacts
+ // when used at the same time as Bloom (because both effects used the same source, so
+ // the stronger bloom was, the more DoF was eaten away in out of focus areas)
+ int depthOfFieldTarget = RenderEffect(context, true);
+
+ // Motion blur is a separate pass - could potentially be done after DoF depending on the
+ // kind of results you're looking for...
+ int motionBlurTarget = RenderEffect(context, true);
+
+ // Prepare exposure histogram if needed
+ if (ShouldGenerateLogHistogram(context))
+ m_LogHistogram.Generate(context);
+
+ // Uber effects
+ // 1336238: override xrActiveEye in multipass with the currently rendered eye to fix flickering issue.
+ int xrActiveEyeBackup = context.xrActiveEye;
+ if (context.stereoRenderingMode == PostProcessRenderContext.StereoRenderingMode.MultiPass)
+ context.xrActiveEye = eye;
+ RenderEffect(context);
+ context.xrActiveEye = xrActiveEyeBackup; // restore the eye
+
+ uberSheet.properties.SetTexture(ShaderIDs.AutoExposureTex, context.autoExposureTexture);
+
+ RenderEffect(context);
+ RenderEffect(context);
+ RenderEffect(context);
+ RenderEffect(context);
+ RenderEffect(context);
+
+ if (!breakBeforeColorGrading)
+ RenderEffect(context);
+
+ if (isFinalPass)
+ {
+ uberSheet.EnableKeyword("FINALPASS");
+ dithering.Render(context);
+ ApplyFlip(context, uberSheet.properties);
+ }
+ else
+ {
+ ApplyDefaultFlip(uberSheet.properties);
+ }
+
+ if (context.stereoActive && context.stereoRenderingMode == PostProcessRenderContext.StereoRenderingMode.SinglePassInstanced)
+ {
+ uberSheet.properties.SetFloat(ShaderIDs.DepthSlice, eye);
+ cmd.BlitFullscreenTriangleToTexArray(context.source, context.destination, uberSheet, 0, false, eye);
+ }
+ else if (isFinalPass && context.stereoActive && context.numberOfEyes > 1 && context.stereoRenderingMode == PostProcessRenderContext.StereoRenderingMode.SinglePass)
+ {
+ cmd.BlitFullscreenTriangleToDoubleWide(context.source, context.destination, uberSheet, 0, eye);
+ }
+#if LWRP_1_0_0_OR_NEWER || UNIVERSAL_1_0_0_OR_NEWER
+ else if (isFinalPass)
+ cmd.BlitFullscreenTriangle(context.source, context.destination, uberSheet, 0, false, context.camera.pixelRect);
+#endif
+ else
+ cmd.BlitFullscreenTriangle(context.source, context.destination, uberSheet, 0);
+
+ context.source = context.destination;
+ context.destination = finalDestination;
+
+ if (releaseTargetAfterUse > -1) cmd.ReleaseTemporaryRT(releaseTargetAfterUse);
+ if (motionBlurTarget > -1) cmd.ReleaseTemporaryRT(motionBlurTarget);
+ if (depthOfFieldTarget > -1) cmd.ReleaseTemporaryRT(depthOfFieldTarget);
+ if (context.bloomBufferNameID > -1) cmd.ReleaseTemporaryRT(context.bloomBufferNameID);
+
+ cmd.EndSample("BuiltinStack");
+
+ return tempTarget;
+ }
+
+ // This pass will have to be disabled for HDR screen output as it's an LDR pass
+ void RenderFinalPass(PostProcessRenderContext context, int releaseTargetAfterUse = -1, int eye = -1)
+ {
+ var cmd = context.command;
+ cmd.BeginSample("FinalPass");
+
+ if (breakBeforeColorGrading)
+ {
+ var sheet = context.propertySheets.Get(context.resources.shaders.discardAlpha);
+ if (context.stereoActive && context.stereoRenderingMode == PostProcessRenderContext.StereoRenderingMode.SinglePassInstanced)
+ sheet.EnableKeyword("STEREO_INSTANCING_ENABLED");
+
+ if (context.stereoActive && context.stereoRenderingMode == PostProcessRenderContext.StereoRenderingMode.SinglePassInstanced)
+ {
+ sheet.properties.SetFloat(ShaderIDs.DepthSlice, eye);
+ cmd.BlitFullscreenTriangleToTexArray(context.source, context.destination, sheet, 0, false, eye);
+ }
+ else if (context.stereoActive && context.numberOfEyes > 1 && context.stereoRenderingMode == PostProcessRenderContext.StereoRenderingMode.SinglePass)
+ {
+ cmd.BlitFullscreenTriangleToDoubleWide(context.source, context.destination, sheet, 0, eye);
+ }
+ else
+ cmd.BlitFullscreenTriangle(context.source, context.destination, sheet, 0);
+ }
+ else
+ {
+ var uberSheet = context.propertySheets.Get(context.resources.shaders.finalPass);
+ uberSheet.ClearKeywords();
+ uberSheet.properties.Clear();
+ context.uberSheet = uberSheet;
+ int tempTarget = -1;
+
+ if (context.stereoActive && context.stereoRenderingMode == PostProcessRenderContext.StereoRenderingMode.SinglePassInstanced)
+ uberSheet.EnableKeyword("STEREO_INSTANCING_ENABLED");
+
+ if (antialiasingMode == Antialiasing.FastApproximateAntialiasing)
+ {
+ uberSheet.EnableKeyword(fastApproximateAntialiasing.fastMode
+ ? "FXAA_LOW"
+ : "FXAA"
+ );
+
+ if (RuntimeUtilities.hasAlpha(context.sourceFormat))
+ {
+ if (fastApproximateAntialiasing.keepAlpha)
+ uberSheet.EnableKeyword("FXAA_KEEP_ALPHA");
+ }
+ else
+ uberSheet.EnableKeyword("FXAA_NO_ALPHA");
+ }
+ else if (antialiasingMode == Antialiasing.SubpixelMorphologicalAntialiasing && subpixelMorphologicalAntialiasing.IsSupported())
+ {
+ tempTarget = m_TargetPool.Get();
+ var finalDestination = context.destination;
+ context.GetScreenSpaceTemporaryRT(context.command, tempTarget, 0, context.sourceFormat);
+ context.destination = tempTarget;
+ subpixelMorphologicalAntialiasing.Render(context);
+ context.source = tempTarget;
+ context.destination = finalDestination;
+ }
+
+ dithering.Render(context);
+
+ ApplyFlip(context, uberSheet.properties);
+ if (context.stereoActive && context.stereoRenderingMode == PostProcessRenderContext.StereoRenderingMode.SinglePassInstanced)
+ {
+ uberSheet.properties.SetFloat(ShaderIDs.DepthSlice, eye);
+ cmd.BlitFullscreenTriangleToTexArray(context.source, context.destination, uberSheet, 0, false, eye);
+ }
+ else if (context.stereoActive && context.numberOfEyes > 1 && context.stereoRenderingMode == PostProcessRenderContext.StereoRenderingMode.SinglePass)
+ {
+ cmd.BlitFullscreenTriangleToDoubleWide(context.source, context.destination, uberSheet, 0, eye);
+ }
+ else
+#if LWRP_1_0_0_OR_NEWER || UNIVERSAL_1_0_0_OR_NEWER
+ cmd.BlitFullscreenTriangle(context.source, context.destination, uberSheet, 0, false, context.camera.pixelRect);
+#else
+ cmd.BlitFullscreenTriangle(context.source, context.destination, uberSheet, 0);
+#endif
+
+ if (tempTarget > -1)
+ cmd.ReleaseTemporaryRT(tempTarget);
+ }
+
+ if (releaseTargetAfterUse > -1)
+ cmd.ReleaseTemporaryRT(releaseTargetAfterUse);
+
+ cmd.EndSample("FinalPass");
+ }
+
+ int RenderEffect(PostProcessRenderContext context, bool useTempTarget = false)
+ where T : PostProcessEffectSettings
+ {
+ var effect = GetBundle();
+
+ if (!effect.settings.IsEnabledAndSupported(context))
+ return -1;
+
+ if (m_IsRenderingInSceneView && !effect.attribute.allowInSceneView)
+ return -1;
+
+ if (!useTempTarget)
+ {
+ effect.renderer.RenderOrLog(context);
+ return -1;
+ }
+
+ var finalDestination = context.destination;
+ var tempTarget = m_TargetPool.Get();
+ context.GetScreenSpaceTemporaryRT(context.command, tempTarget, 0, context.sourceFormat);
+ context.destination = tempTarget;
+ effect.renderer.RenderOrLog(context);
+ context.source = tempTarget;
+ context.destination = finalDestination;
+ return tempTarget;
+ }
+
+ bool ShouldGenerateLogHistogram(PostProcessRenderContext context)
+ {
+ bool autoExpo = GetBundle().settings.IsEnabledAndSupported(context);
+ bool lightMeter = debugLayer.lightMeter.IsRequestedAndSupported(context);
+ return autoExpo || lightMeter;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/PostProcessLayer.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessLayer.cs.meta
new file mode 100644
index 0000000..522d05b
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessLayer.cs.meta
@@ -0,0 +1,14 @@
+fileFormatVersion: 2
+guid: 948f4100a11a5c24981795d21301da5c
+timeCreated: 1493713997
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences:
+ - volumeTrigger: {instanceID: 0}
+ - m_Resources: {fileID: 11400000, guid: d82512f9c8e5d4a4d938b575d47f88d4, type: 2}
+ executionOrder: 0
+ icon: {fileID: 2800000, guid: 5f51e0b22aa8cb84b9f422576ce87ff9, type: 3}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/PostProcessManager.cs b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessManager.cs
new file mode 100644
index 0000000..f6b5a01
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessManager.cs
@@ -0,0 +1,462 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine.Assertions;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// This manager tracks all volumes in the scene and does all the interpolation work. It is
+ /// automatically created as soon as Post-processing is active in a scene.
+ ///
+ public sealed class PostProcessManager
+ {
+ static PostProcessManager s_Instance;
+
+ ///
+ /// The current singleton instance of .
+ ///
+ public static PostProcessManager instance
+ {
+ get
+ {
+ if (s_Instance == null)
+ s_Instance = new PostProcessManager();
+
+ return s_Instance;
+ }
+ }
+
+ const int k_MaxLayerCount = 32; // Max amount of layers available in Unity
+ readonly Dictionary> m_SortedVolumes;
+ readonly List m_Volumes;
+ readonly Dictionary m_SortNeeded;
+ readonly List m_BaseSettings;
+ readonly List m_TempColliders;
+
+ ///
+ /// This dictionary maps all available to their
+ /// corresponding . It can be used to list all loaded
+ /// builtin and custom effects.
+ ///
+ public readonly Dictionary settingsTypes;
+
+ PostProcessManager()
+ {
+ m_SortedVolumes = new Dictionary>();
+ m_Volumes = new List();
+ m_SortNeeded = new Dictionary();
+ m_BaseSettings = new List();
+ m_TempColliders = new List(5);
+
+ settingsTypes = new Dictionary();
+ ReloadBaseTypes();
+ }
+
+#if UNITY_EDITOR
+ // Called every time Unity recompile scripts in the editor. We need this to keep track of
+ // any new custom effect the user might add to the project
+ [UnityEditor.Callbacks.DidReloadScripts]
+ static void OnEditorReload()
+ {
+ instance.ReloadBaseTypes();
+ }
+
+#endif
+
+ void CleanBaseTypes()
+ {
+ settingsTypes.Clear();
+
+ foreach (var settings in m_BaseSettings)
+ RuntimeUtilities.Destroy(settings);
+
+ m_BaseSettings.Clear();
+ }
+
+ // This will be called only once at runtime and everytime script reload kicks-in in the
+ // editor as we need to keep track of any compatible post-processing effects in the project
+ void ReloadBaseTypes()
+ {
+ CleanBaseTypes();
+
+ // Rebuild the base type map
+ var types = RuntimeUtilities.GetAllTypesDerivedFrom()
+ .Where(
+ t => t.IsDefined(typeof(PostProcessAttribute), false)
+ && !t.IsAbstract
+ );
+
+ foreach (var type in types)
+ {
+ settingsTypes.Add(type, type.GetAttribute());
+
+ // Create an instance for each effect type, these will be used for the lowest
+ // priority global volume as we need a default state when exiting volume ranges
+ var inst = (PostProcessEffectSettings)ScriptableObject.CreateInstance(type);
+ inst.SetAllOverridesTo(true, false);
+ m_BaseSettings.Add(inst);
+ }
+ }
+
+ ///
+ /// Gets a list of all volumes currently affecting the given layer. Results aren't sorted
+ /// and the list isn't cleared.
+ ///
+ /// The layer to look for
+ /// A list to store the volumes found
+ /// Should we skip disabled volumes?
+ /// Should we skip 0-weight volumes?
+ public void GetActiveVolumes(PostProcessLayer layer, List results, bool skipDisabled = true, bool skipZeroWeight = true)
+ {
+ // If no trigger is set, only global volumes will have influence
+ int mask = layer.volumeLayer.value;
+ var volumeTrigger = layer.volumeTrigger;
+ bool onlyGlobal = volumeTrigger == null;
+ var triggerPos = onlyGlobal ? Vector3.zero : volumeTrigger.position;
+
+ // Sort the cached volume list(s) for the given layer mask if needed and return it
+ var volumes = GrabVolumes(mask);
+
+ // Traverse all volumes
+ foreach (var volume in volumes)
+ {
+ // Skip disabled volumes and volumes without any data or weight
+ if ((skipDisabled && !volume.enabled) || volume.profileRef == null || (skipZeroWeight && volume.weight <= 0f))
+ continue;
+
+ // Global volume always have influence
+ if (volume.isGlobal)
+ {
+ results.Add(volume);
+ continue;
+ }
+
+ if (onlyGlobal)
+ continue;
+
+ // If volume isn't global and has no collider, skip it as it's useless
+ var colliders = m_TempColliders;
+ volume.GetComponents(colliders);
+ if (colliders.Count == 0)
+ continue;
+
+ // Find closest distance to volume, 0 means it's inside it
+ float closestDistanceSqr = float.PositiveInfinity;
+
+ foreach (var collider in colliders)
+ {
+ if (!collider.enabled)
+ continue;
+
+ var closestPoint = collider.ClosestPoint(triggerPos); // 5.6-only API
+ var d = ((closestPoint - triggerPos) / 2f).sqrMagnitude;
+
+ if (d < closestDistanceSqr)
+ closestDistanceSqr = d;
+ }
+
+ colliders.Clear();
+ float blendDistSqr = volume.blendDistance * volume.blendDistance;
+
+ // Check for influence
+ if (closestDistanceSqr <= blendDistSqr)
+ results.Add(volume);
+ }
+ }
+
+ ///
+ /// Gets the highest priority volume affecting a given layer.
+ ///
+ /// The layer to look for
+ /// The highest priority volume affecting the layer
+ public PostProcessVolume GetHighestPriorityVolume(PostProcessLayer layer)
+ {
+ if (layer == null)
+ throw new ArgumentNullException("layer");
+
+ return GetHighestPriorityVolume(layer.volumeLayer);
+ }
+
+ ///
+ /// Gets the highest priority volume affecting in a given
+ /// .
+ ///
+ /// The layer mask to look for
+ /// The highest priority volume affecting the layer mask
+ ///
+ public PostProcessVolume GetHighestPriorityVolume(LayerMask mask)
+ {
+ float highestPriority = float.NegativeInfinity;
+ PostProcessVolume output = null;
+
+ List volumes;
+ if (m_SortedVolumes.TryGetValue(mask, out volumes))
+ {
+ foreach (var volume in volumes)
+ {
+ if (volume.priority > highestPriority)
+ {
+ highestPriority = volume.priority;
+ output = volume;
+ }
+ }
+ }
+
+ return output;
+ }
+
+ ///
+ /// Helper method to spawn a new volume in the scene.
+ ///
+ /// The unity layer to put the volume in
+ /// The priority to set this volume to
+ /// A list of effects to put in this volume
+ ///
+ public PostProcessVolume QuickVolume(int layer, float priority, params PostProcessEffectSettings[] settings)
+ {
+ var gameObject = new GameObject()
+ {
+ name = "Quick Volume",
+ layer = layer,
+ hideFlags = HideFlags.HideAndDontSave
+ };
+
+ var volume = gameObject.AddComponent();
+ volume.priority = priority;
+ volume.isGlobal = true;
+ var profile = volume.profile;
+
+ foreach (var s in settings)
+ {
+ Assert.IsNotNull(s, "Trying to create a volume with null effects");
+ profile.AddSettings(s);
+ }
+
+ return volume;
+ }
+
+ internal void SetLayerDirty(int layer)
+ {
+ Assert.IsTrue(layer >= 0 && layer <= k_MaxLayerCount, "Invalid layer bit");
+
+ foreach (var kvp in m_SortedVolumes)
+ {
+ var mask = kvp.Key;
+
+ if ((mask & (1 << layer)) != 0)
+ m_SortNeeded[mask] = true;
+ }
+ }
+
+ internal void UpdateVolumeLayer(PostProcessVolume volume, int prevLayer, int newLayer)
+ {
+ Assert.IsTrue(prevLayer >= 0 && prevLayer <= k_MaxLayerCount, "Invalid layer bit");
+ Unregister(volume, prevLayer);
+ Unregister(volume, newLayer);
+ Register(volume, newLayer);
+ }
+
+ void Register(PostProcessVolume volume, int layer)
+ {
+ m_Volumes.Add(volume);
+
+ // Look for existing cached layer masks and add it there if needed
+ foreach (var kvp in m_SortedVolumes)
+ {
+ var mask = kvp.Key;
+
+ if ((mask & (1 << layer)) != 0)
+ kvp.Value.Add(volume);
+ }
+
+ SetLayerDirty(layer);
+ }
+
+ internal void Register(PostProcessVolume volume)
+ {
+ int layer = volume.gameObject.layer;
+ Register(volume, layer);
+ }
+
+ void Unregister(PostProcessVolume volume, int layer)
+ {
+ m_Volumes.Remove(volume);
+
+ foreach (var kvp in m_SortedVolumes)
+ {
+ var mask = kvp.Key;
+
+ // Skip layer masks this volume doesn't belong to
+ if ((mask & (1 << layer)) == 0)
+ continue;
+
+ kvp.Value.Remove(volume);
+ }
+ }
+
+ internal void Unregister(PostProcessVolume volume)
+ {
+ Unregister(volume, volume.previousLayer);
+ Unregister(volume, volume.gameObject.layer);
+ }
+
+ // Faster version of OverrideSettings to force replace values in the global state
+ void ReplaceData(PostProcessLayer postProcessLayer)
+ {
+ foreach (var settings in m_BaseSettings)
+ {
+ var target = postProcessLayer.GetBundle(settings.GetType()).settings;
+ int count = settings.parameters.Count;
+
+ for (int i = 0; i < count; i++)
+ target.parameters[i].SetValue(settings.parameters[i]);
+ }
+ }
+
+ internal void UpdateSettings(PostProcessLayer postProcessLayer, Camera camera)
+ {
+ // Reset to base state
+ ReplaceData(postProcessLayer);
+
+ // If no trigger is set, only global volumes will have influence
+ int mask = postProcessLayer.volumeLayer.value;
+ var volumeTrigger = postProcessLayer.volumeTrigger;
+ bool onlyGlobal = volumeTrigger == null;
+ var triggerPos = onlyGlobal ? Vector3.zero : volumeTrigger.position;
+
+ // Sort the cached volume list(s) for the given layer mask if needed and return it
+ var volumes = GrabVolumes(mask);
+
+ // Traverse all volumes
+ foreach (var volume in volumes)
+ {
+#if UNITY_EDITOR
+ // Skip volumes that aren't in the scene currently displayed in the scene view
+ if (!IsVolumeRenderedByCamera(volume, camera))
+ continue;
+#endif
+
+ // Skip disabled volumes and volumes without any data or weight
+ if (!volume.enabled || volume.profileRef == null || volume.weight <= 0f)
+ continue;
+
+ var settings = volume.profileRef.settings;
+
+ // Global volume always have influence
+ if (volume.isGlobal)
+ {
+ postProcessLayer.OverrideSettings(settings, Mathf.Clamp01(volume.weight));
+ continue;
+ }
+
+ if (onlyGlobal)
+ continue;
+
+ // If volume isn't global and has no collider, skip it as it's useless
+ var colliders = m_TempColliders;
+ volume.GetComponents(colliders);
+ if (colliders.Count == 0)
+ continue;
+
+ // Find closest distance to volume, 0 means it's inside it
+ float closestDistanceSqr = float.PositiveInfinity;
+
+ foreach (var collider in colliders)
+ {
+ if (!collider.enabled)
+ continue;
+
+ var closestPoint = collider.ClosestPoint(triggerPos); // 5.6-only API
+ var d = ((closestPoint - triggerPos) / 2f).sqrMagnitude;
+
+ if (d < closestDistanceSqr)
+ closestDistanceSqr = d;
+ }
+
+ colliders.Clear();
+ float blendDistSqr = volume.blendDistance * volume.blendDistance;
+
+ // Volume has no influence, ignore it
+ // Note: Volume doesn't do anything when `closestDistanceSqr = blendDistSqr` but
+ // we can't use a >= comparison as blendDistSqr could be set to 0 in which
+ // case volume would have total influence
+ if (closestDistanceSqr > blendDistSqr)
+ continue;
+
+ // Volume has influence
+ float interpFactor = 1f;
+
+ if (blendDistSqr > 0f)
+ interpFactor = 1f - (closestDistanceSqr / blendDistSqr);
+
+ // No need to clamp01 the interpolation factor as it'll always be in [0;1[ range
+ postProcessLayer.OverrideSettings(settings, interpFactor * Mathf.Clamp01(volume.weight));
+ }
+ }
+
+ List GrabVolumes(LayerMask mask)
+ {
+ List list;
+
+ if (!m_SortedVolumes.TryGetValue(mask, out list))
+ {
+ // New layer mask detected, create a new list and cache all the volumes that belong
+ // to this mask in it
+ list = new List();
+
+ foreach (var volume in m_Volumes)
+ {
+ if ((mask & (1 << volume.gameObject.layer)) == 0)
+ continue;
+
+ list.Add(volume);
+ m_SortNeeded[mask] = true;
+ }
+
+ m_SortedVolumes.Add(mask, list);
+ }
+
+ // Check sorting state
+ bool sortNeeded;
+ if (m_SortNeeded.TryGetValue(mask, out sortNeeded) && sortNeeded)
+ {
+ m_SortNeeded[mask] = false;
+ SortByPriority(list);
+ }
+
+ return list;
+ }
+
+ // Custom insertion sort. First sort will be slower but after that it'll be faster than
+ // using List.Sort() which is also unstable by nature.
+ // Sort order is ascending.
+ static void SortByPriority(List volumes)
+ {
+ Assert.IsNotNull(volumes, "Trying to sort volumes of non-initialized layer");
+
+ for (int i = 1; i < volumes.Count; i++)
+ {
+ var temp = volumes[i];
+ int j = i - 1;
+
+ while (j >= 0 && volumes[j].priority > temp.priority)
+ {
+ volumes[j + 1] = volumes[j];
+ j--;
+ }
+
+ volumes[j + 1] = temp;
+ }
+ }
+
+ static bool IsVolumeRenderedByCamera(PostProcessVolume volume, Camera camera)
+ {
+#if UNITY_2018_3_OR_NEWER && UNITY_EDITOR
+ return UnityEditor.SceneManagement.StageUtility.IsGameObjectRenderedByCamera(volume.gameObject, camera);
+#else
+ return true;
+#endif
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/PostProcessManager.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessManager.cs.meta
new file mode 100644
index 0000000..8baecdb
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessManager.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 18ff20fea2d39cf428e31d3e75b4ae79
+timeCreated: 1485268412
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/PostProcessProfile.cs b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessProfile.cs
new file mode 100644
index 0000000..7f4b543
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessProfile.cs
@@ -0,0 +1,190 @@
+using System;
+using System.Collections.Generic;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// An asset holding a set of post-processing settings to use with a .
+ ///
+ ///
+ public sealed class PostProcessProfile : ScriptableObject
+ {
+ ///
+ /// A list of all settings stored in this profile.
+ ///
+ [Tooltip("A list of all settings currently stored in this profile.")]
+ public List settings = new List();
+
+ ///
+ /// Sets to true if the content of the profile has changed. This is only really used
+ /// in the editor to handle inspector refreshes.
+ ///
+ [NonSerialized]
+ public bool isDirty = true;
+
+ void OnEnable()
+ {
+ // Make sure every setting is valid. If a profile holds a script that doesn't exist
+ // anymore, nuke it to keep the profile clean. Note that if you delete a script that is
+ // currently in use in a profile you'll still get a one-time error in the console, it's
+ // harmless and happens because Unity does a redraw of the editor (and thus the current
+ // frame) before the recompilation step.
+ settings.RemoveAll(x => x == null);
+ }
+
+ ///
+ /// Adds settings for an effect to the profile.
+ ///
+ /// A type of
+ /// The instance created from the given type
+ ///
+ public T AddSettings()
+ where T : PostProcessEffectSettings
+ {
+ return (T)AddSettings(typeof(T));
+ }
+
+ ///
+ /// Adds settings for an effect to the profile.
+ ///
+ /// A type of
+ /// The instance created from the given type
+ ///
+ public PostProcessEffectSettings AddSettings(Type type)
+ {
+ if (HasSettings(type))
+ throw new InvalidOperationException("Effect already exists in the stack");
+
+ var effect = (PostProcessEffectSettings)CreateInstance(type);
+ effect.hideFlags = HideFlags.HideInInspector | HideFlags.HideInHierarchy;
+ effect.name = type.Name;
+ effect.enabled.value = true;
+ settings.Add(effect);
+ isDirty = true;
+ return effect;
+ }
+
+ ///
+ /// Adds settings for an effect to the profile.
+ ///
+ /// An instance of
+ /// The given effect instance
+ ///
+ public PostProcessEffectSettings AddSettings(PostProcessEffectSettings effect)
+ {
+ if (HasSettings(settings.GetType()))
+ throw new InvalidOperationException("Effect already exists in the stack");
+
+ settings.Add(effect);
+ isDirty = true;
+ return effect;
+ }
+
+ ///
+ /// Removes settings for an effect from the profile.
+ ///
+ /// The type to look for and remove from the profile
+ /// Thrown if the effect doesn't exist in the
+ /// profile
+ public void RemoveSettings()
+ where T : PostProcessEffectSettings
+ {
+ RemoveSettings(typeof(T));
+ }
+
+ ///
+ /// Removes settings for an effect from the profile.
+ ///
+ /// The type to look for and remove from the profile
+ /// Thrown if the effect doesn't exist in the
+ /// profile
+ public void RemoveSettings(Type type)
+ {
+ int toRemove = -1;
+
+ for (int i = 0; i < settings.Count; i++)
+ {
+ if (settings[i].GetType() == type)
+ {
+ toRemove = i;
+ break;
+ }
+ }
+
+ if (toRemove < 0)
+ throw new InvalidOperationException("Effect doesn't exist in the profile");
+
+ settings.RemoveAt(toRemove);
+ isDirty = true;
+ }
+
+ ///
+ /// Checks if an effect has been added to the profile.
+ ///
+ /// The type to look for
+ /// true if the effect exists in the profile, false otherwise
+ public bool HasSettings()
+ where T : PostProcessEffectSettings
+ {
+ return HasSettings(typeof(T));
+ }
+
+ ///
+ /// Checks if an effect has been added to the profile.
+ ///
+ /// The type to look for
+ /// true if the effect exists in the profile, false otherwise
+ public bool HasSettings(Type type)
+ {
+ foreach (var setting in settings)
+ {
+ if (setting.GetType() == type)
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Returns settings for a given effect type.
+ ///
+ /// The type to look for
+ /// Settings for the given effect type, null otherwise
+ public T GetSetting() where T : PostProcessEffectSettings
+ {
+ foreach (var setting in settings)
+ {
+ if (setting is T)
+ return setting as T;
+ }
+
+ return null;
+ }
+
+ ///
+ /// Gets settings for a given effect type.
+ ///
+ /// The type to look for
+ /// When this method returns, contains the value associated with
+ /// the specified type, if the type is found; otherwise, this parameter will be null.
+ /// This parameter is passed uninitialized.
+ /// true if the effect exists in the profile, false otherwise
+ public bool TryGetSettings(out T outSetting)
+ where T : PostProcessEffectSettings
+ {
+ var type = typeof(T);
+ outSetting = null;
+
+ foreach (var setting in settings)
+ {
+ if (setting.GetType() == type)
+ {
+ outSetting = (T)setting;
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/PostProcessProfile.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessProfile.cs.meta
new file mode 100644
index 0000000..940b439
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessProfile.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 8e6292b2c06870d4495f009f912b9600
+timeCreated: 1507906488
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {fileID: 2800000, guid: 5f51e0b22aa8cb84b9f422576ce87ff9, type: 3}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/PostProcessRenderContext.cs b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessRenderContext.cs
new file mode 100644
index 0000000..bc6f560
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessRenderContext.cs
@@ -0,0 +1,461 @@
+using System.Collections.Generic;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+#if (ENABLE_VR_MODULE && ENABLE_VR)
+ using XRSettings = UnityEngine.XR.XRSettings;
+#endif
+
+ ///
+ /// A context object passed around all post-processing effects in a frame.
+ ///
+ public sealed class PostProcessRenderContext
+ {
+ // -----------------------------------------------------------------------------------------
+ // The following should be filled by the render pipeline
+
+ Camera m_Camera;
+
+ ///
+ /// The camera currently being rendered.
+ ///
+ public Camera camera
+ {
+ get { return m_Camera; }
+ set
+ {
+ m_Camera = value;
+
+#if !UNITY_SWITCH && (ENABLE_VR_MODULE && ENABLE_VR)
+ if (m_Camera.stereoEnabled)
+ {
+ var xrDesc = XRSettings.eyeTextureDesc;
+ stereoRenderingMode = StereoRenderingMode.SinglePass;
+ numberOfEyes = 1;
+
+#if UNITY_2018_3_OR_NEWER
+ if (XRSettings.stereoRenderingMode == XRSettings.StereoRenderingMode.MultiPass)
+ stereoRenderingMode = StereoRenderingMode.MultiPass;
+#endif
+
+#if UNITY_STANDALONE || UNITY_EDITOR || UNITY_PS4 || UNITY_PS5
+ if (xrDesc.dimension == TextureDimension.Tex2DArray)
+ stereoRenderingMode = StereoRenderingMode.SinglePassInstanced;
+#endif
+ if (stereoRenderingMode == StereoRenderingMode.SinglePassInstanced)
+ numberOfEyes = 2;
+
+ width = xrDesc.width;
+ height = xrDesc.height;
+ m_sourceDescriptor = xrDesc;
+
+ if (m_Camera.stereoActiveEye == Camera.MonoOrStereoscopicEye.Right)
+ xrActiveEye = (int)Camera.StereoscopicEye.Right;
+
+ screenWidth = XRSettings.eyeTextureWidth;
+ screenHeight = XRSettings.eyeTextureHeight;
+ stereoActive = true;
+ }
+ else
+#endif
+ {
+ width = m_Camera.pixelWidth;
+ height = m_Camera.pixelHeight;
+ m_sourceDescriptor.width = width;
+ m_sourceDescriptor.height = height;
+ screenWidth = width;
+ screenHeight = height;
+ stereoActive = false;
+ numberOfEyes = 1;
+ }
+ }
+ }
+
+ public void SetRenderSize(Vector2Int renderSize)
+ {
+ // TODO: I suppose we should support XR as well at some point
+ width = renderSize.x;
+ height = renderSize.y;
+ m_sourceDescriptor.width = width;
+ m_sourceDescriptor.height = height;
+ }
+
+ ///
+ /// The command buffer to fill render commands in.
+ ///
+ public CommandBuffer command { get; set; }
+
+ ///
+ /// The source target for this pass (can't be the same as ).
+ ///
+ public RenderTargetIdentifier source { get; set; }
+
+ ///
+ /// The destination target for this pass (can't be the same as ).
+ ///
+ public RenderTargetIdentifier destination { get; set; }
+
+ ///
+ /// The texture format used for the source target.
+ ///
+ // We need this to be set explictely as we don't have any way of knowing if we're rendering
+ // using HDR or not as scriptable render pipelines may ignore the HDR toggle on camera
+ // completely
+ public RenderTextureFormat sourceFormat { get; set; }
+
+ ///
+ /// Should we flip the last pass?
+ ///
+ public bool flip { get; set; }
+
+ // -----------------------------------------------------------------------------------------
+ // The following is auto-populated by the post-processing stack
+
+ ///
+ /// The resource asset contains reference to external resources (shaders, textures...).
+ ///
+ public PostProcessResources resources { get; internal set; }
+
+ ///
+ /// The property sheet factory handled by the currently active .
+ ///
+ public PropertySheetFactory propertySheets { get; internal set; }
+
+ ///
+ /// A dictionary to store custom user data objects. This is handy to share data between
+ /// custom effects.
+ ///
+ public Dictionary userData { get; private set; }
+
+ ///
+ /// A reference to the internal debug layer.
+ ///
+ public PostProcessDebugLayer debugLayer { get; internal set; }
+
+ ///
+ /// The current camera width (in pixels).
+ ///
+ public int width { get; private set; }
+
+ ///
+ /// The current camera height (in pixels).
+ ///
+ public int height { get; private set; }
+
+ ///
+ /// Is stereo rendering active?
+ ///
+ public bool stereoActive { get; private set; }
+
+ ///
+ /// The current active rendering eye (for XR).
+ ///
+ public int xrActiveEye { get; set; }
+
+ ///
+ /// The number of eyes for XR outputs.
+ ///
+ public int numberOfEyes { get; private set; }
+
+ ///
+ /// Available XR rendering modes.
+ ///
+ public enum StereoRenderingMode
+ {
+ ///
+ /// Multi-pass.
+ ///
+ MultiPass = 0,
+
+ ///
+ /// Single-pass.
+ ///
+ SinglePass,
+
+ ///
+ /// Single-pass instanced.
+ ///
+ SinglePassInstanced,
+
+ ///
+ /// Single-pass multi-view.
+ ///
+ SinglePassMultiview
+ }
+
+ ///
+ /// The current rendering mode for XR.
+ ///
+ public StereoRenderingMode stereoRenderingMode { get; private set; }
+
+ ///
+ /// The width of the logical screen size.
+ ///
+ public int screenWidth { get; private set; }
+
+ ///
+ /// The height of the logical screen size.
+ ///
+ public int screenHeight { get; private set; }
+
+ ///
+ /// Are we currently rendering in the scene view?
+ ///
+ public bool isSceneView { get; internal set; }
+
+ ///
+ /// The current anti-aliasing method used by the camera.
+ ///
+ public PostProcessLayer.Antialiasing antialiasing { get; internal set; }
+
+ ///
+ /// A reference to the temporal anti-aliasing settings for the rendering layer. This is
+ /// mostly used to grab the jitter vector and other TAA-related values when an effect needs
+ /// to do temporal reprojection.
+ ///
+ public TemporalAntialiasing temporalAntialiasing { get; internal set; }
+
+ ///
+ /// A reference to the FSR2 settings for the rendering layer.
+ ///
+ public SuperResolution superResolution { get; internal set; }
+
+ // Internal values used for builtin effects
+ // Beware, these may not have been set before a specific builtin effect has been executed
+ internal PropertySheet uberSheet;
+ internal Texture autoExposureTexture;
+ internal LogHistogram logHistogram;
+ internal Texture logLut;
+ internal AutoExposure autoExposure;
+ internal int bloomBufferNameID;
+#if UNITY_2018_2_OR_NEWER
+ internal bool physicalCamera;
+#endif
+
+ ///
+ /// Resets the state of this context object. This is called by the render pipeline on every
+ /// frame and allows re-using the same context object between frames without having to
+ /// recreate a new one.
+ ///
+ public void Reset()
+ {
+ m_Camera = null;
+ width = 0;
+ height = 0;
+ m_sourceDescriptor = new RenderTextureDescriptor(0, 0);
+#if UNITY_2018_2_OR_NEWER
+ physicalCamera = false;
+#endif
+ stereoActive = false;
+ xrActiveEye = (int)Camera.StereoscopicEye.Left;
+ screenWidth = 0;
+ screenHeight = 0;
+
+ command = null;
+ source = 0;
+ destination = 0;
+ sourceFormat = RenderTextureFormat.ARGB32;
+ flip = false;
+
+ resources = null;
+ propertySheets = null;
+ debugLayer = null;
+ isSceneView = false;
+ antialiasing = PostProcessLayer.Antialiasing.None;
+ temporalAntialiasing = null;
+
+ uberSheet = null;
+ autoExposureTexture = null;
+ logLut = null;
+ autoExposure = null;
+ bloomBufferNameID = -1;
+
+ if (userData == null)
+ userData = new Dictionary();
+
+ userData.Clear();
+ }
+
+ ///
+ /// Checks if temporal anti-aliasing is supported and enabled.
+ ///
+ /// true if temporal anti-aliasing is supported and enabled, false
+ /// otherwise
+ public bool IsTemporalAntialiasingActive()
+ {
+ return antialiasing == PostProcessLayer.Antialiasing.TemporalAntialiasing
+ && !isSceneView
+ && temporalAntialiasing.IsSupported();
+ }
+
+ public bool IsSuperResolutionActive()
+ {
+ return antialiasing == PostProcessLayer.Antialiasing.SuperResolution
+ && Application.isPlaying
+ && !isSceneView
+ && superResolution.IsSupported();
+ }
+
+ ///
+ /// Checks if a specific debug overlay is enabled.
+ ///
+ /// The debug overlay to look for
+ /// true if the specified debug overlay is enable, false
+ /// otherwise
+ public bool IsDebugOverlayEnabled(DebugOverlay overlay)
+ {
+ return debugLayer.debugOverlay == overlay;
+ }
+
+ ///
+ /// Blit a source render target to the debug overlay target. This is a direct shortcut to
+ /// .
+ ///
+ /// The command buffer to send render commands to
+ /// The source target
+ /// The property sheet to use for the blit
+ /// The pass to use for the property sheet
+ ///
+ public void PushDebugOverlay(CommandBuffer cmd, RenderTargetIdentifier source, PropertySheet sheet, int pass)
+ {
+ debugLayer.PushDebugOverlay(cmd, source, sheet, pass);
+ }
+
+ // TODO: Change w/h name to texture w/h in order to make
+ // size usages explicit
+ RenderTextureDescriptor m_sourceDescriptor;
+ internal RenderTextureDescriptor GetDescriptor(int depthBufferBits = 0, RenderTextureFormat colorFormat = RenderTextureFormat.Default, RenderTextureReadWrite readWrite = RenderTextureReadWrite.Default)
+ {
+ var modifiedDesc = new RenderTextureDescriptor(m_sourceDescriptor.width, m_sourceDescriptor.height,
+ m_sourceDescriptor.colorFormat, depthBufferBits);
+ modifiedDesc.dimension = m_sourceDescriptor.dimension;
+ modifiedDesc.volumeDepth = m_sourceDescriptor.volumeDepth;
+ modifiedDesc.vrUsage = m_sourceDescriptor.vrUsage;
+ modifiedDesc.msaaSamples = m_sourceDescriptor.msaaSamples;
+ modifiedDesc.memoryless = m_sourceDescriptor.memoryless;
+
+ modifiedDesc.useMipMap = m_sourceDescriptor.useMipMap;
+ modifiedDesc.autoGenerateMips = m_sourceDescriptor.autoGenerateMips;
+ modifiedDesc.enableRandomWrite = m_sourceDescriptor.enableRandomWrite;
+ modifiedDesc.shadowSamplingMode = m_sourceDescriptor.shadowSamplingMode;
+
+#if UNITY_2019_1_OR_NEWER
+ if (RuntimeUtilities.IsDynamicResolutionEnabled(m_Camera))
+ modifiedDesc.useDynamicScale = true;
+#endif
+
+ if (colorFormat != RenderTextureFormat.Default)
+ modifiedDesc.colorFormat = colorFormat;
+
+#if UNITY_2019_1_OR_NEWER
+ if (readWrite == RenderTextureReadWrite.sRGB)
+ modifiedDesc.sRGB = true;
+ else if (readWrite == RenderTextureReadWrite.Linear)
+ modifiedDesc.sRGB = false;
+ else if (readWrite == RenderTextureReadWrite.Default)
+ modifiedDesc.sRGB = QualitySettings.activeColorSpace != ColorSpace.Gamma;
+#else
+ modifiedDesc.sRGB = readWrite != RenderTextureReadWrite.Linear;
+#endif
+
+ return modifiedDesc;
+ }
+
+ ///
+ /// Grabs a temporary render target with the current display size.
+ ///
+ /// The command buffer to grab a render target from
+ /// The shader property name for this texture
+ /// The number of bits to use for the depth buffer
+ /// The render texture format
+ /// The color space conversion mode
+ /// The texture filtering mode
+ /// Override the display width; use 0 to disable the override
+ /// Override the display height; use 0 to disable the override
+ /// Enable random access write into this render texture
+ public void GetScreenSpaceTemporaryRT(CommandBuffer cmd, int nameID,
+ int depthBufferBits = 0, RenderTextureFormat colorFormat = RenderTextureFormat.Default, RenderTextureReadWrite readWrite = RenderTextureReadWrite.Default,
+ FilterMode filter = FilterMode.Bilinear, int widthOverride = 0, int heightOverride = 0, bool enableRandomWrite = false)
+ {
+ var desc = GetDescriptor(depthBufferBits, colorFormat, readWrite);
+ if (widthOverride > 0)
+ desc.width = widthOverride;
+ if (heightOverride > 0)
+ desc.height = heightOverride;
+
+ //intermediates in VR are unchanged
+ if (stereoActive && desc.dimension == Rendering.TextureDimension.Tex2DArray)
+ desc.dimension = Rendering.TextureDimension.Tex2D;
+
+ if (enableRandomWrite)
+ desc.enableRandomWrite = true;
+
+#if UNITY_2019_1_OR_NEWER
+ cmd.GetTemporaryRT(nameID, desc, filter);
+#elif UNITY_2017_3_OR_NEWER
+ cmd.GetTemporaryRT(nameID, desc.width, desc.height, desc.depthBufferBits, filter, desc.colorFormat, readWrite, desc.msaaSamples, desc.enableRandomWrite, desc.memoryless, RuntimeUtilities.IsDynamicResolutionEnabled(m_Camera));
+#else
+ cmd.GetTemporaryRT(nameID, desc.width, desc.height, desc.depthBufferBits, filter, desc.colorFormat, readWrite, desc.msaaSamples, desc.enableRandomWrite, desc.memoryless);
+#endif
+ }
+
+ ///
+ /// Grabs a temporary render target with the current display size.
+ ///
+ /// The number of bits to use for the depth buffer
+ /// The render texture format
+ /// The color space conversion mode
+ /// Override the display width; use 0 to disable the override
+ /// Override the display height; use 0 to disable the override
+ /// A temporary render target
+ public RenderTexture GetScreenSpaceTemporaryRT(int depthBufferBits = 0, RenderTextureFormat colorFormat = RenderTextureFormat.Default,
+ RenderTextureReadWrite readWrite = RenderTextureReadWrite.Default, int widthOverride = 0, int heightOverride = 0)
+ {
+ var desc = GetDescriptor(depthBufferBits, colorFormat, readWrite);
+ if (widthOverride > 0)
+ desc.width = widthOverride;
+ if (heightOverride > 0)
+ desc.height = heightOverride;
+
+ return RenderTexture.GetTemporary(desc);
+ }
+
+ ///
+ /// Update current single-pass stereo state for TAA, AO, etc.
+ ///
+ /// The enabled state of Temporal Anti-aliasing
+ /// The enabled state of Ambient Occlusion
+ /// The enabled state of Screen-space Reflections
+ public void UpdateSinglePassStereoState(bool isTAAEnabled, bool isAOEnabled, bool isSSREnabled)
+ {
+#if UNITY_2019_1_OR_NEWER && ENABLE_VR_MODULE && ENABLE_VR
+ var xrDesc = XRSettings.eyeTextureDesc;
+ screenWidth = XRSettings.eyeTextureWidth;
+
+ if (stereoRenderingMode == StereoRenderingMode.SinglePass)
+ {
+ //For complex effects, it's more efficient to disable XR single-pass interface
+ if (isTAAEnabled || isAOEnabled || isSSREnabled)
+ {
+ numberOfEyes = 1;
+ }
+ else
+ {
+ //Use XR-interface method:
+ //We take care of providing stereoized camera render texture to postprocessing framework and rendering out the final postprocessed results to the each of the eye textures
+ // https://docs.google.com/document/d/1hANbhKCRIJs6ww7XoAIXbX3ArdAs7OBOTfZL1MqgtPI
+
+ numberOfEyes = 2;
+ xrDesc.width /= 2;
+ xrDesc.vrUsage = VRTextureUsage.None;
+ screenWidth /= 2;
+ }
+
+ width = xrDesc.width;
+ height = xrDesc.height;
+ m_sourceDescriptor = xrDesc;
+ }
+#endif
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/PostProcessRenderContext.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessRenderContext.cs.meta
new file mode 100644
index 0000000..780771f
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessRenderContext.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: b7733f6a6fd11474e8fc598901f90fab
+timeCreated: 1488801729
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/PostProcessResources.cs b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessResources.cs
new file mode 100644
index 0000000..fb9e469
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessResources.cs
@@ -0,0 +1,310 @@
+using System;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// This asset is used to store references to shaders and other resources we might need at
+ /// runtime without having to use a `Resources` folder. This allows for better memory management,
+ /// better dependency tracking and better interoperability with asset bundles.
+ ///
+ public sealed class PostProcessResources : ScriptableObject
+ {
+ ///
+ /// All the shaders used by post-processing.
+ ///
+ [Serializable]
+ public sealed class Shaders
+ {
+ ///
+ /// The shader used for the bloom effect.
+ ///
+ public Shader bloom;
+
+ ///
+ /// The shader used for internal blit copies.
+ ///
+ public Shader copy;
+
+ ///
+ /// The shader used for built-in blit copies in the built-in pipeline.
+ ///
+ public Shader copyStd;
+
+ ///
+ /// The shader used for built-in blit copies in the built-in pipeline when using a
+ /// texture array (for stereo rendering).
+ ///
+ public Shader copyStdFromTexArray;
+
+ ///
+ /// The shader used for built-in blit copies in the built-in pipeline when using a
+ /// double-wide texture (for stereo rendering).
+ ///
+ public Shader copyStdFromDoubleWide;
+
+ ///
+ /// The shader used to kill the alpha.
+ ///
+ public Shader discardAlpha;
+
+ ///
+ /// The shader used for the depth of field effect.
+ ///
+ public Shader depthOfField;
+
+ ///
+ /// The shader used for the final pass.
+ ///
+ public Shader finalPass;
+
+ ///
+ /// The shader used to generate the grain texture.
+ ///
+ public Shader grainBaker;
+
+ ///
+ /// The shader used for the motion blur effect.
+ ///
+ public Shader motionBlur;
+
+ ///
+ /// The shader used for the temporal anti-aliasing effect.
+ ///
+ public Shader temporalAntialiasing;
+
+ ///
+ /// The shader used for the sub-pixel morphological anti-aliasing effect.
+ ///
+ public Shader subpixelMorphologicalAntialiasing;
+
+ ///
+ /// The shader use by the volume manager to interpolate between two 2D textures.
+ ///
+ public Shader texture2dLerp;
+
+ ///
+ /// The uber shader that combine several effects into one.
+ ///
+ public Shader uber;
+
+ ///
+ /// The shader used to bake the 2D lookup table for color grading.
+ ///
+ public Shader lut2DBaker;
+
+ ///
+ /// The shader used to draw the light meter monitor.
+ ///
+ public Shader lightMeter;
+
+ ///
+ /// The shader used to draw the histogram monitor.
+ ///
+ public Shader gammaHistogram;
+
+ ///
+ /// The shader used to draw the waveform monitor.
+ ///
+ public Shader waveform;
+
+ ///
+ /// The shader used to draw the vectorscope monitor.
+ ///
+ public Shader vectorscope;
+
+ ///
+ /// The shader used to draw debug overlays.
+ ///
+ public Shader debugOverlays;
+
+ ///
+ /// The shader used for the deferred fog effect.
+ ///
+ public Shader deferredFog;
+
+ ///
+ /// The shader used for the scalable ambient occlusion effect.
+ ///
+ public Shader scalableAO;
+
+ ///
+ /// The shader used for the multi-scale ambient occlusion effect.
+ ///
+ public Shader multiScaleAO;
+
+ ///
+ /// The shader used for the screen-space reflection effect.
+ ///
+ public Shader screenSpaceReflections;
+
+ ///
+ /// Returns a copy of this class and its content.
+ ///
+ /// A copy of this class and its content.
+ public Shaders Clone()
+ {
+ return (Shaders)MemberwiseClone();
+ }
+ }
+
+ ///
+ /// All the compute shaders used by post-processing.
+ ///
+ [Serializable]
+ public sealed class ComputeShaders
+ {
+ ///
+ /// The compute shader used for the auto-exposure effect.
+ ///
+ public ComputeShader autoExposure;
+
+ ///
+ /// The compute shader used to compute an histogram of the current frame.
+ ///
+ public ComputeShader exposureHistogram;
+
+ ///
+ /// The compute shader used to bake the 3D lookup table for color grading.
+ ///
+ public ComputeShader lut3DBaker;
+
+ ///
+ /// The compute shader used by the volume manager to interpolate between two 3D textures.
+ ///
+ public ComputeShader texture3dLerp;
+
+ ///
+ /// The compute shader used to compute the histogram monitor.
+ ///
+ public ComputeShader gammaHistogram;
+
+ ///
+ /// The compute shader used to compute the waveform monitor.
+ ///
+ public ComputeShader waveform;
+
+ ///
+ /// The compute shader used to compute the vectorscope monitor.
+ ///
+ public ComputeShader vectorscope;
+
+ ///
+ /// The compute shader used for the first downsampling pass of MSVO.
+ ///
+ public ComputeShader multiScaleAODownsample1;
+
+ ///
+ /// The compute shader used for the second downsampling pass of MSVO.
+ ///
+ public ComputeShader multiScaleAODownsample2;
+
+ ///
+ /// The compute shader used for the render pass of MSVO.
+ ///
+ public ComputeShader multiScaleAORender;
+
+ ///
+ /// The compute shader used for the upsampling pass of MSVO.
+ ///
+ public ComputeShader multiScaleAOUpsample;
+
+ ///
+ /// The compute shader used to a fast gaussian downsample.
+ ///
+ public ComputeShader gaussianDownsample;
+
+ ///
+ /// Compute shaders that need to be looked up by name.
+ ///
+ public NamedComputeShader[] namedShaders;
+
+ ///
+ /// Returns a copy of this class and its content.
+ ///
+ /// A copy of this class and its content.
+ public ComputeShaders Clone()
+ {
+ return (ComputeShaders)MemberwiseClone();
+ }
+
+ public ComputeShader FindComputeShader(string name)
+ {
+ for (int i = 0; i < namedShaders.Length; ++i)
+ {
+ if (namedShaders[i].name == name)
+ return namedShaders[i].shader;
+ }
+
+ return null;
+ }
+ }
+
+ [Serializable]
+ public class NamedComputeShader
+ {
+ public string name;
+ public ComputeShader shader;
+ }
+
+ ///
+ /// A set of textures needed by the sub-pixel morphological anti-aliasing effect.
+ ///
+ [Serializable]
+ public sealed class SMAALuts
+ {
+ ///
+ /// The area lookup table.
+ ///
+ public Texture2D area;
+
+ ///
+ /// The search lookup table.
+ ///
+ public Texture2D search;
+ }
+
+ ///
+ /// A set of 64x64, single-channel blue noise textures.
+ ///
+ public Texture2D[] blueNoise64;
+
+ ///
+ /// A set of 256x256, single-channel blue noise textures.
+ ///
+ public Texture2D[] blueNoise256;
+
+ ///
+ /// Lookup tables used by the sub-pixel morphological anti-aliasing effect.
+ ///
+ public SMAALuts smaaLuts;
+
+ ///
+ /// All the shaders used by post-processing.
+ ///
+ public Shaders shaders;
+
+ ///
+ /// All the compute shaders used by post-processing.
+ ///
+ public ComputeShaders computeShaders;
+
+#if UNITY_EDITOR
+ ///
+ /// A delegate used to track resource changes.
+ ///
+ public delegate void ChangeHandler();
+
+ ///
+ /// Set this callback to be notified of resource changes.
+ ///
+ public ChangeHandler changeHandler;
+
+ void OnValidate()
+ {
+ if (changeHandler != null)
+ changeHandler();
+ }
+
+#endif
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/PostProcessResources.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessResources.cs.meta
new file mode 100644
index 0000000..6111ab7
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessResources.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 30f4b897495c7ad40b2d47143e02aaba
+timeCreated: 1493713089
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/PostProcessVolume.cs b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessVolume.cs
new file mode 100644
index 0000000..fa78775
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessVolume.cs
@@ -0,0 +1,279 @@
+using System.Collections.Generic;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ //
+ // Here's a quick look at the architecture of this framework and how it's integrated into Unity
+ // (written between versions 5.6 and 2017.1):
+ //
+ // Users have to be able to plug in their own effects without having to modify the codebase and
+ // these custom effects should work out-of-the-box with all the other features we provide
+ // (volume blending etc). This relies on heavy use of polymorphism, but the only way to get
+ // the serialization system to work well with polymorphism in Unity is to use ScriptableObjects.
+ //
+ // Users can push their custom effects at different (hardcoded) injection points.
+ //
+ // Each effect consists of at least two classes (+ shaders): a POD "Settings" class which only
+ // stores parameters, and a "Renderer" class that holds the rendering logic. Settings are linked
+ // to renderers using a PostProcessAttribute. These are automatically collected at init time
+ // using reflection. Settings in this case are ScriptableObjects, we only need to serialize
+ // these.
+ //
+ // We could store these settings object straight into each volume and call it a day, but
+ // unfortunately there's one feature of Unity that doesn't work well with scene-stored assets:
+ // prefabs. So we need to store all of these settings in a disk-asset and treat them as
+ // sub-assets.
+ //
+ // Note: We have to use ScriptableObject for everything but these don't work with the Animator
+ // tool. It's unfortunate but it's the only way to make it easily extensible. On the other
+ // hand, users can animate post-processing effects using Volumes or straight up scripting.
+ //
+ // Volume blending leverages the physics system for distance checks to the nearest point on
+ // volume colliders. Each volume can have several colliders or any type (cube, mesh...), making
+ // it quite a powerful feature to use.
+ //
+ // Volumes & blending are handled by a singleton manager (see PostProcessManager).
+ //
+ // Rendering is handled by a PostProcessLayer component living on the camera, which mean you
+ // can easily toggle post-processing on & off or change the anti-aliasing type per-camera,
+ // which is very useful when doing multi-layered camera rendering or any other technique that
+ // involves multiple-camera setups. This PostProcessLayer component can also filters volumes
+ // by layers (as in Unity layers) so you can easily choose which volumes should affect the
+ // camera.
+ //
+ // All post-processing shaders MUST use the custom Standard Shader Library bundled with the
+ // framework. The reason for that is because the codebase is meant to work without any
+ // modification on the Classic Render Pipelines (Forward, Deferred...) and the upcoming
+ // Scriptable Render Pipelines (HDPipe, LDPipe...). But these don't have compatible shader
+ // libraries so instead of writing two code paths we chose to provide a minimalist, generic
+ // Standard Library geared toward post-processing use. An added bonus to that if users create
+ // their own post-processing effects using this framework, then they'll work without any
+ // modification on both Classic and Scriptable Render Pipelines.
+ //
+
+ ///
+ /// A post-process volume component holding a post-process profile.
+ ///
+ ///
+#if UNITY_2018_3_OR_NEWER
+ [ExecuteAlways]
+#else
+ [ExecuteInEditMode]
+#endif
+ [AddComponentMenu("Rendering/Post-process Volume", 1001)]
+ public sealed class PostProcessVolume : MonoBehaviour
+ {
+ ///
+ /// The shared profile of this volume.
+ /// Modifying sharedProfile will change all volumes using this profile, and change
+ /// profile settings that are stored in the project too.
+ ///
+ ///
+ /// It is not recommended to modify profiles returned by sharedProfile. If you want
+ /// to modify the profile of a volume use instead.
+ ///
+ ///
+ public PostProcessProfile sharedProfile;
+
+ ///
+ /// Should this volume be applied to the whole scene?
+ ///
+ [Tooltip("Check this box to mark this volume as global. This volume's Profile will be applied to the whole Scene.")]
+ public bool isGlobal = false;
+
+ ///
+ /// The outer distance to start blending from. A value of 0 means no blending and the volume
+ /// overrides will be applied immediatly upon entry.
+ ///
+ [Min(0f), Tooltip("The distance (from the attached Collider) to start blending from. A value of 0 means there will be no blending and the Volume overrides will be applied immediatly upon entry to the attached Collider.")]
+ public float blendDistance = 0f;
+
+ ///
+ /// The total weight of this volume in the scene. 0 means it won't do anything, 1 means full
+ /// effect.
+ ///
+ [Range(0f, 1f), Tooltip("The total weight of this Volume in the Scene. A value of 0 signifies that it will have no effect, 1 signifies full effect.")]
+ public float weight = 1f;
+
+ ///
+ /// The volume priority in the stack. Higher number means higher priority. Negative values
+ /// are supported.
+ ///
+ [Tooltip("The volume priority in the stack. A higher value means higher priority. Negative values are supported.")]
+ public float priority = 0f;
+
+ ///
+ /// Returns the first instantiated assigned to the volume.
+ /// Modifying will change the profile for this volume only. If
+ /// the profile is used by any other volume, this will clone the shared profile and start
+ /// using it from now on.
+ ///
+ ///
+ /// This property automatically instantiates the profile and make it unique to this volume
+ /// so you can safely edit it via scripting at runtime without changing the original asset
+ /// in the project.
+ /// Note that if you pass in your own profile, it is your responsibility to destroy it once
+ /// it's not in use anymore.
+ ///
+ ///
+ ///
+ public PostProcessProfile profile
+ {
+ get
+ {
+ if (m_InternalProfile == null)
+ {
+ m_InternalProfile = ScriptableObject.CreateInstance();
+
+ if (sharedProfile != null)
+ {
+ foreach (var item in sharedProfile.settings)
+ {
+ var itemCopy = Instantiate(item);
+ m_InternalProfile.settings.Add(itemCopy);
+ }
+ }
+ }
+
+ return m_InternalProfile;
+ }
+ set
+ {
+ m_InternalProfile = value;
+ }
+ }
+
+ internal PostProcessProfile profileRef
+ {
+ get
+ {
+ return m_InternalProfile == null
+ ? sharedProfile
+ : m_InternalProfile;
+ }
+ }
+
+ ///
+ /// Checks if the volume has an intantiated profile or is using a shared profile.
+ ///
+ /// true if the profile has been intantiated
+ ///
+ ///
+ public bool HasInstantiatedProfile()
+ {
+ return m_InternalProfile != null;
+ }
+
+ internal int previousLayer => m_PreviousLayer;
+
+ int m_PreviousLayer;
+ float m_PreviousPriority;
+ List m_TempColliders;
+ PostProcessProfile m_InternalProfile;
+
+ void OnEnable()
+ {
+ PostProcessManager.instance.Register(this);
+ m_PreviousLayer = gameObject.layer;
+ m_TempColliders = new List();
+ }
+
+ void OnDisable()
+ {
+ PostProcessManager.instance.Unregister(this);
+ }
+
+ void Update()
+ {
+ // Unfortunately we need to track the current layer to update the volume manager in
+ // real-time as the user could change it at any time in the editor or at runtime.
+ // Because no event is raised when the layer changes, we have to track it on every
+ // frame :/
+ int layer = gameObject.layer;
+ if (layer != m_PreviousLayer)
+ {
+ PostProcessManager.instance.UpdateVolumeLayer(this, m_PreviousLayer, layer);
+ m_PreviousLayer = layer;
+ }
+
+ // Same for `priority`. We could use a property instead, but it doesn't play nice with
+ // the serialization system. Using a custom Attribute/PropertyDrawer for a property is
+ // possible but it doesn't work with Undo/Redo in the editor, which makes it useless.
+ if (priority != m_PreviousPriority)
+ {
+ PostProcessManager.instance.SetLayerDirty(layer);
+ m_PreviousPriority = priority;
+ }
+ }
+
+ // TODO: Look into a better volume previsualization system
+ void OnDrawGizmos()
+ {
+ var colliders = m_TempColliders;
+ GetComponents(colliders);
+
+ if (isGlobal || colliders == null)
+ return;
+
+#if UNITY_EDITOR
+ // Can't access the UnityEditor.Rendering.PostProcessing namespace from here, so
+ // we'll get the preferred color manually
+ unchecked
+ {
+ int value = UnityEditor.EditorPrefs.GetInt("PostProcessing.Volume.GizmoColor", (int)0x8033cc1a);
+ Gizmos.color = ColorUtilities.ToRGBA((uint)value);
+ }
+#endif
+
+ var scale = transform.lossyScale;
+ var invScale = new Vector3(1f / scale.x, 1f / scale.y, 1f / scale.z);
+ Gizmos.matrix = Matrix4x4.TRS(transform.position, transform.rotation, scale);
+
+ // Draw a separate gizmo for each collider
+ foreach (var collider in colliders)
+ {
+ if (!collider.enabled)
+ continue;
+
+ // We'll just use scaling as an approximation for volume skin. It's far from being
+ // correct (and is completely wrong in some cases). Ultimately we'd use a distance
+ // field or at least a tesselate + push modifier on the collider's mesh to get a
+ // better approximation, but the current Gizmo system is a bit limited and because
+ // everything is dynamic in Unity and can be changed at anytime, it's hard to keep
+ // track of changes in an elegant way (which we'd need to implement a nice cache
+ // system for generated volume meshes).
+ var type = collider.GetType();
+
+ if (type == typeof(BoxCollider))
+ {
+ var c = (BoxCollider)collider;
+ Gizmos.DrawCube(c.center, c.size);
+ Gizmos.DrawWireCube(c.center, c.size + 4f * blendDistance * invScale);
+ }
+ else if (type == typeof(SphereCollider))
+ {
+ var c = (SphereCollider)collider;
+ Gizmos.DrawSphere(c.center, c.radius);
+ Gizmos.DrawWireSphere(c.center, c.radius + invScale.x * blendDistance * 2f);
+ }
+ else if (type == typeof(MeshCollider))
+ {
+ var c = (MeshCollider)collider;
+
+ // Only convex mesh colliders are allowed
+ if (!c.convex)
+ c.convex = true;
+
+ // Mesh pivot should be centered or this won't work
+ Gizmos.DrawMesh(c.sharedMesh);
+ Gizmos.DrawWireMesh(c.sharedMesh, Vector3.zero, Quaternion.identity, Vector3.one + 4f * blendDistance * invScale);
+ }
+
+ // Nothing for capsule (DrawCapsule isn't exposed in Gizmo), terrain, wheel and
+ // other colliders...
+ }
+
+ colliders.Clear();
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/PostProcessVolume.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessVolume.cs.meta
new file mode 100644
index 0000000..6396bcb
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/PostProcessVolume.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 8b9a305e18de0c04dbd257a21cd47087
+timeCreated: 1492775877
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {fileID: 2800000, guid: 5f51e0b22aa8cb84b9f422576ce87ff9, type: 3}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Unity.Postprocessing.Runtime.asmdef b/com.unity.postprocessing/PostProcessing/Runtime/Unity.Postprocessing.Runtime.asmdef
new file mode 100644
index 0000000..91449de
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Unity.Postprocessing.Runtime.asmdef
@@ -0,0 +1,29 @@
+{
+ "name": "Unity.Postprocessing.Runtime",
+ "references": [],
+ "optionalUnityReferences": [],
+ "includePlatforms": [],
+ "excludePlatforms": [],
+ "versionDefines": [
+ {
+ "name": "com.unity.render-pipelines.lightweight",
+ "expression": "1.0.0",
+ "define": "LWRP_1_0_0_OR_NEWER"
+ },
+ {
+ "name": "com.unity.render-pipelines.universal",
+ "expression": "1.0.0",
+ "define": "UNIVERSAL_1_0_0_OR_NEWER"
+ },
+ {
+ "name": "com.unity.modules.vr",
+ "expression": "1.0.0",
+ "define": "ENABLE_VR_MODULE"
+ },
+ {
+ "name": "com.unity.modules.xr",
+ "expression": "1.0.0",
+ "define": "ENABLE_XR_MODULE"
+ }
+ ]
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Unity.Postprocessing.Runtime.asmdef.meta b/com.unity.postprocessing/PostProcessing/Runtime/Unity.Postprocessing.Runtime.asmdef.meta
new file mode 100644
index 0000000..43f1ab1
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Unity.Postprocessing.Runtime.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: d60799ab2a985554ea1a39cd38695018
+AssemblyDefinitionImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Utils.meta b/com.unity.postprocessing/PostProcessing/Runtime/Utils.meta
new file mode 100644
index 0000000..4ff2fa6
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Utils.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 8f735421c1ed8e54c992b4640aca9a89
+folderAsset: yes
+timeCreated: 1487868402
+licenseType: Pro
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Utils/ColorUtilities.cs b/com.unity.postprocessing/PostProcessing/Runtime/Utils/ColorUtilities.cs
new file mode 100644
index 0000000..5a97975
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Utils/ColorUtilities.cs
@@ -0,0 +1,182 @@
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// A set of utilities to manipulate color values.
+ ///
+ public static class ColorUtilities
+ {
+ ///
+ /// Gets the Y coordinate for the chromaticity of the standard illuminant.
+ ///
+ /// The X coordinate
+ /// The Y coordinate for the chromaticity of the standard illuminant
+ ///
+ /// Based on: "An analytical model of chromaticity of the standard illuminant" by Judd et al.
+ /// http://en.wikipedia.org/wiki/Standard_illuminant#Illuminant_series_D
+ /// Slightly modified to adjust it with the D65 white point (x=0.31271, y=0.32902).
+ ///
+ public static float StandardIlluminantY(float x)
+ {
+ return 2.87f * x - 3f * x * x - 0.27509507f;
+ }
+
+ ///
+ /// Converts CIExy chromaticity to CAT02 LMS.
+ ///
+ /// The X coordinate
+ /// The Y coordinate
+ /// The CIExy chromaticity converted to CAT02 LMS
+ ///
+ /// See: http://en.wikipedia.org/wiki/LMS_color_space#CAT02
+ ///
+ public static Vector3 CIExyToLMS(float x, float y)
+ {
+ float Y = 1f;
+ float X = Y * x / y;
+ float Z = Y * (1f - x - y) / y;
+
+ float L = 0.7328f * X + 0.4296f * Y - 0.1624f * Z;
+ float M = -0.7036f * X + 1.6975f * Y + 0.0061f * Z;
+ float S = 0.0030f * X + 0.0136f * Y + 0.9834f * Z;
+
+ return new Vector3(L, M, S);
+ }
+
+ ///
+ /// Computes the color balance coefficients in the CAT02 LMS space.
+ ///
+ /// The color temperature offset
+ /// The color tint offset (green/magenta)
+ /// The color balance coefficients in the CAT02 LMS space.
+ public static Vector3 ComputeColorBalance(float temperature, float tint)
+ {
+ // Range ~[-1.67;1.67] works best
+ float t1 = temperature / 60f;
+ float t2 = tint / 60f;
+
+ // Get the CIE xy chromaticity of the reference white point.
+ // Note: 0.31271 = x value on the D65 white point
+ float x = 0.31271f - t1 * (t1 < 0f ? 0.1f : 0.05f);
+ float y = StandardIlluminantY(x) + t2 * 0.05f;
+
+ // Calculate the coefficients in the LMS space.
+ var w1 = new Vector3(0.949237f, 1.03542f, 1.08728f); // D65 white point
+ var w2 = CIExyToLMS(x, y);
+ return new Vector3(w1.x / w2.x, w1.y / w2.y, w1.z / w2.z);
+ }
+
+ ///
+ /// Converts trackball values to Lift coefficients.
+ ///
+ /// The trackball color value (with offset in the W component)
+ /// The converted trackball value
+ public static Vector3 ColorToLift(Vector4 color)
+ {
+ // Shadows
+ var S = new Vector3(color.x, color.y, color.z);
+ float lumLift = S.x * 0.2126f + S.y * 0.7152f + S.z * 0.0722f;
+ S = new Vector3(S.x - lumLift, S.y - lumLift, S.z - lumLift);
+
+ float liftOffset = color.w;
+ return new Vector3(S.x + liftOffset, S.y + liftOffset, S.z + liftOffset);
+ }
+
+ ///
+ /// Converts trackball values to inverted Gamma coefficients.
+ ///
+ /// The trackball color value (with offset in the W component)
+ /// The converted trackball value
+ public static Vector3 ColorToInverseGamma(Vector4 color)
+ {
+ // Midtones
+ var M = new Vector3(color.x, color.y, color.z);
+ float lumGamma = M.x * 0.2126f + M.y * 0.7152f + M.z * 0.0722f;
+ M = new Vector3(M.x - lumGamma, M.y - lumGamma, M.z - lumGamma);
+
+ float gammaOffset = color.w + 1f;
+ return new Vector3(
+ 1f / Mathf.Max(M.x + gammaOffset, 1e-03f),
+ 1f / Mathf.Max(M.y + gammaOffset, 1e-03f),
+ 1f / Mathf.Max(M.z + gammaOffset, 1e-03f)
+ );
+ }
+
+ ///
+ /// Converts trackball values to Gain coefficients.
+ ///
+ /// The trackball color value (with offset in the W component)
+ /// The converted trackball value
+ public static Vector3 ColorToGain(Vector4 color)
+ {
+ // Highlights
+ var H = new Vector3(color.x, color.y, color.z);
+ float lumGain = H.x * 0.2126f + H.y * 0.7152f + H.z * 0.0722f;
+ H = new Vector3(H.x - lumGain, H.y - lumGain, H.z - lumGain);
+
+ float gainOffset = color.w + 1f;
+ return new Vector3(H.x + gainOffset, H.y + gainOffset, H.z + gainOffset);
+ }
+
+ // Alexa LogC converters (El 1000)
+ // See http://www.vocas.nl/webfm_send/964
+ const float logC_cut = 0.011361f;
+ const float logC_a = 5.555556f;
+ const float logC_b = 0.047996f;
+ const float logC_c = 0.244161f;
+ const float logC_d = 0.386036f;
+ const float logC_e = 5.301883f;
+ const float logC_f = 0.092819f;
+
+ ///
+ /// Converts a LogC (Alexa El 1000) value to linear.
+ ///
+ /// A LogC (Alexa El 1000) value
+ /// The input convert to linear
+ public static float LogCToLinear(float x)
+ {
+ return x > logC_e * logC_cut + logC_f
+ ? (Mathf.Pow(10f, (x - logC_d) / logC_c) - logC_b) / logC_a
+ : (x - logC_f) / logC_e;
+ }
+
+ ///
+ /// Converts a linear value to LogC (Alexa El 1000).
+ ///
+ /// A linear value
+ /// The input value converted to LogC
+ public static float LinearToLogC(float x)
+ {
+ return x > logC_cut
+ ? logC_c * Mathf.Log10(logC_a * x + logC_b) + logC_d
+ : logC_e * x + logC_f;
+ }
+
+ ///
+ /// Converts a color to its ARGB hexadecimal representation.
+ ///
+ /// The color to convert
+ /// The color converted to its ARGB hexadecimal representation
+ public static uint ToHex(Color c)
+ {
+ return ((uint)(c.a * 255) << 24)
+ | ((uint)(c.r * 255) << 16)
+ | ((uint)(c.g * 255) << 8)
+ | ((uint)(c.b * 255));
+ }
+
+ ///
+ /// Converts an ARGB hexadecimal input to a color structure.
+ ///
+ /// The hexadecimal input
+ /// The ARGB hexadecimal input converted to a color structure.
+ public static Color ToRGBA(uint hex)
+ {
+ return new Color(
+ ((hex >> 16) & 0xff) / 255f, // r
+ ((hex >> 8) & 0xff) / 255f, // g
+ ((hex) & 0xff) / 255f, // b
+ ((hex >> 24) & 0xff) / 255f // a
+ );
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Utils/ColorUtilities.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Utils/ColorUtilities.cs.meta
new file mode 100644
index 0000000..b15a270
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Utils/ColorUtilities.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: c3c112f1ddeedfe45839158cc4b148d4
+timeCreated: 1494794407
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Utils/HableCurve.cs b/com.unity.postprocessing/PostProcessing/Runtime/Utils/HableCurve.cs
new file mode 100644
index 0000000..3af960c
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Utils/HableCurve.cs
@@ -0,0 +1,394 @@
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// A raw implementation of John Hable's artist-friendly tonemapping curve.
+ /// See http://filmicworlds.com/blog/filmic-tonemapping-with-piecewise-power-curves/
+ ///
+ public class HableCurve
+ {
+ class Segment
+ {
+ public float offsetX;
+ public float offsetY;
+ public float scaleX;
+ public float scaleY;
+ public float lnA;
+ public float B;
+
+ public float Eval(float x)
+ {
+ float x0 = (x - offsetX) * scaleX;
+ float y0 = 0f;
+
+ // log(0) is undefined but our function should evaluate to 0. There are better ways to handle this,
+ // but it's doing it the slow way here for clarity.
+ if (x0 > 0)
+ y0 = Mathf.Exp(lnA + B * Mathf.Log(x0));
+
+ return y0 * scaleY + offsetY;
+ }
+ }
+
+ struct DirectParams
+ {
+ internal float x0;
+ internal float y0;
+ internal float x1;
+ internal float y1;
+ internal float W;
+
+ internal float overshootX;
+ internal float overshootY;
+
+ internal float gamma;
+ }
+
+ ///
+ /// The curve's white point.
+ ///
+ public float whitePoint { get; private set; }
+
+ ///
+ /// The inverse of the curve's white point.
+ ///
+ public float inverseWhitePoint { get; private set; }
+
+ internal float x0 { get; private set; }
+ internal float x1 { get; private set; }
+
+ // Toe, mid, shoulder
+ readonly Segment[] m_Segments = new Segment[3];
+
+ ///
+ /// Creates a new curve.
+ ///
+ public HableCurve()
+ {
+ for (int i = 0; i < 3; i++)
+ m_Segments[i] = new Segment();
+
+ uniforms = new Uniforms(this);
+ }
+
+ ///
+ /// Evaluates a given point on the curve.
+ ///
+ /// The point within the curve to evaluate (on the horizontal axis)
+ /// The value of the curve, at the point specified
+ public float Eval(float x)
+ {
+ float normX = x * inverseWhitePoint;
+ int index = (normX < x0) ? 0 : ((normX < x1) ? 1 : 2);
+ var segment = m_Segments[index];
+ float ret = segment.Eval(normX);
+ return ret;
+ }
+
+ ///
+ /// Initializes the curve with given settings.
+ ///
+ /// Affects the transition between the toe and the mid section of
+ /// the curve. A value of 0 means no toe, a value of 1 means a very hard transition
+ /// Affects how much of the dynamic range is in the toe. With a
+ /// small value, the toe will be very short and quickly transition into the linear section,
+ /// and with a longer value having a longer toe
+ /// Affects the transition between the mid section and the
+ /// shoulder of the curve. A value of 0 means no shoulder, a value of 1 means a very hard
+ /// transition
+ /// Affects how many F-stops (EV) to add to the dynamic range
+ /// of the curve
+ /// Affects how much overshoot to add to the shoulder
+ /// Applies a gamma function to the curve
+ public void Init(float toeStrength, float toeLength, float shoulderStrength, float shoulderLength, float shoulderAngle, float gamma)
+ {
+ var dstParams = new DirectParams();
+
+ // This is not actually the display gamma. It's just a UI space to avoid having to
+ // enter small numbers for the input.
+ const float kPerceptualGamma = 2.2f;
+
+ // Constraints
+ {
+ toeLength = Mathf.Pow(Mathf.Clamp01(toeLength), kPerceptualGamma);
+ toeStrength = Mathf.Clamp01(toeStrength);
+ shoulderAngle = Mathf.Clamp01(shoulderAngle);
+ shoulderStrength = Mathf.Clamp(shoulderStrength, 1e-5f, 1f - 1e-5f);
+ shoulderLength = Mathf.Max(0f, shoulderLength);
+ gamma = Mathf.Max(1e-5f, gamma);
+ }
+
+ // Apply base params
+ {
+ // Toe goes from 0 to 0.5
+ float x0 = toeLength * 0.5f;
+ float y0 = (1f - toeStrength) * x0; // Lerp from 0 to x0
+
+ float remainingY = 1f - y0;
+
+ float initialW = x0 + remainingY;
+
+ float y1_offset = (1f - shoulderStrength) * remainingY;
+ float x1 = x0 + y1_offset;
+ float y1 = y0 + y1_offset;
+
+ // Filmic shoulder strength is in F stops
+ float extraW = RuntimeUtilities.Exp2(shoulderLength) - 1f;
+
+ float W = initialW + extraW;
+
+ dstParams.x0 = x0;
+ dstParams.y0 = y0;
+ dstParams.x1 = x1;
+ dstParams.y1 = y1;
+ dstParams.W = W;
+
+ // Bake the linear to gamma space conversion
+ dstParams.gamma = gamma;
+ }
+
+ dstParams.overshootX = (dstParams.W * 2f) * shoulderAngle * shoulderLength;
+ dstParams.overshootY = 0.5f * shoulderAngle * shoulderLength;
+
+ InitSegments(dstParams);
+ }
+
+ void InitSegments(DirectParams srcParams)
+ {
+ var paramsCopy = srcParams;
+
+ whitePoint = srcParams.W;
+ inverseWhitePoint = 1f / srcParams.W;
+
+ // normalize params to 1.0 range
+ paramsCopy.W = 1f;
+ paramsCopy.x0 /= srcParams.W;
+ paramsCopy.x1 /= srcParams.W;
+ paramsCopy.overshootX = srcParams.overshootX / srcParams.W;
+
+ float toeM = 0f;
+ float shoulderM = 0f;
+ {
+ float m, b;
+ AsSlopeIntercept(out m, out b, paramsCopy.x0, paramsCopy.x1, paramsCopy.y0, paramsCopy.y1);
+
+ float g = srcParams.gamma;
+
+ // Base function of linear section plus gamma is
+ // y = (mx+b)^g
+ //
+ // which we can rewrite as
+ // y = exp(g*ln(m) + g*ln(x+b/m))
+ //
+ // and our evaluation function is (skipping the if parts):
+ /*
+ float x0 = (x - offsetX) * scaleX;
+ y0 = exp(m_lnA + m_B*log(x0));
+ return y0*scaleY + m_offsetY;
+ */
+
+ var midSegment = m_Segments[1];
+ midSegment.offsetX = -(b / m);
+ midSegment.offsetY = 0f;
+ midSegment.scaleX = 1f;
+ midSegment.scaleY = 1f;
+ midSegment.lnA = g * Mathf.Log(m);
+ midSegment.B = g;
+
+ toeM = EvalDerivativeLinearGamma(m, b, g, paramsCopy.x0);
+ shoulderM = EvalDerivativeLinearGamma(m, b, g, paramsCopy.x1);
+
+ // apply gamma to endpoints
+ paramsCopy.y0 = Mathf.Max(1e-5f, Mathf.Pow(paramsCopy.y0, paramsCopy.gamma));
+ paramsCopy.y1 = Mathf.Max(1e-5f, Mathf.Pow(paramsCopy.y1, paramsCopy.gamma));
+
+ paramsCopy.overshootY = Mathf.Pow(1f + paramsCopy.overshootY, paramsCopy.gamma) - 1f;
+ }
+
+ this.x0 = paramsCopy.x0;
+ this.x1 = paramsCopy.x1;
+
+ // Toe section
+ {
+ var toeSegment = m_Segments[0];
+ toeSegment.offsetX = 0;
+ toeSegment.offsetY = 0f;
+ toeSegment.scaleX = 1f;
+ toeSegment.scaleY = 1f;
+
+ float lnA, B;
+ SolveAB(out lnA, out B, paramsCopy.x0, paramsCopy.y0, toeM);
+ toeSegment.lnA = lnA;
+ toeSegment.B = B;
+ }
+
+ // Shoulder section
+ {
+ // Use the simple version that is usually too flat
+ var shoulderSegment = m_Segments[2];
+
+ float x0 = (1f + paramsCopy.overshootX) - paramsCopy.x1;
+ float y0 = (1f + paramsCopy.overshootY) - paramsCopy.y1;
+
+ float lnA, B;
+ SolveAB(out lnA, out B, x0, y0, shoulderM);
+
+ shoulderSegment.offsetX = (1f + paramsCopy.overshootX);
+ shoulderSegment.offsetY = (1f + paramsCopy.overshootY);
+
+ shoulderSegment.scaleX = -1f;
+ shoulderSegment.scaleY = -1f;
+ shoulderSegment.lnA = lnA;
+ shoulderSegment.B = B;
+ }
+
+ // Normalize so that we hit 1.0 at our white point. We wouldn't have do this if we
+ // skipped the overshoot part.
+ {
+ // Evaluate shoulder at the end of the curve
+ float scale = m_Segments[2].Eval(1f);
+ float invScale = 1f / scale;
+
+ m_Segments[0].offsetY *= invScale;
+ m_Segments[0].scaleY *= invScale;
+
+ m_Segments[1].offsetY *= invScale;
+ m_Segments[1].scaleY *= invScale;
+
+ m_Segments[2].offsetY *= invScale;
+ m_Segments[2].scaleY *= invScale;
+ }
+ }
+
+ // Find a function of the form:
+ // f(x) = e^(lnA + Bln(x))
+ // where
+ // f(0) = 0; not really a constraint
+ // f(x0) = y0
+ // f'(x0) = m
+ void SolveAB(out float lnA, out float B, float x0, float y0, float m)
+ {
+ B = (m * x0) / y0;
+ lnA = Mathf.Log(y0) - B * Mathf.Log(x0);
+ }
+
+ // Convert to y=mx+b
+ void AsSlopeIntercept(out float m, out float b, float x0, float x1, float y0, float y1)
+ {
+ float dy = (y1 - y0);
+ float dx = (x1 - x0);
+
+ if (dx == 0)
+ m = 1f;
+ else
+ m = dy / dx;
+
+ b = y0 - x0 * m;
+ }
+
+ // f(x) = (mx+b)^g
+ // f'(x) = gm(mx+b)^(g-1)
+ float EvalDerivativeLinearGamma(float m, float b, float g, float x)
+ {
+ float ret = g * m * Mathf.Pow(m * x + b, g - 1f);
+ return ret;
+ }
+
+ ///
+ /// Utility class to retrieve curve values for shader evaluation.
+ ///
+ public class Uniforms
+ {
+ HableCurve parent;
+
+ internal Uniforms(HableCurve parent)
+ {
+ this.parent = parent;
+ }
+
+ ///
+ /// A pre-built holding: (inverseWhitePoint, x0, x1, 0).
+ ///
+ public Vector4 curve
+ {
+ get { return new Vector4(parent.inverseWhitePoint, parent.x0, parent.x1, 0f); }
+ }
+
+ ///
+ /// A pre-built holding: (toe.offsetX, toe.offsetY, toe.scaleX, toe.scaleY).
+ ///
+ public Vector4 toeSegmentA
+ {
+ get
+ {
+ var toe = parent.m_Segments[0];
+ return new Vector4(toe.offsetX, toe.offsetY, toe.scaleX, toe.scaleY);
+ }
+ }
+
+ ///
+ /// A pre-built holding: (toe.lnA, toe.B, 0, 0).
+ ///
+ public Vector4 toeSegmentB
+ {
+ get
+ {
+ var toe = parent.m_Segments[0];
+ return new Vector4(toe.lnA, toe.B, 0f, 0f);
+ }
+ }
+
+ ///
+ /// A pre-built holding: (mid.offsetX, mid.offsetY, mid.scaleX, mid.scaleY).
+ ///
+ public Vector4 midSegmentA
+ {
+ get
+ {
+ var mid = parent.m_Segments[1];
+ return new Vector4(mid.offsetX, mid.offsetY, mid.scaleX, mid.scaleY);
+ }
+ }
+
+ ///
+ /// A pre-built holding: (mid.lnA, mid.B, 0, 0).
+ ///
+ public Vector4 midSegmentB
+ {
+ get
+ {
+ var mid = parent.m_Segments[1];
+ return new Vector4(mid.lnA, mid.B, 0f, 0f);
+ }
+ }
+
+ ///
+ /// A pre-built holding: (toe.offsetX, toe.offsetY, toe.scaleX, toe.scaleY).
+ ///
+ public Vector4 shoSegmentA
+ {
+ get
+ {
+ var sho = parent.m_Segments[2];
+ return new Vector4(sho.offsetX, sho.offsetY, sho.scaleX, sho.scaleY);
+ }
+ }
+
+ ///
+ /// A pre-built holding: (sho.lnA, sho.B, 0, 0).
+ ///
+ public Vector4 shoSegmentB
+ {
+ get
+ {
+ var sho = parent.m_Segments[2];
+ return new Vector4(sho.lnA, sho.B, 0f, 0f);
+ }
+ }
+ }
+
+ ///
+ /// The builtin instance for this curve.
+ ///
+ public readonly Uniforms uniforms;
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Utils/HableCurve.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Utils/HableCurve.cs.meta
new file mode 100644
index 0000000..7ee502c
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Utils/HableCurve.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 599b4e72f6c212d40819cfde14826671
+timeCreated: 1494795842
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Utils/HaltonSeq.cs b/com.unity.postprocessing/PostProcessing/Runtime/Utils/HaltonSeq.cs
new file mode 100644
index 0000000..ab29694
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Utils/HaltonSeq.cs
@@ -0,0 +1,30 @@
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// Halton sequence utility.
+ ///
+ public static class HaltonSeq
+ {
+ ///
+ /// Gets a value from the Halton sequence for a given index and radix.
+ ///
+ /// The sequence index
+ /// The sequence base
+ /// A number from the Halton sequence between 0 and 1.
+ public static float Get(int index, int radix)
+ {
+ float result = 0f;
+ float fraction = 1f / (float)radix;
+
+ while (index > 0)
+ {
+ result += (float)(index % radix) * fraction;
+
+ index /= radix;
+ fraction /= (float)radix;
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Utils/HaltonSeq.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Utils/HaltonSeq.cs.meta
new file mode 100644
index 0000000..8cff6e3
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Utils/HaltonSeq.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 616483d5bdbf13c43ae1b005134b8c11
+timeCreated: 1493633892
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Utils/LogHistogram.cs b/com.unity.postprocessing/PostProcessing/Runtime/Utils/LogHistogram.cs
new file mode 100644
index 0000000..abf2ce9
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Utils/LogHistogram.cs
@@ -0,0 +1,62 @@
+namespace UnityEngine.Rendering.PostProcessing
+{
+ internal sealed class LogHistogram
+ {
+ public const int rangeMin = -9; // ev
+ public const int rangeMax = 9; // ev
+
+ // Don't forget to update 'ExposureHistogram.hlsl' if you change these values !
+ const int k_Bins = 128;
+
+ public ComputeBuffer data { get; private set; }
+
+ public void Generate(PostProcessRenderContext context)
+ {
+ if (data == null)
+ data = new ComputeBuffer(k_Bins, sizeof(uint));
+
+ uint threadX, threadY, threadZ;
+ var scaleOffsetRes = GetHistogramScaleOffsetRes(context);
+ var compute = context.resources.computeShaders.exposureHistogram;
+ var cmd = context.command;
+ cmd.BeginSample("LogHistogram");
+
+ // Clear the buffer on every frame as we use it to accumulate luminance values on each frame
+ int kernel = compute.FindKernel("KEyeHistogramClear");
+ cmd.SetComputeBufferParam(compute, kernel, "_HistogramBuffer", data);
+ compute.GetKernelThreadGroupSizes(kernel, out threadX, out threadY, out threadZ);
+ cmd.DispatchCompute(compute, kernel, Mathf.CeilToInt(k_Bins / (float)threadX), 1, 1);
+
+ // Get a log histogram
+ kernel = compute.FindKernel("KEyeHistogram");
+ cmd.SetComputeBufferParam(compute, kernel, "_HistogramBuffer", data);
+ cmd.SetComputeTextureParam(compute, kernel, "_Source", context.source);
+ cmd.SetComputeVectorParam(compute, "_ScaleOffsetRes", scaleOffsetRes);
+
+ compute.GetKernelThreadGroupSizes(kernel, out threadX, out threadY, out threadZ);
+ cmd.DispatchCompute(compute, kernel,
+ Mathf.CeilToInt(scaleOffsetRes.z / 2f / threadX),
+ Mathf.CeilToInt(scaleOffsetRes.w / 2f / threadY),
+ 1
+ );
+
+ cmd.EndSample("LogHistogram");
+ }
+
+ public Vector4 GetHistogramScaleOffsetRes(PostProcessRenderContext context)
+ {
+ float diff = rangeMax - rangeMin;
+ float scale = 1f / diff;
+ float offset = -rangeMin * scale;
+ return new Vector4(scale, offset, context.width, context.height);
+ }
+
+ public void Release()
+ {
+ if (data != null)
+ data.Release();
+
+ data = null;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Utils/LogHistogram.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Utils/LogHistogram.cs.meta
new file mode 100644
index 0000000..1b01a15
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Utils/LogHistogram.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: a4b23776a3150a74ea5ad6271a3d8f15
+timeCreated: 1496324052
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Utils/MeshUtilities.cs b/com.unity.postprocessing/PostProcessing/Runtime/Utils/MeshUtilities.cs
new file mode 100644
index 0000000..08e5bba
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Utils/MeshUtilities.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine.Assertions;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ static class MeshUtilities
+ {
+ static Dictionary s_Primitives;
+ static Dictionary s_ColliderPrimitives;
+
+ static MeshUtilities()
+ {
+ s_Primitives = new Dictionary();
+ s_ColliderPrimitives = new Dictionary
+ {
+ { typeof(BoxCollider), PrimitiveType.Cube },
+ { typeof(SphereCollider), PrimitiveType.Sphere },
+ { typeof(CapsuleCollider), PrimitiveType.Capsule }
+ };
+ }
+
+ internal static Mesh GetColliderMesh(Collider collider)
+ {
+ var type = collider.GetType();
+
+ if (type == typeof(MeshCollider))
+ return ((MeshCollider)collider).sharedMesh;
+
+ Assert.IsTrue(s_ColliderPrimitives.ContainsKey(type), "Unknown collider");
+ return GetPrimitive(s_ColliderPrimitives[type]);
+ }
+
+ internal static Mesh GetPrimitive(PrimitiveType primitiveType)
+ {
+ Mesh mesh;
+
+ if (!s_Primitives.TryGetValue(primitiveType, out mesh))
+ {
+ mesh = GetBuiltinMesh(primitiveType);
+ s_Primitives.Add(primitiveType, mesh);
+ }
+
+ return mesh;
+ }
+
+ // (Not pretty) hack to get meshes from `unity default resources` in user land
+ // What it does is create a new GameObject using the CreatePrimitive utility, retrieve its
+ // mesh and discard it...
+ static Mesh GetBuiltinMesh(PrimitiveType primitiveType)
+ {
+ var gameObject = GameObject.CreatePrimitive(primitiveType);
+ var mesh = gameObject.GetComponent().sharedMesh;
+ RuntimeUtilities.Destroy(gameObject);
+ return mesh;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Utils/MeshUtilities.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Utils/MeshUtilities.cs.meta
new file mode 100644
index 0000000..7405ea4
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Utils/MeshUtilities.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 4b42fa3a7c4baed49bb4f6a56dadc03f
+timeCreated: 1488548727
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Utils/PostProcessEffectRendererExtensions.cs b/com.unity.postprocessing/PostProcessing/Runtime/Utils/PostProcessEffectRendererExtensions.cs
new file mode 100644
index 0000000..8cd80b7
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Utils/PostProcessEffectRendererExtensions.cs
@@ -0,0 +1,34 @@
+using System;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ static class PostProcessEffectRendererExtensions
+ {
+ ///
+ /// Render with a try catch for all exception.
+ ///
+ /// If an exception occurs during the call, it will be logged
+ /// and returned.
+ ///
+ /// Use this method instead of in critical contexts
+ /// to avoid entering the exception flow.
+ ///
+ /// The renderer to render.
+ /// A context object
+ ///
+ public static Exception RenderOrLog(this PostProcessEffectRenderer self, PostProcessRenderContext context)
+ {
+ try
+ {
+ self.Render(context);
+ }
+ catch (Exception e)
+ {
+ Debug.LogException(e);
+ return e;
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Utils/PostProcessEffectRendererExtensions.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Utils/PostProcessEffectRendererExtensions.cs.meta
new file mode 100644
index 0000000..08a476a
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Utils/PostProcessEffectRendererExtensions.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 442c24ca7e1a877449477a4154f887f8
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Utils/PropertySheet.cs b/com.unity.postprocessing/PostProcessing/Runtime/Utils/PropertySheet.cs
new file mode 100644
index 0000000..9dcc1f8
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Utils/PropertySheet.cs
@@ -0,0 +1,58 @@
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// The post-processing stack is entirely built around the use of
+ /// and as such requires the use of to properly deal with
+ /// the deferred nature of .
+ /// This wrapper abstracts the creation and destruction of
+ /// and to make the process easier.
+ ///
+ ///
+ public sealed class PropertySheet
+ {
+ ///
+ /// The actual to fill.
+ ///
+ public MaterialPropertyBlock properties { get; private set; }
+
+ internal Material material { get; private set; }
+
+ internal PropertySheet(Material material)
+ {
+ this.material = material;
+ properties = new MaterialPropertyBlock();
+ }
+
+ ///
+ /// Clears all keywords set on the source material.
+ ///
+ public void ClearKeywords()
+ {
+ material.shaderKeywords = null;
+ }
+
+ ///
+ /// Enableds a given keyword on the source material.
+ ///
+ /// The keyword to enable
+ public void EnableKeyword(string keyword)
+ {
+ material.EnableKeyword(keyword);
+ }
+
+ ///
+ /// Disables a given keyword on the source material.
+ ///
+ /// The keyword to disable
+ public void DisableKeyword(string keyword)
+ {
+ material.DisableKeyword(keyword);
+ }
+
+ internal void Release()
+ {
+ RuntimeUtilities.Destroy(material);
+ material = null;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Utils/PropertySheet.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Utils/PropertySheet.cs.meta
new file mode 100644
index 0000000..0ecf547
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Utils/PropertySheet.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 4da61023839a0604d834e6ffde67ad52
+timeCreated: 1489745652
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Utils/PropertySheetFactory.cs b/com.unity.postprocessing/PostProcessing/Runtime/Utils/PropertySheetFactory.cs
new file mode 100644
index 0000000..b707009
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Utils/PropertySheetFactory.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Collections.Generic;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// A factory for easy creation and destruction of
+ /// and .
+ ///
+ ///
+ public sealed class PropertySheetFactory
+ {
+ readonly Dictionary m_Sheets;
+
+ ///
+ /// Creates a new factory.
+ ///
+ public PropertySheetFactory()
+ {
+ m_Sheets = new Dictionary();
+ }
+
+ ///
+ /// Gets a for a given shader identifier. Sheets are recycled
+ /// so you can safely call this method on every frame.
+ ///
+ /// The name of the shader to retrieve a sheet for
+ /// A sheet for the given shader
+ ///
+ /// This method will not work when loading post-processing from an asset bundle. For this
+ /// reason it is recommended to use instead.
+ ///
+ /// Thrown if the shader is invalid
+ [Obsolete("Use PropertySheet.Get(Shader) with a direct reference to the Shader instead.")]
+ public PropertySheet Get(string shaderName)
+ {
+ var shader = Shader.Find(shaderName);
+
+ if (shader == null)
+ throw new ArgumentException(string.Format("Invalid shader ({0})", shaderName));
+
+ return Get(shader);
+ }
+
+ ///
+ /// Gets a for a given shader instance. Sheets are recycled so
+ /// you can safely call this method on every frame.
+ ///
+ /// A shader instance to retrieve a sheet for
+ /// A sheet for the given shader
+ /// Thrown if the shader is invalid
+ public PropertySheet Get(Shader shader)
+ {
+ PropertySheet sheet;
+
+ if (shader == null)
+ throw new ArgumentException(string.Format("Invalid shader ({0})", shader));
+
+ if (m_Sheets.TryGetValue(shader, out sheet))
+ return sheet;
+
+ var shaderName = shader.name;
+ var material = new Material(shader)
+ {
+ name = string.Format("PostProcess - {0}", shaderName.Substring(shaderName.LastIndexOf('/') + 1)),
+ hideFlags = HideFlags.DontSave
+ };
+
+ sheet = new PropertySheet(material);
+ m_Sheets.Add(shader, sheet);
+ return sheet;
+ }
+
+ ///
+ /// Releases all resources used by this factory.
+ ///
+ ///
+ /// You don't need to call this method when using the builtin factory from
+ /// .
+ ///
+ public void Release()
+ {
+ foreach (var sheet in m_Sheets.Values)
+ sheet.Release();
+
+ m_Sheets.Clear();
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Utils/PropertySheetFactory.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Utils/PropertySheetFactory.cs.meta
new file mode 100644
index 0000000..52eb27a
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Utils/PropertySheetFactory.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: e034505fdac568a45af53ec1cdb0fbb3
+timeCreated: 1489748399
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Utils/RuntimeUtilities.cs b/com.unity.postprocessing/PostProcessing/Runtime/Utils/RuntimeUtilities.cs
new file mode 100644
index 0000000..13497b8
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Utils/RuntimeUtilities.cs
@@ -0,0 +1,1285 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Reflection;
+using System.Text;
+using UnityEngine.Assertions;
+
+#if UNITY_EDITOR
+using UnityEditor;
+#endif
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ using SceneManagement;
+ using UnityObject = UnityEngine.Object;
+ using LoadAction = RenderBufferLoadAction;
+ using StoreAction = RenderBufferStoreAction;
+
+ ///
+ /// A set of runtime utilities used by the post-processing stack.
+ ///
+ public static class RuntimeUtilities
+ {
+ #region Textures
+
+ static Texture2D m_WhiteTexture;
+
+ ///
+ /// A 1x1 white texture.
+ ///
+ ///
+ /// This texture is only created once and recycled afterward. You shouldn't modify it.
+ ///
+ public static Texture2D whiteTexture
+ {
+ get
+ {
+ if (m_WhiteTexture == null)
+ {
+ m_WhiteTexture = new Texture2D(1, 1, TextureFormat.ARGB32, false) { name = "White Texture" };
+ m_WhiteTexture.SetPixel(0, 0, Color.white);
+ m_WhiteTexture.Apply();
+ }
+
+ return m_WhiteTexture;
+ }
+ }
+
+ static Texture3D m_WhiteTexture3D;
+
+ ///
+ /// A 1x1x1 white texture.
+ ///
+ ///
+ /// This texture is only created once and recycled afterward. You shouldn't modify it.
+ ///
+ public static Texture3D whiteTexture3D
+ {
+ get
+ {
+ if (m_WhiteTexture3D == null)
+ {
+ m_WhiteTexture3D = new Texture3D(1, 1, 1, TextureFormat.ARGB32, false) { name = "White Texture 3D" };
+ m_WhiteTexture3D.SetPixels(new Color[] { Color.white });
+ m_WhiteTexture3D.Apply();
+ }
+
+ return m_WhiteTexture3D;
+ }
+ }
+
+ static Texture2D m_BlackTexture;
+
+ ///
+ /// A 1x1 black texture.
+ ///
+ ///
+ /// This texture is only created once and recycled afterward. You shouldn't modify it.
+ ///
+ public static Texture2D blackTexture
+ {
+ get
+ {
+ if (m_BlackTexture == null)
+ {
+ m_BlackTexture = new Texture2D(1, 1, TextureFormat.ARGB32, false) { name = "Black Texture" };
+ m_BlackTexture.SetPixel(0, 0, Color.black);
+ m_BlackTexture.Apply();
+ }
+
+ return m_BlackTexture;
+ }
+ }
+
+ static Texture3D m_BlackTexture3D;
+
+ ///
+ /// A 1x1x1 black texture.
+ ///
+ ///
+ /// This texture is only created once and recycled afterward. You shouldn't modify it.
+ ///
+ public static Texture3D blackTexture3D
+ {
+ get
+ {
+ if (m_BlackTexture3D == null)
+ {
+ m_BlackTexture3D = new Texture3D(1, 1, 1, TextureFormat.ARGB32, false) { name = "Black Texture 3D" };
+ m_BlackTexture3D.SetPixels(new Color[] { Color.black });
+ m_BlackTexture3D.Apply();
+ }
+
+ return m_BlackTexture3D;
+ }
+ }
+
+ static Texture2D m_TransparentTexture;
+
+ ///
+ /// A 1x1 transparent texture.
+ ///
+ ///
+ /// This texture is only created once and recycled afterward. You shouldn't modify it.
+ ///
+ public static Texture2D transparentTexture
+ {
+ get
+ {
+ if (m_TransparentTexture == null)
+ {
+ m_TransparentTexture = new Texture2D(1, 1, TextureFormat.ARGB32, false) { name = "Transparent Texture" };
+ m_TransparentTexture.SetPixel(0, 0, Color.clear);
+ m_TransparentTexture.Apply();
+ }
+
+ return m_TransparentTexture;
+ }
+ }
+
+ static Texture3D m_TransparentTexture3D;
+
+ ///
+ /// A 1x1x1 transparent texture.
+ ///
+ ///
+ /// This texture is only created once and recycled afterward. You shouldn't modify it.
+ ///
+ public static Texture3D transparentTexture3D
+ {
+ get
+ {
+ if (m_TransparentTexture3D == null)
+ {
+ m_TransparentTexture3D = new Texture3D(1, 1, 1, TextureFormat.ARGB32, false) { name = "Transparent Texture 3D" };
+ m_TransparentTexture3D.SetPixels(new Color[] { Color.clear });
+ m_TransparentTexture3D.Apply();
+ }
+
+ return m_TransparentTexture3D;
+ }
+ }
+
+ static Dictionary m_LutStrips = new Dictionary();
+
+ ///
+ /// Gets a 2D lookup table for color grading use. Its size will be width = height * height.
+ ///
+ /// The height of the lookup table
+ /// A 2D lookup table
+ ///
+ /// Lookup tables are recycled and only created once per size. You shouldn't modify them.
+ ///
+ public static Texture2D GetLutStrip(int size)
+ {
+ Texture2D texture;
+ if (!m_LutStrips.TryGetValue(size, out texture))
+ {
+ int width = size * size;
+ int height = size;
+ var pixels = new Color[width * height];
+ float inv = 1f / (size - 1f);
+
+ for (int z = 0; z < size; z++)
+ {
+ var offset = z * size;
+ var b = z * inv;
+
+ for (int y = 0; y < size; y++)
+ {
+ var g = y * inv;
+
+ for (int x = 0; x < size; x++)
+ {
+ var r = x * inv;
+ pixels[y * width + offset + x] = new Color(r, g, b);
+ }
+ }
+ }
+
+ var format = TextureFormat.RGBAHalf;
+ if (!format.IsSupported())
+ format = TextureFormat.ARGB32;
+
+ texture = new Texture2D(size * size, size, format, false, true)
+ {
+ name = "Strip Lut" + size,
+ hideFlags = HideFlags.DontSave,
+ filterMode = FilterMode.Bilinear,
+ wrapMode = TextureWrapMode.Clamp,
+ anisoLevel = 0
+ };
+ texture.SetPixels(pixels);
+ texture.Apply();
+ m_LutStrips.Add(size, texture);
+ }
+
+ return texture;
+ }
+
+ #endregion
+
+ #region Rendering
+
+ static PostProcessResources s_Resources;
+ static Mesh s_FullscreenTriangle;
+
+ ///
+ /// A fullscreen triangle mesh.
+ ///
+ public static Mesh fullscreenTriangle
+ {
+ get
+ {
+ if (s_FullscreenTriangle != null)
+ return s_FullscreenTriangle;
+
+ s_FullscreenTriangle = new Mesh { name = "Fullscreen Triangle" };
+
+ // Because we have to support older platforms (GLES2/3, DX9 etc) we can't do all of
+ // this directly in the vertex shader using vertex ids :(
+ s_FullscreenTriangle.SetVertices(new List
+ {
+ new Vector3(-1f, -1f, 0f),
+ new Vector3(-1f, 3f, 0f),
+ new Vector3(3f, -1f, 0f)
+ });
+ s_FullscreenTriangle.SetIndices(new[] { 0, 1, 2 }, MeshTopology.Triangles, 0, false);
+ s_FullscreenTriangle.UploadMeshData(false);
+
+ return s_FullscreenTriangle;
+ }
+ }
+
+ static Material s_CopyStdMaterial;
+
+ ///
+ /// A simple copy material to use with the builtin pipelines.
+ ///
+ public static Material copyStdMaterial
+ {
+ get
+ {
+ if (s_CopyStdMaterial != null)
+ return s_CopyStdMaterial;
+
+ Assert.IsNotNull(s_Resources);
+ var shader = s_Resources.shaders.copyStd;
+ s_CopyStdMaterial = new Material(shader)
+ {
+ name = "PostProcess - CopyStd",
+ hideFlags = HideFlags.HideAndDontSave
+ };
+
+ return s_CopyStdMaterial;
+ }
+ }
+
+ static Material s_CopyStdFromDoubleWideMaterial;
+
+ ///
+ /// A double-wide copy material to use with VR and the builtin pipelines.
+ ///
+ public static Material copyStdFromDoubleWideMaterial
+ {
+ get
+ {
+ if (s_CopyStdFromDoubleWideMaterial != null)
+ return s_CopyStdFromDoubleWideMaterial;
+
+ Assert.IsNotNull(s_Resources);
+ var shader = s_Resources.shaders.copyStdFromDoubleWide;
+ s_CopyStdFromDoubleWideMaterial = new Material(shader)
+ {
+ name = "PostProcess - CopyStdFromDoubleWide",
+ hideFlags = HideFlags.HideAndDontSave
+ };
+
+ return s_CopyStdFromDoubleWideMaterial;
+ }
+ }
+
+ static Material s_CopyMaterial;
+
+ ///
+ /// A simple copy material independent from the rendering pipeline.
+ ///
+ public static Material copyMaterial
+ {
+ get
+ {
+ if (s_CopyMaterial != null)
+ return s_CopyMaterial;
+
+ Assert.IsNotNull(s_Resources);
+ var shader = s_Resources.shaders.copy;
+ s_CopyMaterial = new Material(shader)
+ {
+ name = "PostProcess - Copy",
+ hideFlags = HideFlags.HideAndDontSave
+ };
+
+ return s_CopyMaterial;
+ }
+ }
+
+ static Material s_CopyFromTexArrayMaterial;
+
+ ///
+ /// A copy material with a texture array slice as a source for the builtin pipelines.
+ ///
+ public static Material copyFromTexArrayMaterial
+ {
+ get
+ {
+ if (s_CopyFromTexArrayMaterial != null)
+ return s_CopyFromTexArrayMaterial;
+
+ Assert.IsNotNull(s_Resources);
+ var shader = s_Resources.shaders.copyStdFromTexArray;
+ s_CopyFromTexArrayMaterial = new Material(shader)
+ {
+ name = "PostProcess - CopyFromTexArray",
+ hideFlags = HideFlags.HideAndDontSave
+ };
+
+ return s_CopyFromTexArrayMaterial;
+ }
+ }
+
+ static PropertySheet s_CopySheet;
+
+ ///
+ /// A pre-configured for .
+ ///
+ public static PropertySheet copySheet
+ {
+ get
+ {
+ if (s_CopySheet == null)
+ s_CopySheet = new PropertySheet(copyMaterial);
+
+ return s_CopySheet;
+ }
+ }
+
+ static PropertySheet s_CopyFromTexArraySheet;
+
+ ///
+ /// A pre-configured for .
+ ///
+ public static PropertySheet copyFromTexArraySheet
+ {
+ get
+ {
+ if (s_CopyFromTexArraySheet == null)
+ s_CopyFromTexArraySheet = new PropertySheet(copyFromTexArrayMaterial);
+
+ return s_CopyFromTexArraySheet;
+ }
+ }
+
+ internal static bool isValidResources()
+ {
+ return s_Resources != null;
+ }
+
+ internal static void UpdateResources(PostProcessResources resources)
+ {
+ Destroy(s_CopyMaterial);
+ Destroy(s_CopyStdMaterial);
+ Destroy(s_CopyFromTexArrayMaterial);
+ Destroy(s_CopyStdFromDoubleWideMaterial);
+
+ s_CopyMaterial = null;
+ s_CopyStdMaterial = null;
+ s_CopyFromTexArrayMaterial = null;
+ s_CopyStdFromDoubleWideMaterial = null;
+
+ s_CopySheet = null;
+ s_CopyFromTexArraySheet = null;
+
+ s_Resources = resources;
+ }
+
+ ///
+ /// Sets the current render target using specified .
+ ///
+ /// The command buffer to set the render target on
+ /// The render target to set
+ /// The load action
+ /// The store action
+ ///
+ /// are only used on Unity 2018.2 or newer.
+ ///
+ public static void SetRenderTargetWithLoadStoreAction(this CommandBuffer cmd, RenderTargetIdentifier rt, RenderBufferLoadAction loadAction, RenderBufferStoreAction storeAction)
+ {
+#if UNITY_2018_2_OR_NEWER
+ cmd.SetRenderTarget(rt, loadAction, storeAction);
+#else
+ cmd.SetRenderTarget(rt);
+#endif
+ }
+
+ ///
+ /// Sets the current render target using specified .
+ ///
+ /// The command buffer to set the render target on
+ /// The render target to set
+ /// The load action
+ /// The store action
+ /// The load action for the depth/stencil part of rt
+ /// The store action for the depth/stencil part of rt
+ ///
+ /// are only used on Unity 2018.2 or newer.
+ ///
+ public static void SetRenderTargetWithLoadStoreAction(this CommandBuffer cmd, RenderTargetIdentifier rt,
+ RenderBufferLoadAction loadAction, RenderBufferStoreAction storeAction,
+ RenderBufferLoadAction depthLoadAction, RenderBufferStoreAction depthStoreAction)
+ {
+#if UNITY_2018_2_OR_NEWER
+ cmd.SetRenderTarget(rt, loadAction, storeAction, depthLoadAction, depthStoreAction);
+#else
+ cmd.SetRenderTarget(rt);
+#endif
+ }
+
+ ///
+ /// Sets the current render target and its depth using specified .
+ ///
+ /// The command buffer to set the render target on
+ /// The render target to set as color
+ /// The load action for the color render target
+ /// The store action for the color render target
+ /// The render target to set as depth
+ /// The load action for the depth render target
+ /// The store action for the depth render target
+ public static void SetRenderTargetWithLoadStoreAction(this CommandBuffer cmd,
+ RenderTargetIdentifier color, RenderBufferLoadAction colorLoadAction, RenderBufferStoreAction colorStoreAction,
+ RenderTargetIdentifier depth, RenderBufferLoadAction depthLoadAction, RenderBufferStoreAction depthStoreAction)
+ {
+#if UNITY_2018_2_OR_NEWER
+ cmd.SetRenderTarget(color, colorLoadAction, colorStoreAction, depth, depthLoadAction, depthStoreAction);
+#else
+ cmd.SetRenderTarget(color, depth);
+#endif
+ }
+
+ ///
+ /// Does a copy of source to destination using a fullscreen triangle.
+ ///
+ /// The command buffer to use
+ /// The source render target
+ /// The destination render target
+ /// Should the destination target be cleared?
+ /// An optional viewport to consider for the blit
+ /// Should the depth buffer be preserved?
+ public static void BlitFullscreenTriangle(this CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier destination, bool clear = false, Rect? viewport = null, bool preserveDepth = false)
+ {
+ cmd.SetGlobalTexture(ShaderIDs.MainTex, source);
+ var colorLoad = viewport == null ? LoadAction.DontCare : LoadAction.Load;
+ cmd.SetRenderTargetWithLoadStoreAction(destination, colorLoad, StoreAction.Store, preserveDepth ? LoadAction.Load : colorLoad, StoreAction.Store);
+
+ if (viewport != null)
+ cmd.SetViewport(viewport.Value);
+
+ if (clear)
+ cmd.ClearRenderTarget(true, true, Color.clear);
+
+ cmd.DrawMesh(fullscreenTriangle, Matrix4x4.identity, copyMaterial, 0, 0);
+ }
+
+ ///
+ /// Blits a fullscreen triangle using a given material.
+ ///
+ /// The command buffer to use
+ /// The source render target
+ /// The destination render target
+ /// The property sheet to use
+ /// The pass from the material to use
+ /// The load action for this blit
+ /// An optional viewport to consider for the blit
+ /// Should the depth buffer be preserved?
+ public static void BlitFullscreenTriangle(this CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier destination, PropertySheet propertySheet, int pass, RenderBufferLoadAction loadAction, Rect? viewport = null, bool preserveDepth = false)
+ {
+ cmd.SetGlobalTexture(ShaderIDs.MainTex, source);
+#if UNITY_2018_2_OR_NEWER
+ bool clear = (loadAction == LoadAction.Clear);
+ if (clear)
+ loadAction = LoadAction.DontCare;
+#else
+ bool clear = false;
+#endif
+ if (viewport != null)
+ loadAction = LoadAction.Load;
+
+ cmd.SetRenderTargetWithLoadStoreAction(destination, loadAction, StoreAction.Store, preserveDepth ? LoadAction.Load : loadAction, StoreAction.Store);
+
+ if (viewport != null)
+ cmd.SetViewport(viewport.Value);
+
+ if (clear)
+ cmd.ClearRenderTarget(true, true, Color.clear);
+
+ cmd.DrawMesh(fullscreenTriangle, Matrix4x4.identity, propertySheet.material, 0, pass, propertySheet.properties);
+ }
+
+ ///
+ /// Blits a fullscreen triangle using a given material.
+ ///
+ /// The command buffer to use
+ /// The source render target
+ /// The destination render target
+ /// The property sheet to use
+ /// The pass from the material to use
+ /// Should the destination target be cleared?
+ /// An optional viewport to consider for the blit
+ /// Should the depth buffer be preserved?
+ public static void BlitFullscreenTriangle(this CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier destination, PropertySheet propertySheet, int pass, bool clear = false, Rect? viewport = null, bool preserveDepth = false)
+ {
+#if UNITY_2018_2_OR_NEWER
+ cmd.BlitFullscreenTriangle(source, destination, propertySheet, pass, clear ? LoadAction.Clear : LoadAction.DontCare, viewport, preserveDepth);
+#else
+ cmd.SetGlobalTexture(ShaderIDs.MainTex, source);
+ var loadAction = viewport == null ? LoadAction.DontCare : LoadAction.Load;
+ cmd.SetRenderTargetWithLoadStoreAction(destination, loadAction, StoreAction.Store, preserveDepth ? LoadAction.Load : loadAction, StoreAction.Store);
+
+ if (viewport != null)
+ cmd.SetViewport(viewport.Value);
+
+ if (clear)
+ cmd.ClearRenderTarget(true, true, Color.clear);
+
+ cmd.DrawMesh(fullscreenTriangle, Matrix4x4.identity, propertySheet.material, 0, pass, propertySheet.properties);
+#endif
+ }
+
+ ///
+ /// Blits a fullscreen triangle from a double-wide source.
+ ///
+ /// The command buffer to use
+ /// The source render target
+ /// The destination render target
+ /// The material to use for the blit
+ /// The pass from the material to use
+ /// The target eye
+ public static void BlitFullscreenTriangleFromDoubleWide(this CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier destination, Material material, int pass, int eye)
+ {
+ Vector4 uvScaleOffset = new Vector4(0.5f, 1.0f, 0, 0);
+
+ if (eye == 1)
+ uvScaleOffset.z = 0.5f;
+ cmd.SetGlobalVector(ShaderIDs.UVScaleOffset, uvScaleOffset);
+ cmd.BuiltinBlit(source, destination, material, pass);
+ }
+
+ ///
+ /// Blits a fullscreen triangle to a double-wide destination.
+ ///
+ /// The command buffer to use
+ /// The source render target
+ /// The destination render target
+ /// The property sheet to use
+ /// The pass from the material to use
+ /// The target eye
+ public static void BlitFullscreenTriangleToDoubleWide(this CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier destination, PropertySheet propertySheet, int pass, int eye)
+ {
+ Vector4 posScaleOffset = new Vector4(0.5f, 1.0f, -0.5f, 0);
+
+ if (eye == 1)
+ posScaleOffset.z = 0.5f;
+ propertySheet.EnableKeyword("STEREO_DOUBLEWIDE_TARGET");
+ propertySheet.properties.SetVector(ShaderIDs.PosScaleOffset, posScaleOffset);
+ cmd.BlitFullscreenTriangle(source, destination, propertySheet, 0);
+ }
+
+ ///
+ /// Blits a fullscreen triangle using a given material.
+ ///
+ /// The command buffer to use
+ /// The source texture array
+ /// The destination render target
+ /// The property sheet to use
+ /// The pass from the material to use
+ /// Should the destination target be cleared?
+ /// The slice to use for the texture array
+ public static void BlitFullscreenTriangleFromTexArray(this CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier destination, PropertySheet propertySheet, int pass, bool clear = false, int depthSlice = -1)
+ {
+ cmd.SetGlobalTexture(ShaderIDs.MainTex, source);
+ cmd.SetGlobalFloat(ShaderIDs.DepthSlice, depthSlice);
+ cmd.SetRenderTargetWithLoadStoreAction(destination, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store);
+
+ if (clear)
+ cmd.ClearRenderTarget(true, true, Color.clear);
+
+ cmd.DrawMesh(fullscreenTriangle, Matrix4x4.identity, propertySheet.material, 0, pass, propertySheet.properties);
+ }
+
+ ///
+ /// Blits a fullscreen triangle using a given material.
+ ///
+ /// The command buffer to use
+ /// The source render target
+ /// The destination render target
+ /// The property sheet to use
+ /// The pass from the material to use
+ /// Should the destination target be cleared?
+ /// The array slice to consider as a source
+ public static void BlitFullscreenTriangleToTexArray(this CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier destination, PropertySheet propertySheet, int pass, bool clear = false, int depthSlice = -1)
+ {
+ cmd.SetGlobalTexture(ShaderIDs.MainTex, source);
+ cmd.SetGlobalFloat(ShaderIDs.DepthSlice, depthSlice);
+ cmd.SetRenderTarget(destination, 0, CubemapFace.Unknown, -1);
+
+ if (clear)
+ cmd.ClearRenderTarget(true, true, Color.clear);
+
+ cmd.DrawMesh(fullscreenTriangle, Matrix4x4.identity, propertySheet.material, 0, pass, propertySheet.properties);
+ }
+
+ ///
+ /// Blits a fullscreen triangle using a given material.
+ ///
+ /// The command buffer to use
+ /// The source render target
+ /// The destination render target
+ /// The depth render target
+ /// The property sheet to use
+ /// The pass from the material to use
+ /// Should the destination target be cleared?
+ /// An optional viewport to consider for the blit
+ public static void BlitFullscreenTriangle(this CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier destination, RenderTargetIdentifier depth, PropertySheet propertySheet, int pass, bool clear = false, Rect? viewport = null)
+ {
+ cmd.SetGlobalTexture(ShaderIDs.MainTex, source);
+
+ LoadAction loadAction = viewport == null ? LoadAction.DontCare : LoadAction.Load;
+ if (clear)
+ {
+ cmd.SetRenderTargetWithLoadStoreAction(destination, loadAction, StoreAction.Store, depth, loadAction, StoreAction.Store);
+ cmd.ClearRenderTarget(true, true, Color.clear);
+ }
+ else
+ {
+ cmd.SetRenderTargetWithLoadStoreAction(destination, loadAction, StoreAction.Store, depth, LoadAction.Load, StoreAction.Store);
+ }
+
+ if (viewport != null)
+ cmd.SetViewport(viewport.Value);
+
+ cmd.DrawMesh(fullscreenTriangle, Matrix4x4.identity, propertySheet.material, 0, pass, propertySheet.properties);
+ }
+
+ ///
+ /// Blits a fullscreen triangle using a given material.
+ ///
+ /// The command buffer to use
+ /// The source render target
+ /// An array of destinations render targets
+ /// The depth render target
+ /// The property sheet to use
+ /// The pass from the material to use
+ /// Should the destination target be cleared?
+ /// An optional viewport to consider for the blit
+ public static void BlitFullscreenTriangle(this CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier[] destinations, RenderTargetIdentifier depth, PropertySheet propertySheet, int pass, bool clear = false, Rect? viewport = null)
+ {
+ cmd.SetGlobalTexture(ShaderIDs.MainTex, source);
+ cmd.SetRenderTarget(destinations, depth);
+
+ if (viewport != null)
+ cmd.SetViewport(viewport.Value);
+
+ if (clear)
+ cmd.ClearRenderTarget(true, true, Color.clear);
+
+ cmd.DrawMesh(fullscreenTriangle, Matrix4x4.identity, propertySheet.material, 0, pass, propertySheet.properties);
+ }
+
+ ///
+ /// Does a copy of source to destination using the builtin blit command.
+ ///
+ /// The command buffer to use
+ /// The source render target
+ /// The destination render target
+ public static void BuiltinBlit(this CommandBuffer cmd, Rendering.RenderTargetIdentifier source, RenderTargetIdentifier destination)
+ {
+#if UNITY_2018_2_OR_NEWER
+ cmd.SetRenderTarget(destination, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store);
+ destination = BuiltinRenderTextureType.CurrentActive;
+#endif
+ cmd.Blit(source, destination);
+ }
+
+ ///
+ /// Blits a fullscreen quad using the builtin blit command and a given material.
+ ///
+ /// The command buffer to use
+ /// The source render target
+ /// The destination render target
+ /// The material to use for the blit
+ /// The pass from the material to use
+ public static void BuiltinBlit(this CommandBuffer cmd, Rendering.RenderTargetIdentifier source, RenderTargetIdentifier destination, Material mat, int pass = 0)
+ {
+#if UNITY_2018_2_OR_NEWER
+ cmd.SetRenderTarget(destination, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store);
+ destination = BuiltinRenderTextureType.CurrentActive;
+#endif
+ cmd.Blit(source, destination, mat, pass);
+ }
+
+ // Fast basic copy texture if available, falls back to blit copy if not
+ // Assumes that both textures have the exact same type and format
+ ///
+ /// Copies the content of a texture into the other. Both textures must have the same size
+ /// and format or this method will fail.
+ ///
+ /// The command buffer to use
+ /// The source render target
+ /// The destination render target
+ ///
+ /// If the CopyTexture command isn't supported on the target platform it will revert to a
+ /// fullscreen blit command instead.
+ ///
+ public static void CopyTexture(CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier destination)
+ {
+ if (SystemInfo.copyTextureSupport > CopyTextureSupport.None)
+ {
+ cmd.CopyTexture(source, destination);
+ return;
+ }
+
+ cmd.BlitFullscreenTriangle(source, destination);
+ }
+
+ // TODO: Generalize the GetTemporaryRT and Blit commands in order to support
+ // RT Arrays for Stereo Instancing/MultiView
+
+ #endregion
+
+ #region Unity specifics & misc methods
+
+ ///
+ /// Returns true if a scriptable render pipeline is currently in use, false
+ /// otherwise.
+ ///
+ public static bool scriptableRenderPipelineActive
+ {
+#if UNITY_2019_3_OR_NEWER
+ get { return GraphicsSettings.currentRenderPipeline != null; }
+#else
+ get { return GraphicsSettings.renderPipelineAsset != null; }
+#endif
+ }
+
+ ///
+ /// Returns true if deferred shading is supported on the target platform,
+ /// false otherwise.
+ ///
+ public static bool supportsDeferredShading
+ {
+ get { return scriptableRenderPipelineActive || GraphicsSettings.GetShaderMode(BuiltinShaderType.DeferredShading) != BuiltinShaderMode.Disabled; }
+ }
+
+ ///
+ /// Returns true if is supported on the
+ /// target platform, false otherwise.
+ ///
+ public static bool supportsDepthNormals
+ {
+ get { return scriptableRenderPipelineActive || GraphicsSettings.GetShaderMode(BuiltinShaderType.DepthNormals) != BuiltinShaderMode.Disabled; }
+ }
+
+#if UNITY_EDITOR
+ ///
+ /// Returns true if single-pass stereo rendering is selected, false otherwise.
+ ///
+ ///
+ /// This property only works in the editor.
+ ///
+ public static bool isSinglePassStereoSelected
+ {
+ get
+ {
+#if (ENABLE_VR_MODULE && ENABLE_VR) && !UNITY_2020_1_OR_NEWER
+ return UnityEditorInternal.VR.VREditor.GetVREnabledOnTargetGroup(BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget))
+ && PlayerSettings.stereoRenderingPath == UnityEditor.StereoRenderingPath.SinglePass;
+#else
+ return false;
+#endif
+ }
+ }
+#endif
+
+ ///
+ /// Returns true if single-pass stereo rendering is active, false otherwise.
+ ///
+ ///
+ /// This property only works in the editor.
+ ///
+ // TODO: Check for SPSR support at runtime
+ public static bool isSinglePassStereoEnabled
+ {
+ get
+ {
+#if UNITY_EDITOR
+ return isSinglePassStereoSelected && Application.isPlaying;
+#elif !(ENABLE_VR_MODULE && ENABLE_VR)
+ return false;
+#else
+ return UnityEngine.XR.XRSettings.eyeTextureDesc.vrUsage == VRTextureUsage.TwoEyes;
+#endif
+ }
+ }
+
+ ///
+ /// Returns true if VR is enabled, false otherwise.
+ ///
+ public static bool isVREnabled
+ {
+ get
+ {
+#if (ENABLE_VR_MODULE && ENABLE_VR) && UNITY_EDITOR && !UNITY_2020_1_OR_NEWER
+ return UnityEditorInternal.VR.VREditor.GetVREnabledOnTargetGroup(BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget));
+#elif UNITY_XBOXONE || !(ENABLE_VR_MODULE && ENABLE_VR)
+ return false;
+#else
+ return UnityEngine.XR.XRSettings.enabled;
+#endif
+ }
+ }
+
+ ///
+ /// Returns true if the target platform is Android and the selected API is OpenGL,
+ /// false otherwise.
+ ///
+ public static bool isAndroidOpenGL
+ {
+ get { return Application.platform == RuntimePlatform.Android && SystemInfo.graphicsDeviceType != GraphicsDeviceType.Vulkan; }
+ }
+
+ ///
+ /// Gets the default HDR render texture format for the current target platform.
+ ///
+ public static RenderTextureFormat defaultHDRRenderTextureFormat
+ {
+ get
+ {
+#if !UNITY_2019_3_OR_NEWER && (UNITY_ANDROID || UNITY_IPHONE || UNITY_TVOS || UNITY_EDITOR)
+ RenderTextureFormat format = RenderTextureFormat.RGB111110Float;
+#if UNITY_EDITOR
+ var target = EditorUserBuildSettings.activeBuildTarget;
+ if (target != BuildTarget.Android && target != BuildTarget.iOS && target != BuildTarget.tvOS)
+ return RenderTextureFormat.DefaultHDR;
+#endif // UNITY_EDITOR
+ if (format.IsSupported())
+ return format;
+#endif // #if !UNITY_2019_3_OR_NEWER && (UNITY_ANDROID || UNITY_IPHONE || UNITY_TVOS || UNITY_EDITOR)
+ return RenderTextureFormat.DefaultHDR;
+ }
+ }
+
+ ///
+ /// Checks if a given render texture format is a floating-point format.
+ ///
+ /// The format to test
+ /// true if the format is floating-point, false otherwise
+ public static bool isFloatingPointFormat(RenderTextureFormat format)
+ {
+ return format == RenderTextureFormat.DefaultHDR || format == RenderTextureFormat.ARGBHalf || format == RenderTextureFormat.ARGBFloat ||
+ format == RenderTextureFormat.RGFloat || format == RenderTextureFormat.RGHalf ||
+ format == RenderTextureFormat.RFloat || format == RenderTextureFormat.RHalf ||
+ format == RenderTextureFormat.RGB111110Float;
+ }
+
+ ///
+ /// Checks if a given render texture format has an alpha channel.
+ ///
+ /// The format to test
+ /// true if the format has an alpha channel, false otherwise
+ internal static bool hasAlpha(RenderTextureFormat format)
+ {
+ UnityEngine.Experimental.Rendering.GraphicsFormat gformat = UnityEngine.Experimental.Rendering.GraphicsFormatUtility.GetGraphicsFormat(format, RenderTextureReadWrite.Default);
+ return UnityEngine.Experimental.Rendering.GraphicsFormatUtility.HasAlphaChannel(gformat);
+ }
+
+ ///
+ /// Properly destroys a given Unity object.
+ ///
+ /// The object to destroy
+ public static void Destroy(UnityObject obj)
+ {
+ if (obj != null)
+ {
+#if UNITY_EDITOR
+ if (Application.isPlaying)
+ UnityObject.Destroy(obj);
+ else
+ UnityObject.DestroyImmediate(obj);
+#else
+ UnityObject.Destroy(obj);
+#endif
+ }
+ }
+
+ ///
+ /// Returns true if the current color space setting is set to Linear,
+ /// false otherwise.
+ ///
+ public static bool isLinearColorSpace
+ {
+ get { return QualitySettings.activeColorSpace == ColorSpace.Linear; }
+ }
+
+ ///
+ /// Checks if resolved depth is available on the current target platform.
+ ///
+ /// A rendering camera
+ /// true if resolved depth is available, false otherwise
+ public static bool IsResolvedDepthAvailable(Camera camera)
+ {
+ // AFAIK resolved depth is only available on D3D11/12 via BuiltinRenderTextureType.ResolvedDepth
+ // TODO: Is there more proper way to determine this? What about SRPs?
+ var gtype = SystemInfo.graphicsDeviceType;
+ return camera.actualRenderingPath == RenderingPath.DeferredShading &&
+ (gtype == GraphicsDeviceType.Direct3D11
+ || gtype == GraphicsDeviceType.Direct3D12
+#if UNITY_GAMECORE
+ || gtype == GraphicsDeviceType.GameCoreXboxSeries
+ || gtype == GraphicsDeviceType.GameCoreXboxOne
+#endif
+ || gtype == GraphicsDeviceType.XboxOne
+ || gtype == GraphicsDeviceType.XboxOneD3D12
+ );
+ }
+
+ ///
+ /// Properly destroys a given profile.
+ ///
+ /// The profile to destroy
+ /// Should we destroy all the embedded settings?
+ public static void DestroyProfile(PostProcessProfile profile, bool destroyEffects)
+ {
+ if (destroyEffects)
+ {
+ foreach (var effect in profile.settings)
+ Destroy(effect);
+ }
+
+ Destroy(profile);
+ }
+
+ ///
+ /// Properly destroys a volume.
+ ///
+ /// The volume to destroy
+ /// Should we destroy the attached profile?
+ /// Should we destroy the volume Game Object?
+ public static void DestroyVolume(PostProcessVolume volume, bool destroyProfile, bool destroyGameObject = false)
+ {
+ if (destroyProfile)
+ DestroyProfile(volume.profileRef, true);
+
+ var gameObject = volume.gameObject;
+ Destroy(volume);
+
+ if (destroyGameObject)
+ Destroy(gameObject);
+ }
+
+ ///
+ /// Checks if a post-processing layer is active.
+ ///
+ /// The layer to check; can be null
+ /// true if the layer is enabled, false otherwise
+ public static bool IsPostProcessingActive(PostProcessLayer layer)
+ {
+ return layer != null
+ && layer.enabled;
+ }
+
+ ///
+ /// Checks if temporal anti-aliasing is active on a given post-process layer.
+ ///
+ /// The layer to check
+ /// true if temporal anti-aliasing is active, false otherwise
+ public static bool IsTemporalAntialiasingActive(PostProcessLayer layer)
+ {
+ return IsPostProcessingActive(layer)
+ && layer.antialiasingMode == PostProcessLayer.Antialiasing.TemporalAntialiasing
+ && layer.temporalAntialiasing.IsSupported();
+ }
+#if UNITY_2017_3_OR_NEWER
+ ///
+ /// Checks if dynamic resolution is enabled on a given camera.
+ ///
+ /// The camera to check
+ /// true if dynamic resolution is enabled, false otherwise
+ public static bool IsDynamicResolutionEnabled(Camera camera)
+ {
+ return camera.allowDynamicResolution || (camera.targetTexture != null && camera.targetTexture.useDynamicScale);
+ }
+#endif
+ ///
+ /// Gets all scene objects in the hierarchy, including inactive objects. This method is slow
+ /// on large scenes and should be used with extreme caution.
+ ///
+ /// The component to look for
+ /// A list of all components of type T in the scene
+ public static IEnumerable GetAllSceneObjects()
+ where T : Component
+ {
+ var queue = new Queue();
+ var roots = SceneManager.GetActiveScene().GetRootGameObjects();
+
+ foreach (var root in roots)
+ {
+ queue.Enqueue(root.transform);
+
+ if (root.TryGetComponent(out var comp))
+ yield return comp;
+ }
+
+ while (queue.Count > 0)
+ {
+ foreach (Transform child in queue.Dequeue())
+ {
+ queue.Enqueue(child);
+
+ if (child.TryGetComponent(out var comp))
+ yield return comp;
+ }
+ }
+ }
+
+ ///
+ /// Creates an instance of a class if it's null.
+ ///
+ /// The type to create
+ /// A reference to an instance to check and create if needed
+ public static void CreateIfNull(ref T obj)
+ where T : class, new()
+ {
+ if (obj == null)
+ obj = new T();
+ }
+
+ #endregion
+
+ #region Maths
+
+ ///
+ /// Returns the base-2 exponential function of , which is 2
+ /// raised to the power .
+ ///
+ /// Value of the exponent
+ /// The base-2 exponential function of
+ public static float Exp2(float x)
+ {
+ return Mathf.Exp(x * 0.69314718055994530941723212145818f);
+ }
+
+ ///
+ /// Gets a jittered perspective projection matrix for a given camera.
+ ///
+ /// The camera to build the projection matrix for
+ /// The jitter offset
+ /// A jittered projection matrix
+ public static Matrix4x4 GetJitteredPerspectiveProjectionMatrix(Camera camera, Vector2 offset)
+ {
+ float near = camera.nearClipPlane;
+ float far = camera.farClipPlane;
+
+ float vertical = Mathf.Tan(0.5f * Mathf.Deg2Rad * camera.fieldOfView) * near;
+ float horizontal = vertical * camera.aspect;
+
+ offset.x *= horizontal / (0.5f * camera.pixelWidth);
+ offset.y *= vertical / (0.5f * camera.pixelHeight);
+
+ var matrix = camera.projectionMatrix;
+
+ matrix[0, 2] += offset.x / horizontal;
+ matrix[1, 2] += offset.y / vertical;
+
+ return matrix;
+ }
+
+ ///
+ /// Gets a jittered orthographic projection matrix for a given camera.
+ ///
+ /// The camera to build the orthographic matrix for
+ /// The jitter offset
+ /// A jittered projection matrix
+ public static Matrix4x4 GetJitteredOrthographicProjectionMatrix(Camera camera, Vector2 offset)
+ {
+ float vertical = camera.orthographicSize;
+ float horizontal = vertical * camera.aspect;
+
+ offset.x *= horizontal / (0.5f * camera.pixelWidth);
+ offset.y *= vertical / (0.5f * camera.pixelHeight);
+
+ float left = offset.x - horizontal;
+ float right = offset.x + horizontal;
+ float top = offset.y + vertical;
+ float bottom = offset.y - vertical;
+
+ return Matrix4x4.Ortho(left, right, bottom, top, camera.nearClipPlane, camera.farClipPlane);
+ }
+
+ ///
+ /// Gets a jittered perspective projection matrix from an original projection matrix.
+ ///
+ /// The current render context
+ /// The original projection matrix
+ /// The jitter offset
+ /// A jittered projection matrix
+ public static Matrix4x4 GenerateJitteredProjectionMatrixFromOriginal(PostProcessRenderContext context, Matrix4x4 origProj, Vector2 jitter)
+ {
+ var planes = origProj.decomposeProjection;
+
+ float vertFov = Math.Abs(planes.top) + Math.Abs(planes.bottom);
+ float horizFov = Math.Abs(planes.left) + Math.Abs(planes.right);
+
+ var planeJitter = new Vector2(jitter.x * horizFov / context.screenWidth,
+ jitter.y * vertFov / context.screenHeight);
+
+ planes.left += planeJitter.x;
+ planes.right += planeJitter.x;
+ planes.top += planeJitter.y;
+ planes.bottom += planeJitter.y;
+
+ var jitteredMatrix = Matrix4x4.Frustum(planes);
+
+ return jitteredMatrix;
+ }
+
+ #endregion
+
+ #region Reflection
+
+ static IEnumerable m_AssemblyTypes;
+
+ ///
+ /// Gets all currently available assembly types.
+ ///
+ /// A list of all currently available assembly types
+ ///
+ /// This method is slow and should be use with extreme caution. We recommend you use
+ /// instead if possible.
+ ///
+ ///
+ public static IEnumerable GetAllAssemblyTypes()
+ {
+ if (m_AssemblyTypes == null)
+ {
+ m_AssemblyTypes = AppDomain.CurrentDomain.GetAssemblies()
+ .SelectMany(t =>
+ {
+ // Ugly hack to handle mis-versioned dlls
+ var innerTypes = new Type[0];
+ try
+ {
+ innerTypes = t.GetTypes();
+ }
+ catch { }
+ return innerTypes;
+ });
+ }
+
+ return m_AssemblyTypes;
+ }
+
+ ///
+ /// Gets all currently available assembly types derived from type .
+ ///
+ /// The type to look for
+ /// A list of all currently available assembly types derived from type
+ public static IEnumerable GetAllTypesDerivedFrom()
+ {
+#if UNITY_EDITOR && UNITY_2019_2_OR_NEWER
+ return UnityEditor.TypeCache.GetTypesDerivedFrom();
+#else
+ return GetAllAssemblyTypes().Where(t => t.IsSubclassOf(typeof(T)));
+#endif
+ }
+
+ ///
+ /// Helper method to get the first attribute of type T on a given type.
+ ///
+ /// The attribute type to look for
+ /// The type to explore
+ /// The attribute found
+ public static T GetAttribute(this Type type) where T : Attribute
+ {
+ Assert.IsTrue(type.IsDefined(typeof(T), false), "Attribute not found");
+ return (T)type.GetCustomAttributes(typeof(T), false)[0];
+ }
+
+ ///
+ /// Returns all attributes set on a specific member.
+ ///
+ /// The class type where the member is defined
+ /// The member type
+ /// An expression path to the member
+ /// An array of attributes
+ ///
+ /// This method doesn't return inherited attributes, only explicit ones.
+ ///
+ public static Attribute[] GetMemberAttributes(Expression> expr)
+ {
+ Expression body = expr;
+
+ if (body is LambdaExpression)
+ body = ((LambdaExpression)body).Body;
+
+ switch (body.NodeType)
+ {
+ case ExpressionType.MemberAccess:
+ var fi = (FieldInfo)((MemberExpression)body).Member;
+ return fi.GetCustomAttributes(false).Cast().ToArray();
+ default:
+ throw new InvalidOperationException();
+ }
+ }
+
+ ///
+ /// Returns a string path from an expression. This is mostly used to retrieve serialized
+ /// properties without hardcoding the field path as a string and thus allowing proper
+ /// refactoring features.
+ ///
+ /// The class type where the member is defined
+ /// The member type
+ /// An expression path fo the member
+ /// A string representation of the expression path
+ public static string GetFieldPath(Expression> expr)
+ {
+ MemberExpression me;
+ switch (expr.Body.NodeType)
+ {
+ case ExpressionType.MemberAccess:
+ me = expr.Body as MemberExpression;
+ break;
+ default:
+ throw new InvalidOperationException();
+ }
+
+ var members = new List();
+ while (me != null)
+ {
+ members.Add(me.Member.Name);
+ me = me.Expression as MemberExpression;
+ }
+
+ var sb = new StringBuilder();
+ for (int i = members.Count - 1; i >= 0; i--)
+ {
+ sb.Append(members[i]);
+ if (i > 0) sb.Append('.');
+ }
+
+ return sb.ToString();
+ }
+
+ #endregion
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Utils/RuntimeUtilities.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Utils/RuntimeUtilities.cs.meta
new file mode 100644
index 0000000..f26dd0e
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Utils/RuntimeUtilities.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: a2ed510c13db63f4ea5749ef503a99b5
+timeCreated: 1487868442
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Utils/ShaderIDs.cs b/com.unity.postprocessing/PostProcessing/Runtime/Utils/ShaderIDs.cs
new file mode 100644
index 0000000..f555f7b
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Utils/ShaderIDs.cs
@@ -0,0 +1,158 @@
+namespace UnityEngine.Rendering.PostProcessing
+{
+ // Pre-hashed shader ids - naming conventions are a bit off in this file as we use the same
+ // fields names as in the shaders for ease of use... Would be nice to clean this up at some
+ // point.
+ static class ShaderIDs
+ {
+ internal static readonly int MainTex = Shader.PropertyToID("_MainTex");
+
+ internal static readonly int Jitter = Shader.PropertyToID("_Jitter");
+ internal static readonly int Sharpness = Shader.PropertyToID("_Sharpness");
+ internal static readonly int FinalBlendParameters = Shader.PropertyToID("_FinalBlendParameters");
+ internal static readonly int HistoryTex = Shader.PropertyToID("_HistoryTex");
+
+ internal static readonly int SMAA_Flip = Shader.PropertyToID("_SMAA_Flip");
+ internal static readonly int SMAA_Flop = Shader.PropertyToID("_SMAA_Flop");
+
+ internal static readonly int AOParams = Shader.PropertyToID("_AOParams");
+ internal static readonly int AOColor = Shader.PropertyToID("_AOColor");
+ internal static readonly int OcclusionTexture1 = Shader.PropertyToID("_OcclusionTexture1");
+ internal static readonly int OcclusionTexture2 = Shader.PropertyToID("_OcclusionTexture2");
+ internal static readonly int SAOcclusionTexture = Shader.PropertyToID("_SAOcclusionTexture");
+ internal static readonly int MSVOcclusionTexture = Shader.PropertyToID("_MSVOcclusionTexture");
+ internal static readonly int DepthCopy = Shader.PropertyToID("DepthCopy");
+ internal static readonly int LinearDepth = Shader.PropertyToID("LinearDepth");
+ internal static readonly int LowDepth1 = Shader.PropertyToID("LowDepth1");
+ internal static readonly int LowDepth2 = Shader.PropertyToID("LowDepth2");
+ internal static readonly int LowDepth3 = Shader.PropertyToID("LowDepth3");
+ internal static readonly int LowDepth4 = Shader.PropertyToID("LowDepth4");
+ internal static readonly int TiledDepth1 = Shader.PropertyToID("TiledDepth1");
+ internal static readonly int TiledDepth2 = Shader.PropertyToID("TiledDepth2");
+ internal static readonly int TiledDepth3 = Shader.PropertyToID("TiledDepth3");
+ internal static readonly int TiledDepth4 = Shader.PropertyToID("TiledDepth4");
+ internal static readonly int Occlusion1 = Shader.PropertyToID("Occlusion1");
+ internal static readonly int Occlusion2 = Shader.PropertyToID("Occlusion2");
+ internal static readonly int Occlusion3 = Shader.PropertyToID("Occlusion3");
+ internal static readonly int Occlusion4 = Shader.PropertyToID("Occlusion4");
+ internal static readonly int Combined1 = Shader.PropertyToID("Combined1");
+ internal static readonly int Combined2 = Shader.PropertyToID("Combined2");
+ internal static readonly int Combined3 = Shader.PropertyToID("Combined3");
+
+ internal static readonly int SSRResolveTemp = Shader.PropertyToID("_SSRResolveTemp");
+ internal static readonly int Noise = Shader.PropertyToID("_Noise");
+ internal static readonly int Test = Shader.PropertyToID("_Test");
+ internal static readonly int Resolve = Shader.PropertyToID("_Resolve");
+ internal static readonly int History = Shader.PropertyToID("_History");
+ internal static readonly int ViewMatrix = Shader.PropertyToID("_ViewMatrix");
+ internal static readonly int InverseViewMatrix = Shader.PropertyToID("_InverseViewMatrix");
+ internal static readonly int ScreenSpaceProjectionMatrix = Shader.PropertyToID("_ScreenSpaceProjectionMatrix");
+ internal static readonly int Params2 = Shader.PropertyToID("_Params2");
+
+ internal static readonly int FogColor = Shader.PropertyToID("_FogColor");
+ internal static readonly int FogParams = Shader.PropertyToID("_FogParams");
+
+ internal static readonly int VelocityScale = Shader.PropertyToID("_VelocityScale");
+ internal static readonly int MaxBlurRadius = Shader.PropertyToID("_MaxBlurRadius");
+ internal static readonly int RcpMaxBlurRadius = Shader.PropertyToID("_RcpMaxBlurRadius");
+ internal static readonly int VelocityTex = Shader.PropertyToID("_VelocityTex");
+ internal static readonly int Tile2RT = Shader.PropertyToID("_Tile2RT");
+ internal static readonly int Tile4RT = Shader.PropertyToID("_Tile4RT");
+ internal static readonly int Tile8RT = Shader.PropertyToID("_Tile8RT");
+ internal static readonly int TileMaxOffs = Shader.PropertyToID("_TileMaxOffs");
+ internal static readonly int TileMaxLoop = Shader.PropertyToID("_TileMaxLoop");
+ internal static readonly int TileVRT = Shader.PropertyToID("_TileVRT");
+ internal static readonly int NeighborMaxTex = Shader.PropertyToID("_NeighborMaxTex");
+ internal static readonly int LoopCount = Shader.PropertyToID("_LoopCount");
+
+ internal static readonly int DepthOfFieldTemp = Shader.PropertyToID("_DepthOfFieldTemp");
+ internal static readonly int DepthOfFieldTex = Shader.PropertyToID("_DepthOfFieldTex");
+ internal static readonly int Distance = Shader.PropertyToID("_Distance");
+ internal static readonly int LensCoeff = Shader.PropertyToID("_LensCoeff");
+ internal static readonly int MaxCoC = Shader.PropertyToID("_MaxCoC");
+ internal static readonly int RcpMaxCoC = Shader.PropertyToID("_RcpMaxCoC");
+ internal static readonly int RcpAspect = Shader.PropertyToID("_RcpAspect");
+ internal static readonly int CoCTex = Shader.PropertyToID("_CoCTex");
+ internal static readonly int TaaParams = Shader.PropertyToID("_TaaParams");
+
+ internal static readonly int AutoExposureTex = Shader.PropertyToID("_AutoExposureTex");
+ internal static readonly int HistogramBuffer = Shader.PropertyToID("_HistogramBuffer");
+ internal static readonly int Params = Shader.PropertyToID("_Params");
+ internal static readonly int ScaleOffsetRes = Shader.PropertyToID("_ScaleOffsetRes");
+
+ internal static readonly int BloomTex = Shader.PropertyToID("_BloomTex");
+ internal static readonly int SampleScale = Shader.PropertyToID("_SampleScale");
+ internal static readonly int Threshold = Shader.PropertyToID("_Threshold");
+ internal static readonly int ColorIntensity = Shader.PropertyToID("_ColorIntensity");
+ internal static readonly int Bloom_DirtTex = Shader.PropertyToID("_Bloom_DirtTex");
+ internal static readonly int Bloom_Settings = Shader.PropertyToID("_Bloom_Settings");
+ internal static readonly int Bloom_Color = Shader.PropertyToID("_Bloom_Color");
+ internal static readonly int Bloom_DirtTileOffset = Shader.PropertyToID("_Bloom_DirtTileOffset");
+
+ internal static readonly int ChromaticAberration_Amount = Shader.PropertyToID("_ChromaticAberration_Amount");
+ internal static readonly int ChromaticAberration_SpectralLut = Shader.PropertyToID("_ChromaticAberration_SpectralLut");
+
+ internal static readonly int Distortion_CenterScale = Shader.PropertyToID("_Distortion_CenterScale");
+ internal static readonly int Distortion_Amount = Shader.PropertyToID("_Distortion_Amount");
+
+ internal static readonly int Lut2D = Shader.PropertyToID("_Lut2D");
+ internal static readonly int Lut3D = Shader.PropertyToID("_Lut3D");
+ internal static readonly int Lut3D_Params = Shader.PropertyToID("_Lut3D_Params");
+ internal static readonly int Lut2D_Params = Shader.PropertyToID("_Lut2D_Params");
+ internal static readonly int UserLut2D_Params = Shader.PropertyToID("_UserLut2D_Params");
+ internal static readonly int PostExposure = Shader.PropertyToID("_PostExposure");
+ internal static readonly int ColorBalance = Shader.PropertyToID("_ColorBalance");
+ internal static readonly int ColorFilter = Shader.PropertyToID("_ColorFilter");
+ internal static readonly int HueSatCon = Shader.PropertyToID("_HueSatCon");
+ internal static readonly int Brightness = Shader.PropertyToID("_Brightness");
+ internal static readonly int ChannelMixerRed = Shader.PropertyToID("_ChannelMixerRed");
+ internal static readonly int ChannelMixerGreen = Shader.PropertyToID("_ChannelMixerGreen");
+ internal static readonly int ChannelMixerBlue = Shader.PropertyToID("_ChannelMixerBlue");
+ internal static readonly int Lift = Shader.PropertyToID("_Lift");
+ internal static readonly int InvGamma = Shader.PropertyToID("_InvGamma");
+ internal static readonly int Gain = Shader.PropertyToID("_Gain");
+ internal static readonly int Curves = Shader.PropertyToID("_Curves");
+ internal static readonly int CustomToneCurve = Shader.PropertyToID("_CustomToneCurve");
+ internal static readonly int ToeSegmentA = Shader.PropertyToID("_ToeSegmentA");
+ internal static readonly int ToeSegmentB = Shader.PropertyToID("_ToeSegmentB");
+ internal static readonly int MidSegmentA = Shader.PropertyToID("_MidSegmentA");
+ internal static readonly int MidSegmentB = Shader.PropertyToID("_MidSegmentB");
+ internal static readonly int ShoSegmentA = Shader.PropertyToID("_ShoSegmentA");
+ internal static readonly int ShoSegmentB = Shader.PropertyToID("_ShoSegmentB");
+
+ internal static readonly int Vignette_Color = Shader.PropertyToID("_Vignette_Color");
+ internal static readonly int Vignette_Center = Shader.PropertyToID("_Vignette_Center");
+ internal static readonly int Vignette_Settings = Shader.PropertyToID("_Vignette_Settings");
+ internal static readonly int Vignette_Mask = Shader.PropertyToID("_Vignette_Mask");
+ internal static readonly int Vignette_Opacity = Shader.PropertyToID("_Vignette_Opacity");
+ internal static readonly int Vignette_Mode = Shader.PropertyToID("_Vignette_Mode");
+
+ internal static readonly int Grain_Params1 = Shader.PropertyToID("_Grain_Params1");
+ internal static readonly int Grain_Params2 = Shader.PropertyToID("_Grain_Params2");
+ internal static readonly int GrainTex = Shader.PropertyToID("_GrainTex");
+ internal static readonly int Phase = Shader.PropertyToID("_Phase");
+ internal static readonly int GrainNoiseParameters = Shader.PropertyToID("_NoiseParameters");
+
+ internal static readonly int LumaInAlpha = Shader.PropertyToID("_LumaInAlpha");
+
+ internal static readonly int DitheringTex = Shader.PropertyToID("_DitheringTex");
+ internal static readonly int Dithering_Coords = Shader.PropertyToID("_Dithering_Coords");
+
+ internal static readonly int From = Shader.PropertyToID("_From");
+ internal static readonly int To = Shader.PropertyToID("_To");
+ internal static readonly int Interp = Shader.PropertyToID("_Interp");
+ internal static readonly int TargetColor = Shader.PropertyToID("_TargetColor");
+
+ internal static readonly int HalfResFinalCopy = Shader.PropertyToID("_HalfResFinalCopy");
+ internal static readonly int WaveformSource = Shader.PropertyToID("_WaveformSource");
+ internal static readonly int WaveformBuffer = Shader.PropertyToID("_WaveformBuffer");
+ internal static readonly int VectorscopeBuffer = Shader.PropertyToID("_VectorscopeBuffer");
+
+ internal static readonly int RenderViewportScaleFactor = Shader.PropertyToID("_RenderViewportScaleFactor");
+
+ internal static readonly int UVTransform = Shader.PropertyToID("_UVTransform");
+ internal static readonly int DepthSlice = Shader.PropertyToID("_DepthSlice");
+ internal static readonly int UVScaleOffset = Shader.PropertyToID("_UVScaleOffset");
+ internal static readonly int PosScaleOffset = Shader.PropertyToID("_PosScaleOffset");
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Utils/ShaderIDs.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Utils/ShaderIDs.cs.meta
new file mode 100644
index 0000000..51297d7
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Utils/ShaderIDs.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: e4026acd2810a474b9be96bbeb80b959
+timeCreated: 1488904676
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Utils/Spline.cs b/com.unity.postprocessing/PostProcessing/Runtime/Utils/Spline.cs
new file mode 100644
index 0000000..2195044
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Utils/Spline.cs
@@ -0,0 +1,148 @@
+using System;
+using UnityEngine.Assertions;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ ///
+ /// A wrapper on top of to handle zero-key curves and keyframe
+ /// loops.
+ ///
+ [Serializable]
+ public sealed class Spline
+ {
+ ///
+ /// Precision of the curve.
+ ///
+ public const int k_Precision = 128;
+
+ ///
+ /// The inverse of the precision of the curve.
+ ///
+ public const float k_Step = 1f / k_Precision;
+
+ ///
+ /// The underlying animation curve instance.
+ ///
+ public AnimationCurve curve;
+
+ [SerializeField]
+ bool m_Loop;
+
+ [SerializeField]
+ float m_ZeroValue;
+
+ [SerializeField]
+ float m_Range;
+
+ AnimationCurve m_InternalLoopingCurve;
+
+ // Used to track frame changes for data caching
+ int frameCount = -1;
+
+ ///
+ /// An array holding pre-computed curve values.
+ ///
+ public float[] cachedData;
+
+ ///
+ /// Creates a new spline.
+ ///
+ /// The animation curve to base this spline off
+ /// The value to return when the curve has no keyframe
+ /// Should this curve loop?
+ /// The curve bounds
+ public Spline(AnimationCurve curve, float zeroValue, bool loop, Vector2 bounds)
+ {
+ Assert.IsNotNull(curve);
+ this.curve = curve;
+ m_ZeroValue = zeroValue;
+ m_Loop = loop;
+ m_Range = bounds.magnitude;
+ cachedData = new float[k_Precision];
+ }
+
+ ///
+ /// Caches the curve data at a given frame. The curve data will only be cached once per
+ /// frame.
+ ///
+ /// A frame number
+ public void Cache(int frame)
+ {
+ // Note: it would be nice to have a way to check if a curve has changed in any way, that
+ // would save quite a few CPU cycles instead of having to force cache it once per frame :/
+
+ // Only cache once per frame
+ if (frame == frameCount)
+ return;
+
+ var length = curve.length;
+
+ if (m_Loop && length > 1)
+ {
+ if (m_InternalLoopingCurve == null)
+ m_InternalLoopingCurve = new AnimationCurve();
+
+ var prev = curve[length - 1];
+ prev.time -= m_Range;
+ var next = curve[0];
+ next.time += m_Range;
+ m_InternalLoopingCurve.keys = curve.keys;
+ m_InternalLoopingCurve.AddKey(prev);
+ m_InternalLoopingCurve.AddKey(next);
+ }
+
+ for (int i = 0; i < k_Precision; i++)
+ cachedData[i] = Evaluate((float)i * k_Step, length);
+
+ frameCount = Time.renderedFrameCount;
+ }
+
+ ///
+ /// Evaluates the curve at a point in time.
+ ///
+ /// The time to evaluate
+ /// The number of keyframes in the curve
+ /// The value of the curve at time
+ public float Evaluate(float t, int length)
+ {
+ if (length == 0)
+ return m_ZeroValue;
+
+ if (!m_Loop || length == 1)
+ return curve.Evaluate(t);
+
+ return m_InternalLoopingCurve.Evaluate(t);
+ }
+
+ ///
+ /// Evaluates the curve at a point in time.
+ ///
+ /// The time to evaluate
+ /// The value of the curve at time
+ ///
+ /// Calling the length getter on a curve is expensive to it's better to cache its length and
+ /// call instead of getting the length for every call.
+ ///
+ public float Evaluate(float t)
+ {
+ // Calling the length getter on a curve is expensive (!?) so it's better to cache its
+ // length and call Evaluate(t, length) instead of getting the length for every call to
+ // Evaluate(t)
+ return Evaluate(t, curve.length);
+ }
+
+ ///
+ /// Returns the computed hash code for this parameter.
+ ///
+ /// A computed hash code
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ int hash = 17;
+ hash = hash * 23 + curve.GetHashCode(); // Not implemented in Unity, so it'll always return the same value :(
+ return hash;
+ }
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Utils/Spline.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Utils/Spline.cs.meta
new file mode 100644
index 0000000..ca5720b
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Utils/Spline.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: c687cf9a3e8607a4b991e6d445a2f9bf
+timeCreated: 1493978176
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Utils/TargetPool.cs b/com.unity.postprocessing/PostProcessing/Runtime/Utils/TargetPool.cs
new file mode 100644
index 0000000..cf72342
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Utils/TargetPool.cs
@@ -0,0 +1,48 @@
+using System.Collections.Generic;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ class TargetPool
+ {
+ readonly List m_Pool;
+ int m_Current;
+
+ internal TargetPool()
+ {
+ m_Pool = new List();
+ Get(); // Pre-warm with a default target to avoid black frame on first frame
+ }
+
+ internal int Get()
+ {
+ int ret = Get(m_Current);
+ m_Current++;
+ return ret;
+ }
+
+ int Get(int i)
+ {
+ int ret;
+
+ if (m_Pool.Count > i)
+ {
+ ret = m_Pool[i];
+ }
+ else
+ {
+ // Avoid discontinuities
+ while (m_Pool.Count <= i)
+ m_Pool.Add(Shader.PropertyToID("_TargetPool" + i));
+
+ ret = m_Pool[i];
+ }
+
+ return ret;
+ }
+
+ internal void Reset()
+ {
+ m_Current = 0;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Utils/TargetPool.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Utils/TargetPool.cs.meta
new file mode 100644
index 0000000..994555e
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Utils/TargetPool.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 3ae5839b763bada47af0cca23c360452
+timeCreated: 1495121926
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Utils/TextureFormatUtilities.cs b/com.unity.postprocessing/PostProcessing/Runtime/Utils/TextureFormatUtilities.cs
new file mode 100644
index 0000000..fc92663
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Utils/TextureFormatUtilities.cs
@@ -0,0 +1,173 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine.Assertions;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ // Temporary code dump until the texture format refactor goes into trunk...
+
+ ///
+ /// A set of utilities to deal with texture formats.
+ ///
+ public static class TextureFormatUtilities
+ {
+ static Dictionary s_FormatAliasMap;
+ static Dictionary s_SupportedRenderTextureFormats;
+ static Dictionary s_SupportedTextureFormats;
+
+ static TextureFormatUtilities()
+ {
+ s_FormatAliasMap = new Dictionary
+ {
+ { (int)TextureFormat.Alpha8, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.ARGB4444, RenderTextureFormat.ARGB4444 },
+ { (int)TextureFormat.RGB24, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.RGBA32, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.ARGB32, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.RGB565, RenderTextureFormat.RGB565 },
+ { (int)TextureFormat.R16, RenderTextureFormat.RHalf },
+ { (int)TextureFormat.DXT1, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.DXT5, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.RGBA4444, RenderTextureFormat.ARGB4444 },
+ { (int)TextureFormat.BGRA32, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.RHalf, RenderTextureFormat.RHalf },
+ { (int)TextureFormat.RGHalf, RenderTextureFormat.RGHalf },
+ { (int)TextureFormat.RGBAHalf, RenderTextureFormat.ARGBHalf },
+ { (int)TextureFormat.RFloat, RenderTextureFormat.RFloat },
+ { (int)TextureFormat.RGFloat, RenderTextureFormat.RGFloat },
+ { (int)TextureFormat.RGBAFloat, RenderTextureFormat.ARGBFloat },
+ { (int)TextureFormat.RGB9e5Float, RenderTextureFormat.ARGBHalf },
+ { (int)TextureFormat.BC4, RenderTextureFormat.R8 },
+ { (int)TextureFormat.BC5, RenderTextureFormat.RGHalf },
+ { (int)TextureFormat.BC6H, RenderTextureFormat.ARGBHalf },
+ { (int)TextureFormat.BC7, RenderTextureFormat.ARGB32 },
+ #if !UNITY_IOS && !UNITY_TVOS
+ { (int)TextureFormat.DXT1Crunched, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.DXT5Crunched, RenderTextureFormat.ARGB32 },
+ #endif
+ { (int)TextureFormat.PVRTC_RGB2, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.PVRTC_RGBA2, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.PVRTC_RGB4, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.PVRTC_RGBA4, RenderTextureFormat.ARGB32 },
+ #if !UNITY_2018_1_OR_NEWER
+ { (int)TextureFormat.ATC_RGB4, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.ATC_RGBA8, RenderTextureFormat.ARGB32 },
+ #endif
+ { (int)TextureFormat.ETC_RGB4, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.ETC2_RGB, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.ETC2_RGBA1, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.ETC2_RGBA8, RenderTextureFormat.ARGB32 },
+ #if UNITY_2019_1_OR_NEWER
+ { (int)TextureFormat.ASTC_4x4, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.ASTC_5x5, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.ASTC_6x6, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.ASTC_8x8, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.ASTC_10x10, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.ASTC_12x12, RenderTextureFormat.ARGB32 },
+ #else
+ { (int)TextureFormat.ASTC_RGB_4x4, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.ASTC_RGB_5x5, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.ASTC_RGB_6x6, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.ASTC_RGB_8x8, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.ASTC_RGB_10x10, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.ASTC_RGB_12x12, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.ASTC_RGBA_4x4, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.ASTC_RGBA_5x5, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.ASTC_RGBA_6x6, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.ASTC_RGBA_8x8, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.ASTC_RGBA_10x10, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.ASTC_RGBA_12x12, RenderTextureFormat.ARGB32 },
+ #endif
+ #if !UNITY_2018_3_OR_NEWER
+ { (int)TextureFormat.ETC_RGB4_3DS, RenderTextureFormat.ARGB32 },
+ { (int)TextureFormat.ETC_RGBA8_3DS, RenderTextureFormat.ARGB32 }
+ #endif
+ };
+
+ // TODO: refactor the next two scopes in a generic function once we have support for enum constraints on generics
+ // In 2018.1 SystemInfo.SupportsRenderTextureFormat() generates garbage so we need to
+ // cache its calls to avoid that...
+ {
+ s_SupportedRenderTextureFormats = new Dictionary();
+ var values = Enum.GetValues(typeof(RenderTextureFormat));
+
+ foreach (var format in values)
+ {
+ if ((int)format < 0) // Safe guard, negative values are deprecated stuff
+ continue;
+
+ if (IsObsolete(format))
+ continue;
+
+ bool supported = SystemInfo.SupportsRenderTextureFormat((RenderTextureFormat)format);
+ s_SupportedRenderTextureFormats[(int)format] = supported;
+ }
+ }
+
+ // Same for TextureFormat
+ {
+ s_SupportedTextureFormats = new Dictionary();
+ var values = Enum.GetValues(typeof(TextureFormat));
+
+ foreach (var format in values)
+ {
+ if ((int)format < 0) // Crashes the runtime otherwise (!)
+ continue;
+
+ if (IsObsolete(format))
+ continue;
+
+ bool supported = SystemInfo.SupportsTextureFormat((TextureFormat)format);
+ s_SupportedTextureFormats[(int)format] = supported;
+ }
+ }
+ }
+
+ static bool IsObsolete(object value)
+ {
+ var fieldInfo = value.GetType().GetField(value.ToString());
+ var attributes = (ObsoleteAttribute[])fieldInfo.GetCustomAttributes(typeof(ObsoleteAttribute), false);
+ return attributes != null && attributes.Length > 0;
+ }
+
+ ///
+ /// Returns a compatible with the given texture's format.
+ ///
+ /// A texture to get a compatible format from
+ /// A compatible render texture format
+ public static RenderTextureFormat GetUncompressedRenderTextureFormat(Texture texture)
+ {
+ Assert.IsNotNull(texture);
+
+ if (texture is RenderTexture)
+ return (texture as RenderTexture).format;
+
+ if (texture is Texture2D)
+ {
+ var inFormat = ((Texture2D)texture).format;
+ RenderTextureFormat outFormat;
+
+ if (!s_FormatAliasMap.TryGetValue((int)inFormat, out outFormat))
+ throw new NotSupportedException("Texture format not supported");
+
+ return outFormat;
+ }
+
+ return RenderTextureFormat.Default;
+ }
+
+ internal static bool IsSupported(this RenderTextureFormat format)
+ {
+ bool supported;
+ s_SupportedRenderTextureFormats.TryGetValue((int)format, out supported);
+ return supported;
+ }
+
+ internal static bool IsSupported(this TextureFormat format)
+ {
+ bool supported;
+ s_SupportedTextureFormats.TryGetValue((int)format, out supported);
+ return supported;
+ }
+ }
+}
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Utils/TextureFormatUtilities.cs.meta b/com.unity.postprocessing/PostProcessing/Runtime/Utils/TextureFormatUtilities.cs.meta
new file mode 100644
index 0000000..cd71444
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Utils/TextureFormatUtilities.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: f8baf5b99881c054d90afcd1dffd11eb
+timeCreated: 1493127411
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.postprocessing/PostProcessing/Runtime/Utils/TextureLerper.cs b/com.unity.postprocessing/PostProcessing/Runtime/Utils/TextureLerper.cs
new file mode 100644
index 0000000..bbb7ab6
--- /dev/null
+++ b/com.unity.postprocessing/PostProcessing/Runtime/Utils/TextureLerper.cs
@@ -0,0 +1,228 @@
+using System.Collections.Generic;
+using UnityEngine.Assertions;
+
+namespace UnityEngine.Rendering.PostProcessing
+{
+ class TextureLerper
+ {
+ static TextureLerper m_Instance;
+ internal static TextureLerper instance
+ {
+ get
+ {
+ if (m_Instance == null)
+ m_Instance = new TextureLerper();
+
+ return m_Instance;
+ }
+ }
+
+ CommandBuffer m_Command;
+ PropertySheetFactory m_PropertySheets;
+ PostProcessResources m_Resources;
+
+ List m_Recycled;
+ List m_Actives;
+
+ TextureLerper()
+ {
+ m_Recycled = new List();
+ m_Actives = new List